Add delay manager config options.
Add a new field trial with more flexible parsing and new options:
- Resample packet delays to only update histogram with maximum observed
delay every X ms.
- Setting the maximum history size (in ms) used for calculating the
relative arrival delay.
Legacy field trial used for configuration is maintained.
Bug: webrtc:10333
Change-Id: I35b004f5d8209c85b33cb49def3816db51650946
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/192789
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32591}
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index 6b10d33..33eeb96 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -22,6 +22,7 @@
#include "modules/audio_coding/neteq/histogram.h"
#include "modules/include/module_common_types_public.h"
#include "rtc_base/checks.h"
+#include "rtc_base/experiments/struct_parameters_parser.h"
#include "rtc_base/logging.h"
#include "rtc_base/numerics/safe_conversions.h"
#include "rtc_base/numerics/safe_minmax.h"
@@ -32,29 +33,34 @@
constexpr int kMinBaseMinimumDelayMs = 0;
constexpr int kMaxBaseMinimumDelayMs = 10000;
-constexpr int kMaxHistoryMs = 2000; // Oldest packet to include in history to
- // calculate relative packet arrival delay.
constexpr int kDelayBuckets = 100;
constexpr int kBucketSizeMs = 20;
constexpr int kStartDelayMs = 80;
constexpr int kMaxNumReorderedPackets = 5;
-int PercentileToQuantile(double percentile) {
- return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5);
-}
-
-struct DelayHistogramConfig {
- int quantile = 1041529569; // 0.97 in Q30.
- int forget_factor = 32745; // 0.9993 in Q15.
+struct DelayManagerConfig {
+ double quantile = 0.97;
+ double forget_factor = 0.9993;
absl::optional<double> start_forget_weight = 2;
-};
+ absl::optional<int> resample_interval_ms;
+ int max_history_ms = 2000;
-// TODO(jakobi): Remove legacy field trial.
-DelayHistogramConfig GetDelayHistogramConfig() {
- constexpr char kDelayHistogramFieldTrial[] =
- "WebRTC-Audio-NetEqDelayHistogram";
- DelayHistogramConfig config;
- if (webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial)) {
+ std::unique_ptr<webrtc::StructParametersParser> Parser() {
+ return webrtc::StructParametersParser::Create( //
+ "quantile", &quantile, //
+ "forget_factor", &forget_factor, //
+ "start_forget_weight", &start_forget_weight, //
+ "resample_interval_ms", &resample_interval_ms, //
+ "max_history_ms", &max_history_ms);
+ }
+
+ // TODO(jakobi): remove legacy field trial.
+ void MaybeUpdateFromLegacyFieldTrial() {
+ constexpr char kDelayHistogramFieldTrial[] =
+ "WebRTC-Audio-NetEqDelayHistogram";
+ if (!webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial)) {
+ return;
+ }
const auto field_trial_string =
webrtc::field_trial::FindFullName(kDelayHistogramFieldTrial);
double percentile = -1.0;
@@ -64,27 +70,36 @@
&forget_factor, &start_forget_weight) >= 2 &&
percentile >= 0.0 && percentile <= 100.0 && forget_factor >= 0.0 &&
forget_factor <= 1.0) {
- config.quantile = PercentileToQuantile(percentile);
- config.forget_factor = (1 << 15) * forget_factor;
- config.start_forget_weight =
- start_forget_weight >= 1 ? absl::make_optional(start_forget_weight)
- : absl::nullopt;
+ this->quantile = percentile / 100;
+ this->forget_factor = forget_factor;
+ this->start_forget_weight = start_forget_weight >= 1
+ ? absl::make_optional(start_forget_weight)
+ : absl::nullopt;
}
}
- RTC_LOG(LS_INFO) << "Delay histogram config:"
- " quantile="
- << config.quantile
- << " forget_factor=" << config.forget_factor
- << " start_forget_weight="
- << config.start_forget_weight.value_or(0);
- return config;
-}
+
+ explicit DelayManagerConfig() {
+ Parser()->Parse(webrtc::field_trial::FindFullName(
+ "WebRTC-Audio-NetEqDelayManagerConfig"));
+ MaybeUpdateFromLegacyFieldTrial();
+ RTC_LOG(LS_INFO) << "Delay manager config:"
+ " quantile="
+ << quantile << " forget_factor=" << forget_factor
+ << " start_forget_weight="
+ << start_forget_weight.value_or(0)
+ << " resample_interval_ms="
+ << resample_interval_ms.value_or(0)
+ << " max_history_ms=" << max_history_ms;
+ }
+};
} // namespace
DelayManager::DelayManager(int max_packets_in_buffer,
int base_minimum_delay_ms,
int histogram_quantile,
+ absl::optional<int> resample_interval_ms,
+ int max_history_ms,
const TickTimer* tick_timer,
std::unique_ptr<Histogram> histogram)
: first_packet_received_(false),
@@ -92,6 +107,8 @@
histogram_(std::move(histogram)),
histogram_quantile_(histogram_quantile),
tick_timer_(tick_timer),
+ resample_interval_ms_(resample_interval_ms),
+ max_history_ms_(max_history_ms),
base_minimum_delay_ms_(base_minimum_delay_ms),
effective_minimum_delay_ms_(base_minimum_delay_ms),
minimum_delay_ms_(0),
@@ -108,12 +125,15 @@
int max_packets_in_buffer,
int base_minimum_delay_ms,
const TickTimer* tick_timer) {
- auto config = GetDelayHistogramConfig();
+ DelayManagerConfig config;
+ int forget_factor_q15 = (1 << 15) * config.forget_factor;
+ int quantile_q30 = (1 << 30) * config.quantile;
std::unique_ptr<Histogram> histogram = std::make_unique<Histogram>(
- kDelayBuckets, config.forget_factor, config.start_forget_weight);
- return std::make_unique<DelayManager>(max_packets_in_buffer,
- base_minimum_delay_ms, config.quantile,
- tick_timer, std::move(histogram));
+ kDelayBuckets, forget_factor_q15, config.start_forget_weight);
+ return std::make_unique<DelayManager>(
+ max_packets_in_buffer, base_minimum_delay_ms, quantile_q30,
+ config.resample_interval_ms, config.max_history_ms, tick_timer,
+ std::move(histogram));
}
DelayManager::~DelayManager() {}
@@ -132,6 +152,8 @@
last_timestamp_ = timestamp;
first_packet_received_ = true;
num_reordered_packets_ = 0;
+ resample_stopwatch_ = tick_timer_->GetNewStopwatch();
+ max_delay_in_interval_ms_ = 0;
return absl::nullopt;
}
@@ -139,7 +161,7 @@
1000 * static_cast<int32_t>(timestamp - last_timestamp_) / sample_rate_hz;
const int iat_ms = packet_iat_stopwatch_->ElapsedMs();
const int iat_delay_ms = iat_ms - expected_iat_ms;
- absl::optional<int> relative_delay;
+ int relative_delay;
bool reordered = !IsNewerTimestamp(timestamp, last_timestamp_);
if (reordered) {
relative_delay = std::max(iat_delay_ms, 0);
@@ -147,11 +169,28 @@
UpdateDelayHistory(iat_delay_ms, timestamp, sample_rate_hz);
relative_delay = CalculateRelativePacketArrivalDelay();
}
- const int index = relative_delay.value() / kBucketSizeMs;
- if (index < histogram_->NumBuckets()) {
- // Maximum delay to register is 2000 ms.
- histogram_->Add(index);
+
+ absl::optional<int> histogram_update;
+ if (resample_interval_ms_) {
+ if (static_cast<int>(resample_stopwatch_->ElapsedMs()) >
+ *resample_interval_ms_) {
+ histogram_update = max_delay_in_interval_ms_;
+ resample_stopwatch_ = tick_timer_->GetNewStopwatch();
+ max_delay_in_interval_ms_ = 0;
+ }
+ max_delay_in_interval_ms_ =
+ std::max(max_delay_in_interval_ms_, relative_delay);
+ } else {
+ histogram_update = relative_delay;
}
+ if (histogram_update) {
+ const int index = *histogram_update / kBucketSizeMs;
+ if (index < histogram_->NumBuckets()) {
+ // Maximum delay to register is 2000 ms.
+ histogram_->Add(index);
+ }
+ }
+
// Calculate new |target_level_ms_| based on updated statistics.
int bucket_index = histogram_->Quantile(histogram_quantile_);
target_level_ms_ = (1 + bucket_index) * kBucketSizeMs;
@@ -191,7 +230,7 @@
delay.timestamp = timestamp;
delay_history_.push_back(delay);
while (timestamp - delay_history_.front().timestamp >
- static_cast<uint32_t>(kMaxHistoryMs * sample_rate_hz / 1000)) {
+ static_cast<uint32_t>(max_history_ms_ * sample_rate_hz / 1000)) {
delay_history_.pop_front();
}
}
@@ -226,6 +265,8 @@
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
first_packet_received_ = false;
num_reordered_packets_ = 0;
+ resample_stopwatch_ = tick_timer_->GetNewStopwatch();
+ max_delay_in_interval_ms_ = 0;
}
int DelayManager::TargetDelayMs() const {