Adds field trial to separate audio and video packets for delay-based overuse detection.

The decision to route audio packets to a separate overuse detector
is off by default and requires the field trial
WebRTC-Bwe-SeparateAudioPackets/enabled,packet_threshold:10,time_threshold:1000ms/
The parameters control the threshold for switching over to the
audio overuse detector if we stop receiving feedback for video.

Bug: webrtc:10932
Change-Id: Icdde35bc7a98b18b1a344bd2d620a890fd9421d9
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/168342
Reviewed-by: Sebastian Jansson <srte@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Commit-Queue: Björn Terelius <terelius@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#30694}
This commit is contained in:
Björn Terelius
2020-03-05 16:52:10 +01:00
committed by Commit Bot
parent 822c373986
commit 987ef48258
11 changed files with 262 additions and 42 deletions

View File

@ -34,15 +34,18 @@ constexpr int kAbsSendTimeFraction = 18;
constexpr int kAbsSendTimeInterArrivalUpshift = 8;
constexpr int kInterArrivalShift =
kAbsSendTimeFraction + kAbsSendTimeInterArrivalUpshift;
constexpr int kTimestampGroupTicks =
(kTimestampGroupLengthMs << kInterArrivalShift) / 1000;
constexpr double kTimestampToMs =
1000.0 / static_cast<double>(1 << kInterArrivalShift);
// This ssrc is used to fulfill the current API but will be removed
// after the API has been changed.
constexpr uint32_t kFixedSsrc = 0;
} // namespace
constexpr char BweIgnoreSmallPacketsSettings::kKey[];
constexpr char BweSeparateAudioPacketsSettings::kKey[];
BweIgnoreSmallPacketsSettings::BweIgnoreSmallPacketsSettings(
const WebRtcKeyValueConfig* key_value_config) {
@ -58,6 +61,20 @@ BweIgnoreSmallPacketsSettings::Parser() {
"small", &small_threshold);
}
BweSeparateAudioPacketsSettings::BweSeparateAudioPacketsSettings(
const WebRtcKeyValueConfig* key_value_config) {
Parser()->Parse(
key_value_config->Lookup(BweSeparateAudioPacketsSettings::kKey));
}
std::unique_ptr<StructParametersParser>
BweSeparateAudioPacketsSettings::Parser() {
return StructParametersParser::Create( //
"enabled", &enabled, //
"packet_threshold", &packet_threshold, //
"time_threshold", &time_threshold);
}
DelayBasedBwe::Result::Result()
: updated(false),
probe(false),
@ -72,8 +89,6 @@ DelayBasedBwe::Result::Result(bool probe, DataRate target_bitrate)
recovered_from_overuse(false),
backoff_in_alr(false) {}
DelayBasedBwe::Result::~Result() {}
DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
RtcEventLog* event_log,
NetworkStatePredictor* network_state_predictor)
@ -81,10 +96,17 @@ DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
key_value_config_(key_value_config),
ignore_small_(key_value_config),
fraction_large_packets_(0.5),
separate_audio_(key_value_config),
audio_packets_since_last_video_(0),
last_video_packet_recv_time_(Timestamp::MinusInfinity()),
network_state_predictor_(network_state_predictor),
inter_arrival_(),
delay_detector_(
video_inter_arrival_(),
video_delay_detector_(
new TrendlineEstimator(key_value_config_, network_state_predictor_)),
audio_inter_arrival_(),
audio_delay_detector_(
new TrendlineEstimator(key_value_config_, network_state_predictor_)),
active_delay_detector_(video_delay_detector_.get()),
last_seen_packet_(Timestamp::MinusInfinity()),
uma_recorded_(false),
rate_control_(key_value_config, /*send_side=*/true),
@ -94,8 +116,10 @@ DelayBasedBwe::DelayBasedBwe(const WebRtcKeyValueConfig* key_value_config,
alr_limited_backoff_enabled_(
key_value_config->Lookup("WebRTC-Bwe-AlrLimitedBackoff")
.find("Enabled") == 0) {
RTC_LOG(LS_INFO) << "Initialized DelayBasedBwe with field trial "
RTC_LOG(LS_INFO) << "Initialized DelayBasedBwe with small packet filtering "
<< ignore_small_.Parser()->Encode()
<< ", separate audio overuse detection"
<< separate_audio_.Parser()->Encode()
<< " and alr limited backoff "
<< (alr_limited_backoff_enabled_ ? "enabled" : "disabled");
}
@ -127,15 +151,15 @@ DelayBasedBwe::Result DelayBasedBwe::IncomingPacketFeedbackVector(
}
bool delayed_feedback = true;
bool recovered_from_overuse = false;
BandwidthUsage prev_detector_state = delay_detector_->State();
BandwidthUsage prev_detector_state = active_delay_detector_->State();
for (const auto& packet_feedback : packet_feedback_vector) {
delayed_feedback = false;
IncomingPacketFeedback(packet_feedback, msg.feedback_time);
if (prev_detector_state == BandwidthUsage::kBwUnderusing &&
delay_detector_->State() == BandwidthUsage::kBwNormal) {
active_delay_detector_->State() == BandwidthUsage::kBwNormal) {
recovered_from_overuse = true;
}
prev_detector_state = delay_detector_->State();
prev_detector_state = active_delay_detector_->State();
}
if (delayed_feedback) {
@ -155,25 +179,18 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback,
// Reset if the stream has timed out.
if (last_seen_packet_.IsInfinite() ||
at_time - last_seen_packet_ > kStreamTimeOut) {
inter_arrival_.reset(
new InterArrival((kTimestampGroupLengthMs << kInterArrivalShift) / 1000,
kTimestampToMs, true));
delay_detector_.reset(
video_inter_arrival_.reset(
new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
video_delay_detector_.reset(
new TrendlineEstimator(key_value_config_, network_state_predictor_));
audio_inter_arrival_.reset(
new InterArrival(kTimestampGroupTicks, kTimestampToMs, true));
audio_delay_detector_.reset(
new TrendlineEstimator(key_value_config_, network_state_predictor_));
active_delay_detector_ = video_delay_detector_.get();
}
last_seen_packet_ = at_time;
uint32_t send_time_24bits =
static_cast<uint32_t>(
((static_cast<uint64_t>(packet_feedback.sent_packet.send_time.ms())
<< kAbsSendTimeFraction) +
500) /
1000) &
0x00FFFFFF;
// Shift up send time to use the full 32 bits that inter_arrival works with,
// so wrapping works properly.
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
// Ignore "small" packets if many/most packets in the call are "large". The
// packet size may have a significant effect on the propagation delay,
// especially at low bandwidths. Variations in packet size will then show up
@ -190,17 +207,51 @@ void DelayBasedBwe::IncomingPacketFeedback(const PacketResult& packet_feedback,
}
}
uint32_t ts_delta = 0;
int64_t t_delta = 0;
// As an alternative to ignoring small packets, we can separate audio and
// video packets for overuse detection.
InterArrival* inter_arrival_for_packet = video_inter_arrival_.get();
DelayIncreaseDetectorInterface* delay_detector_for_packet =
video_delay_detector_.get();
if (separate_audio_.enabled) {
if (packet_feedback.sent_packet.audio) {
inter_arrival_for_packet = audio_inter_arrival_.get();
delay_detector_for_packet = audio_delay_detector_.get();
audio_packets_since_last_video_++;
if (audio_packets_since_last_video_ > separate_audio_.packet_threshold &&
packet_feedback.receive_time - last_video_packet_recv_time_ >
separate_audio_.time_threshold) {
active_delay_detector_ = audio_delay_detector_.get();
}
} else {
audio_packets_since_last_video_ = 0;
last_video_packet_recv_time_ =
std::max(last_video_packet_recv_time_, packet_feedback.receive_time);
active_delay_detector_ = video_delay_detector_.get();
}
}
uint32_t send_time_24bits =
static_cast<uint32_t>(
((static_cast<uint64_t>(packet_feedback.sent_packet.send_time.ms())
<< kAbsSendTimeFraction) +
500) /
1000) &
0x00FFFFFF;
// Shift up send time to use the full 32 bits that inter_arrival works with,
// so wrapping works properly.
uint32_t timestamp = send_time_24bits << kAbsSendTimeInterArrivalUpshift;
uint32_t timestamp_delta = 0;
int64_t recv_delta_ms = 0;
int size_delta = 0;
bool calculated_deltas = inter_arrival_->ComputeDeltas(
bool calculated_deltas = inter_arrival_for_packet->ComputeDeltas(
timestamp, packet_feedback.receive_time.ms(), at_time.ms(),
packet_size.bytes(), &ts_delta, &t_delta, &size_delta);
double ts_delta_ms = (1000.0 * ts_delta) / (1 << kInterArrivalShift);
delay_detector_->Update(t_delta, ts_delta_ms,
packet_feedback.sent_packet.send_time.ms(),
packet_feedback.receive_time.ms(),
packet_size.bytes(), calculated_deltas);
packet_size.bytes(), &timestamp_delta, &recv_delta_ms, &size_delta);
double send_delta_ms = (1000.0 * timestamp_delta) / (1 << kInterArrivalShift);
delay_detector_for_packet->Update(recv_delta_ms, send_delta_ms,
packet_feedback.sent_packet.send_time.ms(),
packet_feedback.receive_time.ms(),
packet_size.bytes(), calculated_deltas);
}
DataRate DelayBasedBwe::TriggerOveruse(Timestamp at_time,
@ -219,7 +270,7 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
Result result;
// Currently overusing the bandwidth.
if (delay_detector_->State() == BandwidthUsage::kBwOverusing) {
if (active_delay_detector_->State() == BandwidthUsage::kBwOverusing) {
if (has_once_detected_overuse_ && in_alr && alr_limited_backoff_enabled_) {
if (rate_control_.TimeToReduceFurther(at_time, prev_bitrate_)) {
result.updated =
@ -254,7 +305,7 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
result.recovered_from_overuse = recovered_from_overuse;
}
}
BandwidthUsage detector_state = delay_detector_->State();
BandwidthUsage detector_state = active_delay_detector_->State();
if ((result.updated && prev_bitrate_ != result.target_bitrate) ||
detector_state != prev_state_) {
DataRate bitrate = result.updated ? result.target_bitrate : prev_bitrate_;
@ -275,7 +326,7 @@ DelayBasedBwe::Result DelayBasedBwe::MaybeUpdateEstimate(
bool DelayBasedBwe::UpdateEstimate(Timestamp at_time,
absl::optional<DataRate> acked_bitrate,
DataRate* target_rate) {
const RateControlInput input(delay_detector_->State(), acked_bitrate);
const RateControlInput input(active_delay_detector_->State(), acked_bitrate);
*target_rate = rate_control_.Update(&input, at_time);
return rate_control_.ValidEstimate();
}

View File

@ -48,12 +48,26 @@ struct BweIgnoreSmallPacketsSettings {
std::unique_ptr<StructParametersParser> Parser();
};
struct BweSeparateAudioPacketsSettings {
static constexpr char kKey[] = "WebRTC-Bwe-SeparateAudioPackets";
BweSeparateAudioPacketsSettings() = default;
explicit BweSeparateAudioPacketsSettings(
const WebRtcKeyValueConfig* key_value_config);
bool enabled = false;
int packet_threshold = 10;
TimeDelta time_threshold = TimeDelta::Seconds(1);
std::unique_ptr<StructParametersParser> Parser();
};
class DelayBasedBwe {
public:
struct Result {
Result();
Result(bool probe, DataRate target_bitrate);
~Result();
~Result() = default;
bool updated;
bool probe;
DataRate target_bitrate = DataRate::Zero();
@ -108,9 +122,20 @@ class DelayBasedBwe {
BweIgnoreSmallPacketsSettings ignore_small_;
double fraction_large_packets_;
// Alternatively, run two separate overuse detectors for audio and video,
// and fall back to the audio one if we haven't seen a video packet in a
// while.
BweSeparateAudioPacketsSettings separate_audio_;
int64_t audio_packets_since_last_video_;
Timestamp last_video_packet_recv_time_;
NetworkStatePredictor* network_state_predictor_;
std::unique_ptr<InterArrival> inter_arrival_;
std::unique_ptr<DelayIncreaseDetectorInterface> delay_detector_;
std::unique_ptr<InterArrival> video_inter_arrival_;
std::unique_ptr<DelayIncreaseDetectorInterface> video_delay_detector_;
std::unique_ptr<InterArrival> audio_inter_arrival_;
std::unique_ptr<DelayIncreaseDetectorInterface> audio_delay_detector_;
DelayIncreaseDetectorInterface* active_delay_detector_;
Timestamp last_seen_packet_;
bool uma_recorded_;
AimdRateControl rate_control_;

View File

@ -80,7 +80,7 @@ std::deque<FieldLogger*> GoogCcStatePrinter::CreateLoggers() {
};
auto trend = [this] {
return reinterpret_cast<TrendlineEstimator*>(
controller_->delay_based_bwe_->delay_detector_.get());
controller_->delay_based_bwe_->active_delay_detector_);
};
auto acknowledged_rate = [this] {
return controller_->acknowledged_bitrate_estimator_->bitrate();