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:
@ -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() {}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 {}
|
||||||
|
|
||||||
|
@ -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));
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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(
|
||||||
|
/*fs_hz*/ 8000,
|
||||||
/*should_update_stats*/ _,
|
/*should_update_stats*/ _,
|
||||||
/*main_sequence_number*/ kFirstSequenceNumber,
|
/*info*/
|
||||||
/*main_timestamp*/ kFirstTimestamp,
|
AllOf(
|
||||||
/*fs_hz*/ 8000));
|
Field(&NetEqController::PacketArrivedInfo::is_cng_or_dtmf,
|
||||||
EXPECT_CALL(*mock_neteq_controller_,
|
false),
|
||||||
PacketArrived(/*last_cng_or_dtmf*/ false,
|
Field(&NetEqController::PacketArrivedInfo::main_sequence_number,
|
||||||
/*packet_length_samples*/ _,
|
kFirstSequenceNumber),
|
||||||
|
Field(&NetEqController::PacketArrivedInfo::main_timestamp,
|
||||||
|
kFirstTimestamp))));
|
||||||
|
EXPECT_CALL(
|
||||||
|
*mock_neteq_controller_,
|
||||||
|
PacketArrived(
|
||||||
|
/*fs_hz*/ 8000,
|
||||||
/*should_update_stats*/ _,
|
/*should_update_stats*/ _,
|
||||||
/*main_sequence_number*/ kFirstSequenceNumber + 1,
|
/*info*/
|
||||||
/*main_timestamp*/ kFirstTimestamp + 160,
|
AllOf(
|
||||||
/*fs_hz*/ 8000));
|
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(
|
||||||
|
*mock_neteq_controller_,
|
||||||
PacketArrived(
|
PacketArrived(
|
||||||
/*last_cng_or_dtmf*/ _,
|
/*fs_hz*/ 8000,
|
||||||
/*packet_length_samples*/ kPayloadLengthSamples,
|
|
||||||
/*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));
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user