Signal to NetEq Controller if arrived packets are DTX packets.

This CL also puts the arguments in a struct to allow for easier future additions.

Bug: webrtc:11005
Change-Id: I47bf664e7106b724eb1fc42299c42bbf022393ef
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/188385
Commit-Queue: Ivo Creusen <ivoc@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32409}
This commit is contained in:
Ivo Creusen
2020-10-14 17:54:22 +02:00
committed by Commit Bot
parent c4de62d51f
commit a2b31c35ff
6 changed files with 99 additions and 47 deletions

View File

@ -97,6 +97,14 @@ class NetEqController {
size_t sync_buffer_samples; 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; virtual ~NetEqController() = default;
// Resets object to a clean state. // Resets object to a clean state.
@ -154,15 +162,33 @@ class NetEqController {
// Returns the target buffer level in ms. // Returns the target buffer level in ms.
virtual int TargetLevelMs() const = 0; virtual int TargetLevelMs() const = 0;
// Notify the NetEqController that a packet has arrived. Returns the relative // Deprecated.
// arrival delay, if it can be computed. // TODO(ivoc): Remove when downstream is updated.
virtual absl::optional<int> PacketArrived(bool last_cng_or_dtmf, virtual absl::optional<int> PacketArrived(bool last_cng_or_dtmf,
size_t packet_length_samples, size_t packet_length_samples,
bool should_update_stats, bool should_update_stats,
uint16_t main_sequence_number, uint16_t main_sequence_number,
uint32_t main_timestamp, 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<int> 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. // Notify the NetEqController that we are currently in muted state.
// TODO(ivoc): Make pure virtual when downstream is updated. // TODO(ivoc): Make pure virtual when downstream is updated.
virtual void NotifyMutedState() {} virtual void NotifyMutedState() {}

View File

@ -198,26 +198,24 @@ void DecisionLogic::ExpandDecision(NetEq::Operation operation) {
} }
} }
absl::optional<int> DecisionLogic::PacketArrived(bool is_cng_or_dtmf, absl::optional<int> DecisionLogic::PacketArrived(
size_t packet_length_samples, int fs_hz,
bool should_update_stats, bool should_update_stats,
uint16_t main_sequence_number, const PacketArrivedInfo& info) {
uint32_t main_timestamp, if (info.is_cng_or_dtmf) {
int fs_hz) {
if (is_cng_or_dtmf) {
last_pack_cng_or_dtmf_ = true; last_pack_cng_or_dtmf_ = true;
return absl::nullopt; return absl::nullopt;
} }
if (!should_update_stats) { if (!should_update_stats) {
return absl::nullopt; return absl::nullopt;
} }
if (packet_length_samples > 0 && fs_hz > 0 && if (info.packet_length_samples > 0 && fs_hz > 0 &&
packet_length_samples != packet_length_samples_) { info.packet_length_samples != packet_length_samples_) {
packet_length_samples_ = packet_length_samples; packet_length_samples_ = info.packet_length_samples;
delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz); delay_manager_->SetPacketAudioLength(packet_length_samples_ * 1000 / fs_hz);
} }
auto relative_delay = delay_manager_->Update( 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; last_pack_cng_or_dtmf_ = false;
return relative_delay; return relative_delay;
} }

View File

@ -72,12 +72,9 @@ class DecisionLogic : public NetEqController {
int TargetLevelMs() const override { return delay_manager_->TargetDelayMs(); } int TargetLevelMs() const override { return delay_manager_->TargetDelayMs(); }
absl::optional<int> PacketArrived(bool is_cng_or_dtmf, absl::optional<int> PacketArrived(int fs_hz,
size_t packet_length_samples,
bool should_update_stats, bool should_update_stats,
uint16_t main_sequence_number, const PacketArrivedInfo& info) override;
uint32_t main_timestamp,
int fs_hz) override;
void RegisterEmptyPacket() override {} void RegisterEmptyPacket() override {}

View File

@ -51,6 +51,12 @@ class MockNetEqController : public NetEqController {
uint32_t main_timestamp, uint32_t main_timestamp,
int fs_hz), int fs_hz),
(override)); (override));
MOCK_METHOD(absl::optional<int>,
PacketArrived,
(int fs_hz,
bool should_update_stats,
const PacketArrivedInfo& info),
(override));
MOCK_METHOD(bool, PeakFound, (), (const, override)); MOCK_METHOD(bool, PeakFound, (), (const, override));
MOCK_METHOD(int, GetFilteredBufferLevel, (), (const, override)); MOCK_METHOD(int, GetFilteredBufferLevel, (), (const, override));
MOCK_METHOD(void, set_sample_memory, (int32_t value), (override)); MOCK_METHOD(void, set_sample_memory, (int32_t value), (override));

View File

