Use packet arrival history in delay manager.
It replaces the relative arrival delay tracker which is equivalent. This results in a slight bit-exactness change but nothing that should affect quality. Bug: webrtc:13322 Change-Id: I6ed5d6fdfa724859122928a8838acce27ac2e5d0 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/263380 Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org> Reviewed-by: Minyue Li <minyue@webrtc.org> Cr-Commit-Position: refs/heads/main@{#37004}
This commit is contained in:

committed by
WebRTC LUCI CQ

parent
c1fb359b2a
commit
01ab7d501b
@ -986,8 +986,6 @@ rtc_library("neteq") {
|
|||||||
"neteq/random_vector.h",
|
"neteq/random_vector.h",
|
||||||
"neteq/red_payload_splitter.cc",
|
"neteq/red_payload_splitter.cc",
|
||||||
"neteq/red_payload_splitter.h",
|
"neteq/red_payload_splitter.h",
|
||||||
"neteq/relative_arrival_delay_tracker.cc",
|
|
||||||
"neteq/relative_arrival_delay_tracker.h",
|
|
||||||
"neteq/reorder_optimizer.cc",
|
"neteq/reorder_optimizer.cc",
|
||||||
"neteq/reorder_optimizer.h",
|
"neteq/reorder_optimizer.h",
|
||||||
"neteq/statistics_calculator.cc",
|
"neteq/statistics_calculator.cc",
|
||||||
@ -2037,7 +2035,6 @@ if (rtc_include_tests) {
|
|||||||
"neteq/post_decode_vad_unittest.cc",
|
"neteq/post_decode_vad_unittest.cc",
|
||||||
"neteq/random_vector_unittest.cc",
|
"neteq/random_vector_unittest.cc",
|
||||||
"neteq/red_payload_splitter_unittest.cc",
|
"neteq/red_payload_splitter_unittest.cc",
|
||||||
"neteq/relative_arrival_delay_tracker_unittest.cc",
|
|
||||||
"neteq/reorder_optimizer_unittest.cc",
|
"neteq/reorder_optimizer_unittest.cc",
|
||||||
"neteq/statistics_calculator_unittest.cc",
|
"neteq/statistics_calculator_unittest.cc",
|
||||||
"neteq/sync_buffer_unittest.cc",
|
"neteq/sync_buffer_unittest.cc",
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -106,7 +107,6 @@ void DecisionLogic::SoftReset() {
|
|||||||
packet_length_samples_ = 0;
|
packet_length_samples_ = 0;
|
||||||
sample_memory_ = 0;
|
sample_memory_ = 0;
|
||||||
prev_time_scale_ = false;
|
prev_time_scale_ = false;
|
||||||
last_pack_cng_or_dtmf_ = true;
|
|
||||||
timescale_countdown_ =
|
timescale_countdown_ =
|
||||||
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
|
tick_timer_->GetNewCountdown(kMinTimescaleInterval + 1);
|
||||||
time_stretched_cn_samples_ = 0;
|
time_stretched_cn_samples_ = 0;
|
||||||
@ -239,11 +239,7 @@ absl::optional<int> DecisionLogic::PacketArrived(
|
|||||||
bool should_update_stats,
|
bool should_update_stats,
|
||||||
const PacketArrivedInfo& info) {
|
const PacketArrivedInfo& info) {
|
||||||
buffer_flush_ = buffer_flush_ || info.buffer_flush;
|
buffer_flush_ = buffer_flush_ || info.buffer_flush;
|
||||||
if (info.is_cng_or_dtmf) {
|
if (!should_update_stats || info.is_cng_or_dtmf) {
|
||||||
last_pack_cng_or_dtmf_ = true;
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
if (!should_update_stats) {
|
|
||||||
return absl::nullopt;
|
return absl::nullopt;
|
||||||
}
|
}
|
||||||
if (info.packet_length_samples > 0 && fs_hz > 0 &&
|
if (info.packet_length_samples > 0 && fs_hz > 0 &&
|
||||||
@ -251,12 +247,18 @@ absl::optional<int> DecisionLogic::PacketArrived(
|
|||||||
packet_length_samples_ = info.packet_length_samples;
|
packet_length_samples_ = info.packet_length_samples;
|
||||||
delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
|
delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
|
||||||
}
|
}
|
||||||
packet_arrival_history_.Insert(
|
int64_t time_now_ms = tick_timer_->ticks() * tick_timer_->ms_per_tick();
|
||||||
info.main_timestamp, tick_timer_->ticks() * tick_timer_->ms_per_tick());
|
packet_arrival_history_.Insert(info.main_timestamp, time_now_ms);
|
||||||
auto relative_delay = delay_manager_->Update(
|
if (packet_arrival_history_.size() < 2) {
|
||||||
info.main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_);
|
// No meaningful delay estimate unless at least 2 packets have arrived.
|
||||||
last_pack_cng_or_dtmf_ = false;
|
return absl::nullopt;
|
||||||
return relative_delay;
|
}
|
||||||
|
int arrival_delay_ms =
|
||||||
|
packet_arrival_history_.GetDelayMs(info.main_timestamp, time_now_ms);
|
||||||
|
bool reordered =
|
||||||
|
!packet_arrival_history_.IsNewestRtpTimestamp(info.main_timestamp);
|
||||||
|
delay_manager_->Update(arrival_delay_ms, reordered);
|
||||||
|
return arrival_delay_ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
|
void DecisionLogic::FilterBufferLevel(size_t buffer_size_samples) {
|
||||||
|
@ -191,7 +191,6 @@ class DecisionLogic : public NetEqController {
|
|||||||
std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
|
std::unique_ptr<TickTimer::Countdown> timescale_countdown_;
|
||||||
int num_consecutive_expands_ = 0;
|
int num_consecutive_expands_ = 0;
|
||||||
int time_stretched_cn_samples_ = 0;
|
int time_stretched_cn_samples_ = 0;
|
||||||
bool last_pack_cng_or_dtmf_ = true;
|
|
||||||
bool buffer_flush_ = false;
|
bool buffer_flush_ = false;
|
||||||
int last_playout_delay_ms_ = 0;
|
int last_playout_delay_ms_ = 0;
|
||||||
};
|
};
|
||||||
|
@ -51,7 +51,6 @@ DelayManager::Config::Config() {
|
|||||||
"forget_factor", &forget_factor, //
|
"forget_factor", &forget_factor, //
|
||||||
"start_forget_weight", &start_forget_weight, //
|
"start_forget_weight", &start_forget_weight, //
|
||||||
"resample_interval_ms", &resample_interval_ms, //
|
"resample_interval_ms", &resample_interval_ms, //
|
||||||
"max_history_ms", &max_history_ms, //
|
|
||||||
"use_reorder_optimizer", &use_reorder_optimizer, //
|
"use_reorder_optimizer", &use_reorder_optimizer, //
|
||||||
"reorder_forget_factor", &reorder_forget_factor, //
|
"reorder_forget_factor", &reorder_forget_factor, //
|
||||||
"ms_per_loss_percent", &ms_per_loss_percent)
|
"ms_per_loss_percent", &ms_per_loss_percent)
|
||||||
@ -66,7 +65,6 @@ void DelayManager::Config::Log() {
|
|||||||
<< " start_forget_weight=" << start_forget_weight.value_or(0)
|
<< " start_forget_weight=" << start_forget_weight.value_or(0)
|
||||||
<< " resample_interval_ms="
|
<< " resample_interval_ms="
|
||||||
<< resample_interval_ms.value_or(0)
|
<< resample_interval_ms.value_or(0)
|
||||||
<< " max_history_ms=" << max_history_ms
|
|
||||||
<< " use_reorder_optimizer=" << use_reorder_optimizer
|
<< " use_reorder_optimizer=" << use_reorder_optimizer
|
||||||
<< " reorder_forget_factor=" << reorder_forget_factor
|
<< " reorder_forget_factor=" << reorder_forget_factor
|
||||||
<< " ms_per_loss_percent=" << ms_per_loss_percent;
|
<< " ms_per_loss_percent=" << ms_per_loss_percent;
|
||||||
@ -80,7 +78,6 @@ DelayManager::DelayManager(const Config& config, const TickTimer* tick_timer)
|
|||||||
config.start_forget_weight,
|
config.start_forget_weight,
|
||||||
config.resample_interval_ms),
|
config.resample_interval_ms),
|
||||||
reorder_optimizer_(MaybeCreateReorderOptimizer(config)),
|
reorder_optimizer_(MaybeCreateReorderOptimizer(config)),
|
||||||
relative_arrival_delay_tracker_(tick_timer, config.max_history_ms),
|
|
||||||
base_minimum_delay_ms_(config.base_minimum_delay_ms),
|
base_minimum_delay_ms_(config.base_minimum_delay_ms),
|
||||||
effective_minimum_delay_ms_(config.base_minimum_delay_ms),
|
effective_minimum_delay_ms_(config.base_minimum_delay_ms),
|
||||||
minimum_delay_ms_(0),
|
minimum_delay_ms_(0),
|
||||||
@ -93,27 +90,14 @@ DelayManager::DelayManager(const Config& config, const TickTimer* tick_timer)
|
|||||||
|
|
||||||
DelayManager::~DelayManager() {}
|
DelayManager::~DelayManager() {}
|
||||||
|
|
||||||
absl::optional<int> DelayManager::Update(uint32_t timestamp,
|
void DelayManager::Update(int arrival_delay_ms, bool reordered) {
|
||||||
int sample_rate_hz,
|
|
||||||
bool reset) {
|
|
||||||
if (reset) {
|
|
||||||
relative_arrival_delay_tracker_.Reset();
|
|
||||||
}
|
|
||||||
absl::optional<int> relative_delay =
|
|
||||||
relative_arrival_delay_tracker_.Update(timestamp, sample_rate_hz);
|
|
||||||
if (!relative_delay) {
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool reordered =
|
|
||||||
relative_arrival_delay_tracker_.newest_timestamp() != timestamp;
|
|
||||||
if (!reorder_optimizer_ || !reordered) {
|
if (!reorder_optimizer_ || !reordered) {
|
||||||
underrun_optimizer_.Update(*relative_delay);
|
underrun_optimizer_.Update(arrival_delay_ms);
|
||||||
}
|
}
|
||||||
target_level_ms_ =
|
target_level_ms_ =
|
||||||
underrun_optimizer_.GetOptimalDelayMs().value_or(kStartDelayMs);
|
underrun_optimizer_.GetOptimalDelayMs().value_or(kStartDelayMs);
|
||||||
if (reorder_optimizer_) {
|
if (reorder_optimizer_) {
|
||||||
reorder_optimizer_->Update(*relative_delay, reordered, target_level_ms_);
|
reorder_optimizer_->Update(arrival_delay_ms, reordered, target_level_ms_);
|
||||||
target_level_ms_ = std::max(
|
target_level_ms_ = std::max(
|
||||||
target_level_ms_, reorder_optimizer_->GetOptimalDelayMs().value_or(0));
|
target_level_ms_, reorder_optimizer_->GetOptimalDelayMs().value_or(0));
|
||||||
}
|
}
|
||||||
@ -126,11 +110,8 @@ absl::optional<int> DelayManager::Update(uint32_t timestamp,
|
|||||||
target_level_ms_ = std::min(
|
target_level_ms_ = std::min(
|
||||||
target_level_ms_, 3 * max_packets_in_buffer_ * packet_len_ms_ / 4);
|
target_level_ms_, 3 * max_packets_in_buffer_ * packet_len_ms_ / 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
return relative_delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int DelayManager::SetPacketAudioLength(int length_ms) {
|
int DelayManager::SetPacketAudioLength(int length_ms) {
|
||||||
if (length_ms <= 0) {
|
if (length_ms <= 0) {
|
||||||
RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms;
|
RTC_LOG_F(LS_ERROR) << "length_ms = " << length_ms;
|
||||||
@ -143,7 +124,6 @@ int DelayManager::SetPacketAudioLength(int length_ms) {
|
|||||||
void DelayManager::Reset() {
|
void DelayManager::Reset() {
|
||||||
packet_len_ms_ = 0;
|
packet_len_ms_ = 0;
|
||||||
underrun_optimizer_.Reset();
|
underrun_optimizer_.Reset();
|
||||||
relative_arrival_delay_tracker_.Reset();
|
|
||||||
target_level_ms_ = kStartDelayMs;
|
target_level_ms_ = kStartDelayMs;
|
||||||
if (reorder_optimizer_) {
|
if (reorder_optimizer_) {
|
||||||
reorder_optimizer_->Reset();
|
reorder_optimizer_->Reset();
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "absl/types/optional.h"
|
#include "absl/types/optional.h"
|
||||||
#include "api/neteq/tick_timer.h"
|
#include "api/neteq/tick_timer.h"
|
||||||
#include "modules/audio_coding/neteq/histogram.h"
|
#include "modules/audio_coding/neteq/histogram.h"
|
||||||
#include "modules/audio_coding/neteq/relative_arrival_delay_tracker.h"
|
|
||||||
#include "modules/audio_coding/neteq/reorder_optimizer.h"
|
#include "modules/audio_coding/neteq/reorder_optimizer.h"
|
||||||
#include "modules/audio_coding/neteq/underrun_optimizer.h"
|
#include "modules/audio_coding/neteq/underrun_optimizer.h"
|
||||||
|
|
||||||
@ -36,7 +35,6 @@ class DelayManager {
|
|||||||
double forget_factor = 0.983;
|
double forget_factor = 0.983;
|
||||||
absl::optional<double> start_forget_weight = 2;
|
absl::optional<double> start_forget_weight = 2;
|
||||||
absl::optional<int> resample_interval_ms = 500;
|
absl::optional<int> resample_interval_ms = 500;
|
||||||
int max_history_ms = 2000;
|
|
||||||
|
|
||||||
bool use_reorder_optimizer = true;
|
bool use_reorder_optimizer = true;
|
||||||
double reorder_forget_factor = 0.9993;
|
double reorder_forget_factor = 0.9993;
|
||||||
@ -54,14 +52,11 @@ class DelayManager {
|
|||||||
DelayManager(const DelayManager&) = delete;
|
DelayManager(const DelayManager&) = delete;
|
||||||
DelayManager& operator=(const DelayManager&) = delete;
|
DelayManager& operator=(const DelayManager&) = delete;
|
||||||
|
|
||||||
// Updates the delay manager with a new incoming packet, with `timestamp` from
|
// Updates the delay manager that a new packet arrived with delay
|
||||||
// the RTP header. This updates the statistics and a new target buffer level
|
// `arrival_delay_ms`. This updates the statistics and a new target buffer
|
||||||
// is calculated. Returns the relative delay if it can be calculated. If
|
// level is calculated. The `reordered` flag indicates if the packet was
|
||||||
// `reset` is true, restarts the relative arrival delay calculation from this
|
// reordered.
|
||||||
// packet.
|
virtual void Update(int arrival_delay_ms, bool reordered);
|
||||||
virtual absl::optional<int> Update(uint32_t timestamp,
|
|
||||||
int sample_rate_hz,
|
|
||||||
bool reset = false);
|
|
||||||
|
|
||||||
// Resets all state.
|
// Resets all state.
|
||||||
virtual void Reset();
|
virtual void Reset();
|
||||||
@ -105,7 +100,6 @@ class DelayManager {
|
|||||||
const int max_packets_in_buffer_;
|
const int max_packets_in_buffer_;
|
||||||
UnderrunOptimizer underrun_optimizer_;
|
UnderrunOptimizer underrun_optimizer_;
|
||||||
std::unique_ptr<ReorderOptimizer> reorder_optimizer_;
|
std::unique_ptr<ReorderOptimizer> reorder_optimizer_;
|
||||||
RelativeArrivalDelayTracker relative_arrival_delay_tracker_;
|
|
||||||
|
|
||||||
int base_minimum_delay_ms_;
|
int base_minimum_delay_ms_;
|
||||||
int effective_minimum_delay_ms_; // Used as lower bound for target delay.
|
int effective_minimum_delay_ms_; // Used as lower bound for target delay.
|
||||||
|
@ -30,9 +30,7 @@ namespace webrtc {
|
|||||||
namespace {
|
namespace {
|
||||||
constexpr int kMaxNumberOfPackets = 200;
|
constexpr int kMaxNumberOfPackets = 200;
|
||||||
constexpr int kTimeStepMs = 10;
|
constexpr int kTimeStepMs = 10;
|
||||||
constexpr int kFs = 8000;
|
|
||||||
constexpr int kFrameSizeMs = 20;
|
constexpr int kFrameSizeMs = 20;
|
||||||
constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000;
|
|
||||||
constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs;
|
constexpr int kMaxBufferSizeMs = kMaxNumberOfPackets * kFrameSizeMs;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -41,25 +39,22 @@ class DelayManagerTest : public ::testing::Test {
|
|||||||
protected:
|
protected:
|
||||||
DelayManagerTest();
|
DelayManagerTest();
|
||||||
virtual void SetUp();
|
virtual void SetUp();
|
||||||
absl::optional<int> InsertNextPacket();
|
void Update(int delay);
|
||||||
void IncreaseTime(int inc_ms);
|
void IncreaseTime(int inc_ms);
|
||||||
|
|
||||||
TickTimer tick_timer_;
|
TickTimer tick_timer_;
|
||||||
DelayManager dm_;
|
DelayManager dm_;
|
||||||
uint32_t ts_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DelayManagerTest::DelayManagerTest()
|
DelayManagerTest::DelayManagerTest()
|
||||||
: dm_(DelayManager::Config(), &tick_timer_), ts_(0x12345678) {}
|
: dm_(DelayManager::Config(), &tick_timer_) {}
|
||||||
|
|
||||||
void DelayManagerTest::SetUp() {
|
void DelayManagerTest::SetUp() {
|
||||||
dm_.SetPacketAudioLength(kFrameSizeMs);
|
dm_.SetPacketAudioLength(kFrameSizeMs);
|
||||||
}
|
}
|
||||||
|
|
||||||
absl::optional<int> DelayManagerTest::InsertNextPacket() {
|
void DelayManagerTest::Update(int delay) {
|
||||||
auto relative_delay = dm_.Update(ts_, kFs);
|
dm_.Update(delay, false);
|
||||||
ts_ += kTsIncrement;
|
|
||||||
return relative_delay;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DelayManagerTest::IncreaseTime(int inc_ms) {
|
void DelayManagerTest::IncreaseTime(int inc_ms) {
|
||||||
@ -75,28 +70,28 @@ TEST_F(DelayManagerTest, CreateAndDestroy) {
|
|||||||
|
|
||||||
TEST_F(DelayManagerTest, UpdateNormal) {
|
TEST_F(DelayManagerTest, UpdateNormal) {
|
||||||
for (int i = 0; i < 50; ++i) {
|
for (int i = 0; i < 50; ++i) {
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
IncreaseTime(kFrameSizeMs);
|
IncreaseTime(kFrameSizeMs);
|
||||||
}
|
}
|
||||||
EXPECT_EQ(20, dm_.TargetDelayMs());
|
EXPECT_EQ(20, dm_.TargetDelayMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayManagerTest, MaxDelay) {
|
TEST_F(DelayManagerTest, MaxDelay) {
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
const int kMaxDelayMs = 60;
|
const int kMaxDelayMs = 60;
|
||||||
EXPECT_GT(dm_.TargetDelayMs(), kMaxDelayMs);
|
EXPECT_GT(dm_.TargetDelayMs(), kMaxDelayMs);
|
||||||
EXPECT_TRUE(dm_.SetMaximumDelay(kMaxDelayMs));
|
EXPECT_TRUE(dm_.SetMaximumDelay(kMaxDelayMs));
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
EXPECT_EQ(kMaxDelayMs, dm_.TargetDelayMs());
|
EXPECT_EQ(kMaxDelayMs, dm_.TargetDelayMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayManagerTest, MinDelay) {
|
TEST_F(DelayManagerTest, MinDelay) {
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
int kMinDelayMs = 7 * kFrameSizeMs;
|
int kMinDelayMs = 7 * kFrameSizeMs;
|
||||||
EXPECT_LT(dm_.TargetDelayMs(), kMinDelayMs);
|
EXPECT_LT(dm_.TargetDelayMs(), kMinDelayMs);
|
||||||
dm_.SetMinimumDelay(kMinDelayMs);
|
dm_.SetMinimumDelay(kMinDelayMs);
|
||||||
IncreaseTime(kFrameSizeMs);
|
IncreaseTime(kFrameSizeMs);
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
EXPECT_EQ(kMinDelayMs, dm_.TargetDelayMs());
|
EXPECT_EQ(kMinDelayMs, dm_.TargetDelayMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +215,7 @@ TEST_F(DelayManagerTest, MinimumDelayMemorization) {
|
|||||||
|
|
||||||
TEST_F(DelayManagerTest, BaseMinimumDelay) {
|
TEST_F(DelayManagerTest, BaseMinimumDelay) {
|
||||||
// First packet arrival.
|
// First packet arrival.
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
|
|
||||||
constexpr int kBaseMinimumDelayMs = 7 * kFrameSizeMs;
|
constexpr int kBaseMinimumDelayMs = 7 * kFrameSizeMs;
|
||||||
EXPECT_LT(dm_.TargetDelayMs(), kBaseMinimumDelayMs);
|
EXPECT_LT(dm_.TargetDelayMs(), kBaseMinimumDelayMs);
|
||||||
@ -228,14 +223,12 @@ TEST_F(DelayManagerTest, BaseMinimumDelay) {
|
|||||||
EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs);
|
EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs);
|
||||||
|
|
||||||
IncreaseTime(kFrameSizeMs);
|
IncreaseTime(kFrameSizeMs);
|
||||||
InsertNextPacket();
|
Update(0);
|
||||||
EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs);
|
EXPECT_EQ(dm_.GetBaseMinimumDelay(), kBaseMinimumDelayMs);
|
||||||
EXPECT_EQ(kBaseMinimumDelayMs, dm_.TargetDelayMs());
|
EXPECT_EQ(kBaseMinimumDelayMs, dm_.TargetDelayMs());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayManagerTest, Failures) {
|
TEST_F(DelayManagerTest, Failures) {
|
||||||
// Wrong sample rate.
|
|
||||||
EXPECT_EQ(absl::nullopt, dm_.Update(0, -1));
|
|
||||||
// Wrong packet size.
|
// Wrong packet size.
|
||||||
EXPECT_EQ(-1, dm_.SetPacketAudioLength(0));
|
EXPECT_EQ(-1, dm_.SetPacketAudioLength(0));
|
||||||
EXPECT_EQ(-1, dm_.SetPacketAudioLength(-1));
|
EXPECT_EQ(-1, dm_.SetPacketAudioLength(-1));
|
||||||
@ -250,13 +243,4 @@ TEST_F(DelayManagerTest, Failures) {
|
|||||||
EXPECT_FALSE(dm_.SetMaximumDelay(60));
|
EXPECT_FALSE(dm_.SetMaximumDelay(60));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(DelayManagerTest, RelativeArrivalDelayStatistic) {
|
|
||||||
EXPECT_EQ(absl::nullopt, InsertNextPacket());
|
|
||||||
IncreaseTime(kFrameSizeMs);
|
|
||||||
EXPECT_EQ(0, InsertNextPacket());
|
|
||||||
IncreaseTime(2 * kFrameSizeMs);
|
|
||||||
|
|
||||||
EXPECT_EQ(20, InsertNextPacket());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
} // namespace webrtc
|
||||||
|
@ -57,10 +57,10 @@ TEST_F(NetEqDecodingTest, MAYBE_TestBitExactness) {
|
|||||||
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
|
webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp");
|
||||||
|
|
||||||
const std::string output_checksum =
|
const std::string output_checksum =
|
||||||
"5e56fabfacd6fa202f3a00bcb4e034d6d817e6b3";
|
"dee7a10ab92526876a70a85bc48a4906901af3df";
|
||||||
|
|
||||||
const std::string network_stats_checksum =
|
const std::string network_stats_checksum =
|
||||||
"dfbf60f913a25a1f2f1066f85b4b08c24eed0ef2";
|
"911dbf5fd97f48d25b8f0967286eb73c9d6f6158";
|
||||||
|
|
||||||
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
|
DecodeAndCompare(input_rtp_file, output_checksum, network_stats_checksum,
|
||||||
absl::GetFlag(FLAGS_gen_ref));
|
absl::GetFlag(FLAGS_gen_ref));
|
||||||
|
@ -23,12 +23,16 @@ PacketArrivalHistory::PacketArrivalHistory(int window_size_ms)
|
|||||||
void PacketArrivalHistory::Insert(uint32_t rtp_timestamp,
|
void PacketArrivalHistory::Insert(uint32_t rtp_timestamp,
|
||||||
int64_t arrival_time_ms) {
|
int64_t arrival_time_ms) {
|
||||||
RTC_DCHECK(sample_rate_khz_ > 0);
|
RTC_DCHECK(sample_rate_khz_ > 0);
|
||||||
int64_t unwrapped_rtp_timestamp_ms =
|
int64_t unwrapped_rtp_timestamp = timestamp_unwrapper_.Unwrap(rtp_timestamp);
|
||||||
timestamp_unwrapper_.Unwrap(rtp_timestamp) / sample_rate_khz_;
|
if (!newest_rtp_timestamp_ ||
|
||||||
history_.emplace_back(unwrapped_rtp_timestamp_ms, arrival_time_ms);
|
unwrapped_rtp_timestamp > *newest_rtp_timestamp_) {
|
||||||
|
newest_rtp_timestamp_ = unwrapped_rtp_timestamp;
|
||||||
|
}
|
||||||
|
history_.emplace_back(unwrapped_rtp_timestamp / sample_rate_khz_,
|
||||||
|
arrival_time_ms);
|
||||||
MaybeUpdateCachedArrivals(history_.back());
|
MaybeUpdateCachedArrivals(history_.back());
|
||||||
while (history_.front().rtp_timestamp_ms + window_size_ms_ <
|
while (history_.front().rtp_timestamp_ms + window_size_ms_ <
|
||||||
unwrapped_rtp_timestamp_ms) {
|
unwrapped_rtp_timestamp / sample_rate_khz_) {
|
||||||
if (&history_.front() == min_packet_arrival_) {
|
if (&history_.front() == min_packet_arrival_) {
|
||||||
min_packet_arrival_ = nullptr;
|
min_packet_arrival_ = nullptr;
|
||||||
}
|
}
|
||||||
@ -59,6 +63,7 @@ void PacketArrivalHistory::Reset() {
|
|||||||
min_packet_arrival_ = nullptr;
|
min_packet_arrival_ = nullptr;
|
||||||
max_packet_arrival_ = nullptr;
|
max_packet_arrival_ = nullptr;
|
||||||
timestamp_unwrapper_ = TimestampUnwrapper();
|
timestamp_unwrapper_ = TimestampUnwrapper();
|
||||||
|
newest_rtp_timestamp_ = absl::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PacketArrivalHistory::GetDelayMs(uint32_t rtp_timestamp,
|
int PacketArrivalHistory::GetDelayMs(uint32_t rtp_timestamp,
|
||||||
@ -78,6 +83,15 @@ int PacketArrivalHistory::GetMaxDelayMs() const {
|
|||||||
return GetPacketArrivalDelayMs(*max_packet_arrival_);
|
return GetPacketArrivalDelayMs(*max_packet_arrival_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PacketArrivalHistory::IsNewestRtpTimestamp(uint32_t rtp_timestamp) const {
|
||||||
|
if (!newest_rtp_timestamp_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int64_t unwrapped_rtp_timestamp =
|
||||||
|
timestamp_unwrapper_.UnwrapWithoutUpdate(rtp_timestamp);
|
||||||
|
return unwrapped_rtp_timestamp == *newest_rtp_timestamp_;
|
||||||
|
}
|
||||||
|
|
||||||
int PacketArrivalHistory::GetPacketArrivalDelayMs(
|
int PacketArrivalHistory::GetPacketArrivalDelayMs(
|
||||||
const PacketArrival& packet_arrival) const {
|
const PacketArrival& packet_arrival) const {
|
||||||
if (!min_packet_arrival_) {
|
if (!min_packet_arrival_) {
|
||||||
|
@ -13,8 +13,8 @@
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
|
#include "absl/types/optional.h"
|
||||||
#include "api/neteq/tick_timer.h"
|
#include "api/neteq/tick_timer.h"
|
||||||
#include "modules/include/module_common_types_public.h"
|
#include "modules/include/module_common_types_public.h"
|
||||||
|
|
||||||
@ -34,17 +34,21 @@ class PacketArrivalHistory {
|
|||||||
// `(time_ms - p.arrival_time_ms) - (rtp_timestamp - p.rtp_timestamp)`
|
// `(time_ms - p.arrival_time_ms) - (rtp_timestamp - p.rtp_timestamp)`
|
||||||
// where `p` is chosen as the packet arrival in the history that maximizes the
|
// where `p` is chosen as the packet arrival in the history that maximizes the
|
||||||
// delay.
|
// delay.
|
||||||
int GetDelayMs(uint32_t rtp_timestamp, int64_t times_ms) const;
|
int GetDelayMs(uint32_t rtp_timestamp, int64_t time_ms) const;
|
||||||
|
|
||||||
// Get the maximum packet arrival delay observed in the history.
|
// Get the maximum packet arrival delay observed in the history.
|
||||||
int GetMaxDelayMs() const;
|
int GetMaxDelayMs() const;
|
||||||
|
|
||||||
|
bool IsNewestRtpTimestamp(uint32_t rtp_timestamp) const;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
void set_sample_rate(int sample_rate) {
|
void set_sample_rate(int sample_rate) {
|
||||||
sample_rate_khz_ = sample_rate / 1000;
|
sample_rate_khz_ = sample_rate / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t size() const { return history_.size(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct PacketArrival {
|
struct PacketArrival {
|
||||||
PacketArrival(int64_t rtp_timestamp_ms, int64_t arrival_time_ms)
|
PacketArrival(int64_t rtp_timestamp_ms, int64_t arrival_time_ms)
|
||||||
@ -69,6 +73,7 @@ class PacketArrivalHistory {
|
|||||||
const PacketArrival* max_packet_arrival_ = nullptr;
|
const PacketArrival* max_packet_arrival_ = nullptr;
|
||||||
const int window_size_ms_;
|
const int window_size_ms_;
|
||||||
TimestampUnwrapper timestamp_unwrapper_;
|
TimestampUnwrapper timestamp_unwrapper_;
|
||||||
|
absl::optional<int64_t> newest_rtp_timestamp_;
|
||||||
int sample_rate_khz_ = 0;
|
int sample_rate_khz_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +35,8 @@ class PacketArrivalHistoryTest : public testing::Test {
|
|||||||
timestamp_ = timestamp;
|
timestamp_ = timestamp;
|
||||||
}
|
}
|
||||||
history_.Insert(timestamp, time_ms_);
|
history_.Insert(timestamp, time_ms_);
|
||||||
|
EXPECT_EQ(history_.IsNewestRtpTimestamp(timestamp),
|
||||||
|
timestamp_delta_ms >= 0);
|
||||||
return history_.GetDelayMs(timestamp, time_ms_);
|
return history_.GetDelayMs(timestamp, time_ms_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/relative_arrival_delay_tracker.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "modules/include/module_common_types_public.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
absl::optional<int> RelativeArrivalDelayTracker::Update(uint32_t timestamp,
|
|
||||||
int sample_rate_hz) {
|
|
||||||
if (sample_rate_hz <= 0) {
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
if (!last_timestamp_) {
|
|
||||||
// Restart relative delay esimation from this packet.
|
|
||||||
delay_history_.clear();
|
|
||||||
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
|
|
||||||
newest_timestamp_ = timestamp;
|
|
||||||
last_timestamp_ = timestamp;
|
|
||||||
return absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
const int expected_iat_ms =
|
|
||||||
1000ll * static_cast<int32_t>(timestamp - *last_timestamp_) /
|
|
||||||
sample_rate_hz;
|
|
||||||
const int iat_ms = packet_iat_stopwatch_->ElapsedMs();
|
|
||||||
const int iat_delay_ms = iat_ms - expected_iat_ms;
|
|
||||||
UpdateDelayHistory(iat_delay_ms, timestamp, sample_rate_hz);
|
|
||||||
int relative_delay = CalculateRelativePacketArrivalDelay();
|
|
||||||
|
|
||||||
packet_iat_stopwatch_ = tick_timer_->GetNewStopwatch();
|
|
||||||
last_timestamp_ = timestamp;
|
|
||||||
if (IsNewerTimestamp(timestamp, *newest_timestamp_)) {
|
|
||||||
newest_timestamp_ = timestamp;
|
|
||||||
}
|
|
||||||
|
|
||||||
return relative_delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RelativeArrivalDelayTracker::Reset() {
|
|
||||||
delay_history_.clear();
|
|
||||||
packet_iat_stopwatch_.reset();
|
|
||||||
newest_timestamp_ = absl::nullopt;
|
|
||||||
last_timestamp_ = absl::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RelativeArrivalDelayTracker::UpdateDelayHistory(int iat_delay_ms,
|
|
||||||
uint32_t timestamp,
|
|
||||||
int sample_rate_hz) {
|
|
||||||
PacketDelay delay;
|
|
||||||
delay.iat_delay_ms = iat_delay_ms;
|
|
||||||
delay.timestamp = timestamp;
|
|
||||||
delay_history_.push_back(delay);
|
|
||||||
while (static_cast<int32_t>(timestamp - delay_history_.front().timestamp) >
|
|
||||||
max_history_ms_ * sample_rate_hz / 1000) {
|
|
||||||
delay_history_.pop_front();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int RelativeArrivalDelayTracker::CalculateRelativePacketArrivalDelay() const {
|
|
||||||
// This effectively calculates arrival delay of a packet relative to the
|
|
||||||
// packet preceding the history window. If the arrival delay ever becomes
|
|
||||||
// smaller than zero, it means the reference packet is invalid, and we
|
|
||||||
// move the reference.
|
|
||||||
int relative_delay = 0;
|
|
||||||
for (const PacketDelay& delay : delay_history_) {
|
|
||||||
relative_delay += delay.iat_delay_ms;
|
|
||||||
relative_delay = std::max(relative_delay, 0);
|
|
||||||
}
|
|
||||||
return relative_delay;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef MODULES_AUDIO_CODING_NETEQ_RELATIVE_ARRIVAL_DELAY_TRACKER_H_
|
|
||||||
#define MODULES_AUDIO_CODING_NETEQ_RELATIVE_ARRIVAL_DELAY_TRACKER_H_
|
|
||||||
|
|
||||||
#include <deque>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "absl/types/optional.h"
|
|
||||||
#include "api/neteq/tick_timer.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
class RelativeArrivalDelayTracker {
|
|
||||||
public:
|
|
||||||
RelativeArrivalDelayTracker(const TickTimer* tick_timer, int max_history_ms)
|
|
||||||
: tick_timer_(tick_timer), max_history_ms_(max_history_ms) {}
|
|
||||||
|
|
||||||
absl::optional<int> Update(uint32_t timestamp, int sample_rate_hz);
|
|
||||||
|
|
||||||
void Reset();
|
|
||||||
|
|
||||||
absl::optional<uint32_t> newest_timestamp() const {
|
|
||||||
return newest_timestamp_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Updates `delay_history_`.
|
|
||||||
void UpdateDelayHistory(int iat_delay_ms,
|
|
||||||
uint32_t timestamp,
|
|
||||||
int sample_rate_hz);
|
|
||||||
|
|
||||||
// Calculate relative packet arrival delay from `delay_history_`.
|
|
||||||
int CalculateRelativePacketArrivalDelay() const;
|
|
||||||
|
|
||||||
const TickTimer* tick_timer_;
|
|
||||||
const int max_history_ms_;
|
|
||||||
|
|
||||||
struct PacketDelay {
|
|
||||||
int iat_delay_ms;
|
|
||||||
uint32_t timestamp;
|
|
||||||
};
|
|
||||||
std::deque<PacketDelay> delay_history_;
|
|
||||||
|
|
||||||
absl::optional<uint32_t> newest_timestamp_;
|
|
||||||
absl::optional<uint32_t> last_timestamp_;
|
|
||||||
|
|
||||||
std::unique_ptr<TickTimer::Stopwatch>
|
|
||||||
packet_iat_stopwatch_; // Time elapsed since last packet.
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
||||||
#endif // MODULES_AUDIO_CODING_NETEQ_RELATIVE_ARRIVAL_DELAY_TRACKER_H_
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2021 The WebRTC project authors. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by a BSD-style license
|
|
||||||
* that can be found in the LICENSE file in the root of the source
|
|
||||||
* tree. An additional intellectual property rights grant can be found
|
|
||||||
* in the file PATENTS. All contributing project authors may
|
|
||||||
* be found in the AUTHORS file in the root of the source tree.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "modules/audio_coding/neteq/relative_arrival_delay_tracker.h"
|
|
||||||
|
|
||||||
#include "test/gtest.h"
|
|
||||||
|
|
||||||
namespace webrtc {
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
constexpr int kMaxHistoryMs = 2000;
|
|
||||||
constexpr int kFs = 8000;
|
|
||||||
constexpr int kFrameSizeMs = 20;
|
|
||||||
constexpr int kTsIncrement = kFrameSizeMs * kFs / 1000;
|
|
||||||
constexpr uint32_t kTs = 0x12345678;
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
TEST(RelativeArrivalDelayTrackerTest, RelativeArrivalDelay) {
|
|
||||||
TickTimer tick_timer;
|
|
||||||
RelativeArrivalDelayTracker tracker(&tick_timer, kMaxHistoryMs);
|
|
||||||
|
|
||||||
EXPECT_FALSE(tracker.Update(kTs, kFs));
|
|
||||||
|
|
||||||
tick_timer.Increment(kFrameSizeMs / tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(tracker.Update(kTs + kTsIncrement, kFs), 0);
|
|
||||||
|
|
||||||
tick_timer.Increment(2 * kFrameSizeMs / tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(tracker.Update(kTs + 2 * kTsIncrement, kFs), 20);
|
|
||||||
|
|
||||||
EXPECT_EQ(tracker.Update(kTs, kFs), 60); // Reordered, 60ms delayed.
|
|
||||||
|
|
||||||
tick_timer.Increment(2 * kFrameSizeMs / tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(tracker.Update(kTs + 3 * kTsIncrement, kFs), 40);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(RelativeArrivalDelayTrackerTest, ReorderedPackets) {
|
|
||||||
TickTimer tick_timer;
|
|
||||||
RelativeArrivalDelayTracker tracker(&tick_timer, kMaxHistoryMs);
|
|
||||||
|
|
||||||
// Insert first packet.
|
|
||||||
EXPECT_FALSE(tracker.Update(kTs, kFs));
|
|
||||||
|
|
||||||
// Insert reordered packet.
|
|
||||||
EXPECT_EQ(tracker.Update(kTs - 4 * kTsIncrement, kFs), 80);
|
|
||||||
EXPECT_EQ(tracker.newest_timestamp(), kTs);
|
|
||||||
|
|
||||||
// Insert another reordered packet.
|
|
||||||
EXPECT_EQ(tracker.Update(kTs - kTsIncrement, kFs), 20);
|
|
||||||
EXPECT_EQ(tracker.newest_timestamp(), kTs);
|
|
||||||
|
|
||||||
// Insert the next packet in order and verify that the relative delay is
|
|
||||||
// estimated based on the first inserted packet.
|
|
||||||
tick_timer.Increment(4 * kFrameSizeMs / tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(tracker.Update(kTs + kTsIncrement, kFs), 60);
|
|
||||||
EXPECT_EQ(tracker.newest_timestamp(), kTs + kTsIncrement);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(RelativeArrivalDelayTrackerTest, MaxDelayHistory) {
|
|
||||||
TickTimer tick_timer;
|
|
||||||
RelativeArrivalDelayTracker tracker(&tick_timer, kMaxHistoryMs);
|
|
||||||
|
|
||||||
EXPECT_FALSE(tracker.Update(kTs, kFs));
|
|
||||||
|
|
||||||
// Insert 20 ms iat delay in the delay history.
|
|
||||||
tick_timer.Increment(2 * kFrameSizeMs / tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(tracker.Update(kTs + kTsIncrement, kFs), 20);
|
|
||||||
|
|
||||||
// Insert next packet with a timestamp difference larger than maximum history
|
|
||||||
// size. This removes the previously inserted iat delay from the history.
|
|
||||||
tick_timer.Increment((kMaxHistoryMs + kFrameSizeMs) /
|
|
||||||
tick_timer.ms_per_tick());
|
|
||||||
EXPECT_EQ(
|
|
||||||
tracker.Update(kTs + 2 * kTsIncrement + kFs * kMaxHistoryMs / 1000, kFs),
|
|
||||||
0);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webrtc
|
|
Reference in New Issue
Block a user