diff --git a/api/neteq/neteq_controller.h b/api/neteq/neteq_controller.h index 499b999686..8344cd17dc 100644 --- a/api/neteq/neteq_controller.h +++ b/api/neteq/neteq_controller.h @@ -97,6 +97,14 @@ class NetEqController { size_t sync_buffer_samples; }; + struct PacketArrivedInfo { + size_t packet_length_samples; + uint32_t main_timestamp; + uint16_t main_sequence_number; + bool is_cng_or_dtmf; + bool is_dtx; + }; + virtual ~NetEqController() = default; // Resets object to a clean state. @@ -154,15 +162,33 @@ class NetEqController { // Returns the target buffer level in ms. virtual int TargetLevelMs() const = 0; - // Notify the NetEqController that a packet has arrived. Returns the relative - // arrival delay, if it can be computed. + // Deprecated. + // TODO(ivoc): Remove when downstream is updated. virtual absl::optional PacketArrived(bool last_cng_or_dtmf, size_t packet_length_samples, bool should_update_stats, uint16_t main_sequence_number, uint32_t main_timestamp, - int fs_hz) = 0; + int fs_hz) { + PacketArrivedInfo info; + info.is_dtx = false; + info.is_cng_or_dtmf = last_cng_or_dtmf; + info.packet_length_samples = packet_length_samples; + info.main_sequence_number = main_sequence_number; + info.main_timestamp = main_timestamp; + return PacketArrived(fs_hz, should_update_stats, info); + } + // Notify the NetEqController that a packet has arrived. Returns the relative + // arrival delay, if it can be computed. + // TODO(ivoc): Make pure virtual when downstream is updated. + virtual absl::optional PacketArrived(int fs_hz, + bool should_update_stats, + const PacketArrivedInfo& info) { + return PacketArrived(info.is_cng_or_dtmf, info.packet_length_samples, + should_update_stats, info.main_sequence_number, + info.main_timestamp, fs_hz); + } // Notify the NetEqController that we are currently in muted state. // TODO(ivoc): Make pure virtual when downstream is updated. virtual void NotifyMutedState() {} diff --git a/modules/audio_coding/neteq/decision_logic.cc b/modules/audio_coding/neteq/decision_logic.cc index a4de9b8bb4..fb26b9995f 100644 --- a/modules/audio_coding/neteq/decision_logic.cc +++ b/modules/audio_coding/neteq/decision_logic.cc @@ -198,26 +198,24 @@ void DecisionLogic::ExpandDecision(NetEq::Operation operation) { } } -absl::optional DecisionLogic::PacketArrived(bool is_cng_or_dtmf, - size_t packet_length_samples, - bool should_update_stats, - uint16_t main_sequence_number, - uint32_t main_timestamp, - int fs_hz) { - if (is_cng_or_dtmf) { +absl::optional DecisionLogic::PacketArrived( + int fs_hz, + bool should_update_stats, + const PacketArrivedInfo& info) { + if (info.is_cng_or_dtmf) { last_pack_cng_or_dtmf_ = true; return absl::nullopt; } if (!should_update_stats) { return absl::nullopt; } - if (packet_length_samples > 0 && fs_hz > 0 && - packet_length_samples != packet_length_samples_) { - packet_length_samples_ = packet_length_samples; + if (info.packet_length_samples > 0 && fs_hz > 0 && + info.packet_length_samples != packet_length_samples_) { + packet_length_samples_ = info.packet_length_samples; delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz); } auto relative_delay = delay_manager_->Update( - main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_); + info.main_timestamp, fs_hz, /*reset=*/last_pack_cng_or_dtmf_); last_pack_cng_or_dtmf_ = false; return relative_delay; } diff --git a/modules/audio_coding/neteq/decision_logic.h b/modules/audio_coding/neteq/decision_logic.h index d4d69edb04..d69c249fd3 100644 --- a/modules/audio_coding/neteq/decision_logic.h +++ b/modules/audio_coding/neteq/decision_logic.h @@ -72,12 +72,9 @@ class DecisionLogic : public NetEqController { int TargetLevelMs() const override { return delay_manager_->TargetDelayMs(); } - absl::optional PacketArrived(bool is_cng_or_dtmf, - size_t packet_length_samples, + absl::optional PacketArrived(int fs_hz, bool should_update_stats, - uint16_t main_sequence_number, - uint32_t main_timestamp, - int fs_hz) override; + const PacketArrivedInfo& info) override; void RegisterEmptyPacket() override {} diff --git a/modules/audio_coding/neteq/mock/mock_neteq_controller.h b/modules/audio_coding/neteq/mock/mock_neteq_controller.h index ec348caed0..b8ffbb2360 100644 --- a/modules/audio_coding/neteq/mock/mock_neteq_controller.h +++ b/modules/audio_coding/neteq/mock/mock_neteq_controller.h @@ -51,6 +51,12 @@ class MockNetEqController : public NetEqController { uint32_t main_timestamp, int fs_hz), (override)); + MOCK_METHOD(absl::optional, + PacketArrived, + (int fs_hz, + bool should_update_stats, + const PacketArrivedInfo& info), + (override)); MOCK_METHOD(bool, PeakFound, (), (const, override)); MOCK_METHOD(int, GetFilteredBufferLevel, (), (const, override)); MOCK_METHOD(void, set_sample_memory, (int32_t value), (override)); diff --git a/modules/audio_coding/neteq/neteq_impl.cc b/modules/audio_coding/neteq/neteq_impl.cc index 61e4de6a59..ba6d9c1c7d 100644 --- a/modules/audio_coding/neteq/neteq_impl.cc +++ b/modules/audio_coding/neteq/neteq_impl.cc @@ -680,6 +680,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, } PacketList parsed_packet_list; + bool is_dtx = false; while (!packet_list.empty()) { Packet& packet = packet_list.front(); const DecoderDatabase::DecoderInfo* info = @@ -720,6 +721,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, for (auto& result : results) { RTC_DCHECK(result.frame); RTC_DCHECK_GE(result.priority, 0); + is_dtx = is_dtx || result.frame->IsDtxPacket(); if (first) { // Re-use the node and move it to parsed_packet_list. packet_list.front() = packet_from_result(result); @@ -801,10 +803,13 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, decoder_database_->GetDecoderInfo(main_payload_type); assert(dec_info); // Already checked that the payload type is known. - const bool last_cng_or_dtmf = - dec_info->IsComfortNoise() || dec_info->IsDtmf(); - const size_t packet_length_samples = + NetEqController::PacketArrivedInfo info; + info.is_cng_or_dtmf = dec_info->IsComfortNoise() || dec_info->IsDtmf(); + info.packet_length_samples = number_of_primary_packets * decoder_frame_length_; + info.main_timestamp = main_timestamp; + info.main_sequence_number = main_sequence_number; + info.is_dtx = is_dtx; // Only update statistics if incoming packet is not older than last played // out packet or RTX handling is enabled, and if new codec flag is not // set. @@ -813,9 +818,8 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header, static_cast(main_timestamp - timestamp_) >= 0) && !new_codec_; - auto relative_delay = controller_->PacketArrived( - last_cng_or_dtmf, packet_length_samples, should_update_stats, - main_sequence_number, main_timestamp, fs_hz_); + auto relative_delay = + controller_->PacketArrived(fs_hz_, should_update_stats, info); if (relative_delay) { stats_->RelativePacketArrivalDelay(relative_delay.value()); } diff --git a/modules/audio_coding/neteq/neteq_impl_unittest.cc b/modules/audio_coding/neteq/neteq_impl_unittest.cc index 44660fc483..28dd8f0857 100644 --- a/modules/audio_coding/neteq/neteq_impl_unittest.cc +++ b/modules/audio_coding/neteq/neteq_impl_unittest.cc @@ -284,6 +284,8 @@ TEST_F(NetEqImplTest, RemoveAllPayloadTypes) { } TEST_F(NetEqImplTest, InsertPacket) { + using ::testing::AllOf; + using ::testing::Field; CreateInstance(); const size_t kPayloadLength = 100; const uint8_t kPayloadType = 0; @@ -347,20 +349,32 @@ TEST_F(NetEqImplTest, InsertPacket) { // All expectations within this block must be called in this specific order. InSequence sequence; // Dummy variable. // Expectations when the first packet is inserted. - EXPECT_CALL(*mock_neteq_controller_, - PacketArrived(/*last_cng_or_dtmf*/ false, - /*packet_length_samples*/ _, - /*should_update_stats*/ _, - /*main_sequence_number*/ kFirstSequenceNumber, - /*main_timestamp*/ kFirstTimestamp, - /*fs_hz*/ 8000)); - EXPECT_CALL(*mock_neteq_controller_, - PacketArrived(/*last_cng_or_dtmf*/ false, - /*packet_length_samples*/ _, - /*should_update_stats*/ _, - /*main_sequence_number*/ kFirstSequenceNumber + 1, - /*main_timestamp*/ kFirstTimestamp + 160, - /*fs_hz*/ 8000)); + EXPECT_CALL( + *mock_neteq_controller_, + PacketArrived( + /*fs_hz*/ 8000, + /*should_update_stats*/ _, + /*info*/ + AllOf( + Field(&NetEqController::PacketArrivedInfo::is_cng_or_dtmf, + false), + Field(&NetEqController::PacketArrivedInfo::main_sequence_number, + kFirstSequenceNumber), + Field(&NetEqController::PacketArrivedInfo::main_timestamp, + kFirstTimestamp)))); + EXPECT_CALL( + *mock_neteq_controller_, + PacketArrived( + /*fs_hz*/ 8000, + /*should_update_stats*/ _, + /*info*/ + AllOf( + Field(&NetEqController::PacketArrivedInfo::is_cng_or_dtmf, + false), + Field(&NetEqController::PacketArrivedInfo::main_sequence_number, + kFirstSequenceNumber + 1), + Field(&NetEqController::PacketArrivedInfo::main_timestamp, + kFirstTimestamp + 160)))); } // Insert first packet. @@ -1517,6 +1531,8 @@ TEST_F(NetEqImplTest, InsertEmptyPacket) { } TEST_F(NetEqImplTest, EnableRtxHandling) { + using ::testing::AllOf; + using ::testing::Field; UseNoMocks(); use_mock_neteq_controller_ = true; config_.enable_rtx_handling = true; @@ -1545,14 +1561,19 @@ TEST_F(NetEqImplTest, EnableRtxHandling) { // Insert second packet that was sent before the first packet. rtp_header.sequenceNumber -= 1; rtp_header.timestamp -= kPayloadLengthSamples; - EXPECT_CALL(*mock_neteq_controller_, - PacketArrived( - /*last_cng_or_dtmf*/ _, - /*packet_length_samples*/ kPayloadLengthSamples, - /*should_update_stats*/ _, - /*main_sequence_number*/ rtp_header.sequenceNumber, - /*main_timestamp*/ rtp_header.timestamp, - /*fs_hz*/ 8000)); + EXPECT_CALL( + *mock_neteq_controller_, + PacketArrived( + /*fs_hz*/ 8000, + /*should_update_stats*/ _, + /*info*/ + AllOf( + Field(&NetEqController::PacketArrivedInfo::packet_length_samples, + kPayloadLengthSamples), + Field(&NetEqController::PacketArrivedInfo::main_sequence_number, + rtp_header.sequenceNumber), + Field(&NetEqController::PacketArrivedInfo::main_timestamp, + rtp_header.timestamp)))); EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload)); }