Skip to content
This repository was archived by the owner on Oct 25, 2024. It is now read-only.

Commit 7dff9f3

Browse files
Jakob IvarssonCommit Bot
authored andcommitted
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 <[email protected]> Commit-Queue: Jakob Ivarsson <[email protected]> Cr-Commit-Position: refs/heads/master@{#32591}
1 parent 05f5d63 commit 7dff9f3

File tree

5 files changed

+125
-41
lines changed

5 files changed

+125
-41
lines changed

modules/audio_coding/neteq/decision_logic_unittest.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ class DecisionLogicTest : public ::testing::Test {
6464
std::unique_ptr<Histogram> histogram =
6565
std::make_unique<Histogram>(200, 12345, 2);
6666
auto delay_manager = std::make_unique<MockDelayManager>(
67-
200, 0, 12300, config.tick_timer, std::move(histogram));
67+
200, 0, 12300, absl::nullopt, 2000, config.tick_timer,
68+
std::move(histogram));
6869
mock_delay_manager_ = delay_manager.get();
6970
auto buffer_level_filter = std::make_unique<MockBufferLevelFilter>();
7071
mock_buffer_level_filter_ = buffer_level_filter.get();

modules/audio_coding/neteq/delay_manager.cc

Lines changed: 81 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "modules/audio_coding/neteq/histogram.h"
2323
#include "modules/include/module_common_types_public.h"
2424
#include "rtc_base/checks.h"
25+
#include "rtc_base/experiments/struct_parameters_parser.h"
2526
#include "rtc_base/logging.h"
2627
#include "rtc_base/numerics/safe_conversions.h"
2728
#include "rtc_base/numerics/safe_minmax.h"
@@ -32,29 +33,34 @@ namespace {
3233

3334
constexpr int kMinBaseMinimumDelayMs = 0;
3435
constexpr int kMaxBaseMinimumDelayMs = 10000;
35-
constexpr int kMaxHistoryMs = 2000; // Oldest packet to include in history to
36-
// calculate relative packet arrival delay.
3736
constexpr int kDelayBuckets = 100;
3837
constexpr int kBucketSizeMs = 20;
3938
constexpr int kStartDelayMs = 80;
4039
constexpr int kMaxNumReorderedPackets = 5;
4140

42-
int PercentileToQuantile(double percentile) {
43-
return static_cast<int>((1 << 30) * percentile / 100.0 + 0.5);
44-
}
45-
46-
struct DelayHistogramConfig {
47-
int quantile = 1041529569; // 0.97 in Q30.
48-
int forget_factor = 32745; // 0.9993 in Q15.
41+
struct DelayManagerConfig {
42+
double quantile = 0.97;
43+
double forget_factor = 0.9993;
4944
absl::optional<double> start_forget_weight = 2;
50-
};
45+
absl::optional<int> resample_interval_ms;
46+
int max_history_ms = 2000;
47+
48+
std::unique_ptr<webrtc::StructParametersParser> Parser() {
49+
return webrtc::StructParametersParser::Create( //
50+
"quantile", &quantile, //
51+
"forget_factor", &forget_factor, //
52+
"start_forget_weight", &start_forget_weight, //
53+
"resample_interval_ms", &resample_interval_ms, //
54+
"max_history_ms", &max_history_ms);
55+
}
5156

52-
// TODO(jakobi): Remove legacy field trial.
53-
DelayHistogramConfig GetDelayHistogramConfig() {
54-
constexpr char kDelayHistogramFieldTrial[] =
55-
"WebRTC-Audio-NetEqDelayHistogram";
56-
DelayHistogramConfig config;
57-
if (webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial)) {
57+
// TODO(jakobi): remove legacy field trial.
58+
void MaybeUpdateFromLegacyFieldTrial() {
59+
constexpr char kDelayHistogramFieldTrial[] =
60+
"WebRTC-Audio-NetEqDelayHistogram";
61+
if (!webrtc::field_trial::IsEnabled(kDelayHistogramFieldTrial)) {
62+
return;
63+
}
5864
const auto field_trial_string =
5965
webrtc::field_trial::FindFullName(kDelayHistogramFieldTrial);
6066
double percentile = -1.0;
@@ -64,34 +70,45 @@ DelayHistogramConfig GetDelayHistogramConfig() {
6470
&forget_factor, &start_forget_weight) >= 2 &&
6571
percentile >= 0.0 && percentile <= 100.0 && forget_factor >= 0.0 &&
6672
forget_factor <= 1.0) {
67-
config.quantile = PercentileToQuantile(percentile);
68-
config.forget_factor = (1 << 15) * forget_factor;
69-
config.start_forget_weight =
70-
start_forget_weight >= 1 ? absl::make_optional(start_forget_weight)
71-
: absl::nullopt;
73+
this->quantile = percentile / 100;
74+
this->forget_factor = forget_factor;
75+
this->start_forget_weight = start_forget_weight >= 1
76+
? absl::make_optional(start_forget_weight)
77+
: absl::nullopt;
7278
}
7379
}
74-
RTC_LOG(LS_INFO) << "Delay histogram config:"
75-
" quantile="
76-
<< config.quantile
77-
<< " forget_factor=" << config.forget_factor
78-
<< " start_forget_weight="
79-
<< config.start_forget_weight.value_or(0);
80-
return config;
81-
}
80+
81+
explicit DelayManagerConfig() {
82+
Parser()->Parse(webrtc::field_trial::FindFullName(
83+
"WebRTC-Audio-NetEqDelayManagerConfig"));
84+
MaybeUpdateFromLegacyFieldTrial();
85+
RTC_LOG(LS_INFO) << "Delay manager config:"
86+
" quantile="
87+
<< quantile << " forget_factor=" << forget_factor
88+
<< " start_forget_weight="
89+
<< start_forget_weight.value_or(0)
90+
<< " resample_interval_ms="
91+
<< resample_interval_ms.value_or(0)
92+
<< " max_history_ms=" << max_history_ms;
93+
}
94+
};
8295

8396
} // namespace
8497

