Make stats member of packet buffer.

Bug: none
Change-Id: Ide88e895ea27fdfe5c68aa45295df45bf72bc292
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/325532
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41095}
This commit is contained in:
Jakob Ivarsson 2023-11-07 10:10:47 +01:00 committed by WebRTC LUCI CQ
parent bd523afd3a
commit e925db88c1
6 changed files with 156 additions and 187 deletions

View File

@ -18,23 +18,21 @@ namespace webrtc {
class MockPacketBuffer : public PacketBuffer {
public:
MockPacketBuffer(size_t max_number_of_packets, const TickTimer* tick_timer)
: PacketBuffer(max_number_of_packets, tick_timer) {}
MockPacketBuffer(size_t max_number_of_packets,
const TickTimer* tick_timer,
StatisticsCalculator* stats)
: PacketBuffer(max_number_of_packets, tick_timer, stats) {}
~MockPacketBuffer() override { Die(); }
MOCK_METHOD(void, Die, ());
MOCK_METHOD(void, Flush, (StatisticsCalculator * stats), (override));
MOCK_METHOD(void, Flush, (), (override));
MOCK_METHOD(bool, Empty, (), (const, override));
MOCK_METHOD(int,
InsertPacket,
(Packet && packet, StatisticsCalculator* stats),
(override));
MOCK_METHOD(int, InsertPacket, (Packet && packet), (override));
MOCK_METHOD(int,
InsertPacketList,
(PacketList * packet_list,
const DecoderDatabase& decoder_database,
absl::optional<uint8_t>* current_rtp_payload_type,
absl::optional<uint8_t>* current_cng_rtp_payload_type,
StatisticsCalculator* stats),
absl::optional<uint8_t>* current_cng_rtp_payload_type),
(override));
MOCK_METHOD(int,
NextTimestamp,
@ -46,19 +44,14 @@ class MockPacketBuffer : public PacketBuffer {
(const, override));
MOCK_METHOD(const Packet*, PeekNextPacket, (), (const, override));
MOCK_METHOD(absl::optional<Packet>, GetNextPacket, (), (override));
MOCK_METHOD(int,
DiscardNextPacket,
(StatisticsCalculator * stats),
(override));
MOCK_METHOD(int, DiscardNextPacket, (), (override));
MOCK_METHOD(void,
DiscardOldPackets,
(uint32_t timestamp_limit,
uint32_t horizon_samples,
StatisticsCalculator* stats),
(uint32_t timestamp_limit, uint32_t horizon_samples),
(override));
MOCK_METHOD(void,
DiscardAllOldPackets,
(uint32_t timestamp_limit, StatisticsCalculator* stats),
(uint32_t timestamp_limit),
(override));
MOCK_METHOD(size_t, NumPacketsInBuffer, (), (const, override));
};

View File

@ -84,8 +84,9 @@ NetEqImpl::Dependencies::Dependencies(
new DecoderDatabase(decoder_factory, config.codec_pair_id)),
dtmf_buffer(new DtmfBuffer(config.sample_rate_hz)),
dtmf_tone_generator(new DtmfToneGenerator),
packet_buffer(
new PacketBuffer(config.max_packets_in_buffer, tick_timer.get())),
packet_buffer(new PacketBuffer(config.max_packets_in_buffer,
tick_timer.get(),
stats.get())),
neteq_controller(
CreateNetEqController(controller_factory,
config.min_delay_ms,
@ -265,7 +266,7 @@ void NetEqImpl::SetCodecs(const std::map<int, SdpAudioFormat>& codecs) {
const std::vector<int> changed_payload_types =
decoder_database_->SetCodecs(codecs);
for (const int pt : changed_payload_types) {
packet_buffer_->DiscardPacketsWithPayloadType(pt, stats_.get());
packet_buffer_->DiscardPacketsWithPayloadType(pt);
}
}
@ -283,8 +284,7 @@ int NetEqImpl::RemovePayloadType(uint8_t rtp_payload_type) {
MutexLock lock(&mutex_);
int ret = decoder_database_->Remove(rtp_payload_type);
if (ret == DecoderDatabase::kOK || ret == DecoderDatabase::kDecoderNotFound) {
packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type,
stats_.get());
packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type);
return kOK;
}
return kFail;
@ -441,7 +441,7 @@ absl::optional<NetEq::DecoderFormat> NetEqImpl::GetDecoderFormat(
void NetEqImpl::FlushBuffers() {
MutexLock lock(&mutex_);
RTC_LOG(LS_VERBOSE) << "FlushBuffers";
packet_buffer_->Flush(stats_.get());
packet_buffer_->Flush();
RTC_DCHECK(sync_buffer_.get());
RTC_DCHECK(expand_.get());
sync_buffer_->Flush();
@ -542,7 +542,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
// the packet has been successfully inserted into the packet buffer.
// Flush the packet buffer and DTMF buffer.
packet_buffer_->Flush(stats_.get());
packet_buffer_->Flush();
dtmf_buffer_->Flush();
// Update audio buffer timestamp.
@ -684,7 +684,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
// Insert packets in buffer.
const int ret = packet_buffer_->InsertPacketList(
&parsed_packet_list, *decoder_database_, &current_rtp_payload_type_,
&current_cng_rtp_payload_type_, stats_.get());
&current_cng_rtp_payload_type_);
bool buffer_flush_occured = false;
if (ret == PacketBuffer::kFlushed) {
// Reset DSP timestamp etc. if packet buffer flushed.
@ -1029,8 +1029,7 @@ int NetEqImpl::GetDecision(Operation* operation,
uint32_t end_timestamp = sync_buffer_->end_timestamp();
if (!new_codec_) {
const uint32_t five_seconds_samples = 5 * fs_hz_;
packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples,
stats_.get());
packet_buffer_->DiscardOldPackets(end_timestamp, five_seconds_samples);
}
const Packet* packet = packet_buffer_->PeekNextPacket();
@ -1050,14 +1049,12 @@ int NetEqImpl::GetDecision(Operation* operation,
(end_timestamp >= packet->timestamp ||
end_timestamp + generated_noise_samples > packet->timestamp)) {
// Don't use this packet, discard it.
if (packet_buffer_->DiscardNextPacket(stats_.get()) !=
PacketBuffer::kOK) {
if (packet_buffer_->DiscardNextPacket() != PacketBuffer::kOK) {
RTC_DCHECK_NOTREACHED(); // Must be ok by design.
}
// Check buffer again.
if (!new_codec_) {
packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_,
stats_.get());
packet_buffer_->DiscardOldPackets(end_timestamp, 5 * fs_hz_);
}
packet = packet_buffer_->PeekNextPacket();
}
@ -2016,7 +2013,7 @@ int NetEqImpl::ExtractPackets(size_t required_samples,
// we could end up in the situation where we never decode anything, since
// all incoming packets are considered too old but the buffer will also
// never be flooded and flushed.
packet_buffer_->DiscardAllOldPackets(timestamp_, stats_.get());
packet_buffer_->DiscardAllOldPackets(timestamp_);
}
return rtc::dchecked_cast<int>(extracted_samples);

View File

@ -108,8 +108,8 @@ class NetEqImplTest : public ::testing::Test {
dtmf_tone_generator_ = deps.dtmf_tone_generator.get();
if (use_mock_packet_buffer_) {
std::unique_ptr<MockPacketBuffer> mock(
new MockPacketBuffer(config_.max_packets_in_buffer, tick_timer_));
std::unique_ptr<MockPacketBuffer> mock(new MockPacketBuffer(
config_.max_packets_in_buffer, tick_timer_, deps.stats.get()));
mock_packet_buffer_ = mock.get();
deps.packet_buffer = std::move(mock);
}
@ -120,7 +120,6 @@ class NetEqImplTest : public ::testing::Test {
mock_neteq_controller_ = mock.get();
deps.neteq_controller = std::move(mock);
} else {
deps.stats = std::make_unique<StatisticsCalculator>();
NetEqController::Config controller_config;
controller_config.tick_timer = tick_timer_;
controller_config.base_min_delay_ms = config_.min_delay_ms;
@ -329,8 +328,8 @@ TEST_F(NetEqImplTest, InsertPacket) {
// Expectations for packet buffer.
EXPECT_CALL(*mock_packet_buffer_, Empty())
.WillOnce(Return(false)); // Called once after first packet is inserted.
EXPECT_CALL(*mock_packet_buffer_, Flush(_)).Times(1);
EXPECT_CALL(*mock_packet_buffer_, InsertPacketList(_, _, _, _, _))
EXPECT_CALL(*mock_packet_buffer_, Flush()).Times(1);
EXPECT_CALL(*mock_packet_buffer_, InsertPacketList(_, _, _, _))
.Times(2)
.WillRepeatedly(DoAll(SetArgPointee<2>(kPayloadType),
WithArg<0>(Invoke(DeletePacketsAndReturnOk))));

View File

@ -54,20 +54,14 @@ bool EqualSampleRates(uint8_t pt1,
return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
}
void LogPacketDiscarded(int codec_level, StatisticsCalculator* stats) {
RTC_CHECK(stats);
if (codec_level > 0) {
stats->SecondaryPacketsDiscarded(1);
} else {
stats->PacketsDiscarded(1);
}
}
} // namespace
PacketBuffer::PacketBuffer(size_t max_number_of_packets,
const TickTimer* tick_timer)
: max_number_of_packets_(max_number_of_packets), tick_timer_(tick_timer) {}
const TickTimer* tick_timer,
StatisticsCalculator* stats)
: max_number_of_packets_(max_number_of_packets),
tick_timer_(tick_timer),
stats_(stats) {}
// Destructor. All packets in the buffer will be destroyed.
PacketBuffer::~PacketBuffer() {
@ -75,19 +69,19 @@ PacketBuffer::~PacketBuffer() {
}
// Flush the buffer. All packets in the buffer will be destroyed.
void PacketBuffer::Flush(StatisticsCalculator* stats) {
void PacketBuffer::Flush() {
for (auto& p : buffer_) {
LogPacketDiscarded(p.priority.codec_level, stats);
LogPacketDiscarded(p.priority.codec_level);
}
buffer_.clear();
stats->FlushedPacketBuffer();
stats_->FlushedPacketBuffer();
}
bool PacketBuffer::Empty() const {
return buffer_.empty();
}
int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
int PacketBuffer::InsertPacket(Packet&& packet) {
if (packet.empty()) {
RTC_LOG(LS_WARNING) << "InsertPacket invalid packet";
return kInvalidPacket;
@ -102,7 +96,7 @@ int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
if (buffer_.size() >= max_number_of_packets_) {
// Buffer is full.
Flush(stats);
Flush();
return_val = kFlushed;
RTC_LOG(LS_WARNING) << "Packet buffer flushed.";
}
@ -117,7 +111,7 @@ int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
// timestamp as `rit`, which has a higher priority, do not insert the new
// packet to list.
if (rit != buffer_.rend() && packet.timestamp == rit->timestamp) {
LogPacketDiscarded(packet.priority.codec_level, stats);
LogPacketDiscarded(packet.priority.codec_level);
return return_val;
}
@ -126,7 +120,7 @@ int PacketBuffer::InsertPacket(Packet&& packet, StatisticsCalculator* stats) {
// packet.
PacketList::iterator it = rit.base();
if (it != buffer_.end() && packet.timestamp == it->timestamp) {
LogPacketDiscarded(it->priority.codec_level, stats);
LogPacketDiscarded(it->priority.codec_level);
it = buffer_.erase(it);
}
buffer_.insert(it, std::move(packet)); // Insert the packet at that position.
@ -138,9 +132,7 @@ int PacketBuffer::InsertPacketList(
PacketList* packet_list,
const DecoderDatabase& decoder_database,
absl::optional<uint8_t>* current_rtp_payload_type,
absl::optional<uint8_t>* current_cng_rtp_payload_type,
StatisticsCalculator* stats) {
RTC_DCHECK(stats);
absl::optional<uint8_t>* current_cng_rtp_payload_type) {
bool flushed = false;
for (auto& packet : *packet_list) {
if (decoder_database.IsComfortNoise(packet.payload_type)) {
@ -148,7 +140,7 @@ int PacketBuffer::InsertPacketList(
**current_cng_rtp_payload_type != packet.payload_type) {
// New CNG payload type implies new codec type.
*current_rtp_payload_type = absl::nullopt;
Flush(stats);
Flush();
flushed = true;
}
*current_cng_rtp_payload_type = packet.payload_type;
@ -161,12 +153,12 @@ int PacketBuffer::InsertPacketList(
**current_cng_rtp_payload_type,
decoder_database))) {
*current_cng_rtp_payload_type = absl::nullopt;
Flush(stats);
Flush();
flushed = true;
}
*current_rtp_payload_type = packet.payload_type;
}
int return_val = InsertPacket(std::move(packet), stats);
int return_val = InsertPacket(std::move(packet));
if (return_val == kFlushed) {
// The buffer flushed, but this is not an error. We can still continue.
flushed = true;
@ -228,43 +220,40 @@ absl::optional<Packet> PacketBuffer::GetNextPacket() {
return packet;
}
int PacketBuffer::DiscardNextPacket(StatisticsCalculator* stats) {
int PacketBuffer::DiscardNextPacket() {
if (Empty()) {
return kBufferEmpty;
}
// Assert that the packet sanity checks in InsertPacket method works.
const Packet& packet = buffer_.front();
RTC_DCHECK(!packet.empty());
LogPacketDiscarded(packet.priority.codec_level, stats);
LogPacketDiscarded(packet.priority.codec_level);
buffer_.pop_front();
return kOK;
}
void PacketBuffer::DiscardOldPackets(uint32_t timestamp_limit,
uint32_t horizon_samples,
StatisticsCalculator* stats) {
buffer_.remove_if([timestamp_limit, horizon_samples, stats](const Packet& p) {
uint32_t horizon_samples) {
buffer_.remove_if([this, timestamp_limit, horizon_samples](const Packet& p) {
if (timestamp_limit == p.timestamp ||
!IsObsoleteTimestamp(p.timestamp, timestamp_limit, horizon_samples)) {
return false;
}
LogPacketDiscarded(p.priority.codec_level, stats);
LogPacketDiscarded(p.priority.codec_level);
return true;
});
}
void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit,
StatisticsCalculator* stats) {
DiscardOldPackets(timestamp_limit, 0, stats);
void PacketBuffer::DiscardAllOldPackets(uint32_t timestamp_limit) {
DiscardOldPackets(timestamp_limit, 0);
}
void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type,
StatisticsCalculator* stats) {
buffer_.remove_if([payload_type, stats](const Packet& p) {
void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
buffer_.remove_if([this, payload_type](const Packet& p) {
if (p.payload_type != payload_type) {
return false;
}
LogPacketDiscarded(p.priority.codec_level, stats);
LogPacketDiscarded(p.priority.codec_level);
return true;
});
}
@ -329,4 +318,12 @@ bool PacketBuffer::ContainsDtxOrCngPacket(
return false;
}
void PacketBuffer::LogPacketDiscarded(int codec_level) {
if (codec_level > 0) {
stats_->SecondaryPacketsDiscarded(1);
} else {
stats_->PacketsDiscarded(1);
}
}
} // namespace webrtc

View File

@ -36,7 +36,9 @@ class PacketBuffer {
// Constructor creates a buffer which can hold a maximum of
// `max_number_of_packets` packets.
PacketBuffer(size_t max_number_of_packets, const TickTimer* tick_timer);
PacketBuffer(size_t max_number_of_packets,
const TickTimer* tick_timer,
StatisticsCalculator* stats);
// Deletes all packets in the buffer before destroying the buffer.
virtual ~PacketBuffer();
@ -45,7 +47,7 @@ class PacketBuffer {
PacketBuffer& operator=(const PacketBuffer&) = delete;
// Flushes the buffer and deletes all packets in it.
virtual void Flush(StatisticsCalculator* stats);
virtual void Flush();
// Returns true for an empty buffer.
virtual bool Empty() const;
@ -54,7 +56,7 @@ class PacketBuffer {
// the packet object.
// Returns PacketBuffer::kOK on success, PacketBuffer::kFlushed if the buffer
// was flushed due to overfilling.
virtual int InsertPacket(Packet&& packet, StatisticsCalculator* stats);
virtual int InsertPacket(Packet&& packet);
// Inserts a list of packets into the buffer. The buffer will take over
// ownership of the packet objects.
@ -68,8 +70,7 @@ class PacketBuffer {
PacketList* packet_list,
const DecoderDatabase& decoder_database,
absl::optional<uint8_t>* current_rtp_payload_type,
absl::optional<uint8_t>* current_cng_rtp_payload_type,
StatisticsCalculator* stats);
absl::optional<uint8_t>* current_cng_rtp_payload_type);
// Gets the timestamp for the first packet in the buffer and writes it to the
// output variable `next_timestamp`.
@ -96,7 +97,7 @@ class PacketBuffer {
// Discards the first packet in the buffer. The packet is deleted.
// Returns PacketBuffer::kBufferEmpty if the buffer is empty,
// PacketBuffer::kOK otherwise.
virtual int DiscardNextPacket(StatisticsCalculator* stats);
virtual int DiscardNextPacket();
// Discards all packets that are (strictly) older than timestamp_limit,
// but newer than timestamp_limit - horizon_samples. Setting horizon_samples
@ -104,16 +105,13 @@ class PacketBuffer {
// is, if a packet is more than 2^31 timestamps into the future compared with
// timestamp_limit (including wrap-around), it is considered old.
virtual void DiscardOldPackets(uint32_t timestamp_limit,
uint32_t horizon_samples,
StatisticsCalculator* stats);
uint32_t horizon_samples);
// Discards all packets that are (strictly) older than timestamp_limit.
virtual void DiscardAllOldPackets(uint32_t timestamp_limit,
StatisticsCalculator* stats);
virtual void DiscardAllOldPackets(uint32_t timestamp_limit);
// Removes all packets with a specific payload type from the buffer.
virtual void DiscardPacketsWithPayloadType(uint8_t payload_type,
StatisticsCalculator* stats);
virtual void DiscardPacketsWithPayloadType(uint8_t payload_type);
// Returns the number of packets in the buffer, including duplicates and
// redundant packets.
@ -148,9 +146,12 @@ class PacketBuffer {
}
private:
void LogPacketDiscarded(int codec_level);
size_t max_number_of_packets_;
PacketList buffer_;
const TickTimer* tick_timer_;
StatisticsCalculator* stats_;
};
} // namespace webrtc

View File

@ -108,22 +108,23 @@ namespace webrtc {
TEST(PacketBuffer, CreateAndDestroy) {
TickTimer tick_timer;
PacketBuffer* buffer = new PacketBuffer(10, &tick_timer); // 10 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer* buffer =
new PacketBuffer(10, &tick_timer, &mock_stats); // 10 packets.
EXPECT_TRUE(buffer->Empty());
delete buffer;
}
TEST(PacketBuffer, InsertPacket) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
PacketGenerator gen(17u, 4711u, 0, 10);
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
PacketGenerator gen(17u, 4711u, 0, 10);
MockDecoderDatabase decoder_database;
const int payload_len = 100;
const Packet packet = gen.NextPacket(payload_len, nullptr);
EXPECT_EQ(0, buffer.InsertPacket(/*packet=*/packet.Clone(),
/*stats=*/&mock_stats));
EXPECT_EQ(0, buffer.InsertPacket(/*packet=*/packet.Clone()));
uint32_t next_ts;
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
EXPECT_EQ(4711u, next_ts);
@ -140,23 +141,22 @@ TEST(PacketBuffer, InsertPacket) {
// Test to flush buffer.
TEST(PacketBuffer, FlushBuffer) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
PacketGenerator gen(0, 0, 0, 10);
const int payload_len = 10;
StrictMock<MockStatisticsCalculator> mock_stats;
MockDecoderDatabase decoder_database;
// Insert 10 small packets; should be ok.
for (int i = 0; i < 10; ++i) {
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(/*packet=*/gen.NextPacket(
payload_len, nullptr),
/*stats=*/&mock_stats));
payload_len, nullptr)));
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
EXPECT_FALSE(buffer.Empty());
EXPECT_CALL(mock_stats, PacketsDiscarded(1)).Times(10);
buffer.Flush(&mock_stats);
buffer.Flush();
// Buffer should delete the payloads itself.
EXPECT_EQ(0u, buffer.NumPacketsInBuffer());
EXPECT_TRUE(buffer.Empty());
@ -166,9 +166,9 @@ TEST(PacketBuffer, FlushBuffer) {
// Test to fill the buffer over the limits, and verify that it flushes.
TEST(PacketBuffer, OverfillBuffer) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
PacketGenerator gen(0, 0, 0, 10);
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
PacketGenerator gen(0, 0, 0, 10);
MockDecoderDatabase decoder_database;
// Insert 10 small packets; should be ok.
@ -176,8 +176,7 @@ TEST(PacketBuffer, OverfillBuffer) {
int i;
for (i = 0; i < 10; ++i) {
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(/*packet=*/gen.NextPacket(
payload_len, nullptr),
/*stats=*/&mock_stats));
payload_len, nullptr)));
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
uint32_t next_ts;
@ -188,8 +187,7 @@ TEST(PacketBuffer, OverfillBuffer) {
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=*/packet.Clone(),
/*stats=*/&mock_stats));
buffer.InsertPacket(/*packet=*/packet.Clone()));
EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
EXPECT_EQ(PacketBuffer::kOK, buffer.NextTimestamp(&next_ts));
// Expect last inserted packet to be first in line.
@ -201,7 +199,8 @@ TEST(PacketBuffer, OverfillBuffer) {
// Test inserting a list of packets.
TEST(PacketBuffer, InsertPacketList) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
PacketGenerator gen(0, 0, 0, 10);
PacketList list;
const int payload_len = 10;
@ -218,17 +217,14 @@ TEST(PacketBuffer, InsertPacketList) {
EXPECT_CALL(decoder_database, GetDecoderInfo(0))
.WillRepeatedly(Return(&info));
StrictMock<MockStatisticsCalculator> mock_stats;
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
EXPECT_EQ(
PacketBuffer::kOK,
buffer.InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_TRUE(list.empty()); // The PacketBuffer should have depleted the list.
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
EXPECT_EQ(0, current_pt); // Current payload type changed to 0.
@ -242,7 +238,8 @@ TEST(PacketBuffer, InsertPacketList) {
// TODO(hlundin): Remove this test when legacy operation is no longer needed.
TEST(PacketBuffer, InsertPacketListChangePayloadType) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
PacketGenerator gen(0, 0, 0, 10);
PacketList list;
const int payload_len = 10;
@ -269,18 +266,15 @@ TEST(PacketBuffer, InsertPacketListChangePayloadType) {
EXPECT_CALL(decoder_database, GetDecoderInfo(1))
.WillRepeatedly(Return(&info1));
StrictMock<MockStatisticsCalculator> mock_stats;
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
EXPECT_CALL(mock_stats, PacketsDiscarded(1)).Times(10);
EXPECT_EQ(
PacketBuffer::kFlushed,
buffer.InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kFlushed,
buffer.InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_TRUE(list.empty()); // The PacketBuffer should have depleted the list.
EXPECT_EQ(1u, buffer.NumPacketsInBuffer()); // Only the last packet.
EXPECT_EQ(1, current_pt); // Current payload type changed to 1.
@ -291,7 +285,8 @@ TEST(PacketBuffer, InsertPacketListChangePayloadType) {
TEST(PacketBuffer, ExtractOrderRedundancy) {
TickTimer tick_timer;
PacketBuffer buffer(100, &tick_timer); // 100 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(100, &tick_timer, &mock_stats); // 100 packets.
const int kPackets = 18;
const int kFrameSize = 10;
const int kPayloadLength = 10;
@ -315,8 +310,6 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
PacketGenerator gen(0, 0, 0, kFrameSize);
StrictMock<MockStatisticsCalculator> mock_stats;
// Interleaving the EXPECT_CALL sequence with expectations on the MockFunction
// check ensures that exactly one call to PacketsDiscarded happens in each
// DiscardNextPacket call.
@ -335,8 +328,8 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
}
}
EXPECT_CALL(check, Call(i));
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(/*packet=*/packet.Clone(),
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(/*packet=*/packet.Clone()));
if (packet_facts[i].extract_order >= 0) {
expect_order[packet_facts[i].extract_order] = std::move(packet);
}
@ -355,21 +348,20 @@ TEST(PacketBuffer, ExtractOrderRedundancy) {
TEST(PacketBuffer, DiscardPackets) {
TickTimer tick_timer;
PacketBuffer buffer(100, &tick_timer); // 100 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(100, &tick_timer, &mock_stats); // 100 packets.
const uint16_t start_seq_no = 17;
const uint32_t start_ts = 4711;
const uint32_t ts_increment = 10;
PacketGenerator gen(start_seq_no, start_ts, 0, ts_increment);
PacketList list;
const int payload_len = 10;
StrictMock<MockStatisticsCalculator> mock_stats;
MockDecoderDatabase decoder_database;
constexpr int kTotalPackets = 10;
// Insert 10 small packets.
for (int i = 0; i < kTotalPackets; ++i) {
buffer.InsertPacket(/*packet=*/gen.NextPacket(payload_len, nullptr),
/*stats=*/&mock_stats);
buffer.InsertPacket(/*packet=*/gen.NextPacket(payload_len, nullptr));
}
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
@ -390,7 +382,7 @@ TEST(PacketBuffer, DiscardPackets) {
EXPECT_EQ(current_ts, ts);
EXPECT_CALL(mock_stats, PacketsDiscarded(1));
EXPECT_CALL(check, Call(i));
EXPECT_EQ(PacketBuffer::kOK, buffer.DiscardNextPacket(&mock_stats));
EXPECT_EQ(PacketBuffer::kOK, buffer.DiscardNextPacket());
current_ts += ts_increment;
check.Call(i);
}
@ -403,7 +395,7 @@ TEST(PacketBuffer, DiscardPackets) {
.Times(kRemainingPackets - kSkipPackets);
EXPECT_CALL(check, Call(17)); // Arbitrary id number.
buffer.DiscardOldPackets(start_ts + kTotalPackets * ts_increment,
kRemainingPackets * ts_increment, &mock_stats);
kRemainingPackets * ts_increment);
check.Call(17); // Same arbitrary id number.
EXPECT_EQ(kSkipPackets, buffer.NumPacketsInBuffer());
@ -413,8 +405,7 @@ TEST(PacketBuffer, DiscardPackets) {
// Discard all remaining packets.
EXPECT_CALL(mock_stats, PacketsDiscarded(kSkipPackets));
buffer.DiscardAllOldPackets(start_ts + kTotalPackets * ts_increment,
&mock_stats);
buffer.DiscardAllOldPackets(start_ts + kTotalPackets * ts_increment);
EXPECT_TRUE(buffer.Empty());
EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
@ -422,7 +413,8 @@ TEST(PacketBuffer, DiscardPackets) {
TEST(PacketBuffer, Reordering) {
TickTimer tick_timer;
PacketBuffer buffer(100, &tick_timer); // 100 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(100, &tick_timer, &mock_stats); // 100 packets.
const uint16_t start_seq_no = 17;
const uint32_t start_ts = 4711;
const uint32_t ts_increment = 10;
@ -451,15 +443,12 @@ TEST(PacketBuffer, Reordering) {
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
StrictMock<MockStatisticsCalculator> mock_stats;
EXPECT_EQ(
PacketBuffer::kOK,
buffer.InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
// Extract them and make sure that come out in the right order.
@ -481,7 +470,8 @@ TEST(PacketBuffer, Reordering) {
// and flush out the CNG packet.
TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
TickTimer tick_timer;
PacketBuffer buffer(10, &tick_timer); // 10 packets.
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(10, &tick_timer, &mock_stats); // 10 packets.
const uint8_t kCngPt = 13;
const int kPayloadLen = 10;
const uint8_t kSpeechPt = 100;
@ -504,15 +494,12 @@ TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
StrictMock<MockStatisticsCalculator> mock_stats;
EXPECT_EQ(
PacketBuffer::kOK,
buffer.InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_TRUE(list.empty());
EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
ASSERT_TRUE(buffer.PeekNextPacket());
@ -529,13 +516,12 @@ TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
// Expect the buffer to flush out the CNG packet, since it does not match the
// new speech sample rate.
EXPECT_CALL(mock_stats, PacketsDiscarded(1));
EXPECT_EQ(
PacketBuffer::kFlushed,
buffer.InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kFlushed,
buffer.InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_TRUE(list.empty());
EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
ASSERT_TRUE(buffer.PeekNextPacket());
@ -557,13 +543,13 @@ TEST(PacketBuffer, Failures) {
StrictMock<MockStatisticsCalculator> mock_stats;
MockDecoderDatabase decoder_database;
PacketBuffer* buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
PacketBuffer* buffer =
new PacketBuffer(100, &tick_timer, &mock_stats); // 100 packets.
{
Packet packet = gen.NextPacket(payload_len, nullptr);
packet.payload.Clear();
EXPECT_EQ(PacketBuffer::kInvalidPacket,
buffer->InsertPacket(/*packet=*/std::move(packet),
/*stats=*/&mock_stats));
buffer->InsertPacket(/*packet=*/std::move(packet)));
}
// Buffer should still be empty. Test all empty-checks.
uint32_t temp_ts;
@ -575,13 +561,12 @@ TEST(PacketBuffer, Failures) {
// Discarding packets will not invoke mock_stats.PacketDiscarded() because the
// packet buffer is empty.
EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket(&mock_stats));
buffer->DiscardAllOldPackets(0, &mock_stats);
EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->DiscardNextPacket());
buffer->DiscardAllOldPackets(0);
// Insert one packet to make the buffer non-empty.
EXPECT_EQ(PacketBuffer::kOK, buffer->InsertPacket(/*packet=*/gen.NextPacket(
payload_len, nullptr),
/*stats=*/&mock_stats));
payload_len, nullptr)));
EXPECT_EQ(PacketBuffer::kInvalidPointer, buffer->NextTimestamp(NULL));
EXPECT_EQ(PacketBuffer::kInvalidPointer,
buffer->NextHigherTimestamp(0, NULL));
@ -590,7 +575,7 @@ TEST(PacketBuffer, Failures) {
// Insert packet list of three packets, where the second packet has an invalid
// payload. Expect first packet to be inserted, and the remaining two to be
// discarded.
buffer = new PacketBuffer(100, &tick_timer); // 100 packets.
buffer = new PacketBuffer(100, &tick_timer, &mock_stats); // 100 packets.
PacketList list;
list.push_back(gen.NextPacket(payload_len, nullptr)); // Valid packet.
{
@ -606,13 +591,12 @@ TEST(PacketBuffer, Failures) {
.WillRepeatedly(Return(&info));
absl::optional<uint8_t> current_pt;
absl::optional<uint8_t> current_cng_pt;
EXPECT_EQ(
PacketBuffer::kInvalidPacket,
buffer->InsertPacketList(/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt,
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kInvalidPacket,
buffer->InsertPacketList(
/*packet_list=*/&list,
/*decoder_database=*/decoder_database,
/*current_rtp_payload_type=*/&current_pt,
/*current_cng_rtp_payload_type=*/&current_cng_pt));
EXPECT_TRUE(list.empty()); // The PacketBuffer should have depleted the list.
EXPECT_EQ(1u, buffer->NumPacketsInBuffer());
delete buffer;
@ -735,9 +719,9 @@ TEST(PacketBuffer, GetSpanSamples) {
constexpr int kSampleRateHz = 48000;
constexpr bool kCountWaitingTime = false;
TickTimer tick_timer;
PacketBuffer buffer(3, &tick_timer);
PacketGenerator gen(0, kStartTimeStamp, 0, kFrameSizeSamples);
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(3, &tick_timer, &mock_stats);
PacketGenerator gen(0, kStartTimeStamp, 0, kFrameSizeSamples);
MockDecoderDatabase decoder_database;
Packet packet_1 = gen.NextPacket(kPayloadSizeBytes, nullptr);
@ -753,8 +737,7 @@ TEST(PacketBuffer, GetSpanSamples) {
packet_2.timestamp); // Tmestamp wrapped around.
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(/*packet=*/std::move(packet_1),
/*stats=*/&mock_stats));
buffer.InsertPacket(/*packet=*/std::move(packet_1)));
constexpr size_t kLastDecodedSizeSamples = 2;
// packet_1 has no access to duration, and relies last decoded duration as
@ -764,8 +747,7 @@ TEST(PacketBuffer, GetSpanSamples) {
kCountWaitingTime));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(/*packet=*/std::move(packet_2),
/*stats=*/&mock_stats));
buffer.InsertPacket(/*packet=*/std::move(packet_2)));
EXPECT_EQ(kFrameSizeSamples * 2,
buffer.GetSpanSamples(0, kSampleRateHz, kCountWaitingTime));
@ -785,15 +767,15 @@ TEST(PacketBuffer, GetSpanSamplesCountWaitingTime) {
constexpr bool kCountWaitingTime = true;
constexpr size_t kLastDecodedSizeSamples = 0;
TickTimer tick_timer;
PacketBuffer buffer(3, &tick_timer);
PacketGenerator gen(0, kStartTimeStamp, 0, kFrameSizeSamples);
StrictMock<MockStatisticsCalculator> mock_stats;
PacketBuffer buffer(3, &tick_timer, &mock_stats);
PacketGenerator gen(0, kStartTimeStamp, 0, kFrameSizeSamples);
MockDecoderDatabase decoder_database;
Packet packet = gen.NextPacket(kPayloadSizeBytes, nullptr);
EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(/*packet=*/std::move(packet),
/*stats=*/&mock_stats));
EXPECT_EQ(PacketBuffer::kOK,
buffer.InsertPacket(/*packet=*/std::move(packet)));
EXPECT_EQ(0u, buffer.GetSpanSamples(kLastDecodedSizeSamples, kSampleRateHz,
kCountWaitingTime));