@ -680,6 +680,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
} }
PacketList parsed_packet_list; PacketList parsed_packet_list;
bool is_dtx = false;
while (!packet_list.empty()) { while (!packet_list.empty()) {
Packet& packet = packet_list.front(); Packet& packet = packet_list.front();
const DecoderDatabase::DecoderInfo* info = const DecoderDatabase::DecoderInfo* info =
@ -720,6 +721,7 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
for (auto& result : results) { for (auto& result : results) {
RTC_DCHECK(result.frame); RTC_DCHECK(result.frame);
RTC_DCHECK_GE(result.priority, 0); RTC_DCHECK_GE(result.priority, 0);
is_dtx = is_dtx || result.frame->IsDtxPacket();
if (first) { if (first) {
// Re-use the node and move it to parsed_packet_list. // Re-use the node and move it to parsed_packet_list.
packet_list.front() = packet_from_result(result); packet_list.front() = packet_from_result(result);
@ -801,10 +803,13 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
decoder_database_->GetDecoderInfo(main_payload_type); decoder_database_->GetDecoderInfo(main_payload_type);
assert(dec_info); // Already checked that the payload type is known. assert(dec_info); // Already checked that the payload type is known.
const bool last_cng_or_dtmf = NetEqController::PacketArrivedInfo info;
dec_info->IsComfortNoise() || dec_info->IsDtmf(); info.is_cng_or_dtmf = dec_info->IsComfortNoise() || dec_info->IsDtmf();
const size_t packet_length_samples = info.packet_length_samples =
number_of_primary_packets * decoder_frame_length_; 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 // 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 // out packet or RTX handling is enabled, and if new codec flag is not
// set. // set.
@ -813,9 +818,8 @@ int NetEqImpl::InsertPacketInternal(const RTPHeader& rtp_header,
static_cast<int32_t>(main_timestamp - timestamp_) >= 0) && static_cast<int32_t>(main_timestamp - timestamp_) >= 0) &&
!new_codec_; !new_codec_;
auto relative_delay = controller_->PacketArrived( auto relative_delay =
last_cng_or_dtmf, packet_length_samples, should_update_stats, controller_->PacketArrived(fs_hz_, should_update_stats, info);
main_sequence_number, main_timestamp, fs_hz_);
if (relative_delay) { if (relative_delay) {
stats_->RelativePacketArrivalDelay(relative_delay.value()); stats_->RelativePacketArrivalDelay(relative_delay.value());
} }

View File

@ -284,6 +284,8 @@ TEST_F(NetEqImplTest, RemoveAllPayloadTypes) {
} }
TEST_F(NetEqImplTest, InsertPacket) { TEST_F(NetEqImplTest, InsertPacket) {
using ::testing::AllOf;
using ::testing::Field;
CreateInstance(); CreateInstance();
const size_t kPayloadLength = 100; const size_t kPayloadLength = 100;
const uint8_t kPayloadType = 0; 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. // All expectations within this block must be called in this specific order.
InSequence sequence; // Dummy variable. InSequence sequence; // Dummy variable.
// Expectations when the first packet is inserted. // Expectations when the first packet is inserted.
EXPECT_CALL(*mock_neteq_controller_, EXPECT_CALL(
PacketArrived(/*last_cng_or_dtmf*/ false, *mock_neteq_controller_,
/*packet_length_samples*/ _, PacketArrived(
/*should_update_stats*/ _, /*fs_hz*/ 8000,
/*main_sequence_number*/ kFirstSequenceNumber, /*should_update_stats*/ _,
/*main_timestamp*/ kFirstTimestamp, /*info*/
/*fs_hz*/ 8000)); AllOf(
EXPECT_CALL(*mock_neteq_controller_, Field(&NetEqController::PacketArrivedInfo::is_cng_or_dtmf,
PacketArrived(/*last_cng_or_dtmf*/ false, false),
/*packet_length_samples*/ _, Field(&NetEqController::PacketArrivedInfo::main_sequence_number,
/*should_update_stats*/ _, kFirstSequenceNumber),
/*main_sequence_number*/ kFirstSequenceNumber + 1, Field(&NetEqController::PacketArrivedInfo::main_timestamp,
/*main_timestamp*/ kFirstTimestamp + 160, kFirstTimestamp))));
/*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 + 1),
Field(&NetEqController::PacketArrivedInfo::main_timestamp,
kFirstTimestamp + 160))));
} }
// Insert first packet. // Insert first packet.
@ -1517,6 +1531,8 @@ TEST_F(NetEqImplTest, InsertEmptyPacket) {
} }
TEST_F(NetEqImplTest, EnableRtxHandling) { TEST_F(NetEqImplTest, EnableRtxHandling) {
using ::testing::AllOf;
using ::testing::Field;
UseNoMocks(); UseNoMocks();
use_mock_neteq_controller_ = true; use_mock_neteq_controller_ = true;
config_.enable_rtx_handling = true; config_.enable_rtx_handling = true;
@ -1545,14 +1561,19 @@ TEST_F(NetEqImplTest, EnableRtxHandling) {
// Insert second packet that was sent before the first packet. // Insert second packet that was sent before the first packet.
rtp_header.sequenceNumber -= 1; rtp_header.sequenceNumber -= 1;
rtp_header.timestamp -= kPayloadLengthSamples; rtp_header.timestamp -= kPayloadLengthSamples;
EXPECT_CALL(*mock_neteq_controller_, EXPECT_CALL(
PacketArrived( *mock_neteq_controller_,
/*last_cng_or_dtmf*/ _, PacketArrived(
/*packet_length_samples*/ kPayloadLengthSamples, /*fs_hz*/ 8000,
/*should_update_stats*/ _, /*should_update_stats*/ _,
/*main_sequence_number*/ rtp_header.sequenceNumber, /*info*/
/*main_timestamp*/ rtp_header.timestamp, AllOf(
/*fs_hz*/ 8000)); 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)); EXPECT_EQ(NetEq::kOK, neteq_->InsertPacket(rtp_header, payload));
} }