Wire up experiment for improved screenshare bwe.

Also adds some full stack test variants with the experiment enabled.

BUG=webrtc:7694

Review-Url: https://codereview.webrtc.org/2949553002
Cr-Commit-Position: refs/heads/master@{#18869}
This commit is contained in:
sprang 2017-06-30 13:27:40 -07:00 committed by Commit Bot
parent e96c45b662
commit 89c4a7e57d
9 changed files with 229 additions and 27 deletions

View File

@ -10,28 +10,36 @@
#include "webrtc/modules/pacing/alr_detector.h"
#include <string>
#include "webrtc/base/checks.h"
#include "webrtc/base/format_macros.h"
#include "webrtc/base/logging.h"
#include "webrtc/system_wrappers/include/field_trial.h"
namespace {
// Time period over which outgoing traffic is measured.
constexpr int kMeasurementPeriodMs = 500;
// Sent traffic percentage as a function of network capacity used to determine
// application-limited region. ALR region start when bandwidth usage drops below
// kAlrStartUsagePercent and ends when it raises above kAlrEndUsagePercent.
// NOTE: This is intentionally conservative at the moment until BW adjustments
// of application limited region is fine tuned.
constexpr int kAlrStartUsagePercent = 60;
constexpr int kAlrEndUsagePercent = 70;
} // namespace
namespace webrtc {
const char* AlrDetector::kScreenshareProbingBweExperimentName =
"WebRTC-ProbingScreenshareBwe";
AlrDetector::AlrDetector()
: rate_(kMeasurementPeriodMs, RateStatistics::kBpsScale) {}
: alr_start_usage_percent_(kDefaultAlrStartUsagePercent),
alr_end_usage_percent_(kDefaultAlrEndUsagePercent),
rate_(kMeasurementPeriodMs, RateStatistics::kBpsScale),
estimated_bitrate_bps_(0) {
rtc::Optional<AlrExperimentSettings> experiment_settings =
ParseAlrSettingsFromFieldTrial();
if (experiment_settings) {
alr_start_usage_percent_ = experiment_settings->alr_start_usage_percent;
alr_end_usage_percent_ = experiment_settings->alr_end_usage_percent;
}
}
AlrDetector::~AlrDetector() {}
@ -44,9 +52,9 @@ void AlrDetector::OnBytesSent(size_t bytes_sent, int64_t now_ms) {
return;
int percentage = static_cast<int>(*rate) * 100 / estimated_bitrate_bps_;
if (percentage < kAlrStartUsagePercent && !alr_started_time_ms_) {
if (percentage < alr_start_usage_percent_ && !alr_started_time_ms_) {
alr_started_time_ms_ = rtc::Optional<int64_t>(now_ms);
} else if (percentage > kAlrEndUsagePercent && alr_started_time_ms_) {
} else if (percentage > alr_end_usage_percent_ && alr_started_time_ms_) {
alr_started_time_ms_ = rtc::Optional<int64_t>();
}
}
@ -61,4 +69,38 @@ rtc::Optional<int64_t> AlrDetector::GetApplicationLimitedRegionStartTime()
return alr_started_time_ms_;
}
rtc::Optional<AlrDetector::AlrExperimentSettings>
AlrDetector::ParseAlrSettingsFromFieldTrial() {
rtc::Optional<AlrExperimentSettings> ret;
std::string group_name =
field_trial::FindFullName(kScreenshareProbingBweExperimentName);
const std::string kIgnoredSuffix = "_Dogfood";
if (group_name.rfind(kIgnoredSuffix) ==
group_name.length() - kIgnoredSuffix.length()) {
group_name.resize(group_name.length() - kIgnoredSuffix.length());
}
if (group_name.empty())
return ret;
AlrExperimentSettings settings;
if (sscanf(group_name.c_str(), "%f-%" PRId64 "-%d-%d",
&settings.pacing_factor, &settings.max_paced_queue_time,
&settings.alr_start_usage_percent,
&settings.alr_end_usage_percent) == 4) {
ret.emplace(settings);
LOG(LS_INFO) << "Using screenshare ALR experiment settings: "
"pacing factor: "
<< settings.pacing_factor << ", max pacer queue length: "
<< settings.max_paced_queue_time
<< ", ALR start usage percent: "
<< settings.alr_start_usage_percent
<< ", ALR end usage percent: "
<< settings.alr_end_usage_percent;
}
return ret;
}
} // namespace webrtc

View File

@ -11,6 +11,7 @@
#ifndef WEBRTC_MODULES_PACING_ALR_DETECTOR_H_
#define WEBRTC_MODULES_PACING_ALR_DETECTOR_H_
#include "webrtc/base/optional.h"
#include "webrtc/base/rate_statistics.h"
#include "webrtc/common_types.h"
#include "webrtc/modules/pacing/paced_sender.h"
@ -25,6 +26,7 @@ namespace webrtc {
// AlrDetector provides a signal that can be utilized to adjust
// estimate bandwidth.
// Note: This class is not thread-safe.
class AlrDetector {
public:
AlrDetector();
@ -39,9 +41,28 @@ class AlrDetector {
// started or empty result if the sender is currently not application-limited.
rtc::Optional<int64_t> GetApplicationLimitedRegionStartTime() const;
struct AlrExperimentSettings {
float pacing_factor = PacedSender::kDefaultPaceMultiplier;
int64_t max_paced_queue_time = PacedSender::kMaxQueueLengthMs;
int alr_start_usage_percent = kDefaultAlrStartUsagePercent;
int alr_end_usage_percent = kDefaultAlrEndUsagePercent;
};
static rtc::Optional<AlrExperimentSettings> ParseAlrSettingsFromFieldTrial();
// Sent traffic percentage as a function of network capacity used to determine
// application-limited region. ALR region start when bandwidth usage drops
// below kAlrStartUsagePercent and ends when it raises above
// kAlrEndUsagePercent. NOTE: This is intentionally conservative at the moment
// until BW adjustments of application limited region is fine tuned.
static constexpr int kDefaultAlrStartUsagePercent = 60;
static constexpr int kDefaultAlrEndUsagePercent = 70;
static const char* kScreenshareProbingBweExperimentName;
private:
int alr_start_usage_percent_;
int alr_end_usage_percent_;
RateStatistics rate_;
int estimated_bitrate_bps_ = 0;
int estimated_bitrate_bps_;
// Non-empty in ALR state.
rtc::Optional<int64_t> alr_started_time_ms_;

View File

@ -264,7 +264,9 @@ PacedSender::PacedSender(const Clock* clock,
time_last_update_us_(clock->TimeInMicroseconds()),
first_sent_packet_ms_(-1),
packets_(new paced_sender::PacketQueue(clock)),
packet_counter_(0) {
packet_counter_(0),
pacing_factor_(kDefaultPaceMultiplier),
queue_time_limit(kMaxQueueLengthMs) {
UpdateBudgetWithElapsedTime(kMinPacketLimitMs);
}
@ -314,7 +316,7 @@ void PacedSender::SetEstimatedBitrate(uint32_t bitrate_bps) {
std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
pacing_bitrate_kbps_ =
std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
kDefaultPaceMultiplier;
pacing_factor_;
alr_detector_->SetEstimatedBitrate(bitrate_bps);
}
@ -324,7 +326,7 @@ void PacedSender::SetSendBitrateLimits(int min_send_bitrate_bps,
min_send_bitrate_kbps_ = min_send_bitrate_bps / 1000;
pacing_bitrate_kbps_ =
std::max(min_send_bitrate_kbps_, estimated_bitrate_bps_ / 1000) *
kDefaultPaceMultiplier;
pacing_factor_;
max_padding_bitrate_kbps_ = padding_bitrate / 1000;
padding_budget_->set_target_rate_kbps(
std::min(estimated_bitrate_bps_ / 1000, max_padding_bitrate_kbps_));
@ -419,7 +421,7 @@ void PacedSender::Process() {
// time constraint shall be met. Determine bitrate needed for that.
packets_->UpdateQueueTime(clock_->TimeInMilliseconds());
int64_t avg_time_left_ms = std::max<int64_t>(
1, kMaxQueueLengthMs - packets_->AverageQueueTimeMs());
1, queue_time_limit - packets_->AverageQueueTimeMs());
int min_bitrate_needed_kbps =
static_cast<int>(queue_size_bytes * 8 / avg_time_left_ms);
if (min_bitrate_needed_kbps > target_bitrate_kbps)
@ -535,4 +537,15 @@ void PacedSender::UpdateBudgetWithBytesSent(size_t bytes_sent) {
media_budget_->UseBudget(bytes_sent);
padding_budget_->UseBudget(bytes_sent);
}
void PacedSender::SetPacingFactor(float pacing_factor) {
rtc::CritScope cs(&critsect_);
pacing_factor_ = pacing_factor;
}
void PacedSender::SetQueueTimeLimit(int limit_ms) {
rtc::CritScope cs(&critsect_);
queue_time_limit = limit_ms;
}
} // namespace webrtc

View File

@ -149,6 +149,9 @@ class PacedSender : public Module, public RtpPacketSender {
// Called when the prober is associated with a process thread.
void ProcessThreadAttached(ProcessThread* process_thread) override;
void SetPacingFactor(float pacing_factor);
void SetQueueTimeLimit(int limit_ms);
private:
// Updates the number of bytes that can be sent for the next time interval.
void UpdateBudgetWithElapsedTime(int64_t delta_time_in_ms)
@ -193,6 +196,9 @@ class PacedSender : public Module, public RtpPacketSender {
std::unique_ptr<paced_sender::PacketQueue> packets_ GUARDED_BY(critsect_);
uint64_t packet_counter_;
ProcessThread* process_thread_ = nullptr;
float pacing_factor_ GUARDED_BY(critsect_);
int64_t queue_time_limit GUARDED_BY(critsect_);
};
} // namespace webrtc
#endif // WEBRTC_MODULES_PACING_PACED_SENDER_H_

View File

@ -133,6 +133,7 @@ if (rtc_include_tests) {
]
deps = [
":video_quality_test",
"../modules/pacing:pacing",
"../test:field_trial",
"../test:test_support",
"//testing/gtest",

View File

@ -9,19 +9,29 @@
*/
#include <stdio.h>
#include "webrtc/modules/pacing/alr_detector.h"
#include "webrtc/test/field_trial.h"
#include "webrtc/test/gtest.h"
#include "webrtc/video/video_quality_test.h"
namespace webrtc {
namespace {
static const int kFullStackTestDurationSecs = 45;
} // namespace
class FullStackTest : public VideoQualityTest {
public:
void RunTest(const VideoQualityTest::Params &params) {
RunWithAnalyzer(params);
}
protected:
const std::string kScreenshareSimulcastExperiment =
"WebRTC-SimulcastScreenshare/Enabled/";
const std::string kAlrProbingExperiment =
std::string(AlrDetector::kScreenshareProbingBweExperimentName) +
"/1.1-2875-80-90/";
};
// VideoQualityTest::Params params = {
@ -310,7 +320,7 @@ TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL) {
}
TEST_F(FullStackTest, ScreenshareSlidesVP8_3TL_Simulcast) {
test::ScopedFieldTrials field_trial("WebRTC-SimulcastScreenshare/Enabled/");
test::ScopedFieldTrials field_trial(kScreenshareSimulcastExperiment);
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.screenshare = {true, 10};
@ -389,6 +399,93 @@ TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL_LossyNetRestrictedQueue) {
RunTest(screenshare);
}
TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL_ModeratelyRestricted) {
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.video = {true, 1850, 1110, 5, 50000, 200000, 2000000, false,
"VP8", 2, 1, 400000, false, false, "", ""};
screenshare.screenshare = {true, 10};
screenshare.analyzer = {"screenshare_slides_moderately_restricted", 0.0, 0.0,
kFullStackTestDurationSecs};
screenshare.pipe.loss_percent = 1;
screenshare.pipe.link_capacity_kbps = 1200;
screenshare.pipe.queue_length_packets = 30;
RunTest(screenshare);
}
// TODO(sprang): Retire these tests once experiment is removed.
TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL_LossyNetRestrictedQueue_ALR) {
test::ScopedFieldTrials field_trial(kAlrProbingExperiment);
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.video = {true, 1850, 1110, 5, 50000, 200000, 2000000, false,
"VP8", 2, 1, 400000, false, false, "", ""};
screenshare.screenshare = {true, 10};
screenshare.analyzer = {"screenshare_slides_lossy_limited_ALR", 0.0, 0.0,
kFullStackTestDurationSecs};
screenshare.pipe.loss_percent = 5;
screenshare.pipe.link_capacity_kbps = 200;
screenshare.pipe.queue_length_packets = 30;
RunTest(screenshare);
}
TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL_ALR) {
test::ScopedFieldTrials field_trial(kAlrProbingExperiment);
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.video = {true, 1850, 1110, 5, 50000, 200000, 2000000, false,
"VP8", 2, 1, 400000, false, false, "", ""};
screenshare.screenshare = {true, 10};
screenshare.analyzer = {"screenshare_slides_ALR", 0.0, 0.0,
kFullStackTestDurationSecs};
RunTest(screenshare);
}
TEST_F(FullStackTest, ScreenshareSlidesVP8_2TL_ModeratelyRestricted_ALR) {
test::ScopedFieldTrials field_trial(kAlrProbingExperiment);
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.video = {true, 1850, 1110, 5, 50000, 200000, 2000000, false,
"VP8", 2, 1, 400000, false, false, "", ""};
screenshare.screenshare = {true, 10};
screenshare.analyzer = {"screenshare_slides_moderately_restricted_ALR", 0.0,
0.0, kFullStackTestDurationSecs};
screenshare.pipe.loss_percent = 1;
screenshare.pipe.link_capacity_kbps = 1200;
screenshare.pipe.queue_length_packets = 30;
RunTest(screenshare);
}
TEST_F(FullStackTest, ScreenshareSlidesVP8_3TL_Simulcast_ALR) {
test::ScopedFieldTrials field_trial(kScreenshareSimulcastExperiment +
kAlrProbingExperiment);
VideoQualityTest::Params screenshare;
screenshare.call.send_side_bwe = true;
screenshare.screenshare = {true, 10};
screenshare.video = {true, 1850, 1110, 5, 800000, 2500000,
2500000, false, "VP8", 3, 2, 400000,
false, false, "", ""};
screenshare.analyzer = {"screenshare_slides_simulcast_alr", 0.0, 0.0,
kFullStackTestDurationSecs};
VideoQualityTest::Params screenshare_params_high;
screenshare_params_high.video = {true, 1850, 1110, 5, 800000, 2500000,
2500000, false, "VP8", 3, 0, 400000,
false, false, "", ""};
VideoQualityTest::Params screenshare_params_low;
screenshare_params_low.video = {true, 1850, 1110, 5, 50000, 200000,
2000000, false, "VP8", 2, 0, 400000,
false, false, "", ""};
std::vector<VideoStream> streams = {
DefaultVideoStream(screenshare_params_low),
DefaultVideoStream(screenshare_params_high)};
screenshare.ss = {streams, 1, 1, 0, std::vector<SpatialLayer>(), false};
RunTest(screenshare);
}
const VideoQualityTest::Params::Video kSvcVp9Video = {
true, 1280, 720, 30,
800000, 2500000, 2500000, false,

View File

@ -312,6 +312,7 @@ int main(int argc, char* argv[]) {
// with a scope that outlives the test.
std::string field_trials = webrtc::flags::FLAG_force_fieldtrials;
webrtc::test::InitFieldTrialsFromString(field_trials);
webrtc::test::RunTest(webrtc::Loopback);
return 0;
}

View File

@ -318,6 +318,7 @@ int main(int argc, char* argv[]) {
// with a scope that outlives the test.
std::string field_trials = webrtc::flags::FLAG_force_fieldtrials;
webrtc::test::InitFieldTrialsFromString(field_trials);
webrtc::test::RunTest(webrtc::Loopback);
return 0;
}

View File

@ -27,6 +27,7 @@
#include "webrtc/common_video/include/video_bitrate_allocator.h"
#include "webrtc/modules/bitrate_controller/include/bitrate_controller.h"
#include "webrtc/modules/congestion_controller/include/send_side_congestion_controller.h"
#include "webrtc/modules/pacing/alr_detector.h"
#include "webrtc/modules/pacing/packet_router.h"
#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp.h"
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
@ -345,7 +346,8 @@ class VideoSendStreamImpl : public webrtc::BitrateAllocatorObserver,
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
std::map<uint32_t, RtpState> suspended_ssrcs);
std::map<uint32_t, RtpState> suspended_ssrcs,
VideoEncoderConfig::ContentType content_type);
~VideoSendStreamImpl() override;
// RegisterProcessThread register |module_process_thread| with those objects
@ -475,7 +477,8 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
const std::map<uint32_t, RtpState>& suspended_ssrcs)
const std::map<uint32_t, RtpState>& suspended_ssrcs,
VideoEncoderConfig::ContentType content_type)
: send_stream_(send_stream),
done_event_(done_event),
stats_proxy_(stats_proxy),
@ -487,7 +490,8 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
event_log_(event_log),
config_(config),
initial_encoder_max_bitrate_(initial_encoder_max_bitrate),
suspended_ssrcs_(suspended_ssrcs) {}
suspended_ssrcs_(suspended_ssrcs),
content_type_(content_type) {}
~ConstructionTask() override { done_event_->Set(); }
@ -496,7 +500,8 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
send_stream_->reset(new VideoSendStreamImpl(
stats_proxy_, rtc::TaskQueue::Current(), call_stats_, transport_,
bitrate_allocator_, send_delay_stats_, vie_encoder_, event_log_,
config_, initial_encoder_max_bitrate_, std::move(suspended_ssrcs_)));
config_, initial_encoder_max_bitrate_, std::move(suspended_ssrcs_),
content_type_));
return true;
}
@ -512,6 +517,7 @@ class VideoSendStream::ConstructionTask : public rtc::QueuedTask {
const VideoSendStream::Config* config_;
int initial_encoder_max_bitrate_;
std::map<uint32_t, RtpState> suspended_ssrcs_;
const VideoEncoderConfig::ContentType content_type_;
};
class VideoSendStream::DestructAndGetRtpStateTask : public rtc::QueuedTask {
@ -639,8 +645,8 @@ VideoSendStream::VideoSendStream(
worker_queue_->PostTask(std::unique_ptr<rtc::QueuedTask>(new ConstructionTask(
&send_stream_, &thread_sync_event_, &stats_proxy_, vie_encoder_.get(),
module_process_thread, call_stats, transport, bitrate_allocator,
send_delay_stats, event_log, &config_,
encoder_config.max_bitrate_bps, suspended_ssrcs)));
send_delay_stats, event_log, &config_, encoder_config.max_bitrate_bps,
suspended_ssrcs, encoder_config.content_type)));
// Wait for ConstructionTask to complete so that |send_stream_| can be used.
// |module_process_thread| must be registered and deregistered on the thread
@ -758,7 +764,8 @@ VideoSendStreamImpl::VideoSendStreamImpl(
RtcEventLog* event_log,
const VideoSendStream::Config* config,
int initial_encoder_max_bitrate,
std::map<uint32_t, RtpState> suspended_ssrcs)
std::map<uint32_t, RtpState> suspended_ssrcs,
VideoEncoderConfig::ContentType content_type)
: send_side_bwe_with_overhead_(
webrtc::field_trial::IsEnabled("WebRTC-SendSideBwe-WithOverhead")),
stats_proxy_(stats_proxy),
@ -811,8 +818,21 @@ VideoSendStreamImpl::VideoSendStreamImpl(
RTC_DCHECK(transport_);
RTC_DCHECK(transport_->send_side_cc());
transport->send_side_cc()->EnablePeriodicAlrProbing(
config_->periodic_alr_bandwidth_probing);
if (content_type == VideoEncoderConfig::ContentType::kScreen) {
rtc::Optional<AlrDetector::AlrExperimentSettings> alr_settings =
AlrDetector::ParseAlrSettingsFromFieldTrial();
if (alr_settings) {
transport->send_side_cc()->EnablePeriodicAlrProbing(true);
transport->send_side_cc()->pacer()->SetPacingFactor(
alr_settings->pacing_factor);
transport->send_side_cc()->pacer()->SetQueueTimeLimit(
alr_settings->max_paced_queue_time);
}
}
if (config_->periodic_alr_bandwidth_probing) {
transport->send_side_cc()->EnablePeriodicAlrProbing(true);
}
// RTP/RTCP initialization.