8598
DelayManager::DelayManager(int max_packets_in_buffer,
8699
int base_minimum_delay_ms,
87100
int histogram_quantile,
101+
absl::optional<int> resample_interval_ms,
102+
int max_history_ms,
88103
const TickTimer* tick_timer,
89104
std::unique_ptr<Histogram> histogram)
90105
: first_packet_received_(false),
91106
max_packets_in_buffer_(max_packets_in_buffer),
92107
histogram_(std::move(histogram)),
93108
histogram_quantile_(histogram_quantile),
94109
tick_timer_(tick_timer),
110+
resample_interval_ms_(resample_interval_ms),
111+
max_history_ms_(max_history_ms),
95112
base_minimum_delay_ms_(base_minimum_delay_ms),
96113
effective_minimum_delay_ms_(base_minimum_delay_ms),
97114
minimum_delay_ms_(0),
@@ -108,12 +125,15 @@ std::unique_ptr<DelayManager> DelayManager::Create(
108125
int max_packets_in_buffer,
109126
int base_minimum_delay_ms,
110127
const TickTimer* tick_timer) {
111-
auto config = GetDelayHistogramConfig();
128+
DelayManagerConfig config;
129+
int forget_factor_q15 = (1 << 15) * config.forget_factor;
130+
int quantile_q30 = (1 << 30) * config.quantile;
112131
std::unique_ptr<Histogram> histogram = std::make_unique<Histogram>(
113-
kDelayBuckets, config.forget_factor, config.start_forget_weight);
114-
return std::make_unique<DelayManager>(max_packets_in_buffer,
115-
base_minimum_delay_ms, config.quantile,
116-
tick_timer, std::move(histogram));
132+
kDelayBuckets, forget_factor_q15, config.start_forget_weight);
133+
return std::make_unique<DelayManager>(
134+
max_packets_in_buffer, base_minimum_delay_ms, quantile_q30,
135+
config.resample_interval_ms, config.max_history_ms, tick_timer,
136+
std::move(histogram));
117137
}
118138

119139
DelayManager::~DelayManager() {}
@@ -132,26 +152,45 @@ absl::optional<int> DelayManager::Update(uint32_t timestamp,
132152
last_timestamp_ = timestamp;
133153
first_packet_received_ = true;
134154
num_reordered_packets_ = 0;
155+
resample_stopwatch_ = tick_timer_->GetNewStopwatch();
156+
max_delay_in_interval_ms_ = 0;
135157
return absl::nullopt;
136158
}
137159

