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}
This commit is contained in:
committed by
Commit Bot
parent
05f5d636e5
commit
7dff9f3a76
@ -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 @@ namespace {
|
||||
|
||||
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 @@ DelayHistogramConfig GetDelayHistogramConfig() {
|
||||
&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 @@ DelayManager::DelayManager(int max_packets_in_buffer,
|
||||
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 @@ std::unique_ptr<DelayManager> DelayManager::Create(
|
||||
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 @@ absl::optional<int> DelayManager::Update(uint32_t timestamp,
|
||||
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 @@ absl::optional<int> DelayManager::Update(uint32_t timestamp,
|
||||
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 @@ absl::optional<int> DelayManager::Update(uint32_t timestamp,
|
||||
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 @@ void DelayManager::UpdateDelayHistory(int iat_delay_ms,
|
||||
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 @@ void DelayManager::Reset() {
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user