Adding test on GetSpanSamples() for NetEq PacketBuffer.

Bug: webrtc:10736
Change-Id: I4448c5c8e1ae8ea5e343415c4fc2c0fd095ca8ad
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/144560
Commit-Queue: Minyue Li <minyue@webrtc.org>
Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#28481}
This commit is contained in:
Minyue Li
2019-07-03 16:43:29 +02:00
committed by Commit Bot
parent d2c336f892
commit 3f2eeb8136

View File

@ -11,6 +11,7 @@
// Unit tests for PacketBuffer class.
#include "modules/audio_coding/neteq/packet_buffer.h"
#include "absl/memory/memory.h"
#include "api/audio_codecs/builtin_audio_decoder_factory.h"
#include "modules/audio_coding/neteq/mock/mock_decoder_database.h"
#include "modules/audio_coding/neteq/mock/mock_statistics_calculator.h"
@ -25,7 +26,17 @@ using ::testing::_;
using ::testing::InSequence;
using ::testing::MockFunction;
namespace webrtc {
namespace {
class MockEncodedAudioFrame : public webrtc::AudioDecoder::EncodedAudioFrame {
public:
MOCK_CONST_METHOD0(Duration, size_t());
MOCK_CONST_METHOD0(IsDtxPacket, bool());
MOCK_CONST_METHOD1(
Decode,
absl::optional<DecodeResult>(rtc::ArrayView<int16_t> decoded));
};
// Helper class to generate packets. Packets must be deleted by the user.
class PacketGenerator {
@ -33,7 +44,9 @@ class PacketGenerator {
PacketGenerator(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size);
virtual ~PacketGenerator() {}
void Reset(uint16_t seq_no, uint32_t ts, uint8_t pt, int frame_size);
Packet NextPacket(int payload_size_bytes);
webrtc::Packet NextPacket(
int payload_size_bytes,
std::unique_ptr<webrtc::AudioDecoder::EncodedAudioFrame> audio_frame);
uint16_t seq_no_;
uint32_t ts_;
@ -54,14 +67,17 @@ void PacketGenerator::Reset(uint16_t seq_no, uint32_t ts, uint8_t pt,
frame_size_ = frame_size;
}
Packet PacketGenerator::NextPacket(int payload_size_bytes) {
Packet packet;
webrtc::Packet PacketGenerator::NextPacket(
int payload_size_bytes,
std::unique_ptr<webrtc::AudioDecoder::EncodedAudioFrame> audio_frame) {
webrtc::Packet packet;
packet.sequence_number = seq_no_;
packet.timestamp = ts_;
packet.payload_type = pt_;
packet.payload.SetSize(payload_size_bytes);
++seq_no_;
ts_ += frame_size_;
packet.frame = std::move(audio_frame);
return packet;
}
@ -76,6 +92,10 @@ struct PacketsToInsert {
int extract_order;
};
} // namespace
namespace webrtc {
// Start of test definitions.
TEST(PacketBuffer, CreateAndDestroy) {
@ -92,7 +112,7 @@ TEST(PacketBuffer, InsertPacket) {
StrictMock<MockStatisticsCalculator> mock_stats;
const int payload_len = 100;
const Packet packet = gen.NextPacket(payload_len);
const Packet packet = gen.NextPacket(payload_len, nullptr);
EXPECT_EQ(0, buffer.InsertPacket(packet.Clone(), &mock_stats));
uint32_t next_ts;
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
@ -116,8 +136,9 @@ TEST(PacketBuffer, FlushBuffer) {
// Insert 10 small packets; should be ok.
for (int i = 0; i < 10; ++i) {
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(gen.NextPacket(payload_len), &mock_stats));
EXPECT_EQ(
PacketBuffer::kOK,
buffer.InsertPacket(gen.NextPacket(payload_len, nullptr), &mock_stats));
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
EXPECT_FALSE(buffer.Empty());
@ -139,15 +160,16 @@ TEST(PacketBuffer, OverfillBuffer) {
const int payload_len = 10;
int i;
for (i = 0; i < 10; ++i) {
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(gen.NextPacket(payload_len), &mock_stats));
EXPECT_EQ(
PacketBuffer::kOK,
buffer.InsertPacket(gen.NextPacket(payload_len, nullptr), &mock_stats));
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
uint32_t next_ts;
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
EXPECT_EQ(0u, next_ts); // Expect first inserted packet to be first in line.
const Packet packet = gen.NextPacket(payload_len);
const Packet packet = gen.NextPacket(payload_len, nullptr);
// Insert 11th packet; should flush the buffer and insert it after flushing.
EXPECT_EQ(PacketBuffer::kFlushed,
buffer.InsertPacket(packet.Clone(), &mock_stats));
@ -170,7 +192,7 @@ TEST(PacketBuffer, InsertPacketList) {
// Insert 10 small packets.
for (int i = 0; i < 10; ++i) {
list.push_back(gen.NextPacket(payload_len));
list.push_back(gen.NextPacket(payload_len, nullptr));
}
MockDecoderDatabase decoder_database;
@ -209,11 +231,11 @@ TEST(PacketBuffer, InsertPacketListChangePayloadType) {
// Insert 10 small packets.
for (int i = 0; i < 10; ++i) {
list.push_back(gen.NextPacket(payload_len));
list.push_back(gen.NextPacket(payload_len, nullptr));
}
// Insert 11th packet of another payload type (not CNG).
{
Packet packet = gen.NextPacket(payload_len);
Packet packet = gen.NextPacket(payload_len, nullptr);
packet.payload_type = 1;
list.push_back(std::move(packet));
}
@ -292,7 +314,7 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
packet_facts[i].timestamp,
packet_facts[i].payload_type,
kFrameSize);
Packet packet = gen.NextPacket(kPayloadLength);
Packet packet = gen.NextPacket(kPayloadLength, nullptr);
packet.priority.codec_level = packet_facts[i].primary ? 0 : 1;
if (packet_facts[i].extract_order < 0) {
if (packet.priority.codec_level > 0) {
@ -333,7 +355,7 @@ TEST(PacketBuffer, DiscardPackets) {
constexpr int kTotalPackets = 10;
// Insert 10 small packets.
for (int i = 0; i < kTotalPackets; ++i) {
buffer.InsertPacket(gen.NextPacket(payload_len), &mock_stats);
buffer.InsertPacket(gen.NextPacket(payload_len, nullptr), &mock_stats);
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
@ -397,7 +419,7 @@ TEST(PacketBuffer, Reordering) {
// a (rather strange) reordering.
PacketList list;
for (int i = 0; i < 10; ++i) {
Packet packet = gen.NextPacket(payload_len);
Packet packet = gen.NextPacket(payload_len, nullptr);
if (i % 2) {
list.push_front(std::move(packet));
} else {
@ -459,7 +481,7 @@ TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
// Insert first packet, which is narrow-band CNG.
PacketGenerator gen(0, 0, kCngPt, 10);
PacketList list;
list.push_back(gen.NextPacket(kPayloadLen));
list.push_back(gen.NextPacket(kPayloadLen, nullptr));
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
@ -477,7 +499,7 @@ TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
// Insert second packet, which is wide-band speech.
{
Packet packet = gen.NextPacket(kPayloadLen);
Packet packet = gen.NextPacket(kPayloadLen, nullptr);
packet.payload_type = kSpeechPt;
list.push_back(std::move(packet));
}
@ -509,7 +531,7 @@ TEST(PacketBuffer, Failures) {
PacketBuffer* buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
{
Packet packet = gen.NextPacket(payload_len);
Packet packet = gen.NextPacket(payload_len, nullptr);
packet.payload.Clear();
EXPECT_EQ(PacketBuffer::kInvalidPacket,
buffer->InsertPacket(std::move(packet), &mock_stats));
@ -528,8 +550,9 @@ TEST(PacketBuffer, Failures) {
buffer->DiscardAllOldPackets(0, &mock_stats);
// Insert one packet to make the buffer non-empty.
EXPECT_EQ(PacketBuffer::kOK,
buffer->InsertPacket(gen.NextPacket(payload_len), &mock_stats));
EXPECT_EQ(
PacketBuffer::kOK,
buffer->InsertPacket(gen.NextPacket(payload_len, nullptr), &mock_stats));
EXPECT_EQ(PacketBuffer::kInvalidPointer, buffer->NextTimestamp(NULL));
EXPECT_EQ(PacketBuffer::kInvalidPointer,
buffer->NextHigherTimestamp(0, NULL));
@ -540,13 +563,13 @@ TEST(PacketBuffer, Failures) {
// discarded.
buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
PacketList list;
list.push_back(gen.NextPacket(payload_len)); // Valid packet.
list.push_back(gen.NextPacket(payload_len, nullptr)); // Valid packet.
{
Packet packet = gen.NextPacket(payload_len);
Packet packet = gen.NextPacket(payload_len, nullptr);
packet.payload.Clear(); // Invalid.
list.push_back(std::move(packet));
}
list.push_back(gen.NextPacket(payload_len)); // Valid packet.
list.push_back(gen.NextPacket(payload_len, nullptr)); // Valid packet.
MockDecoderDatabase decoder_database;
auto factory = CreateBuiltinAudioDecoderFactory();
const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
@ -568,8 +591,8 @@ TEST(PacketBuffer, Failures) {
// The function should return true if the first packet "goes before" the second.
TEST(PacketBuffer, ComparePackets) {
PacketGenerator gen(0, 0, 0, 10);
Packet a(gen.NextPacket(10)); // SN = 0, TS = 0.
Packet b(gen.NextPacket(10)); // SN = 1, TS = 10.
Packet a(gen.NextPacket(10, nullptr)); // SN = 0, TS = 0.
Packet b(gen.NextPacket(10, nullptr)); // SN = 1, TS = 10.
EXPECT_FALSE(a == b);
EXPECT_TRUE(a != b);
EXPECT_TRUE(a < b);
@ -624,8 +647,8 @@ TEST(PacketBuffer, ComparePackets) {
EXPECT_FALSE(a <= b);
EXPECT_TRUE(a >= b);
Packet c(gen.NextPacket(0)); // SN = 2, TS = 20.
Packet d(gen.NextPacket(0)); // SN = 3, TS = 20.
Packet c(gen.NextPacket(0, nullptr)); // SN = 2, TS = 20.
Packet d(gen.NextPacket(0, nullptr)); // SN = 3, TS = 20.
c.timestamp = b.timestamp;
d.timestamp = b.timestamp;
c.sequence_number = b.sequence_number;
@ -673,6 +696,52 @@ TEST(PacketBuffer, ComparePackets) {
EXPECT_TRUE(d >= b);
}
TEST(PacketBuffer, GetSpanSamples) {
constexpr size_t kFrameSizeSamples = 10;
constexpr int kPayloadSizeBytes = 1; // Does not matter to this test;
constexpr uint32_t kStartTimeStamp = 0xFFFFFFFE; // Close to wrap around.
constexpr int kSampleRateHz = 48000;
constexpr bool KCountDtxWaitingTime = false;
TickTimer tick_timer;
PacketBuffer buffer(3, &tick_timer);
PacketGenerator gen(0, kStartTimeStamp, 0, kFrameSizeSamples);
StrictMock<MockStatisticsCalculator> mock_stats;
Packet packet_1 = gen.NextPacket(kPayloadSizeBytes, nullptr);
std::unique_ptr<MockEncodedAudioFrame> mock_audio_frame =
absl::make_unique<MockEncodedAudioFrame>();
EXPECT_CALL(*mock_audio_frame, Duration())
.WillRepeatedly(Return(kFrameSizeSamples));
Packet packet_2 =
gen.NextPacket(kPayloadSizeBytes, std::move(mock_audio_frame));
RTC_DCHECK_GT(packet_1.timestamp,
packet_2.timestamp); // Tmestamp wrapped around.
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(std::move(packet_1), &mock_stats));
constexpr size_t kLastDecodedSizeSamples = 2;
// packet_1 has no access to duration, and relies last decoded duration as
// input.
EXPECT_EQ(kLastDecodedSizeSamples,
buffer.GetSpanSamples(kLastDecodedSizeSamples, kSampleRateHz,
KCountDtxWaitingTime));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(std::move(packet_2), &mock_stats));
EXPECT_EQ(kFrameSizeSamples * 2,
buffer.GetSpanSamples(0, kSampleRateHz, KCountDtxWaitingTime));
// packet_2 has access to duration, and ignores last decoded duration as
// input.
EXPECT_EQ(kFrameSizeSamples * 2,
buffer.GetSpanSamples(kLastDecodedSizeSamples, kSampleRateHz,
KCountDtxWaitingTime));
}
namespace {
void TestIsObsoleteTimestamp(uint32_t limit_timestamp) {
// Check with zero horizon, which implies that the horizon is at 2^31, i.e.,
@ -735,4 +804,5 @@ TEST(PacketBuffer, IsObsoleteTimestamp) {
TestIsObsoleteTimestamp(0x80000001); // 2^31 + 1.
TestIsObsoleteTimestamp(0x7FFFFFFF); // 2^31 - 1.
}
} // namespace webrtc