138160
const int expected_iat_ms =
139161
1000 * static_cast<int32_t>(timestamp - last_timestamp_) / sample_rate_hz;
140162
const int iat_ms = packet_iat_stopwatch_->ElapsedMs();
141163
const int iat_delay_ms = iat_ms - expected_iat_ms;
142-
absl::optional<int> relative_delay;
164+
int relative_delay;
143165
bool reordered = !IsNewerTimestamp(timestamp, last_timestamp_);
144166
if (reordered) {
145167
relative_delay = std::max(iat_delay_ms, 0);
146168
} else {
147169
UpdateDelayHistory(iat_delay_ms, timestamp, sample_rate_hz);
148170
relative_delay = CalculateRelativePacketArrivalDelay();
149171
}
150-
const int index = relative_delay.value() / kBucketSizeMs;
151-
if (index < histogram_->NumBuckets()) {
152-
// Maximum delay to register is 2000 ms.
153-
histogram_->Add(index);
172+
173+
absl::optional<int> histogram_update;
174+
if (resample_interval_ms_) {
175+
if (static_cast<int>(resample_stopwatch_->ElapsedMs()) >
176+
*resample_interval_ms_) {
177+
histogram_update = max_delay_in_interval_ms_;
178+
resample_stopwatch_ = tick_timer_->GetNewStopwatch();
179+
max_delay_in_interval_ms_ = 0;
180+
}
181+
max_delay_in_interval_ms_ =
182+
std::max(max_delay_in_interval_ms_, relative_delay);
183+
} else {
184+
histogram_update = relative_delay;
154185
}
186+
if (histogram_update) {
187+
const int index = *histogram_update / kBucketSizeMs;
188+
if (index < histogram_->NumBuckets()) {
189+
// Maximum delay to register is 2000 ms.
190+
histogram_->Add(index);
191+
}
192+
}
193+
155194
// Calculate new |target_level_ms_| based on updated statistics.
156195
int bucket_index = histogram_->Quantile(histogram_quantile_);
157196
target_level_ms_ = (1 + bucket_index) * kBucketSizeMs;
@@ -191,7 +230,7 @@ void DelayManager::UpdateDelayHistory(int iat_delay_ms,
191230
delay.timestamp = timestamp;
192231
delay_history_.push_back(delay);
193232
while (timestamp - delay_history_.front().timestamp >
194-
static_cast<uint32_t>(kMaxHistoryMs * sample_rate_hz / 1000)) {
233+
static_cast<uint32_t>(max_history_ms_ * sample_rate_hz / 1000)) {
195234
delay_history_.pop_front();
196235
}
197236
}
@@ -226,6 +265,8 @@ void DelayManager::Reset() {
226265
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
227266
first_packet_received_ = false;
228267
num_reordered_packets_ = 0;
268+
resample_stopwatch_ = tick_timer_->GetNewStopwatch();
269+
max_delay_in_interval_ms_ = 0;
229270
}
230271

231272
int DelayManager::TargetDelayMs() const {

modules/audio_coding/neteq/delay_manager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class DelayManager {
2828
DelayManager(int max_packets_in_buffer,
2929
int base_minimum_delay_ms,
3030
int histogram_quantile,
31+
absl::optional<int> resample_interval_ms,
32+
int max_history_ms,
3133
const TickTimer* tick_timer,
3234
std::unique_ptr<Histogram> histogram);
3335

@@ -105,6 +107,9 @@ class DelayManager {
105107
std::unique_ptr<Histogram> histogram_;
106108
const int histogram_quantile_;
107109
const TickTimer* tick_timer_;
110+
const absl::optional<int> resample_interval_ms_;
111+
const int max_history_ms_;
112+
108113
int base_minimum_delay_ms_;
109114
int effective_minimum_delay_ms_; // Used as lower bound for target delay.
110115
int minimum_delay_ms_; // Externally set minimum delay.
@@ -116,6 +121,8 @@ class DelayManager {
116121
int target_level_ms_; // Currently preferred buffer level.
117122
uint32_t last_timestamp_; // Timestamp for the last received packet.
118123
int num_reordered_packets_ = 0;
124+
int max_delay_in_interval_ms_ = 0;
125+
std::unique_ptr<TickTimer::Stopwatch> resample_stopwatch_;
119126

120127
struct PacketDelay {
121128
int iat_delay_ms;

modules/audio_coding/neteq/delay_manager_unittest.cc

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include <memory>
1818

19+
#include "absl/types/optional.h"
1920
#include "modules/audio_coding/neteq/histogram.h"
2021
#include "modules/audio_coding/neteq/mock/mock_histogram.h"
2122
#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h"
@@ -29,6 +30,7 @@ namespace webrtc {
2930
namespace {
3031
constexpr int kMaxNumberOfPackets = 240;
3132
constexpr int kMinDelayMs = 0;
33+
constexpr int kMaxHistoryMs = 2000;
3234
constexpr int kTimeStepMs = 10;
3335
constexpr int kFs = 8000;
3436
constexpr int kFrameSizeMs = 20;
@@ -53,6 +55,7 @@ class DelayManagerTest : public ::testing::Test {
5355
MockHistogram* mock_histogram_;
5456
uint32_t ts_;
5557
bool use_mock_histogram_ = false;
58+
absl::optional<int> resample_interval_ms_;
5659
};
5760

5861
DelayManagerTest::DelayManagerTest()
@@ -69,6 +72,7 @@ void DelayManagerTest::RecreateDelayManager() {
6972
std::unique_ptr<Histogram> histogram(mock_histogram_);
7073
dm_ = std::make_unique<DelayManager>(kMaxNumberOfPackets, kMinDelayMs,
7174
kDefaultHistogramQuantile,
75+
resample_interval_ms_, kMaxHistoryMs,
7276
&tick_timer_, std::move(histogram));
7377
} else {
7478
dm_ = DelayManager::Create(kMaxNumberOfPackets, kMinDelayMs, &tick_timer_);
@@ -455,4 +459,31 @@ TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
455459
EXPECT_EQ(20, InsertNextPacket());
456460
}
457461

462+
TEST_F(DelayManagerTest, ResamplePacketDelays) {
463+
use_mock_histogram_ = true;
464+
resample_interval_ms_ = 500;
465+
RecreateDelayManager();
466+
467+
// The histogram should be updated once with the maximum delay observed for
468+
// the following sequence of packets.
469+
EXPECT_CALL(*mock_histogram_, Add(5)).Times(1);
470+
471+
EXPECT_EQ(absl::nullopt, InsertNextPacket());
472+
473+
IncreaseTime(kFrameSizeMs);
474+
EXPECT_EQ(0, InsertNextPacket());
475+
IncreaseTime(3 * kFrameSizeMs);
476+
EXPECT_EQ(2 * kFrameSizeMs, InsertNextPacket());
477+
IncreaseTime(4 * kFrameSizeMs);
478+
EXPECT_EQ(5 * kFrameSizeMs, InsertNextPacket());
479+
480+
for (int i = 4; i >= 0; --i) {
481+
EXPECT_EQ(i * kFrameSizeMs, InsertNextPacket());
482+
}
483+
for (int i = 0; i < *resample_interval_ms_ / kFrameSizeMs; ++i) {
484+
IncreaseTime(kFrameSizeMs);
485+
EXPECT_EQ(0, InsertNextPacket());
486+
}
487+
}
488+
458489
} // namespace webrtc

modules/audio_coding/neteq/mock/mock_delay_manager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ class MockDelayManager : public DelayManager {
2525
MockDelayManager(size_t max_packets_in_buffer,
2626
int base_minimum_delay_ms,
2727
int histogram_quantile,
28+
absl::optional<int> resample_interval_ms,
29+
int max_history_ms,
2830
const TickTimer* tick_timer,
2931
std::unique_ptr<Histogram> histogram)
3032
: DelayManager(max_packets_in_buffer,
3133
base_minimum_delay_ms,
3234
histogram_quantile,
35+
resample_interval_ms,
36+
max_history_ms,
3337
tick_timer,
3438
std::move(histogram)) {}
3539
MOCK_METHOD(int, TargetDelayMs, (), (const));

0 commit comments

Comments
 (0)