webrtc/modules/audio_coding/neteq/packet_arrival_history_unittest.cc
Jakob Ivarsson 53e41a2bc6 Ignore old, duplicate and overlapping packets in packet arrival history.
This should mostly be a noop, but in a follow up cl we will insert all
packets after splitting, which will allow for adapting the delay to FEC
(both RED and codec inband) that is useful for decoding (i.e. not
already covered by primary packets).

A slight behavior change is that reordered packets are no longer
included in max delay calculation.

Implementation details:
- A map ordered by RTP timestamp is used to store the arrivals.
- When inserting new packets, we check if the timestamp is too old, already exists or if the packet is fully covered by another packet (based on timestamp and packet duration).
- Separate deques are used to keep track of "min" and "max" arrivals (as defined by ordering operators). The queues maintain a strictly increasing/decreasing order so that min/max is always at begin().

Bug: webrtc:13322
Change-Id: I8b6cf5afff77b4adc3c29745b95627e955715b5a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/337184
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41656}
2024-02-01 15:05:19 +00:00

171 lines
5.6 KiB
C++

/*
* Copyright (c) 2022 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/packet_arrival_history.h"
#include <cstdint>
#include <limits>
#include "test/gtest.h"
namespace webrtc {
namespace {
constexpr int kFs = 8000;
constexpr int kFsKhz = kFs / 1000;
constexpr int kFrameSizeMs = 20;
constexpr int kFrameSizeSamples = kFrameSizeMs * kFsKhz;
constexpr int kWindowSizeMs = 1000;
class PacketArrivalHistoryTest : public testing::Test {
public:
PacketArrivalHistoryTest() : history_(&tick_timer_, kWindowSizeMs) {
history_.set_sample_rate(kFs);
}
void IncrementTime(int delta_ms) {
tick_timer_.Increment(delta_ms / tick_timer_.ms_per_tick());
}
int InsertPacketAndGetDelay(int timestamp_delta_ms) {
uint32_t timestamp = timestamp_ + timestamp_delta_ms * kFsKhz;
if (timestamp_delta_ms > 0) {
timestamp_ = timestamp;
}
EXPECT_TRUE(history_.Insert(timestamp, kFrameSizeSamples));
EXPECT_EQ(history_.IsNewestRtpTimestamp(timestamp),
timestamp_delta_ms >= 0);
return history_.GetDelayMs(timestamp);
}
protected:
TickTimer tick_timer_;
PacketArrivalHistory history_;
uint32_t timestamp_ = 0x12345678;
};
TEST_F(PacketArrivalHistoryTest, RelativeArrivalDelay) {
// Insert first packet.
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
IncrementTime(kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 0);
IncrementTime(2 * kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 20);
// Reordered packet.
EXPECT_EQ(InsertPacketAndGetDelay(-3 * kFrameSizeMs), 80);
IncrementTime(2 * kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 40);
// Move reference packet forward.
EXPECT_EQ(InsertPacketAndGetDelay(4 * kFrameSizeMs), 0);
IncrementTime(2 * kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 20);
// Earlier packet is now more delayed due to the new reference packet.
EXPECT_EQ(history_.GetMaxDelayMs(), 80);
}
TEST_F(PacketArrivalHistoryTest, ReorderedPackets) {
// Insert first packet.
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
// Insert reordered packet.
EXPECT_EQ(InsertPacketAndGetDelay(-80), 80);
// Insert another reordered packet.
EXPECT_EQ(InsertPacketAndGetDelay(-kFrameSizeMs), 20);
// Insert the next packet in order and verify that the relative delay is
// estimated based on the first inserted packet.
IncrementTime(4 * kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 60);
EXPECT_EQ(history_.GetMaxDelayMs(), 60);
}
TEST_F(PacketArrivalHistoryTest, MaxHistorySize) {
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
IncrementTime(2 * kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 20);
EXPECT_EQ(history_.GetMaxDelayMs(), 20);
// Insert next packet with a timestamp difference larger than maximum history
// size. This removes the previously inserted packet from the history.
IncrementTime(kWindowSizeMs + kFrameSizeMs);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs + kWindowSizeMs), 0);
EXPECT_EQ(history_.GetMaxDelayMs(), 0);
}
TEST_F(PacketArrivalHistoryTest, TimestampWraparound) {
timestamp_ = std::numeric_limits<uint32_t>::max();
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
IncrementTime(2 * kFrameSizeMs);
// Insert timestamp that will wrap around.
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), kFrameSizeMs);
// Insert reordered packet before the wraparound.
EXPECT_EQ(InsertPacketAndGetDelay(-2 * kFrameSizeMs), 3 * kFrameSizeMs);
// Insert another in-order packet after the wraparound.
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 0);
EXPECT_EQ(history_.GetMaxDelayMs(), kFrameSizeMs);
}
TEST_F(PacketArrivalHistoryTest, TimestampWraparoundBackwards) {
timestamp_ = 0;
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
IncrementTime(2 * kFrameSizeMs);
// Insert timestamp that will wrap around.
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), kFrameSizeMs);
// Insert reordered packet before the wraparound.
EXPECT_EQ(InsertPacketAndGetDelay(-2 * kFrameSizeMs), 3 * kFrameSizeMs);
// Insert another in-order packet after the wraparound.
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 0);
EXPECT_EQ(history_.GetMaxDelayMs(), kFrameSizeMs);
}
TEST_F(PacketArrivalHistoryTest, OldPacketShouldNotBeInserted) {
// Insert first packet as reference.
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
// Insert packet with timestamp older than the window size compared to the
// first packet.
EXPECT_FALSE(history_.Insert(timestamp_ - kWindowSizeMs * kFsKhz - 1,
kFrameSizeSamples));
}
TEST_F(PacketArrivalHistoryTest, DuplicatePacketShouldNotBeInserted) {
// Insert first packet as reference.
uint32_t first_timestamp = timestamp_;
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
EXPECT_EQ(InsertPacketAndGetDelay(kFrameSizeMs), 0);
// Same timestamp as the first packet.
EXPECT_FALSE(history_.Insert(first_timestamp, kFrameSizeSamples));
}
TEST_F(PacketArrivalHistoryTest, OverlappingPacketShouldNotBeInserted) {
// Insert first packet as reference.
EXPECT_EQ(InsertPacketAndGetDelay(0), 0);
// 10 ms overlap with the previous packet.
EXPECT_FALSE(history_.Insert(timestamp_ + kFrameSizeSamples / 2,
kFrameSizeSamples / 2));
}
} // namespace
} // namespace webrtc