diff --git a/modules/audio_coding/neteq/mock/mock_packet_buffer.h b/modules/audio_coding/neteq/mock/mock_packet_buffer.h index ac883f7692..fa44f606fc 100644 --- a/modules/audio_coding/neteq/mock/mock_packet_buffer.h +++ b/modules/audio_coding/neteq/mock/mock_packet_buffer.h @@ -27,13 +27,6 @@ class MockPacketBuffer : public PacketBuffer { MOCK_METHOD(void, Flush, (), (override)); 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* current_rtp_payload_type, - absl::optional* current_cng_rtp_payload_type), - (override)); MOCK_METHOD(int, NextTimestamp, (uint32_t * next_timestamp), diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index d444ff74fd..e5c8bf6c08 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc @@ -70,6 +70,62 @@ std::unique_ptr CreateNetEqController( 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 @@ void NetEqImpl::InsertEmptyPacket(const RTPHeader& rtp_header) { 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 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, 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 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, 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 action_override) { diff --git a/modules/audio_coding/neteq/neteq_impl.h b/modules/audio_coding/neteq/neteq_impl.h index f27738bcbf..f8f2b06410 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 Expand; class Merge; class NackTracker; class Normal; -class PacketBuffer; class RedPayloadSplitter; class PostDecodeVad; class PreemptiveExpand; @@ -215,6 +215,12 @@ class NetEqImpl : public webrtc::NetEq { rtc::ArrayView 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 e3bbe498b3..8309dafb58 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -329,14 +329,9 @@ TEST_F(NetEqImplTest, InsertPacket) { 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 @@ TEST_F(NetEqImplTest, NoCrashWith1000Channels) { } } +// 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 412bf66ee8..47c391a18f 100644 --- a/modules/audio_coding/neteq/packet_buffer.cc +++ b/modules/audio_coding/neteq/packet_buffer.cc @@ -44,16 +44,6 @@ class NewTimestampIsLarger { 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 @@ int PacketBuffer::InsertPacket(Packet&& packet) { return return_val; } -int PacketBuffer::InsertPacketList( - PacketList* packet_list, - const DecoderDatabase& decoder_database, - absl::optional* current_rtp_payload_type, - absl::optional* 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 05ae315b68..795dd4e812 100644 --- a/modules/audio_coding/neteq/packet_buffer.h +++ b/modules/audio_coding/neteq/packet_buffer.h @@ -58,20 +58,6 @@ class PacketBuffer { // 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* current_rtp_payload_type, - absl::optional* 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 9c7ded50f9..8f307a9eaf 100644 --- a/modules/audio_coding/neteq/packet_buffer_unittest.cc +++ b/modules/audio_coding/neteq/packet_buffer_unittest.cc @@ -196,92 +196,6 @@ TEST(PacketBuffer, OverfillBuffer) { EXPECT_CALL(decoder_database, Die()); // Called when object is deleted. } -// Test inserting a list of packets. -TEST(PacketBuffer, InsertPacketList) { - TickTimer tick_timer; - StrictMock 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 current_pt; - absl::optional 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 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 current_pt; - absl::optional 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 @@ TEST(PacketBuffer, Reordering) { } } - 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 current_pt; - absl::optional 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 @@ TEST(PacketBuffer, Reordering) { 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 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 current_pt; - absl::optional 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 @@ TEST(PacketBuffer, Failures) { PacketGenerator gen(start_seq_no, start_ts, 0, ts_increment); TickTimer tick_timer; StrictMock 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 current_pt; - absl::optional 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.