Added experiment to improve handling of frame length changes in NetEq.
The field trial effects two things: after a frame length change the IAT
histogram is scaled to prevent an immediate change in target buffer
level. Also, the peak history in the delay peak detector is cleared,
because the size of the peaks is stored in number of packets (which
will be incorrect after a frame length change).
Bug: webrtc:8381
Change-Id: I214b990f6e5959b655b6542884a7f75da181a0d8
Reviewed-on: https://webrtc-review.googlesource.com/8101
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#20284}
diff --git a/modules/audio_coding/neteq/delay_manager.cc b/modules/audio_coding/neteq/delay_manager.cc
index ab98a06..77a41fd 100644
--- a/modules/audio_coding/neteq/delay_manager.cc
+++ b/modules/audio_coding/neteq/delay_manager.cc
@@ -14,12 +14,14 @@
#include <math.h>
#include <algorithm> // max, min
+#include <numeric>
#include "common_audio/signal_processing/include/signal_processing_library.h"
#include "modules/audio_coding/neteq/delay_peak_detector.h"
#include "modules/include/module_common_types.h"
#include "rtc_base/logging.h"
#include "rtc_base/safe_conversions.h"
+#include "system_wrappers/include/field_trial.h"
namespace webrtc {
@@ -31,7 +33,7 @@
iat_vector_(kMaxIat + 1, 0),
iat_factor_(0),
tick_timer_(tick_timer),
- base_target_level_(4), // In Q0 domain.
+ base_target_level_(4), // In Q0 domain.
target_level_(base_target_level_ << 8), // In Q8 domain.
packet_len_ms_(0),
streaming_mode_(false),
@@ -43,7 +45,9 @@
iat_cumulative_sum_(0),
max_iat_cumulative_sum_(0),
peak_detector_(*peak_detector),
- last_pack_cng_or_dtmf_(1) {
+ last_pack_cng_or_dtmf_(1),
+ frame_length_change_experiment_(
+ field_trial::IsEnabled("WebRTC-Audio-NetEqFramelengthExperiment")) {
assert(peak_detector); // Should never be NULL.
Reset();
}
@@ -298,6 +302,10 @@
LOG_F(LS_ERROR) << "length_ms = " << length_ms;
return -1;
}
+ if (frame_length_change_experiment_ && packet_len_ms_ != length_ms) {
+ iat_vector_ = ScaleHistogram(iat_vector_, packet_len_ms_, length_ms);
+ }
+
packet_len_ms_ = length_ms;
peak_detector_.SetPacketAudioLength(packet_len_ms_);
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
@@ -378,6 +386,41 @@
++last_seq_no_;
}
+DelayManager::IATVector DelayManager::ScaleHistogram(const IATVector& histogram,
+ int old_packet_length,
+ int new_packet_length) {
+ RTC_DCHECK_GT(new_packet_length, 0);
+ RTC_DCHECK_EQ(old_packet_length % 10, 0);
+ RTC_DCHECK_EQ(new_packet_length % 10, 0);
+ IATVector new_histogram(histogram.size(), 0);
+ int acc = 0;
+ int time_counter = 0;
+ size_t new_histogram_idx = 0;
+ for (size_t i = 0; i < histogram.size(); i++) {
+ acc += histogram[i];
+ time_counter += old_packet_length;
+ // The bins should be scaled, to ensure the histogram still sums to one.
+ const int scaled_acc = acc * new_packet_length / time_counter;
+ int actually_used_acc = 0;
+ while (time_counter >= new_packet_length) {
+ actually_used_acc += scaled_acc;
+ new_histogram[new_histogram_idx] += scaled_acc;
+ new_histogram_idx =
+ std::min(new_histogram_idx + 1, new_histogram.size() - 1);
+ time_counter -= new_packet_length;
+ }
+ // Only subtract the part that was succesfully written to the new histogram.
+ acc -= actually_used_acc;
+ }
+ // If there is anything left in acc (due to rounding errors), add it to the
+ // last bin.
+ new_histogram[new_histogram_idx] += acc;
+ RTC_DCHECK_EQ(histogram.size(), new_histogram.size());
+ RTC_DCHECK_EQ(accumulate(histogram.begin(), histogram.end(), 0),
+ accumulate(new_histogram.begin(), new_histogram.end(), 0));
+ return new_histogram;
+}
+
bool DelayManager::SetMinimumDelay(int delay_ms) {
// Minimum delay shouldn't be more than maximum delay, if any maximum is set.
// Also, if possible check |delay| to less than 75% of