Refactor NetEq insert packet list.
Move some logic from PacketBuffer to NetEqImpl.
Bug: webrtc:13322
Change-Id: I88b1e55c0cd69700730d9ed41be04fcf1effa03f
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/328861
Commit-Queue: Jakob Ivarsson‎ <jakobi@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#41270}
diff --git a/modules/audio_coding/neteq/mock/mock_packet_buffer.h b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
index ac883f7..fa44f60 100644
--- a/modules/audio_coding/neteq/mock/mock_packet_buffer.h
+++ b/modules/audio_coding/neteq/mock/mock_packet_buffer.h
@@ -28,13 +28,6 @@
MOCK_METHOD(bool, Empty, (), (const, 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),
- (override));
- MOCK_METHOD(int,
NextTimestamp,
(uint32_t * next_timestamp),
(const, override));
diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc
index d444ff7..e5c8bf6 100644
--- a/modules/audio_coding/neteq/neteq_impl.cc
+++ b/modules/audio_coding/neteq/neteq_impl.cc
@@ -70,6 +70,62 @@
return controller_factory.CreateNetEqController(config);
}
+void SetAudioFrameActivityAndType(bool vad_enabled,
+ NetEqImpl::OutputType type,
+ AudioFrame::VADActivity last_vad_activity,
+ AudioFrame* audio_frame) {
+ switch (type) {
+ case NetEqImpl::OutputType::kNormalSpeech: {
+ audio_frame->speech_type_ = AudioFrame::kNormalSpeech;
+ audio_frame->vad_activity_ = AudioFrame::kVadActive;
+ break;
+ }
+ case NetEqImpl::OutputType::kVadPassive: {
+ // This should only be reached if the VAD is enabled.
+ RTC_DCHECK(vad_enabled);
+ audio_frame->speech_type_ = AudioFrame::kNormalSpeech;
+ audio_frame->vad_activity_ = AudioFrame::kVadPassive;
+ break;
+ }
+ case NetEqImpl::OutputType::kCNG: {
+ audio_frame->speech_type_ = AudioFrame::kCNG;
+ audio_frame->vad_activity_ = AudioFrame::kVadPassive;
+ break;
+ }
+ case NetEqImpl::OutputType::kPLC: {
+ audio_frame->speech_type_ = AudioFrame::kPLC;
+ audio_frame->vad_activity_ = last_vad_activity;
+ break;
+ }
+ case NetEqImpl::OutputType::kPLCCNG: {
+ audio_frame->speech_type_ = AudioFrame::kPLCCNG;
+ audio_frame->vad_activity_ = AudioFrame::kVadPassive;
+ break;
+ }
+ case NetEqImpl::OutputType::kCodecPLC: {
+ audio_frame->speech_type_ = AudioFrame::kCodecPLC;
+ audio_frame->vad_activity_ = last_vad_activity;
+ break;
+ }
+ default:
+ RTC_DCHECK_NOTREACHED();
+ }
+ if (!vad_enabled) {
+ // Always set kVadUnknown when receive VAD is inactive.
+ audio_frame->vad_activity_ = AudioFrame::kVadUnknown;
+ }
+}
+
+// Returns true if both payload types are known to the decoder database, and
+// have the same sample rate.
+bool EqualSampleRates(uint8_t pt1,
+ uint8_t pt2,
+ const DecoderDatabase& decoder_database) {
+ auto* di1 = decoder_database.GetDecoderInfo(pt1);
+ auto* di2 = decoder_database.GetDecoderInfo(pt2);
+ return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
+}
+
} // namespace
NetEqImpl::Dependencies::Dependencies(
@@ -183,54 +239,6 @@
controller_->RegisterEmptyPacket();
}
-namespace {
-void SetAudioFrameActivityAndType(bool vad_enabled,
- NetEqImpl::OutputType type,
- AudioFrame::VADActivity last_vad_activity,
- AudioFrame* audio_frame) {
- switch (type) {
- case NetEqImpl::OutputType::kNormalSpeech: {
- audio_frame->speech_type_ = AudioFrame::kNormalSpeech;
- audio_frame->vad_activity_ = AudioFrame::kVadActive;
- break;
- }
- case NetEqImpl::OutputType::kVadPassive: {
- // This should only be reached if the VAD is enabled.
- RTC_DCHECK(vad_enabled);
- audio_frame->speech_type_ = AudioFrame::kNormalSpeech;
- audio_frame->vad_activity_ = AudioFrame::kVadPassive;
- break;
- }
- case NetEqImpl::OutputType::kCNG: {
- audio_frame->speech_type_ = AudioFrame::kCNG;
- audio_frame->vad_activity_ = AudioFrame::kVadPassive;
- break;
- }
- case NetEqImpl::OutputType::kPLC: {
- audio_frame->speech_type_ = AudioFrame::kPLC;
- audio_frame->vad_activity_ = last_vad_activity;
- break;
- }
- case NetEqImpl::OutputType::kPLCCNG: {
- audio_frame->speech_type_ = AudioFrame::kPLCCNG;
- audio_frame->vad_activity_ = AudioFrame::kVadPassive;
- break;
- }
- case NetEqImpl::OutputType::kCodecPLC: {
- audio_frame->speech_type_ = AudioFrame::kCodecPLC;
- audio_frame->vad_activity_ = last_vad_activity;
- break;
- }
- default:
- RTC_DCHECK_NOTREACHED();
- }
- if (!vad_enabled) {
- // Always set kVadUnknown when receive VAD is inactive.
- audio_frame->vad_activity_ = AudioFrame::kVadUnknown;
- }
-}
-} // namespace
-
int NetEqImpl::GetAudio(AudioFrame* audio_frame,
bool* muted,
int* current_sample_rate_hz,
@@ -681,18 +689,25 @@
number_of_primary_packets);
}
- // Insert packets in buffer.
- const int ret = packet_buffer_->InsertPacketList(
- &parsed_packet_list, *decoder_database_, ¤t_rtp_payload_type_,
- ¤t_cng_rtp_payload_type_);
bool buffer_flush_occured = false;
- if (ret == PacketBuffer::kFlushed) {
+ for (Packet& packet : parsed_packet_list) {
+ if (MaybeChangePayloadType(packet.payload_type)) {
+ packet_buffer_->Flush();
+ buffer_flush_occured = true;
+ }
+ int return_val = packet_buffer_->InsertPacket(std::move(packet));
+ if (return_val == PacketBuffer::kFlushed) {
+ buffer_flush_occured = true;
+ } else if (return_val != PacketBuffer::kOK) {
+ // An error occurred.
+ return kOtherError;
+ }
+ }
+
+ if (buffer_flush_occured) {
// Reset DSP timestamp etc. if packet buffer flushed.
new_codec_ = true;
update_sample_rate_and_channels = true;
- buffer_flush_occured = true;
- } else if (ret != PacketBuffer::kOK) {
- return kOtherError;
}
if (first_packet_) {
@@ -759,6 +774,31 @@
return 0;
}
+bool NetEqImpl::MaybeChangePayloadType(uint8_t payload_type) {
+ bool changed = false;
+ if (decoder_database_->IsComfortNoise(payload_type)) {
+ if (current_cng_rtp_payload_type_ &&
+ *current_cng_rtp_payload_type_ != payload_type) {
+ // New CNG payload type implies new codec type.
+ current_rtp_payload_type_ = absl::nullopt;
+ changed = true;
+ }
+ current_cng_rtp_payload_type_ = payload_type;
+ } else if (!decoder_database_->IsDtmf(payload_type)) {
+ // This must be speech.
+ if ((current_rtp_payload_type_ &&
+ *current_rtp_payload_type_ != payload_type) ||
+ (current_cng_rtp_payload_type_ &&
+ !EqualSampleRates(payload_type, *current_cng_rtp_payload_type_,
+ *decoder_database_))) {
+ current_cng_rtp_payload_type_ = absl::nullopt;
+ changed = true;
+ }
+ current_rtp_payload_type_ = payload_type;
+ }
+ return changed;
+}
+
int NetEqImpl::GetAudioInternal(AudioFrame* audio_frame,
bool* muted,
absl::optional<Operation> action_override) {
diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h
index f27738b..f8f2b06 100644
--- a/modules/audio_coding/neteq/neteq_impl.h
+++ b/modules/audio_coding/neteq/neteq_impl.h
@@ -27,6 +27,7 @@
#include "modules/audio_coding/neteq/audio_multi_vector.h"
#include "modules/audio_coding/neteq/expand_uma_logger.h"
#include "modules/audio_coding/neteq/packet.h"
+#include "modules/audio_coding/neteq/packet_buffer.h"
#include "modules/audio_coding/neteq/random_vector.h"
#include "modules/audio_coding/neteq/statistics_calculator.h"
#include "rtc_base/synchronization/mutex.h"
@@ -46,7 +47,6 @@
class Merge;
class NackTracker;
class Normal;
-class PacketBuffer;
class RedPayloadSplitter;
class PostDecodeVad;
class PreemptiveExpand;
@@ -215,6 +215,12 @@
rtc::ArrayView<const uint8_t> payload)
RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+ // Returns true if the payload type changed (this should be followed by
+ // resetting various state). Returns false if the current payload type is
+ // unknown or equal to `payload_type`.
+ bool MaybeChangePayloadType(uint8_t payload_type)
+ RTC_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
+
// Delivers 10 ms of audio data. The data is written to `audio_frame`.
// Returns 0 on success, otherwise an error code.
int GetAudioInternal(AudioFrame* audio_frame,
diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc
index e3bbe49..8309daf 100644
--- a/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -329,14 +329,9 @@
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_, InsertPacket(_))
.Times(2)
- .WillRepeatedly(DoAll(SetArgPointee<2>(kPayloadType),
- WithArg<0>(Invoke(DeletePacketsAndReturnOk))));
- // SetArgPointee<2>(kPayloadType) means that the third argument (zero-based
- // index) is a pointer, and the variable pointed to is set to kPayloadType.
- // Also invoke the function DeletePacketsAndReturnOk to properly delete all
- // packets in the list (to avoid memory leaks in the test).
+ .WillRepeatedly(Return(PacketBuffer::kOK));
EXPECT_CALL(*mock_packet_buffer_, PeekNextPacket())
.Times(1)
.WillOnce(Return(&fake_packet));
@@ -1642,6 +1637,74 @@
}
}
+// The test first inserts a packet with narrow-band CNG, then a packet with
+// wide-band speech. The expected behavior is to detect a change in sample rate,
+// even though no speech packet has been inserted before, and flush out the CNG
+// packet.
+TEST_F(NetEqImplTest, CngFirstThenSpeechWithNewSampleRate) {
+ UseNoMocks();
+ CreateInstance();
+ constexpr int kCnPayloadType = 7;
+ neteq_->RegisterPayloadType(kCnPayloadType, SdpAudioFormat("cn", 8000, 1));
+ constexpr int kSpeechPayloadType = 8;
+ neteq_->RegisterPayloadType(kSpeechPayloadType,
+ SdpAudioFormat("l16", 16000, 1));
+
+ RTPHeader header;
+ header.payloadType = kCnPayloadType;
+ uint8_t payload[320] = {0};
+
+ EXPECT_EQ(neteq_->InsertPacket(header, payload), NetEq::kOK);
+ EXPECT_EQ(neteq_->GetLifetimeStatistics().packets_discarded, 0u);
+
+ header.payloadType = kSpeechPayloadType;
+ header.timestamp += 160;
+ EXPECT_EQ(neteq_->InsertPacket(header, payload), NetEq::kOK);
+ // CN packet should be discarded, since it does not match the
+ // new speech sample rate.
+ EXPECT_EQ(neteq_->GetLifetimeStatistics().packets_discarded, 1u);
+
+ // Next decoded packet should be speech.
+ AudioFrame audio_frame;
+ bool muted;
+ EXPECT_EQ(neteq_->GetAudio(&audio_frame, &muted), NetEq::kOK);
+ EXPECT_EQ(audio_frame.sample_rate_hz(), 16000);
+ EXPECT_EQ(audio_frame.speech_type_, AudioFrame::SpeechType::kNormalSpeech);
+}
+
+TEST_F(NetEqImplTest, InsertPacketChangePayloadType) {
+ UseNoMocks();
+ CreateInstance();
+ constexpr int kPcmuPayloadType = 7;
+ neteq_->RegisterPayloadType(kPcmuPayloadType,
+ SdpAudioFormat("pcmu", 8000, 1));
+ constexpr int kPcmaPayloadType = 8;
+ neteq_->RegisterPayloadType(kPcmaPayloadType,
+ SdpAudioFormat("pcma", 8000, 1));
+
+ RTPHeader header;
+ header.payloadType = kPcmuPayloadType;
+ header.timestamp = 1234;
+ uint8_t payload[160] = {0};
+
+ EXPECT_EQ(neteq_->InsertPacket(header, payload), NetEq::kOK);
+ EXPECT_EQ(neteq_->GetLifetimeStatistics().packets_discarded, 0u);
+
+ header.payloadType = kPcmaPayloadType;
+ header.timestamp += 80;
+ EXPECT_EQ(neteq_->InsertPacket(header, payload), NetEq::kOK);
+ // The previous packet should be discarded since the codec changed.
+ EXPECT_EQ(neteq_->GetLifetimeStatistics().packets_discarded, 1u);
+
+ // Next decoded packet should be speech.
+ AudioFrame audio_frame;
+ bool muted;
+ EXPECT_EQ(neteq_->GetAudio(&audio_frame, &muted), NetEq::kOK);
+ EXPECT_EQ(audio_frame.sample_rate_hz(), 8000);
+ EXPECT_EQ(audio_frame.speech_type_, AudioFrame::SpeechType::kNormalSpeech);
+ // TODO(jakobi): check active decoder.
+}
+
class Decoder120ms : public AudioDecoder {
public:
Decoder120ms(int sample_rate_hz, SpeechType speech_type)
diff --git a/modules/audio_coding/neteq/packet_buffer.cc b/modules/audio_coding/neteq/packet_buffer.cc
index 412bf66..47c391a 100644
--- a/modules/audio_coding/neteq/packet_buffer.cc
+++ b/modules/audio_coding/neteq/packet_buffer.cc
@@ -44,16 +44,6 @@
const Packet& new_packet_;
};
-// Returns true if both payload types are known to the decoder database, and
-// have the same sample rate.
-bool EqualSampleRates(uint8_t pt1,
- uint8_t pt2,
- const DecoderDatabase& decoder_database) {
- auto* di1 = decoder_database.GetDecoderInfo(pt1);
- auto* di2 = decoder_database.GetDecoderInfo(pt2);
- return di1 && di2 && di1->SampleRateHz() == di2->SampleRateHz();
-}
-
} // namespace
PacketBuffer::PacketBuffer(size_t max_number_of_packets,
@@ -128,50 +118,6 @@
return return_val;
}
-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) {
- bool flushed = false;
- for (auto& packet : *packet_list) {
- if (decoder_database.IsComfortNoise(packet.payload_type)) {
- if (*current_cng_rtp_payload_type &&
- **current_cng_rtp_payload_type != packet.payload_type) {
- // New CNG payload type implies new codec type.
- *current_rtp_payload_type = absl::nullopt;
- Flush();
- flushed = true;
- }
- *current_cng_rtp_payload_type = packet.payload_type;
- } else if (!decoder_database.IsDtmf(packet.payload_type)) {
- // This must be speech.
- if ((*current_rtp_payload_type &&
- **current_rtp_payload_type != packet.payload_type) ||
- (*current_cng_rtp_payload_type &&
- !EqualSampleRates(packet.payload_type,
- **current_cng_rtp_payload_type,
- decoder_database))) {
- *current_cng_rtp_payload_type = absl::nullopt;
- Flush();
- flushed = true;
- }
- *current_rtp_payload_type = packet.payload_type;
- }
- 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;
- } else if (return_val != kOK) {
- // An error occurred. Delete remaining packets in list and return.
- packet_list->clear();
- return return_val;
- }
- }
- packet_list->clear();
- return flushed ? kFlushed : kOK;
-}
-
int PacketBuffer::NextTimestamp(uint32_t* next_timestamp) const {
if (Empty()) {
return kBufferEmpty;
diff --git a/modules/audio_coding/neteq/packet_buffer.h b/modules/audio_coding/neteq/packet_buffer.h
index 05ae315..795dd4e 100644
--- a/modules/audio_coding/neteq/packet_buffer.h
+++ b/modules/audio_coding/neteq/packet_buffer.h
@@ -58,20 +58,6 @@
// was flushed due to overfilling.
virtual int InsertPacket(Packet&& packet);
- // Inserts a list of packets into the buffer. The buffer will take over
- // ownership of the packet objects.
- // Returns PacketBuffer::kOK if all packets were inserted successfully.
- // If the buffer was flushed due to overfilling, only a subset of the list is
- // inserted, and PacketBuffer::kFlushed is returned.
- // The last three parameters are included for legacy compatibility.
- // TODO(hlundin): Redesign to not use current_*_payload_type and
- // decoder_database.
- virtual 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);
-
// Gets the timestamp for the first packet in the buffer and writes it to the
// output variable `next_timestamp`.
// Returns PacketBuffer::kBufferEmpty if the buffer is empty,
diff --git a/modules/audio_coding/neteq/packet_buffer_unittest.cc b/modules/audio_coding/neteq/packet_buffer_unittest.cc
index 9c7ded5..8f307a9 100644
--- a/modules/audio_coding/neteq/packet_buffer_unittest.cc
+++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc
@@ -196,92 +196,6 @@
EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
}
-// Test inserting a list of packets.
-TEST(PacketBuffer, InsertPacketList) {
- TickTimer tick_timer;
- 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;
-
- // Insert 10 small packets.
- for (int i = 0; i < 10; ++i) {
- list.push_back(gen.NextPacket(payload_len, nullptr));
- }
-
- MockDecoderDatabase decoder_database;
- auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(0))
- .WillRepeatedly(Return(&info));
-
- 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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_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.
- EXPECT_EQ(absl::nullopt, current_cng_pt); // CNG payload type not changed.
-
- EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
-}
-
-// Test inserting a list of packets. Last packet is of a different payload type.
-// Expecting the buffer to flush.
-// TODO(hlundin): Remove this test when legacy operation is no longer needed.
-TEST(PacketBuffer, InsertPacketListChangePayloadType) {
- TickTimer tick_timer;
- 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;
-
- // Insert 10 small packets.
- for (int i = 0; i < 10; ++i) {
- list.push_back(gen.NextPacket(payload_len, nullptr));
- }
- // Insert 11th packet of another payload type (not CNG).
- {
- Packet packet = gen.NextPacket(payload_len, nullptr);
- packet.payload_type = 1;
- list.push_back(std::move(packet));
- }
-
- MockDecoderDatabase decoder_database;
- auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info0(SdpAudioFormat("pcmu", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(0))
- .WillRepeatedly(Return(&info0));
- const DecoderDatabase::DecoderInfo info1(SdpAudioFormat("pcma", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(1))
- .WillRepeatedly(Return(&info1));
-
- 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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_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.
- EXPECT_EQ(absl::nullopt, current_cng_pt); // CNG payload type not changed.
-
- EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
-}
TEST(PacketBuffer, ExtractOrderRedundancy) {
TickTimer tick_timer;
@@ -434,21 +348,9 @@
}
}
- MockDecoderDatabase decoder_database;
- auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(0))
- .WillRepeatedly(Return(&info));
- 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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_cng_pt));
+ for (Packet& packet : list) {
+ EXPECT_EQ(PacketBuffer::kOK, buffer.InsertPacket(std::move(packet)));
+ }
EXPECT_EQ(10u, buffer.NumPacketsInBuffer());
// Extract them and make sure that come out in the right order.
@@ -460,77 +362,6 @@
current_ts += ts_increment;
}
EXPECT_TRUE(buffer.Empty());
-
- EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
-}
-
-// The test first inserts a packet with narrow-band CNG, then a packet with
-// wide-band speech. The expected behavior of the packet buffer is to detect a
-// change in sample rate, even though no speech packet has been inserted before,
-// and flush out the CNG packet.
-TEST(PacketBuffer, CngFirstThenSpeechWithNewSampleRate) {
- TickTimer tick_timer;
- 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;
-
- MockDecoderDatabase decoder_database;
- auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info_cng(SdpAudioFormat("cn", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(kCngPt))
- .WillRepeatedly(Return(&info_cng));
- const DecoderDatabase::DecoderInfo info_speech(
- SdpAudioFormat("l16", 16000, 1), absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(kSpeechPt))
- .WillRepeatedly(Return(&info_speech));
-
- // Insert first packet, which is narrow-band CNG.
- PacketGenerator gen(0, 0, kCngPt, 10);
- PacketList list;
- list.push_back(gen.NextPacket(kPayloadLen, nullptr));
- 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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_cng_pt));
- EXPECT_TRUE(list.empty());
- EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
- ASSERT_TRUE(buffer.PeekNextPacket());
- EXPECT_EQ(kCngPt, buffer.PeekNextPacket()->payload_type);
- EXPECT_EQ(current_pt, absl::nullopt); // Current payload type not set.
- EXPECT_EQ(kCngPt, current_cng_pt); // CNG payload type set.
-
- // Insert second packet, which is wide-band speech.
- {
- Packet packet = gen.NextPacket(kPayloadLen, nullptr);
- packet.payload_type = kSpeechPt;
- list.push_back(std::move(packet));
- }
- // 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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_cng_pt));
- EXPECT_TRUE(list.empty());
- EXPECT_EQ(1u, buffer.NumPacketsInBuffer());
- ASSERT_TRUE(buffer.PeekNextPacket());
- EXPECT_EQ(kSpeechPt, buffer.PeekNextPacket()->payload_type);
-
- EXPECT_EQ(kSpeechPt, current_pt); // Current payload type set.
- EXPECT_EQ(absl::nullopt, current_cng_pt); // CNG payload type reset.
-
- EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
}
TEST(PacketBuffer, Failures) {
@@ -541,66 +372,26 @@
PacketGenerator gen(start_seq_no, start_ts, 0, ts_increment);
TickTimer tick_timer;
StrictMock<MockStatisticsCalculator> mock_stats;
- MockDecoderDatabase decoder_database;
- PacketBuffer* buffer =
- new PacketBuffer(100, &tick_timer, &mock_stats); // 100 packets.
+ PacketBuffer buffer(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)));
+ buffer.InsertPacket(/*packet=*/std::move(packet)));
}
// Buffer should still be empty. Test all empty-checks.
uint32_t temp_ts;
- EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer->NextTimestamp(&temp_ts));
+ EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer.NextTimestamp(&temp_ts));
EXPECT_EQ(PacketBuffer::kBufferEmpty,
- buffer->NextHigherTimestamp(0, &temp_ts));
- EXPECT_EQ(NULL, buffer->PeekNextPacket());
- EXPECT_FALSE(buffer->GetNextPacket());
+ buffer.NextHigherTimestamp(0, &temp_ts));
+ EXPECT_EQ(NULL, buffer.PeekNextPacket());
+ EXPECT_FALSE(buffer.GetNextPacket());
// Discarding packets will not invoke mock_stats.PacketDiscarded() because the
// packet buffer is empty.
- 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)));
- EXPECT_EQ(PacketBuffer::kInvalidPointer, buffer->NextTimestamp(NULL));
- EXPECT_EQ(PacketBuffer::kInvalidPointer,
- buffer->NextHigherTimestamp(0, NULL));
- delete buffer;
-
- // 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, &mock_stats); // 100 packets.
- PacketList list;
- list.push_back(gen.NextPacket(payload_len, nullptr)); // Valid packet.
- {
- Packet packet = gen.NextPacket(payload_len, nullptr);
- packet.payload.Clear(); // Invalid.
- list.push_back(std::move(packet));
- }
- list.push_back(gen.NextPacket(payload_len, nullptr)); // Valid packet.
- auto factory = CreateBuiltinAudioDecoderFactory();
- const DecoderDatabase::DecoderInfo info(SdpAudioFormat("pcmu", 8000, 1),
- absl::nullopt, factory.get());
- EXPECT_CALL(decoder_database, GetDecoderInfo(0))
- .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=*/¤t_pt,
- /*current_cng_rtp_payload_type=*/¤t_cng_pt));
- EXPECT_TRUE(list.empty()); // The PacketBuffer should have depleted the list.
- EXPECT_EQ(1u, buffer->NumPacketsInBuffer());
- delete buffer;
- EXPECT_CALL(decoder_database, Die()); // Called when object is deleted.
+ EXPECT_EQ(PacketBuffer::kBufferEmpty, buffer.DiscardNextPacket());
+ buffer.DiscardAllOldPackets(0);
}
// Test packet comparison function.