Cleanup NetEq decision logic field trial.
Bug: webrtc:42223518 Change-Id: I2e5064109b9f0358e8e590e4aae6ebeb9d16bc3e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358861 Reviewed-by: Tomas Lundqvist <tomasl@google.com> Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Cr-Commit-Position: refs/heads/main@{#42746}
This commit is contained in:
parent
e864dec2e9
commit
723ea45075
@ -21,10 +21,8 @@
|
||||
#include "modules/audio_coding/neteq/packet_arrival_history.h"
|
||||
#include "modules/audio_coding/neteq/packet_buffer.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 "system_wrappers/include/field_trial.h"
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
@ -32,11 +30,11 @@ namespace {
|
||||
|
||||
constexpr int kPostponeDecodingLevel = 50;
|
||||
constexpr int kTargetLevelWindowMs = 100;
|
||||
constexpr int kMaxWaitForPacketMs = 100;
|
||||
// The granularity of delay adjustments (accelerate/preemptive expand) is 15ms,
|
||||
// but round up since the clock has a granularity of 10ms.
|
||||
constexpr int kDelayAdjustmentGranularityMs = 20;
|
||||
constexpr int kReinitAfterExpandsMs = 1000;
|
||||
constexpr int kPacketHistorySizeMs = 2000;
|
||||
constexpr size_t kCngTimeoutMs = 1000;
|
||||
|
||||
std::unique_ptr<DelayManager> CreateDelayManager(
|
||||
const NetEqController::Config& neteq_config) {
|
||||
@ -65,26 +63,6 @@ bool IsExpand(NetEq::Mode mode) {
|
||||
|
||||
} // namespace
|
||||
|
||||
DecisionLogic::Config::Config() {
|
||||
StructParametersParser::Create(
|
||||
"enable_stable_delay_mode", &enable_stable_delay_mode, //
|
||||
"combine_concealment_decision", &combine_concealment_decision, //
|
||||
"packet_history_size_ms", &packet_history_size_ms, //
|
||||
"cng_timeout_ms", &cng_timeout_ms, //
|
||||
"deceleration_target_level_offset_ms",
|
||||
&deceleration_target_level_offset_ms)
|
||||
->Parse(webrtc::field_trial::FindFullName(
|
||||
"WebRTC-Audio-NetEqDecisionLogicConfig"));
|
||||
RTC_LOG(LS_INFO) << "NetEq decision logic config:"
|
||||
<< " enable_stable_delay_mode=" << enable_stable_delay_mode
|
||||
<< " combine_concealment_decision="
|
||||
<< combine_concealment_decision
|
||||
<< " packet_history_size_ms=" << packet_history_size_ms
|
||||
<< " cng_timeout_ms=" << cng_timeout_ms.value_or(-1)
|
||||
<< " deceleration_target_level_offset_ms="
|
||||
<< deceleration_target_level_offset_ms;
|
||||
}
|
||||
|
||||
DecisionLogic::DecisionLogic(NetEqController::Config config)
|
||||
: DecisionLogic(config,
|
||||
CreateDelayManager(config),
|
||||
@ -97,11 +75,11 @@ DecisionLogic::DecisionLogic(
|
||||
std::unique_ptr<PacketArrivalHistory> packet_arrival_history)
|
||||
: delay_manager_(std::move(delay_manager)),
|
||||
buffer_level_filter_(std::move(buffer_level_filter)),
|
||||
packet_arrival_history_(packet_arrival_history
|
||||
? std::move(packet_arrival_history)
|
||||
: std::make_unique<PacketArrivalHistory>(
|
||||
config.tick_timer,
|
||||
config_.packet_history_size_ms)),
|
||||
packet_arrival_history_(
|
||||
packet_arrival_history
|
||||
? std::move(packet_arrival_history)
|
||||
: std::make_unique<PacketArrivalHistory>(config.tick_timer,
|
||||
kPacketHistorySizeMs)),
|
||||
tick_timer_(config.tick_timer),
|
||||
disallow_time_stretching_(!config.allow_time_stretching),
|
||||
timescale_countdown_(
|
||||
@ -136,8 +114,7 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
|
||||
if (prev_time_scale_) {
|
||||
timescale_countdown_ = tick_timer_->GetNewCountdown(kMinTimescaleInterval);
|
||||
}
|
||||
if (!IsCng(status.last_mode) &&
|
||||
!(config_.combine_concealment_decision && IsExpand(status.last_mode))) {
|
||||
if (!IsCng(status.last_mode) && !IsExpand(status.last_mode)) {
|
||||
FilterBufferLevel(status.packet_buffer_info.span_samples);
|
||||
}
|
||||
|
||||
@ -160,15 +137,6 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
|
||||
return NoPacket(status);
|
||||
}
|
||||
|
||||
// If the expand period was very long, reset NetEQ since it is likely that the
|
||||
// sender was restarted.
|
||||
if (!config_.combine_concealment_decision && IsExpand(status.last_mode) &&
|
||||
status.generated_noise_samples >
|
||||
static_cast<size_t>(kReinitAfterExpandsMs * sample_rate_khz_)) {
|
||||
*reset_decoder = true;
|
||||
return NetEq::Operation::kNormal;
|
||||
}
|
||||
|
||||
if (PostponeDecode(status)) {
|
||||
return NoPacket(status);
|
||||
}
|
||||
@ -190,13 +158,7 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
|
||||
}
|
||||
|
||||
int DecisionLogic::TargetLevelMs() const {
|
||||
int target_delay_ms = delay_manager_->TargetDelayMs();
|
||||
if (!config_.enable_stable_delay_mode) {
|
||||
target_delay_ms =
|
||||
std::max(target_delay_ms,
|
||||
static_cast<int>(packet_length_samples_ / sample_rate_khz_));
|
||||
}
|
||||
return target_delay_ms;
|
||||
return delay_manager_->TargetDelayMs();
|
||||
}
|
||||
|
||||
int DecisionLogic::UnlimitedTargetLevelMs() const {
|
||||
@ -290,9 +252,7 @@ NetEq::Operation DecisionLogic::NoPacket(NetEqController::NetEqStatus status) {
|
||||
return NetEq::Operation::kRfc3389CngNoPacket;
|
||||
case NetEq::Mode::kCodecInternalCng: {
|
||||
// Stop CNG after a timeout.
|
||||
if (config_.cng_timeout_ms &&
|
||||
status.generated_noise_samples >
|
||||
static_cast<size_t>(*config_.cng_timeout_ms * sample_rate_khz_)) {
|
||||
if (status.generated_noise_samples > kCngTimeoutMs * sample_rate_khz_) {
|
||||
return NetEq::Operation::kExpand;
|
||||
}
|
||||
return NetEq::Operation::kCodecInternalCng;
|
||||
@ -307,42 +267,20 @@ NetEq::Operation DecisionLogic::ExpectedPacketAvailable(
|
||||
NetEqController::NetEqStatus status) {
|
||||
if (!disallow_time_stretching_ && status.last_mode != NetEq::Mode::kExpand &&
|
||||
!status.play_dtmf) {
|
||||
if (config_.enable_stable_delay_mode) {
|
||||
const int playout_delay_ms = GetPlayoutDelayMs(status);
|
||||
const int64_t low_limit = TargetLevelMs();
|
||||
const int64_t high_limit = low_limit +
|
||||
packet_arrival_history_->GetMaxDelayMs() +
|
||||
kDelayAdjustmentGranularityMs;
|
||||
if (playout_delay_ms >= high_limit * 4) {
|
||||
return NetEq::Operation::kFastAccelerate;
|
||||
const int playout_delay_ms = GetPlayoutDelayMs(status);
|
||||
const int64_t low_limit = TargetLevelMs();
|
||||
const int64_t high_limit = low_limit +
|
||||
packet_arrival_history_->GetMaxDelayMs() +
|
||||
kDelayAdjustmentGranularityMs;
|
||||
if (playout_delay_ms >= high_limit * 4) {
|
||||
return NetEq::Operation::kFastAccelerate;
|
||||
}
|
||||
if (TimescaleAllowed()) {
|
||||
if (playout_delay_ms >= high_limit) {
|
||||
return NetEq::Operation::kAccelerate;
|
||||
}
|
||||
if (TimescaleAllowed()) {
|
||||
if (playout_delay_ms >= high_limit) {
|
||||
return NetEq::Operation::kAccelerate;
|
||||
}
|
||||
if (playout_delay_ms < low_limit) {
|
||||
return NetEq::Operation::kPreemptiveExpand;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const int target_level_samples = TargetLevelMs() * sample_rate_khz_;
|
||||
const int low_limit = std::max(
|
||||
target_level_samples * 3 / 4,
|
||||
target_level_samples -
|
||||
config_.deceleration_target_level_offset_ms * sample_rate_khz_);
|
||||
const int high_limit = std::max(
|
||||
target_level_samples,
|
||||
low_limit + kDelayAdjustmentGranularityMs * sample_rate_khz_);
|
||||
|
||||
const int buffer_level_samples =
|
||||
buffer_level_filter_->filtered_current_level();
|
||||
if (buffer_level_samples >= high_limit * 4)
|
||||
return NetEq::Operation::kFastAccelerate;
|
||||
if (TimescaleAllowed()) {
|
||||
if (buffer_level_samples >= high_limit)
|
||||
return NetEq::Operation::kAccelerate;
|
||||
if (buffer_level_samples < low_limit)
|
||||
return NetEq::Operation::kPreemptiveExpand;
|
||||
if (playout_delay_ms < low_limit) {
|
||||
return NetEq::Operation::kPreemptiveExpand;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -354,35 +292,20 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable(
|
||||
// Required packet is not available, but a future packet is.
|
||||
// Check if we should continue with an ongoing concealment because the new
|
||||
// packet is too far into the future.
|
||||
if (config_.combine_concealment_decision || IsCng(status.last_mode)) {
|
||||
const int buffer_delay_samples =
|
||||
config_.combine_concealment_decision
|
||||
? status.packet_buffer_info.span_samples_wait_time
|
||||
: status.packet_buffer_info.span_samples;
|
||||
const int buffer_delay_ms = buffer_delay_samples / sample_rate_khz_;
|
||||
const int high_limit = TargetLevelMs() + kTargetLevelWindowMs / 2;
|
||||
const int low_limit =
|
||||
std::max(0, TargetLevelMs() - kTargetLevelWindowMs / 2);
|
||||
const bool above_target_delay = buffer_delay_ms > high_limit;
|
||||
const bool below_target_delay = buffer_delay_ms < low_limit;
|
||||
if ((PacketTooEarly(status) && !above_target_delay) ||
|
||||
(below_target_delay && !config_.combine_concealment_decision)) {
|
||||
return NoPacket(status);
|
||||
}
|
||||
uint32_t timestamp_leap =
|
||||
status.next_packet->timestamp - status.target_timestamp;
|
||||
if (config_.combine_concealment_decision) {
|
||||
if (timestamp_leap != status.generated_noise_samples) {
|
||||
// The delay was adjusted, reinitialize the buffer level filter.
|
||||
buffer_level_filter_->SetFilteredBufferLevel(buffer_delay_samples);
|
||||
}
|
||||
} else {
|
||||
time_stretched_cn_samples_ =
|
||||
timestamp_leap - status.generated_noise_samples;
|
||||
}
|
||||
} else if (IsExpand(status.last_mode) && ShouldContinueExpand(status)) {
|
||||
const int buffer_delay_samples =
|
||||
status.packet_buffer_info.span_samples_wait_time;
|
||||
const int buffer_delay_ms = buffer_delay_samples / sample_rate_khz_;
|
||||
const int high_limit = TargetLevelMs() + kTargetLevelWindowMs / 2;
|
||||
const bool above_target_delay = buffer_delay_ms > high_limit;
|
||||
if ((PacketTooEarly(status) && !above_target_delay)) {
|
||||
return NoPacket(status);
|
||||
}
|
||||
uint32_t timestamp_leap =
|
||||
status.next_packet->timestamp - status.target_timestamp;
|
||||
if (timestamp_leap != status.generated_noise_samples) {
|
||||
// The delay was adjusted, reinitialize the buffer level filter.
|
||||
buffer_level_filter_->SetFilteredBufferLevel(buffer_delay_samples);
|
||||
}
|
||||
|
||||
// Time to play the next packet.
|
||||
switch (status.last_mode) {
|
||||
@ -409,9 +332,7 @@ bool DecisionLogic::PostponeDecode(NetEqController::NetEqStatus status) const {
|
||||
const size_t min_buffer_level_samples =
|
||||
TargetLevelMs() * sample_rate_khz_ * kPostponeDecodingLevel / 100;
|
||||
const size_t buffer_level_samples =
|
||||
config_.combine_concealment_decision
|
||||
? status.packet_buffer_info.span_samples_wait_time
|
||||
: status.packet_buffer_info.span_samples;
|
||||
status.packet_buffer_info.span_samples_wait_time;
|
||||
if (buffer_level_samples >= min_buffer_level_samples) {
|
||||
return false;
|
||||
}
|
||||
@ -421,7 +342,7 @@ bool DecisionLogic::PostponeDecode(NetEqController::NetEqStatus status) const {
|
||||
return false;
|
||||
}
|
||||
// Continue CNG until the buffer is at least at the minimum level.
|
||||
if (config_.combine_concealment_decision && IsCng(status.last_mode)) {
|
||||
if (IsCng(status.last_mode)) {
|
||||
return true;
|
||||
}
|
||||
// Only continue expand if the mute factor is low enough (otherwise the
|
||||
@ -433,32 +354,12 @@ bool DecisionLogic::PostponeDecode(NetEqController::NetEqStatus status) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DecisionLogic::ReinitAfterExpands(
|
||||
NetEqController::NetEqStatus status) const {
|
||||
const uint32_t timestamp_leap =
|
||||
status.next_packet->timestamp - status.target_timestamp;
|
||||
return timestamp_leap >=
|
||||
static_cast<uint32_t>(kReinitAfterExpandsMs * sample_rate_khz_);
|
||||
}
|
||||
|
||||
bool DecisionLogic::PacketTooEarly(NetEqController::NetEqStatus status) const {
|
||||
const uint32_t timestamp_leap =
|
||||
status.next_packet->timestamp - status.target_timestamp;
|
||||
return timestamp_leap > status.generated_noise_samples;
|
||||
}
|
||||
|
||||
bool DecisionLogic::MaxWaitForPacket(
|
||||
NetEqController::NetEqStatus status) const {
|
||||
return status.generated_noise_samples >=
|
||||
static_cast<size_t>(kMaxWaitForPacketMs * sample_rate_khz_);
|
||||
}
|
||||
|
||||
bool DecisionLogic::ShouldContinueExpand(
|
||||
NetEqController::NetEqStatus status) const {
|
||||
return !ReinitAfterExpands(status) && !MaxWaitForPacket(status) &&
|
||||
PacketTooEarly(status) && UnderTargetLevel();
|
||||
}
|
||||
|
||||
int DecisionLogic::GetPlayoutDelayMs(
|
||||
NetEqController::NetEqStatus status) const {
|
||||
uint32_t playout_timestamp =
|
||||
|
||||
@ -140,29 +140,12 @@ class DecisionLogic : public NetEqController {
|
||||
// level, even though the next packet is available.
|
||||
bool PostponeDecode(NetEqController::NetEqStatus status) const;
|
||||
|
||||
// Checks if the timestamp leap is so long into the future that a reset due
|
||||
// to exceeding the expand limit will be done.
|
||||
bool ReinitAfterExpands(NetEqController::NetEqStatus status) const;
|
||||
|
||||
// Checks if we still have not done enough expands to cover the distance from
|
||||
// the last decoded packet to the next available packet.
|
||||
bool PacketTooEarly(NetEqController::NetEqStatus status) const;
|
||||
bool MaxWaitForPacket(NetEqController::NetEqStatus status) const;
|
||||
bool ShouldContinueExpand(NetEqController::NetEqStatus status) const;
|
||||
|
||||
int GetPlayoutDelayMs(NetEqController::NetEqStatus status) const;
|
||||
|
||||
// Runtime configurable options through field trial
|
||||
// WebRTC-Audio-NetEqDecisionLogicConfig.
|
||||
struct Config {
|
||||
Config();
|
||||
|
||||
bool enable_stable_delay_mode = true;
|
||||
bool combine_concealment_decision = true;
|
||||
int deceleration_target_level_offset_ms = 85;
|
||||
int packet_history_size_ms = 2000;
|
||||
absl::optional<int> cng_timeout_ms = 1000;
|
||||
};
|
||||
Config config_;
|
||||
std::unique_ptr<DelayManager> delay_manager_;
|
||||
std::unique_ptr<BufferLevelFilter> buffer_level_filter_;
|
||||
std::unique_ptr<PacketArrivalHistory> packet_arrival_history_;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user