Fix suspend below min bitrate in new API by making it possible to set min bitrate at the receive-side.

In addition to this the ramp-up tests are refactored to use a receive call instead of only a remote bitrate estimator, and to make use of BaseTest.

BUG=webrtc:4836

Review URL: https://codereview.webrtc.org/1368943002

Cr-Commit-Position: refs/heads/master@{#10087}
This commit is contained in:
stefan 2015-09-28 03:57:14 -07:00 committed by Commit bot
parent d2413e514a
commit 4fbd145dce
24 changed files with 461 additions and 645 deletions

View File

@ -85,9 +85,6 @@ class Call : public webrtc::Call, public PacketReceiver {
size_t length,
const PacketTime& packet_time);
void SetBitrateControllerConfig(
const webrtc::Call::Config::BitrateConfig& bitrate_config);
void ConfigureSync(const std::string& sync_group)
EXCLUSIVE_LOCKS_REQUIRED(receive_crit_);
@ -159,7 +156,9 @@ Call::Call(const Call::Config& config)
Trace::CreateTrace();
module_process_thread_->Start();
SetBitrateControllerConfig(config_.bitrate_config);
channel_group_->SetBweBitrates(config_.bitrate_config.min_bitrate_bps,
config_.bitrate_config.start_bitrate_bps,
config_.bitrate_config.max_bitrate_bps);
}
Call::~Call() {
@ -387,17 +386,9 @@ void Call::SetBitrateConfig(
return;
}
config_.bitrate_config = bitrate_config;
SetBitrateControllerConfig(bitrate_config);
}
void Call::SetBitrateControllerConfig(
const webrtc::Call::Config::BitrateConfig& bitrate_config) {
BitrateController* bitrate_controller =
channel_group_->GetBitrateController();
if (bitrate_config.start_bitrate_bps > 0)
bitrate_controller->SetStartBitrate(bitrate_config.start_bitrate_bps);
bitrate_controller->SetMinMaxBitrate(bitrate_config.min_bitrate_bps,
bitrate_config.max_bitrate_bps);
channel_group_->SetBweBitrates(bitrate_config.min_bitrate_bps,
bitrate_config.start_bitrate_bps,
bitrate_config.max_bitrate_bps);
}
void Call::SignalNetworkState(NetworkState state) {

View File

@ -15,7 +15,9 @@
#include <cmath>
#include "webrtc/base/checks.h"
#include "webrtc/modules/remote_bitrate_estimator/overuse_detector.h"
#include "webrtc/modules/remote_bitrate_estimator/include/remote_bitrate_estimator.h"
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
namespace webrtc {
@ -25,8 +27,9 @@ static const int64_t kLogIntervalMs = 1000;
static const double kWithinIncomingBitrateHysteresis = 1.05;
static const int64_t kMaxFeedbackIntervalMs = 1000;
AimdRateControl::AimdRateControl(uint32_t min_bitrate_bps)
: min_configured_bitrate_bps_(min_bitrate_bps),
AimdRateControl::AimdRateControl()
: min_configured_bitrate_bps_(
RemoteBitrateEstimator::kDefaultMinBitrateBps),
max_configured_bitrate_bps_(30000000),
current_bitrate_bps_(max_configured_bitrate_bps_),
avg_max_bitrate_kbps_(-1.0f),
@ -41,11 +44,11 @@ AimdRateControl::AimdRateControl(uint32_t min_bitrate_bps)
beta_(0.85f),
rtt_(kDefaultRttMs),
time_of_last_log_(-1),
in_experiment_(AdaptiveThresholdExperimentIsEnabled()) {
}
in_experiment_(AdaptiveThresholdExperimentIsEnabled()) {}
uint32_t AimdRateControl::GetMinBitrate() const {
return min_configured_bitrate_bps_;
void AimdRateControl::SetMinBitrate(int min_bitrate_bps) {
min_configured_bitrate_bps_ = min_bitrate_bps;
current_bitrate_bps_ = std::max<int>(min_bitrate_bps, current_bitrate_bps_);
}
bool AimdRateControl::ValidEstimate() const {

View File

@ -23,13 +23,13 @@ namespace webrtc {
// multiplicatively.
class AimdRateControl {
public:
explicit AimdRateControl(uint32_t min_bitrate_bps);
AimdRateControl();
virtual ~AimdRateControl() {}
// Returns true if there is a valid estimate of the incoming bitrate, false
// otherwise.
bool ValidEstimate() const;
uint32_t GetMinBitrate() const;
void SetMinBitrate(int min_bitrate_bps);
int64_t GetFeedbackInterval() const;
// Returns true if the bitrate estimate hasn't been changed for more than
// an RTT, or if the incoming_bitrate is more than 5% above the current
@ -81,8 +81,6 @@ class AimdRateControl {
int64_t rtt_;
int64_t time_of_last_log_;
bool in_experiment_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(AimdRateControl);
};
} // namespace webrtc

View File

@ -34,6 +34,7 @@ class MockRemoteBitrateEstimator : public RemoteBitrateEstimator {
// From Module.
MOCK_METHOD0(TimeUntilNextProcess, int64_t());
MOCK_METHOD0(Process, int32_t());
MOCK_METHOD1(SetMinBitrate, void(int));
};
} // namespace webrtc

View File

@ -91,6 +91,8 @@ class RemoteBitrateEstimator : public CallStatsObserver, public Module {
// Returns true if the statistics are available.
virtual bool GetStats(ReceiveBandwidthEstimatorStats* output) const = 0;
virtual void SetMinBitrate(int min_bitrate_bps) = 0;
protected:
static const int64_t kProcessIntervalMs = 500;
static const int64_t kStreamTimeOutMs = 2000;

View File

@ -89,8 +89,7 @@ bool RemoteBitrateEstimatorAbsSendTime::IsWithinClusterBounds(
RemoteBitrateEstimatorAbsSendTime::RemoteBitrateEstimatorAbsSendTime(
RemoteBitrateObserver* observer,
Clock* clock,
uint32_t min_bitrate_bps)
Clock* clock)
: crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
observer_(observer),
clock_(clock),
@ -99,7 +98,6 @@ bool RemoteBitrateEstimatorAbsSendTime::IsWithinClusterBounds(
estimator_(OverUseDetectorOptions()),
detector_(OverUseDetectorOptions()),
incoming_bitrate_(kBitrateWindowMs, 8000),
remote_rate_(min_bitrate_bps),
last_process_time_(-1),
process_interval_ms_(kProcessIntervalMs),
total_propagation_delta_ms_(0),
@ -437,4 +435,9 @@ void RemoteBitrateEstimatorAbsSendTime::UpdateStats(int propagation_delta_ms,
total_propagation_delta_ms_ =
std::max(total_propagation_delta_ms_ + propagation_delta_ms, 0);
}
void RemoteBitrateEstimatorAbsSendTime::SetMinBitrate(int min_bitrate_bps) {
CriticalSectionScoped cs(crit_sect_.get());
remote_rate_.SetMinBitrate(min_bitrate_bps);
}
} // namespace webrtc

View File

@ -66,8 +66,7 @@ struct Cluster {
class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator {
public:
RemoteBitrateEstimatorAbsSendTime(RemoteBitrateObserver* observer,
Clock* clock,
uint32_t min_bitrate_bps);
Clock* clock);
virtual ~RemoteBitrateEstimatorAbsSendTime() {}
void IncomingPacketFeedbackVector(
@ -88,6 +87,7 @@ class RemoteBitrateEstimatorAbsSendTime : public RemoteBitrateEstimator {
bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const override;
bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
void SetMinBitrate(int min_bitrate_bps) override;
private:
typedef std::map<unsigned int, int64_t> Ssrcs;

View File

@ -17,13 +17,11 @@ namespace webrtc {
class RemoteBitrateEstimatorAbsSendTimeTest :
public RemoteBitrateEstimatorTest {
public:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
RemoteBitrateEstimatorAbsSendTimeTest() {}
virtual void SetUp() {
bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime(
bitrate_observer_.get(), &clock_,
kRemoteBitrateEstimatorMinBitrateBps));
bitrate_observer_.get(), &clock_));
}
protected:
RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorAbsSendTimeTest);

View File

@ -44,11 +44,10 @@ struct RemoteBitrateEstimatorSingleStream::Detector {
RemoteBitrateEstimatorSingleStream::RemoteBitrateEstimatorSingleStream(
RemoteBitrateObserver* observer,
Clock* clock,
uint32_t min_bitrate_bps)
Clock* clock)
: clock_(clock),
incoming_bitrate_(kBitrateWindowMs, 8000),
remote_rate_(new AimdRateControl(min_bitrate_bps)),
remote_rate_(new AimdRateControl()),
observer_(observer),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
last_process_time_(-1),
@ -164,7 +163,7 @@ void RemoteBitrateEstimatorSingleStream::UpdateEstimate(int64_t now_ms) {
}
// We can't update the estimate if we don't have any active streams.
if (overuse_detectors_.empty()) {
remote_rate_.reset(new AimdRateControl(remote_rate_->GetMinBitrate()));
remote_rate_.reset(new AimdRateControl());
return;
}
double mean_noise_var = sum_var_noise /
@ -230,4 +229,9 @@ void RemoteBitrateEstimatorSingleStream::GetSsrcs(
}
}
void RemoteBitrateEstimatorSingleStream::SetMinBitrate(int min_bitrate_bps) {
CriticalSectionScoped cs(crit_sect_.get());
remote_rate_->SetMinBitrate(min_bitrate_bps);
}
} // namespace webrtc

View File

@ -24,8 +24,7 @@ namespace webrtc {
class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
public:
RemoteBitrateEstimatorSingleStream(RemoteBitrateObserver* observer,
Clock* clock,
uint32_t min_bitrate_bps);
Clock* clock);
virtual ~RemoteBitrateEstimatorSingleStream();
void IncomingPacket(int64_t arrival_time_ms,
@ -39,6 +38,7 @@ class RemoteBitrateEstimatorSingleStream : public RemoteBitrateEstimator {
bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const override;
bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
void SetMinBitrate(int min_bitrate_bps) override;
private:
struct Detector;

View File

@ -17,13 +17,11 @@ namespace webrtc {
class RemoteBitrateEstimatorSingleTest :
public RemoteBitrateEstimatorTest {
public:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
RemoteBitrateEstimatorSingleTest() {}
virtual void SetUp() {
bitrate_estimator_.reset(new RemoteBitrateEstimatorSingleStream(
bitrate_observer_.get(), &clock_,
kRemoteBitrateEstimatorMinBitrateBps));
bitrate_observer_.get(), &clock_));
}
protected:
RTC_DISALLOW_COPY_AND_ASSIGN(RemoteBitrateEstimatorSingleTest);

View File

@ -63,8 +63,6 @@ bool RemoteEstimatorProxy::GetStats(
return false;
}
void RemoteEstimatorProxy::OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) {
}
int64_t RemoteEstimatorProxy::TimeUntilNextProcess() {
int64_t now = clock_->TimeInMilliseconds();

View File

@ -45,7 +45,8 @@ class RemoteEstimatorProxy : public RemoteBitrateEstimator {
bool LatestEstimate(std::vector<unsigned int>* ssrcs,
unsigned int* bitrate_bps) const override;
bool GetStats(ReceiveBandwidthEstimatorStats* output) const override;
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override;
void OnRttUpdate(int64_t avg_rtt_ms, int64_t max_rtt_ms) override {}
void SetMinBitrate(int min_bitrate_bps) override {}
int64_t TimeUntilNextProcess() override;
int32_t Process() override;

View File

@ -69,15 +69,13 @@ RembReceiver::RembReceiver(int flow_id, bool plot)
recv_stats_(ReceiveStatistics::Create(&clock_)),
latest_estimate_bps_(-1),
last_feedback_ms_(-1),
estimator_(new RemoteBitrateEstimatorAbsSendTime(
this,
&clock_,
kRemoteBitrateEstimatorMinBitrateBps)) {
estimator_(new RemoteBitrateEstimatorAbsSendTime(this, &clock_)) {
std::stringstream ss;
ss << "Estimate_" << flow_id_ << "#1";
estimate_log_prefix_ = ss.str();
// Default RTT in RemoteRateControl is 200 ms ; 50 ms is more realistic.
estimator_->OnRttUpdate(50, 50);
estimator_->SetMinBitrate(kRemoteBitrateEstimatorMinBitrateBps);
}
RembReceiver::~RembReceiver() {

View File

@ -23,9 +23,7 @@ const int kFeedbackIntervalMs = 50;
FullBweSender::FullBweSender(int kbps, BitrateObserver* observer, Clock* clock)
: bitrate_controller_(
BitrateController::CreateBitrateController(clock, observer)),
rbe_(new RemoteBitrateEstimatorAbsSendTime(this,
clock,
1000 * kMinBitrateKbps)),
rbe_(new RemoteBitrateEstimatorAbsSendTime(this, clock)),
feedback_observer_(bitrate_controller_->CreateRtcpBandwidthObserver()),
clock_(clock),
send_time_history_(10000),
@ -36,6 +34,7 @@ FullBweSender::FullBweSender(int kbps, BitrateObserver* observer, Clock* clock)
bitrate_controller_->SetStartBitrate(1000 * kbps);
bitrate_controller_->SetMinMaxBitrate(1000 * kMinBitrateKbps,
1000 * kMaxBitrateKbps);
rbe_->SetMinBitrate(1000 * kMinBitrateKbps);
}
FullBweSender::~FullBweSender() {

View File

@ -21,8 +21,6 @@
#include "webrtc/modules/rtp_rtcp/interface/rtp_payload_registry.h"
#include "webrtc/test/rtp_file_reader.h"
const int kMinBitrateBps = 30000;
namespace flags {
DEFINE_string(extension_type,
@ -116,14 +114,14 @@ bool ParseArgsAndSetupEstimator(int argc,
if (estimator) {
switch (extension) {
case webrtc::kRtpExtensionAbsoluteSendTime: {
*estimator = new webrtc::RemoteBitrateEstimatorAbsSendTime(
observer, clock, kMinBitrateBps);
*estimator =
new webrtc::RemoteBitrateEstimatorAbsSendTime(observer, clock);
*estimator_used = "AbsoluteSendTimeRemoteBitrateEstimator";
break;
}
case webrtc::kRtpExtensionTransmissionTimeOffset: {
*estimator = new webrtc::RemoteBitrateEstimatorSingleStream(
observer, clock, kMinBitrateBps);
*estimator =
new webrtc::RemoteBitrateEstimatorSingleStream(observer, clock);
*estimator_used = "RemoteBitrateEstimator";
break;
}

View File

@ -39,6 +39,10 @@ class TransportFeedbackAdapter : public TransportFeedbackObserver,
void SetBitrateEstimator(RemoteBitrateEstimator* rbe);
RemoteBitrateEstimator* GetBitrateEstimator() const {
return bitrate_estimator_.get();
}
private:
void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) override;

View File

@ -55,8 +55,6 @@ class TestTransport : public Transport {
class RtcpFormatRembTest : public ::testing::Test {
protected:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
RtcpFormatRembTest()
: over_use_detector_options_(),
system_clock_(Clock::GetRealTimeClock()),
@ -66,10 +64,9 @@ class RtcpFormatRembTest : public ::testing::Test {
rtcp_receiver_(nullptr),
test_transport_(nullptr),
remote_bitrate_observer_(),
remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream(
&remote_bitrate_observer_,
system_clock_,
kRemoteBitrateEstimatorMinBitrateBps)) {}
remote_bitrate_estimator_(
new RemoteBitrateEstimatorSingleStream(&remote_bitrate_observer_,
system_clock_)) {}
void SetUp() override;
void TearDown() override;

View File

@ -58,16 +58,13 @@ class TestTransport : public Transport,
class RtcpReceiverTest : public ::testing::Test {
protected:
static const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
RtcpReceiverTest()
: over_use_detector_options_(),
system_clock_(1335900000),
remote_bitrate_observer_(),
remote_bitrate_estimator_(new RemoteBitrateEstimatorSingleStream(
&remote_bitrate_observer_,
&system_clock_,
kRemoteBitrateEstimatorMinBitrateBps)) {
remote_bitrate_estimator_(
new RemoteBitrateEstimatorSingleStream(&remote_bitrate_observer_,
&system_clock_)) {
test_transport_ = new TestTransport();
RtpRtcp::Configuration configuration;

View File

@ -171,9 +171,9 @@ class RtpRtcpObserver {
rtc::CriticalSection crit_;
const rtc::scoped_ptr<EventWrapper> observation_complete_;
const rtc::scoped_ptr<RtpHeaderParser> parser_;
PacketTransport send_transport_, receive_transport_;
private:
PacketTransport send_transport_, receive_transport_;
unsigned int timeout_ms_;
};
} // namespace test

View File

@ -29,8 +29,7 @@
namespace webrtc {
namespace {
static const int kMaxPacketSize = 1500;
const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 30000;
static const int64_t kPollIntervalMs = 250;
std::vector<uint32_t> GenerateSsrcs(size_t num_streams,
uint32_t ssrc_offset) {
@ -41,294 +40,298 @@ std::vector<uint32_t> GenerateSsrcs(size_t num_streams,
}
} // namespace
StreamObserver::StreamObserver(const SsrcMap& rtx_media_ssrcs,
newapi::Transport* feedback_transport,
Clock* clock)
: clock_(clock),
test_done_(EventWrapper::Create()),
rtp_parser_(RtpHeaderParser::Create()),
feedback_transport_(feedback_transport),
receive_stats_(ReceiveStatistics::Create(clock)),
payload_registry_(
new RTPPayloadRegistry(RTPPayloadStrategy::CreateStrategy(false))),
remote_bitrate_estimator_(nullptr),
RampUpTester::RampUpTester(size_t num_streams,
unsigned int start_bitrate_bps,
const std::string& extension_type,
bool rtx,
bool red)
: EndToEndTest(test::CallTest::kLongTimeoutMs),
event_(false, false),
clock_(Clock::GetRealTimeClock()),
num_streams_(num_streams),
rtx_(rtx),
red_(red),
send_stream_(nullptr),
start_bitrate_bps_(start_bitrate_bps),
start_bitrate_verified_(false),
expected_bitrate_bps_(0),
start_bitrate_bps_(0),
rtx_media_ssrcs_(rtx_media_ssrcs),
total_sent_(0),
padding_sent_(0),
rtx_media_sent_(0),
total_packets_sent_(0),
padding_packets_sent_(0),
rtx_media_packets_sent_(0),
test_start_ms_(clock_->TimeInMilliseconds()),
ramp_up_finished_ms_(0) {
// Ideally we would only have to instantiate an RtcpSender, an
// RtpHeaderParser and a RemoteBitrateEstimator here, but due to the current
// state of the RTP module we need a full module and receive statistics to
// be able to produce an RTCP with REMB.
RtpRtcp::Configuration config;
config.receive_statistics = receive_stats_.get();
feedback_transport_.Enable();
config.outgoing_transport = &feedback_transport_;
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
rtp_rtcp_->SetREMBStatus(true);
rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
packet_router_.reset(new PacketRouter());
packet_router_->AddRtpModule(rtp_rtcp_.get());
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
kAbsSendTimeExtensionId);
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransmissionTimeOffset,
kTransmissionTimeOffsetExtensionId);
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionTransportSequenceNumber,
kTransportSequenceNumberExtensionId);
payload_registry_->SetRtxPayloadType(RampUpTest::kSendRtxPayloadType,
RampUpTest::kFakeSendPayloadType);
}
StreamObserver::~StreamObserver() {
packet_router_->RemoveRtpModule(rtp_rtcp_.get());
}
void StreamObserver::set_expected_bitrate_bps(
unsigned int expected_bitrate_bps) {
rtc::CritScope lock(&crit_);
expected_bitrate_bps_ = expected_bitrate_bps;
}
void StreamObserver::set_start_bitrate_bps(unsigned int start_bitrate_bps) {
rtc::CritScope lock(&crit_);
start_bitrate_bps_ = start_bitrate_bps;
}
void StreamObserver::OnReceiveBitrateChanged(
const std::vector<unsigned int>& ssrcs, unsigned int bitrate) {
rtc::CritScope lock(&crit_);
RTC_DCHECK_GT(expected_bitrate_bps_, 0u);
if (start_bitrate_bps_ != 0) {
// For tests with an explicitly set start bitrate, verify the first
// bitrate estimate is close to the start bitrate and lower than the
// test target bitrate. This is to verify a call respects the configured
// start bitrate, but due to the BWE implementation we can't guarantee the
// first estimate really is as high as the start bitrate.
EXPECT_GT(bitrate, 0.9 * start_bitrate_bps_);
start_bitrate_bps_ = 0;
ramp_up_finished_ms_(-1),
extension_type_(extension_type),
ssrcs_(GenerateSsrcs(num_streams, 100)),
rtx_ssrcs_(GenerateSsrcs(num_streams, 200)),
poller_thread_(ThreadWrapper::CreateThread(&BitrateStatsPollingThread,
this,
"BitrateStatsPollingThread")),
sender_call_(nullptr) {
if (rtx_) {
for (size_t i = 0; i < ssrcs_.size(); ++i)
rtx_ssrc_map_[rtx_ssrcs_[i]] = ssrcs_[i];
}
if (bitrate >= expected_bitrate_bps_) {
ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
// Just trigger if there was any rtx padding packet.
if (rtx_media_ssrcs_.empty() || rtx_media_sent_ > 0) {
TriggerTestDone();
poller_thread_->Start();
}
RampUpTester::~RampUpTester() {
event_.Set();
poller_thread_->Stop();
}
Call::Config RampUpTester::GetSenderCallConfig() {
Call::Config call_config;
if (start_bitrate_bps_ != 0) {
call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps_;
}
call_config.bitrate_config.min_bitrate_bps = 10000;
return call_config;
}
void RampUpTester::OnStreamsCreated(
VideoSendStream* send_stream,
const std::vector<VideoReceiveStream*>& receive_streams) {
send_stream_ = send_stream;
}
size_t RampUpTester::GetNumStreams() const {
return num_streams_;
}
void RampUpTester::ModifyConfigs(
VideoSendStream::Config* send_config,
std::vector<VideoReceiveStream::Config>* receive_configs,
VideoEncoderConfig* encoder_config) {
send_config->suspend_below_min_bitrate = true;
if (num_streams_ == 1) {
encoder_config->streams[0].target_bitrate_bps =
encoder_config->streams[0].max_bitrate_bps = 2000000;
// For single stream rampup until 1mbps
expected_bitrate_bps_ = kSingleStreamTargetBps;
} else {
// For multi stream rampup until all streams are being sent. That means
// enough birate to send all the target streams plus the min bitrate of
// the last one.
expected_bitrate_bps_ = encoder_config->streams.back().min_bitrate_bps;
for (size_t i = 0; i < encoder_config->streams.size() - 1; ++i) {
expected_bitrate_bps_ += encoder_config->streams[i].target_bitrate_bps;
}
}
rtp_rtcp_->SetREMBData(bitrate, ssrcs);
rtp_rtcp_->Process();
}
bool StreamObserver::SendRtp(const uint8_t* packet, size_t length) {
rtc::CritScope lock(&crit_);
RTPHeader header;
EXPECT_TRUE(rtp_parser_->Parse(packet, length, &header));
receive_stats_->IncomingPacket(header, length, false);
payload_registry_->SetIncomingPayloadType(header);
RTC_DCHECK(remote_bitrate_estimator_ != nullptr);
remote_bitrate_estimator_->IncomingPacket(
clock_->TimeInMilliseconds(), length - header.headerLength, header, true);
if (remote_bitrate_estimator_->TimeUntilNextProcess() <= 0) {
remote_bitrate_estimator_->Process();
rtp_rtcp_->Process();
}
total_sent_ += length;
padding_sent_ += header.paddingLength;
++total_packets_sent_;
if (header.paddingLength > 0)
++padding_packets_sent_;
// Handle RTX retransmission, but only for non-padding-only packets.
if (rtx_media_ssrcs_.find(header.ssrc) != rtx_media_ssrcs_.end() &&
header.headerLength + header.paddingLength != length) {
rtx_media_sent_ += length - header.headerLength - header.paddingLength;
if (header.paddingLength == 0)
++rtx_media_packets_sent_;
uint8_t restored_packet[kMaxPacketSize];
uint8_t* restored_packet_ptr = restored_packet;
size_t restored_length = length;
EXPECT_TRUE(payload_registry_->RestoreOriginalPacket(
&restored_packet_ptr, packet, &restored_length,
rtx_media_ssrcs_[header.ssrc], header));
EXPECT_TRUE(
rtp_parser_->Parse(restored_packet_ptr, restored_length, &header));
send_config->rtp.extensions.clear();
bool remb;
if (extension_type_ == RtpExtension::kAbsSendTime) {
remb = true;
send_config->rtp.extensions.push_back(
RtpExtension(extension_type_.c_str(), kAbsSendTimeExtensionId));
} else if (extension_type_ == RtpExtension::kTransportSequenceNumber) {
remb = false;
send_config->rtp.extensions.push_back(RtpExtension(
extension_type_.c_str(), kTransportSequenceNumberExtensionId));
} else {
rtp_rtcp_->SetRemoteSSRC(header.ssrc);
remb = true;
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 = ssrcs_;
if (rtx_) {
send_config->rtp.rtx.payload_type = test::CallTest::kSendRtxPayloadType;
send_config->rtp.rtx.ssrcs = rtx_ssrcs_;
}
if (red_) {
send_config->rtp.fec.ulpfec_payload_type =
test::CallTest::kUlpfecPayloadType;
send_config->rtp.fec.red_payload_type = test::CallTest::kRedPayloadType;
}
size_t i = 0;
for (VideoReceiveStream::Config& recv_config : *receive_configs) {
recv_config.rtp.remb = remb;
recv_config.rtp.extensions = send_config->rtp.extensions;
recv_config.rtp.remote_ssrc = ssrcs_[i];
recv_config.rtp.nack.rtp_history_ms = send_config->rtp.nack.rtp_history_ms;
if (red_) {
recv_config.rtp.fec.red_payload_type =
send_config->rtp.fec.red_payload_type;
recv_config.rtp.fec.ulpfec_payload_type =
send_config->rtp.fec.ulpfec_payload_type;
}
if (rtx_) {
recv_config.rtp.rtx[send_config->encoder_settings.payload_type].ssrc =
rtx_ssrcs_[i];
recv_config.rtp.rtx[send_config->encoder_settings.payload_type]
.payload_type = send_config->rtp.rtx.payload_type;
}
++i;
}
return true;
}
bool StreamObserver::SendRtcp(const uint8_t* packet, size_t length) {
return true;
void RampUpTester::OnCallsCreated(Call* sender_call, Call* receiver_call) {
sender_call_ = sender_call;
}
EventTypeWrapper StreamObserver::Wait() {
return test_done_->Wait(test::CallTest::kLongTimeoutMs);
bool RampUpTester::BitrateStatsPollingThread(void* obj) {
return static_cast<RampUpTester*>(obj)->PollStats();
}
void StreamObserver::SetRemoteBitrateEstimator(RemoteBitrateEstimator* rbe) {
remote_bitrate_estimator_.reset(rbe);
bool RampUpTester::PollStats() {
if (sender_call_) {
Call::Stats stats = sender_call_->GetStats();
RTC_DCHECK_GT(expected_bitrate_bps_, 0);
if (!start_bitrate_verified_ && start_bitrate_bps_ != 0) {
// For tests with an explicitly set start bitrate, verify the first
// bitrate estimate is close to the start bitrate and lower than the
// test target bitrate. This is to verify a call respects the configured
// start bitrate, but due to the BWE implementation we can't guarantee the
// first estimate really is as high as the start bitrate.
EXPECT_GT(stats.send_bandwidth_bps, 0.9 * start_bitrate_bps_);
start_bitrate_verified_ = true;
}
if (stats.send_bandwidth_bps >= expected_bitrate_bps_) {
ramp_up_finished_ms_ = clock_->TimeInMilliseconds();
observation_complete_->Set();
}
}
return !event_.Wait(kPollIntervalMs);
}
PacketRouter* StreamObserver::GetPacketRouter() {
return packet_router_.get();
}
void StreamObserver::ReportResult(const std::string& measurement,
size_t value,
const std::string& units) {
void RampUpTester::ReportResult(const std::string& measurement,
size_t value,
const std::string& units) const {
webrtc::test::PrintResult(
measurement, "",
::testing::UnitTest::GetInstance()->current_test_info()->name(),
value, units, false);
}
void StreamObserver::TriggerTestDone() EXCLUSIVE_LOCKS_REQUIRED(crit_) {
ReportResult("ramp-up-total-sent", total_sent_, "bytes");
ReportResult("ramp-up-padding-sent", padding_sent_, "bytes");
ReportResult("ramp-up-rtx-media-sent", rtx_media_sent_, "bytes");
ReportResult("ramp-up-total-packets-sent", total_packets_sent_, "packets");
ReportResult("ramp-up-padding-packets-sent",
padding_packets_sent_,
"packets");
ReportResult("ramp-up-rtx-packets-sent",
rtx_media_packets_sent_,
"packets");
ReportResult("ramp-up-time",
ramp_up_finished_ms_ - test_start_ms_,
"milliseconds");
test_done_->Set();
void RampUpTester::GetStats(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();
}
LowRateStreamObserver::LowRateStreamObserver(
newapi::Transport* feedback_transport,
Clock* clock,
size_t number_of_streams,
bool rtx_used)
: clock_(clock),
number_of_streams_(number_of_streams),
rtx_used_(rtx_used),
test_done_(EventWrapper::Create()),
rtp_parser_(RtpHeaderParser::Create()),
feedback_transport_(feedback_transport),
receive_stats_(ReceiveStatistics::Create(clock)),
send_stream_(nullptr),
void RampUpTester::TriggerTestDone() {
VideoSendStream::Stats send_stats = send_stream_->GetStats();
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 : ssrcs_) {
GetStats(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 : rtx_ssrcs_) {
GetStats(send_stats.substreams[rtx_ssrc], &total_packets_sent, &total_sent,
&padding_sent, &media_sent);
}
ReportResult("ramp-up-total-packets-sent", total_packets_sent, "packets");
ReportResult("ramp-up-total-sent", total_sent, "bytes");
ReportResult("ramp-up-media-sent", media_sent, "bytes");
ReportResult("ramp-up-padding-sent", padding_sent, "bytes");
ReportResult("ramp-up-rtx-total-packets-sent", rtx_total_packets_sent,
"packets");
ReportResult("ramp-up-rtx-total-sent", rtx_total_sent, "bytes");
ReportResult("ramp-up-rtx-media-sent", rtx_media_sent, "bytes");
ReportResult("ramp-up-rtx-padding-sent", rtx_padding_sent, "bytes");
if (ramp_up_finished_ms_ >= 0) {
ReportResult("ramp-up-time", ramp_up_finished_ms_ - test_start_ms_,
"milliseconds");
}
}
void RampUpTester::PerformTest() {
if (Wait() != kEventSignaled) {
printf("Timed out while waiting for ramp-up to complete.");
return;
}
TriggerTestDone();
}
RampUpDownUpTester::RampUpDownUpTester(size_t num_streams,
unsigned int start_bitrate_bps,
const std::string& extension_type,
bool rtx,
bool red)
: RampUpTester(num_streams, start_bitrate_bps, extension_type, rtx, red),
test_state_(kFirstRampup),
state_start_ms_(clock_->TimeInMilliseconds()),
interval_start_ms_(state_start_ms_),
last_remb_bps_(0),
sent_bytes_(0),
total_overuse_bytes_(0),
suspended_in_stats_(false) {
RtpRtcp::Configuration config;
config.receive_statistics = receive_stats_.get();
feedback_transport_.Enable();
config.outgoing_transport = &feedback_transport_;
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(config));
rtp_rtcp_->SetREMBStatus(true);
rtp_rtcp_->SetRTCPStatus(kRtcpNonCompound);
rtp_parser_->RegisterRtpHeaderExtension(kRtpExtensionAbsoluteSendTime,
kAbsSendTimeExtensionId);
const uint32_t kRemoteBitrateEstimatorMinBitrateBps = 10000;
remote_bitrate_estimator_.reset(new RemoteBitrateEstimatorAbsSendTime(
this, clock, kRemoteBitrateEstimatorMinBitrateBps));
interval_start_ms_(clock_->TimeInMilliseconds()),
sent_bytes_(0) {
forward_transport_config_.link_capacity_kbps =
kHighBandwidthLimitBps / 1000;
forward_transport_config_.queue_length_packets = 100; // Something large.
test::DirectTransport::SetConfig(forward_transport_config_);
test::DirectTransport::SetReceiver(this);
send_transport_.SetConfig(forward_transport_config_);
}
void LowRateStreamObserver::SetSendStream(VideoSendStream* send_stream) {
rtc::CritScope lock(&crit_);
send_stream_ = send_stream;
}
RampUpDownUpTester::~RampUpDownUpTester() {}
void LowRateStreamObserver::OnReceiveBitrateChanged(
const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) {
rtc::CritScope lock(&crit_);
rtp_rtcp_->SetREMBData(bitrate, ssrcs);
rtp_rtcp_->Process();
last_remb_bps_ = bitrate;
}
bool LowRateStreamObserver::SendRtp(const uint8_t* data, size_t length) {
rtc::CritScope lock(&crit_);
sent_bytes_ += length;
int64_t now_ms = clock_->TimeInMilliseconds();
if (now_ms > interval_start_ms_ + 1000) { // Let at least 1 second pass.
// Verify that the send rate was about right.
unsigned int average_rate_bps = static_cast<unsigned int>(sent_bytes_) *
8 * 1000 / (now_ms - interval_start_ms_);
// TODO(holmer): Why is this failing?
// EXPECT_LT(average_rate_bps, last_remb_bps_ * 1.1);
if (average_rate_bps > last_remb_bps_ * 1.1) {
total_overuse_bytes_ +=
sent_bytes_ -
last_remb_bps_ / 8 * (now_ms - interval_start_ms_) / 1000;
bool RampUpDownUpTester::PollStats() {
if (send_stream_) {
webrtc::VideoSendStream::Stats stats = send_stream_->GetStats();
int transmit_bitrate_bps = 0;
for (auto it : stats.substreams) {
transmit_bitrate_bps += it.second.total_bitrate_bps;
}
EvolveTestState(average_rate_bps);
interval_start_ms_ = now_ms;
sent_bytes_ = 0;
EvolveTestState(transmit_bitrate_bps, stats.suspended);
}
return test::DirectTransport::SendRtp(data, length);
return !event_.Wait(kPollIntervalMs);
}
PacketReceiver::DeliveryStatus LowRateStreamObserver::DeliverPacket(
MediaType media_type,
const uint8_t* packet,
size_t length,
const PacketTime& packet_time) {
rtc::CritScope lock(&crit_);
RTPHeader header;
EXPECT_TRUE(rtp_parser_->Parse(packet, length, &header));
receive_stats_->IncomingPacket(header, length, false);
remote_bitrate_estimator_->IncomingPacket(
clock_->TimeInMilliseconds(), length - header.headerLength, header, true);
if (remote_bitrate_estimator_->TimeUntilNextProcess() <= 0) {
remote_bitrate_estimator_->Process();
}
suspended_in_stats_ = send_stream_->GetStats().suspended;
return DELIVERY_OK;
Call::Config RampUpDownUpTester::GetReceiverCallConfig() {
Call::Config config;
config.bitrate_config.min_bitrate_bps = 10000;
return config;
}
bool LowRateStreamObserver::SendRtcp(const uint8_t* packet, size_t length) {
return true;
}
std::string LowRateStreamObserver::GetModifierString() {
std::string RampUpDownUpTester::GetModifierString() const {
std::string str("_");
char temp_str[5];
sprintf(temp_str, "%i",
static_cast<int>(number_of_streams_));
sprintf(temp_str, "%i", static_cast<int>(num_streams_));
str += std::string(temp_str);
str += "stream";
str += (number_of_streams_ > 1 ? "s" : "");
str += (num_streams_ > 1 ? "s" : "");
str += "_";
str += (rtx_used_ ? "" : "no");
str += (rtx_ ? "" : "no");
str += "rtx";
return str;
}
void LowRateStreamObserver::EvolveTestState(unsigned int bitrate_bps) {
void RampUpDownUpTester::EvolveTestState(int bitrate_bps, bool suspended) {
int64_t now = clock_->TimeInMilliseconds();
rtc::CritScope lock(&crit_);
RTC_DCHECK(send_stream_ != nullptr);
switch (test_state_) {
case kFirstRampup: {
EXPECT_FALSE(suspended_in_stats_);
EXPECT_FALSE(suspended);
if (bitrate_bps > kExpectedHighBitrateBps) {
// The first ramp-up has reached the target bitrate. Change the
// channel limit, and move to the next test state.
forward_transport_config_.link_capacity_kbps =
kLowBandwidthLimitBps / 1000;
test::DirectTransport::SetConfig(forward_transport_config_);
send_transport_.SetConfig(forward_transport_config_);
test_state_ = kLowRate;
webrtc::test::PrintResult("ramp_up_down_up",
GetModifierString(),
@ -343,12 +346,12 @@ void LowRateStreamObserver::EvolveTestState(unsigned int bitrate_bps) {
break;
}
case kLowRate: {
if (bitrate_bps < kExpectedLowBitrateBps && suspended_in_stats_) {
if (bitrate_bps < kExpectedLowBitrateBps && suspended) {
// The ramp-down was successful. Change the channel limit back to a
// high value, and move to the next test state.
forward_transport_config_.link_capacity_kbps =
kHighBandwidthLimitBps / 1000;
test::DirectTransport::SetConfig(forward_transport_config_);
send_transport_.SetConfig(forward_transport_config_);
test_state_ = kSecondRampup;
webrtc::test::PrintResult("ramp_up_down_up",
GetModifierString(),
@ -363,299 +366,135 @@ void LowRateStreamObserver::EvolveTestState(unsigned int bitrate_bps) {
break;
}
case kSecondRampup: {
if (bitrate_bps > kExpectedHighBitrateBps && !suspended_in_stats_) {
if (bitrate_bps > kExpectedHighBitrateBps && !suspended) {
webrtc::test::PrintResult("ramp_up_down_up",
GetModifierString(),
"second_rampup",
now - state_start_ms_,
"ms",
false);
webrtc::test::PrintResult("ramp_up_down_up",
GetModifierString(),
"total_overuse",
total_overuse_bytes_,
"bytes",
false);
test_done_->Set();
observation_complete_->Set();
}
break;
}
}
}
EventTypeWrapper LowRateStreamObserver::Wait() {
return test_done_->Wait(test::CallTest::kLongTimeoutMs);
}
class SendBitrateAdapter {
class RampUpTest : public test::CallTest {
public:
static const int64_t kPollIntervalMs = 250;
RampUpTest() {}
SendBitrateAdapter(const Call& call,
const std::vector<uint32_t>& ssrcs,
RemoteBitrateObserver* bitrate_observer)
: event_(false, false),
call_(call),
ssrcs_(ssrcs),
bitrate_observer_(bitrate_observer) {
RTC_DCHECK(bitrate_observer != nullptr);
poller_thread_ = ThreadWrapper::CreateThread(&SendBitrateAdapterThread,
this, "SendBitratePoller");
bool thread_start_ok = poller_thread_->Start();
RTC_DCHECK(thread_start_ok);
virtual ~RampUpTest() {
EXPECT_EQ(nullptr, send_stream_);
EXPECT_TRUE(receive_streams_.empty());
}
virtual ~SendBitrateAdapter() {
event_.Set();
poller_thread_->Stop();
}
private:
static bool SendBitrateAdapterThread(void* obj) {
return static_cast<SendBitrateAdapter*>(obj)->PollStats();
}
bool PollStats() {
Call::Stats stats = call_.GetStats();
bitrate_observer_->OnReceiveBitrateChanged(ssrcs_,
stats.send_bandwidth_bps);
return !event_.Wait(kPollIntervalMs);
}
rtc::Event event_;
rtc::scoped_ptr<ThreadWrapper> poller_thread_;
const Call& call_;
const std::vector<uint32_t> ssrcs_;
RemoteBitrateObserver* const bitrate_observer_;
};
void RampUpTest::RunRampUpTest(size_t num_streams,
unsigned int start_bitrate_bps,
const std::string& extension_type,
bool rtx,
bool red) {
std::vector<uint32_t> ssrcs(GenerateSsrcs(num_streams, 100));
std::vector<uint32_t> rtx_ssrcs(GenerateSsrcs(num_streams, 200));
StreamObserver::SsrcMap rtx_ssrc_map;
if (rtx) {
for (size_t i = 0; i < ssrcs.size(); ++i)
rtx_ssrc_map[rtx_ssrcs[i]] = ssrcs[i];
}
test::DirectTransport receiver_transport;
StreamObserver stream_observer(rtx_ssrc_map, &receiver_transport,
Clock::GetRealTimeClock());
CreateSendConfig(num_streams, &stream_observer);
send_config_.rtp.extensions.clear();
rtc::scoped_ptr<SendBitrateAdapter> send_bitrate_adapter_;
if (extension_type == RtpExtension::kAbsSendTime) {
stream_observer.SetRemoteBitrateEstimator(
new RemoteBitrateEstimatorAbsSendTime(
&stream_observer, Clock::GetRealTimeClock(),
kRemoteBitrateEstimatorMinBitrateBps));
send_config_.rtp.extensions.push_back(RtpExtension(
extension_type.c_str(), kAbsSendTimeExtensionId));
} else if (extension_type == RtpExtension::kTransportSequenceNumber) {
stream_observer.SetRemoteBitrateEstimator(new RemoteEstimatorProxy(
Clock::GetRealTimeClock(), stream_observer.GetPacketRouter()));
send_config_.rtp.extensions.push_back(RtpExtension(
extension_type.c_str(), kTransportSequenceNumberExtensionId));
} else {
stream_observer.SetRemoteBitrateEstimator(
new RemoteBitrateEstimatorSingleStream(
&stream_observer, Clock::GetRealTimeClock(),
kRemoteBitrateEstimatorMinBitrateBps));
send_config_.rtp.extensions.push_back(RtpExtension(
extension_type.c_str(), kTransmissionTimeOffsetExtensionId));
}
Call::Config call_config;
if (start_bitrate_bps != 0) {
call_config.bitrate_config.start_bitrate_bps = start_bitrate_bps;
stream_observer.set_start_bitrate_bps(start_bitrate_bps);
}
CreateSenderCall(call_config);
receiver_transport.SetReceiver(sender_call_->Receiver());
if (num_streams == 1) {
encoder_config_.streams[0].target_bitrate_bps = 2000000;
encoder_config_.streams[0].max_bitrate_bps = 2000000;
}
send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
send_config_.rtp.ssrcs = ssrcs;
if (rtx) {
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
send_config_.rtp.rtx.ssrcs = rtx_ssrcs;
}
if (red) {
send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
send_config_.rtp.fec.red_payload_type = kRedPayloadType;
}
if (num_streams == 1) {
// For single stream rampup until 1mbps
stream_observer.set_expected_bitrate_bps(kSingleStreamTargetBps);
} else {
// For multi stream rampup until all streams are being sent. That means
// enough birate to send all the target streams plus the min bitrate of
// the last one.
int expected_bitrate_bps = encoder_config_.streams.back().min_bitrate_bps;
for (size_t i = 0; i < encoder_config_.streams.size() - 1; ++i) {
expected_bitrate_bps += encoder_config_.streams[i].target_bitrate_bps;
}
stream_observer.set_expected_bitrate_bps(expected_bitrate_bps);
}
CreateStreams();
CreateFrameGeneratorCapturer();
if (extension_type == RtpExtension::kTransportSequenceNumber) {
send_bitrate_adapter_.reset(
new SendBitrateAdapter(*sender_call_.get(), ssrcs, &stream_observer));
}
Start();
EXPECT_EQ(kEventSignaled, stream_observer.Wait());
// Destroy the SendBitrateAdapter (if any) to stop the poller thread in it,
// otherwise we might get a data race with the destruction of the call.
send_bitrate_adapter_.reset();
Stop();
DestroyStreams();
}
void RampUpTest::RunRampUpDownUpTest(size_t number_of_streams,
bool rtx,
bool red) {
test::DirectTransport receiver_transport;
LowRateStreamObserver stream_observer(
&receiver_transport, Clock::GetRealTimeClock(), number_of_streams, rtx);
Call::Config call_config;
call_config.bitrate_config.start_bitrate_bps = 60000;
CreateSenderCall(call_config);
receiver_transport.SetReceiver(sender_call_->Receiver());
CreateSendConfig(number_of_streams, &stream_observer);
send_config_.rtp.nack.rtp_history_ms = kNackRtpHistoryMs;
send_config_.rtp.extensions.push_back(RtpExtension(
RtpExtension::kAbsSendTime, kAbsSendTimeExtensionId));
send_config_.suspend_below_min_bitrate = true;
if (rtx) {
send_config_.rtp.rtx.payload_type = kSendRtxPayloadType;
send_config_.rtp.rtx.ssrcs = GenerateSsrcs(number_of_streams, 200);
}
if (red) {
send_config_.rtp.fec.ulpfec_payload_type = kUlpfecPayloadType;
send_config_.rtp.fec.red_payload_type = kRedPayloadType;
}
CreateStreams();
stream_observer.SetSendStream(send_stream_);
CreateFrameGeneratorCapturer();
Start();
EXPECT_EQ(kEventSignaled, stream_observer.Wait());
Stop();
DestroyStreams();
}
TEST_F(RampUpTest, SingleStream) {
RunRampUpTest(1, 0, RtpExtension::kTOffset, false, false);
RampUpTester test(1, 0, RtpExtension::kTOffset, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, Simulcast) {
RunRampUpTest(3, 0, RtpExtension::kTOffset, false, false);
RampUpTester test(3, 0, RtpExtension::kTOffset, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, SimulcastWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kTOffset, true, false);
RampUpTester test(3, 0, RtpExtension::kTOffset, true, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, SimulcastByRedWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kTOffset, true, true);
RampUpTester test(3, 0, RtpExtension::kTOffset, true, true);
RunBaseTest(&test);
}
TEST_F(RampUpTest, SingleStreamWithHighStartBitrate) {
RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset, false,
false);
RampUpTester test(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kTOffset,
false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpOneStream) {
RunRampUpDownUpTest(1, false, false);
RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpThreeStreams) {
RunRampUpDownUpTest(3, false, false);
RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpOneStreamRtx) {
RunRampUpDownUpTest(1, true, false);
RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, true, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpThreeStreamsRtx) {
RunRampUpDownUpTest(3, true, false);
RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, true, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpOneStreamByRedRtx) {
RunRampUpDownUpTest(1, true, true);
RampUpDownUpTester test(1, 60000, RtpExtension::kAbsSendTime, true, true);
RunBaseTest(&test);
}
TEST_F(RampUpTest, UpDownUpThreeStreamsByRedRtx) {
RunRampUpDownUpTest(3, true, true);
RampUpDownUpTester test(3, 60000, RtpExtension::kAbsSendTime, true, true);
RunBaseTest(&test);
}
TEST_F(RampUpTest, AbsSendTimeSingleStream) {
RunRampUpTest(1, 0, RtpExtension::kAbsSendTime, false, false);
RampUpTester test(1, 0, RtpExtension::kAbsSendTime, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, AbsSendTimeSimulcast) {
RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, false, false);
RampUpTester test(3, 0, RtpExtension::kAbsSendTime, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, AbsSendTimeSimulcastWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, false);
RampUpTester test(3, 0, RtpExtension::kAbsSendTime, true, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, AbsSendTimeSimulcastByRedWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kAbsSendTime, true, true);
RampUpTester test(3, 0, RtpExtension::kAbsSendTime, true, true);
RunBaseTest(&test);
}
TEST_F(RampUpTest, AbsSendTimeSingleStreamWithHighStartBitrate) {
RunRampUpTest(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
false, false);
RampUpTester test(1, 0.9 * kSingleStreamTargetBps, RtpExtension::kAbsSendTime,
false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, TransportSequenceNumberSingleStream) {
RunRampUpTest(1, 0, RtpExtension::kTransportSequenceNumber, false, false);
RampUpTester test(1, 0, RtpExtension::kTransportSequenceNumber, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, TransportSequenceNumberSimulcast) {
RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, false, false);
RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, false, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, TransportSequenceNumberSimulcastWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, false);
RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, true, false);
RunBaseTest(&test);
}
TEST_F(RampUpTest, TransportSequenceNumberSimulcastByRedWithRtx) {
RunRampUpTest(3, 0, RtpExtension::kTransportSequenceNumber, true, true);
RampUpTester test(3, 0, RtpExtension::kTransportSequenceNumber, true, true);
RunBaseTest(&test);
}
TEST_F(RampUpTest, TransportSequenceNumberSingleStreamWithHighStartBitrate) {
RunRampUpTest(1, 0.9 * kSingleStreamTargetBps,
RtpExtension::kTransportSequenceNumber, false, false);
RampUpTester test(1, 0.9 * kSingleStreamTargetBps,
RtpExtension::kTransportSequenceNumber, false, false);
RunBaseTest(&test);
}
} // namespace webrtc

View File

@ -36,133 +36,97 @@ class RtpHeaderParser;
class RTPPayloadRegistry;
class RtpRtcp;
class StreamObserver : public newapi::Transport, public RemoteBitrateObserver {
class RampUpTester : public test::EndToEndTest {
public:
typedef std::map<uint32_t, int> BytesSentMap;
typedef std::map<uint32_t, uint32_t> SsrcMap;
StreamObserver(const SsrcMap& rtx_media_ssrcs,
newapi::Transport* feedback_transport,
Clock* clock);
virtual ~StreamObserver();
RampUpTester(size_t num_streams,
unsigned int start_bitrate_bps,
const std::string& extension_type,
bool rtx,
bool red);
~RampUpTester() override;
void set_expected_bitrate_bps(unsigned int expected_bitrate_bps);
void PerformTest() override;
void set_start_bitrate_bps(unsigned int start_bitrate_bps);
protected:
virtual bool PollStats();
void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate) override;
void GetStats(const VideoSendStream::StreamStats& stream,
size_t* total_packets_sent,
size_t* total_sent,
size_t* padding_sent,
size_t* media_sent) const;
bool SendRtp(const uint8_t* packet, size_t length) override;
bool SendRtcp(const uint8_t* packet, size_t length) override;
EventTypeWrapper Wait();
void SetRemoteBitrateEstimator(RemoteBitrateEstimator* rbe);
PacketRouter* GetPacketRouter();
private:
void ReportResult(const std::string& measurement,
size_t value,
const std::string& units);
void TriggerTestDone() EXCLUSIVE_LOCKS_REQUIRED(crit_);
const std::string& units) const;
void TriggerTestDone();
rtc::Event event_;
Clock* const clock_;
const rtc::scoped_ptr<EventWrapper> test_done_;
const rtc::scoped_ptr<RtpHeaderParser> rtp_parser_;
rtc::scoped_ptr<RtpRtcp> rtp_rtcp_;
rtc::scoped_ptr<PacketRouter> packet_router_;
internal::TransportAdapter feedback_transport_;
const rtc::scoped_ptr<ReceiveStatistics> receive_stats_;
const rtc::scoped_ptr<RTPPayloadRegistry> payload_registry_;
rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
rtc::CriticalSection crit_;
unsigned int expected_bitrate_bps_ GUARDED_BY(crit_);
unsigned int start_bitrate_bps_ GUARDED_BY(crit_);
SsrcMap rtx_media_ssrcs_ GUARDED_BY(crit_);
size_t total_sent_ GUARDED_BY(crit_);
size_t padding_sent_ GUARDED_BY(crit_);
size_t rtx_media_sent_ GUARDED_BY(crit_);
int total_packets_sent_ GUARDED_BY(crit_);
int padding_packets_sent_ GUARDED_BY(crit_);
int rtx_media_packets_sent_ GUARDED_BY(crit_);
int64_t test_start_ms_ GUARDED_BY(crit_);
int64_t ramp_up_finished_ms_ GUARDED_BY(crit_);
};
class LowRateStreamObserver : public test::DirectTransport,
public RemoteBitrateObserver,
public PacketReceiver {
public:
LowRateStreamObserver(newapi::Transport* feedback_transport,
Clock* clock,
size_t number_of_streams,
bool rtx_used);
virtual void SetSendStream(VideoSendStream* send_stream);
virtual void OnReceiveBitrateChanged(const std::vector<unsigned int>& ssrcs,
unsigned int bitrate);
bool SendRtp(const uint8_t* data, size_t length) override;
DeliveryStatus DeliverPacket(MediaType media_type,
const uint8_t* packet,
size_t length,
const PacketTime& packet_time) override;
bool SendRtcp(const uint8_t* packet, size_t length) override;
// Produces a string similar to "1stream_nortx", depending on the values of
// number_of_streams_ and rtx_used_;
std::string GetModifierString();
// This method defines the state machine for the ramp up-down-up test.
void EvolveTestState(unsigned int bitrate_bps);
EventTypeWrapper Wait();
const size_t num_streams_;
const bool rtx_;
const bool red_;
VideoSendStream* send_stream_;
private:
static const unsigned int kHighBandwidthLimitBps = 80000;
static const unsigned int kExpectedHighBitrateBps = 60000;
static const unsigned int kLowBandwidthLimitBps = 20000;
static const unsigned int kExpectedLowBitrateBps = 20000;
enum TestStates { kFirstRampup, kLowRate, kSecondRampup };
typedef std::map<uint32_t, uint32_t> SsrcMap;
Clock* const clock_;
const size_t number_of_streams_;
const bool rtx_used_;
const rtc::scoped_ptr<EventWrapper> test_done_;
const rtc::scoped_ptr<RtpHeaderParser> rtp_parser_;
const rtc::scoped_ptr<RTPPayloadRegistry> payload_registry_;
rtc::scoped_ptr<RtpRtcp> rtp_rtcp_;
internal::TransportAdapter feedback_transport_;
const rtc::scoped_ptr<ReceiveStatistics> receive_stats_;
rtc::scoped_ptr<RemoteBitrateEstimator> remote_bitrate_estimator_;
Call::Config GetSenderCallConfig() override;
void OnStreamsCreated(
VideoSendStream* send_stream,
const std::vector<VideoReceiveStream*>& receive_streams) override;
size_t GetNumStreams() const;
void ModifyConfigs(VideoSendStream::Config* send_config,
std::vector<VideoReceiveStream::Config>* receive_configs,
VideoEncoderConfig* encoder_config) override;
void OnCallsCreated(Call* sender_call, Call* receiver_call) override;
rtc::CriticalSection crit_;
VideoSendStream* send_stream_ GUARDED_BY(crit_);
FakeNetworkPipe::Config forward_transport_config_ GUARDED_BY(crit_);
TestStates test_state_ GUARDED_BY(crit_);
int64_t state_start_ms_ GUARDED_BY(crit_);
int64_t interval_start_ms_ GUARDED_BY(crit_);
unsigned int last_remb_bps_ GUARDED_BY(crit_);
size_t sent_bytes_ GUARDED_BY(crit_);
size_t total_overuse_bytes_ GUARDED_BY(crit_);
bool suspended_in_stats_ GUARDED_BY(crit_);
static bool BitrateStatsPollingThread(void* obj);
const int start_bitrate_bps_;
bool start_bitrate_verified_;
int expected_bitrate_bps_;
int64_t test_start_ms_;
int64_t ramp_up_finished_ms_;
const std::string extension_type_;
std::vector<uint32_t> ssrcs_;
std::vector<uint32_t> rtx_ssrcs_;
SsrcMap rtx_ssrc_map_;
rtc::scoped_ptr<ThreadWrapper> poller_thread_;
Call* sender_call_;
};
class RampUpTest : public test::CallTest {
protected:
void RunRampUpTest(size_t num_streams,
class RampUpDownUpTester : public RampUpTester {
public:
RampUpDownUpTester(size_t num_streams,
unsigned int start_bitrate_bps,
const std::string& extension_type,
bool rtx,
bool red);
~RampUpDownUpTester() override;
void RunRampUpDownUpTest(size_t number_of_streams, bool rtx, bool red);
protected:
bool PollStats() override;
private:
static const int kHighBandwidthLimitBps = 80000;
static const int kExpectedHighBitrateBps = 60000;
static const int kLowBandwidthLimitBps = 20000;
static const int kExpectedLowBitrateBps = 20000;
enum TestStates { kFirstRampup, kLowRate, kSecondRampup };
Call::Config GetReceiverCallConfig() override;
std::string GetModifierString() const;
void EvolveTestState(int bitrate_bps, bool suspended);
FakeNetworkPipe::Config forward_transport_config_;
TestStates test_state_;
int64_t state_start_ms_;
int64_t interval_start_ms_;
int sent_bytes_;
};
} // namespace webrtc
#endif // WEBRTC_VIDEO_RAMPUP_TESTS_H_

View File

@ -43,12 +43,10 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator {
: observer_(observer),
clock_(clock),
crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps),
rbe_(new RemoteBitrateEstimatorSingleStream(observer_,
clock_,
min_bitrate_bps_)),
rbe_(new RemoteBitrateEstimatorSingleStream(observer_, clock_)),
using_absolute_send_time_(false),
packets_since_absolute_send_time_(0) {}
packets_since_absolute_send_time_(0),
min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) {}
virtual ~WrappingBitrateEstimator() {}
@ -92,6 +90,12 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator {
return rbe_->GetStats(output);
}
void SetMinBitrate(int min_bitrate_bps) {
CriticalSectionScoped cs(crit_sect_.get());
rbe_->SetMinBitrate(min_bitrate_bps);
min_bitrate_bps_ = min_bitrate_bps;
}
private:
void PickEstimatorFromHeader(const RTPHeader& header)
EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
@ -121,21 +125,20 @@ class WrappingBitrateEstimator : public RemoteBitrateEstimator {
// Instantiate RBE for Time Offset or Absolute Send Time extensions.
void PickEstimator() EXCLUSIVE_LOCKS_REQUIRED(crit_sect_.get()) {
if (using_absolute_send_time_) {
rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_,
min_bitrate_bps_));
rbe_.reset(new RemoteBitrateEstimatorAbsSendTime(observer_, clock_));
} else {
rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_,
min_bitrate_bps_));
rbe_.reset(new RemoteBitrateEstimatorSingleStream(observer_, clock_));
}
rbe_->SetMinBitrate(min_bitrate_bps_);
}
RemoteBitrateObserver* observer_;
Clock* clock_;
rtc::scoped_ptr<CriticalSectionWrapper> crit_sect_;
const uint32_t min_bitrate_bps_;
rtc::scoped_ptr<RemoteBitrateEstimator> rbe_;
bool using_absolute_send_time_;
uint32_t packets_since_absolute_send_time_;
int min_bitrate_bps_;
RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WrappingBitrateEstimator);
};
@ -165,7 +168,8 @@ ChannelGroup::ChannelGroup(ProcessThread* process_thread)
// construction.
bitrate_controller_(
BitrateController::CreateBitrateController(Clock::GetRealTimeClock(),
this)) {
this)),
min_bitrate_bps_(RemoteBitrateEstimator::kDefaultMinBitrateBps) {
call_stats_->RegisterStatsObserver(remote_bitrate_estimator_.get());
pacer_thread_->RegisterModule(pacer_.get());
@ -213,8 +217,9 @@ bool ChannelGroup::CreateSendChannel(int channel_id,
Clock::GetRealTimeClock(), process_thread_));
transport_feedback_adapter_->SetBitrateEstimator(
new RemoteBitrateEstimatorAbsSendTime(
transport_feedback_adapter_.get(), Clock::GetRealTimeClock(),
RemoteBitrateEstimator::kDefaultMinBitrateBps));
transport_feedback_adapter_.get(), Clock::GetRealTimeClock()));
transport_feedback_adapter_->GetBitrateEstimator()->SetMinBitrate(
min_bitrate_bps_);
call_stats_->RegisterStatsObserver(transport_feedback_adapter_.get());
}
transport_feedback_observer = transport_feedback_adapter_.get();
@ -364,6 +369,20 @@ void ChannelGroup::SetSyncInterface(VoEVideoSync* sync_interface) {
channel.second->SetVoiceChannel(-1, sync_interface);
}
void ChannelGroup::SetBweBitrates(int min_bitrate_bps,
int start_bitrate_bps,
int max_bitrate_bps) {
if (start_bitrate_bps > 0)
bitrate_controller_->SetStartBitrate(start_bitrate_bps);
bitrate_controller_->SetMinMaxBitrate(min_bitrate_bps, max_bitrate_bps);
if (remote_bitrate_estimator_.get())
remote_bitrate_estimator_->SetMinBitrate(min_bitrate_bps);
if (transport_feedback_adapter_.get())
transport_feedback_adapter_->GetBitrateEstimator()->SetMinBitrate(
min_bitrate_bps);
min_bitrate_bps_ = min_bitrate_bps;
}
BitrateController* ChannelGroup::GetBitrateController() const {
return bitrate_controller_.get();
}

View File

@ -63,6 +63,9 @@ class ChannelGroup : public BitrateObserver {
ViEChannel* GetChannel(int channel_id) const;
ViEEncoder* GetEncoder(int channel_id) const;
void SetSyncInterface(VoEVideoSync* sync_interface);
void SetBweBitrates(int min_bitrate_bps,
int start_bitrate_bps,
int max_bitrate_bps);
void SetChannelRembStatus(bool sender, bool receiver, ViEChannel* channel);
@ -110,6 +113,7 @@ class ChannelGroup : public BitrateObserver {
rtc::scoped_ptr<BitrateController> bitrate_controller_;
rtc::scoped_ptr<TransportFeedbackAdapter> transport_feedback_adapter_;
int min_bitrate_bps_;
};
} // namespace webrtc