From 723ea450759b227735b1a29eec3916edb084a2aa Mon Sep 17 00:00:00 2001 From: Jakob Ivarsson Date: Thu, 8 Aug 2024 09:21:33 +0000 Subject: [PATCH] Cleanup NetEq decision logic field trial. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: webrtc:42223518 Change-Id: I2e5064109b9f0358e8e590e4aae6ebeb9d16bc3e Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/358861 Reviewed-by: Tomas Lundqvist Commit-Queue: Jakob Ivarsson‎ Cr-Commit-Position: refs/heads/main@{#42746} --- modules/audio_coding/neteq/decision_logic.cc | 173 ++++--------------- modules/audio_coding/neteq/decision_logic.h | 19 +- 2 files changed, 38 insertions(+), 154 deletions(-) diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc index f68c05767d..4717144d47 100644 --- a/modules/audio_coding/neteq/decision_logic.cc +++ b/modules/audio_coding/neteq/decision_logic.cc @@ -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 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 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( - config.tick_timer, - config_.packet_history_size_ms)), + packet_arrival_history_( + packet_arrival_history + ? std::move(packet_arrival_history) + : std::make_unique(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(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(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(*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(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(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 = diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h index a6b02c69cd..7292148c70 100644 --- a/modules/audio_coding/neteq/decision_logic.h +++ b/modules/audio_coding/neteq/decision_logic.h @@ -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 cng_timeout_ms = 1000; - }; - Config config_; std::unique_ptr delay_manager_; std::unique_ptr buffer_level_filter_; std::unique_ptr packet_arrival_history_;