Refactor NetEq delay manager logic.

- Removes dependence on sequence number for calculating target delay.
- Changes target delay unit to milliseconds instead of number of
  packets.
- Moves acceleration/preemptive expand thresholds to decision logic.
  Tests for this will be added in a follow up cl.

Bug: webrtc:10333
Change-Id: If690aae4abf41ef1d9353f0ff01fb7d121cf8a26
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/186265
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32326}
This commit is contained in:
Jakob Ivarsson
2020-10-06 14:36:54 +02:00
committed by Commit Bot
parent 76d3e7a8d1
commit f8e62fcb14
12 changed files with 251 additions and 625 deletions

View File

@ -27,6 +27,7 @@ namespace {
constexpr int kPostponeDecodingLevel = 50;
constexpr int kDefaultTargetLevelWindowMs = 100;
constexpr int kDecelerationTargetLevelOffsetMs = 85;
} // namespace
@ -35,7 +36,6 @@ namespace webrtc {
DecisionLogic::DecisionLogic(NetEqController::Config config)
: delay_manager_(DelayManager::Create(config.max_packets_in_buffer,
config.base_min_delay_ms,
config.enable_rtx_handling,
config.tick_timer)),
tick_timer_(config.tick_timer),
disallow_time_stretching_(!config.allow_time_stretching),
@ -67,6 +67,7 @@ void DecisionLogic::Reset() {
packet_length_samples_ = 0;
sample_memory_ = 0;
prev_time_scale_ = false;
last_pack_cng_or_dtmf_ = true;
timescale_countdown_.reset();
num_consecutive_expands_ = 0;
time_stretched_cn_samples_ = 0;
@ -76,6 +77,7 @@ void DecisionLogic::SoftReset() {
packet_length_samples_ = 0;
sample_memory_ = 0;
prev_time_scale_ = false;
last_pack_cng_or_dtmf_ = true;
timescale_countdown_ =
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
time_stretched_cn_samples_ = 0;
@ -158,12 +160,13 @@ NetEq::Operation DecisionLogic::GetDecision(const NetEqStatus& status,
const size_t current_span =
estimate_dtx_delay_ ? status.packet_buffer_info.span_samples
: status.packet_buffer_info.span_samples_no_dtx;
const int target_level_samples =
delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
if ((status.last_mode == NetEq::Mode::kExpand ||
status.last_mode == NetEq::Mode::kCodecPlc) &&
status.expand_mutefactor < 16384 / 2 &&
current_span<static_cast<size_t>(delay_manager_->TargetLevel() *
packet_length_samples_ *
kPostponeDecodingLevel / 100)>> 8 &&
current_span < static_cast<size_t>(target_level_samples *
kPostponeDecodingLevel / 100) &&
!status.packet_buffer_info.dtx_or_cng) {
return NetEq::Operation::kExpand;
}
@ -195,41 +198,32 @@ void DecisionLogic::ExpandDecision(NetEq::Operation operation) {
}
}
absl::optional<int> DecisionLogic::PacketArrived(bool last_cng_or_dtmf,
absl::optional<int> DecisionLogic::PacketArrived(bool is_cng_or_dtmf,
size_t packet_length_samples,
bool should_update_stats,
uint16_t main_sequence_number,
uint32_t main_timestamp,
int fs_hz) {
delay_manager_->LastDecodedWasCngOrDtmf(last_cng_or_dtmf);
absl::optional<int> relative_delay;
if (delay_manager_->last_pack_cng_or_dtmf() == 0) {
// Calculate the total speech length carried in each packet.
if (packet_length_samples > 0 &&
packet_length_samples != packet_length_samples_) {
packet_length_samples_ = packet_length_samples;
delay_manager_->SetPacketAudioLength(
rtc::dchecked_cast<int>((1000 * packet_length_samples) / fs_hz));
}
// Update statistics.
if (should_update_stats) {
relative_delay =
delay_manager_->Update(main_sequence_number, main_timestamp, fs_hz);
}
} else if (delay_manager_->last_pack_cng_or_dtmf() == -1) {
// This is first "normal" packet after CNG or DTMF.
// Reset packet time counter and measure time until next packet,
// but don't update statistics.
delay_manager_->set_last_pack_cng_or_dtmf(0);
delay_manager_->ResetPacketIatCount();
if (is_cng_or_dtmf) {
last_pack_cng_or_dtmf_ = true;
return absl::nullopt;
}
if (!should_update_stats) {
return absl::nullopt;
}
if (packet_length_samples > 0 && fs_hz > 0 &&
packet_length_samples != packet_length_samples_) {
packet_length_samples_ = packet_length_samples;
delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
}
auto relative_delay = delay_manager_->Update(
main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_);
last_pack_cng_or_dtmf_ = false;
return relative_delay;
}
void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
buffer_level_filter_.SetTargetBufferLevel(
delay_manager_->base_target_level());
buffer_level_filter_.SetTargetBufferLevel(delay_manager_->TargetDelayMs());
int time_stretched_samples = time_stretched_cn_samples_;
if (prev_time_scale_) {
@ -250,8 +244,8 @@ NetEq::Operation DecisionLogic::CngOperation(NetEq::Mode prev_mode,
int32_t timestamp_diff = static_cast<int32_t>(
static_cast<uint32_t>(generated_noise_samples + target_timestamp) -
available_timestamp);
int32_t optimal_level_samp = static_cast<int32_t>(
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8);
int optimal_level_samp =
delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
const int64_t excess_waiting_time_samp =
-static_cast<int64_t>(timestamp_diff) - optimal_level_samp;
@ -295,22 +289,26 @@ NetEq::Operation DecisionLogic::ExpectedPacketAvailable(NetEq::Mode prev_mode,
bool play_dtmf) {
if (!disallow_time_stretching_ && prev_mode != NetEq::Mode::kExpand &&
!play_dtmf) {
// Check criterion for time-stretching. The values are in number of packets
// in Q8.
int low_limit, high_limit;
delay_manager_->BufferLimits(&low_limit, &high_limit);
int buffer_level_packets = 0;
if (packet_length_samples_ > 0) {
buffer_level_packets =
((1 << 8) * buffer_level_filter_.filtered_current_level()) /
packet_length_samples_;
}
if (buffer_level_packets >= high_limit << 2)
const int samples_per_ms = sample_rate_ / 1000;
const int target_level_samples =
delay_manager_->TargetDelayMs() * samples_per_ms;
const int low_limit =
std::max(target_level_samples * 3 / 4,
target_level_samples -
kDecelerationTargetLevelOffsetMs * samples_per_ms);
// |higher_limit| is equal to |target_level|, but should at
// least be 20 ms higher than |lower_limit|.
const int high_limit =
std::max(target_level_samples, low_limit + 20 * samples_per_ms);
const int buffer_level_samples =
buffer_level_filter_.filtered_current_level();
if (buffer_level_samples >= high_limit << 2)
return NetEq::Operation::kFastAccelerate;
if (TimescaleAllowed()) {
if (buffer_level_packets >= high_limit)
if (buffer_level_samples >= high_limit)
return NetEq::Operation::kAccelerate;
if (buffer_level_packets < low_limit)
if (buffer_level_samples < low_limit)
return NetEq::Operation::kPreemptiveExpand;
}
}
@ -352,11 +350,11 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable(
prev_mode == NetEq::Mode::kCodecInternalCng) {
size_t cur_size_samples =
estimate_dtx_delay_
? cur_size_samples = span_samples_in_packet_buffer
? span_samples_in_packet_buffer
: num_packets_in_packet_buffer * decoder_frame_length;
// Target level is in number of packets in Q8.
const size_t target_level_samples =
(delay_manager_->TargetLevel() * packet_length_samples_) >> 8;
delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
const bool generated_enough_noise =
static_cast<uint32_t>(generated_noise_samples + target_timestamp) >=
available_timestamp;
@ -406,13 +404,8 @@ NetEq::Operation DecisionLogic::FuturePacketAvailable(
}
bool DecisionLogic::UnderTargetLevel() const {
int buffer_level_packets = 0;
if (packet_length_samples_ > 0) {
buffer_level_packets =
((1 << 8) * buffer_level_filter_.filtered_current_level()) /
packet_length_samples_;
}
return buffer_level_packets <= delay_manager_->TargetLevel();
return buffer_level_filter_.filtered_current_level() <
delay_manager_->TargetDelayMs() * sample_rate_ / 1000;
}
bool DecisionLogic::ReinitAfterExpands(uint32_t timestamp_leap) const {