Avoid NACKing after DTX.
This is done by not adding missing packets to the NACK list if the number of samples per packet is too large.
Bug: webrtc:10178
Change-Id: If46398d6d05ea35f30d7028040d3b808559e950b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/231841
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Commit-Queue: Jakob Ivarsson <jakobi@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#34984}
diff --git a/modules/audio_coding/neteq/nack_tracker.cc b/modules/audio_coding/neteq/nack_tracker.cc
index c95679a..1df07c9 100644
--- a/modules/audio_coding/neteq/nack_tracker.cc
+++ b/modules/audio_coding/neteq/nack_tracker.cc
@@ -22,7 +22,7 @@
namespace {
const int kDefaultSampleRateKhz = 48;
-const int kDefaultPacketSizeMs = 20;
+const int kMaxPacketSizeMs = 120;
constexpr char kNackTrackerConfigFieldTrial[] =
"WebRTC-Audio-NetEqNackTrackerConfig";
@@ -52,7 +52,6 @@
timestamp_last_decoded_rtp_(0),
any_rtp_decoded_(false),
sample_rate_khz_(kDefaultSampleRateKhz),
- samples_per_packet_(sample_rate_khz_ * kDefaultPacketSizeMs),
max_nack_list_size_(kNackListSizeLimit) {}
NackTracker::~NackTracker() = default;
@@ -95,33 +94,39 @@
UpdatePacketLossRate(sequence_number - sequence_num_last_received_rtp_ - 1);
- UpdateSamplesPerPacket(sequence_number, timestamp);
-
- UpdateList(sequence_number);
+ UpdateList(sequence_number, timestamp);
sequence_num_last_received_rtp_ = sequence_number;
timestamp_last_received_rtp_ = timestamp;
LimitNackListSize();
}
-void NackTracker::UpdateSamplesPerPacket(
+absl::optional<int> NackTracker::GetSamplesPerPacket(
uint16_t sequence_number_current_received_rtp,
- uint32_t timestamp_current_received_rtp) {
+ uint32_t timestamp_current_received_rtp) const {
uint32_t timestamp_increase =
timestamp_current_received_rtp - timestamp_last_received_rtp_;
uint16_t sequence_num_increase =
sequence_number_current_received_rtp - sequence_num_last_received_rtp_;
- samples_per_packet_ = timestamp_increase / sequence_num_increase;
+ int samples_per_packet = timestamp_increase / sequence_num_increase;
+ if (samples_per_packet == 0 ||
+ samples_per_packet > kMaxPacketSizeMs * sample_rate_khz_) {
+ // Not a valid samples per packet.
+ return absl::nullopt;
+ }
+ return samples_per_packet;
}
-void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp) {
+void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp) {
// Some of the packets which were considered late, now are considered missing.
ChangeFromLateToMissing(sequence_number_current_received_rtp);
if (IsNewerSequenceNumber(sequence_number_current_received_rtp,
sequence_num_last_received_rtp_ + 1))
- AddToList(sequence_number_current_received_rtp);
+ AddToList(sequence_number_current_received_rtp,
+ timestamp_current_received_rtp);
}
void NackTracker::ChangeFromLateToMissing(
@@ -134,16 +139,24 @@
it->second.is_missing = true;
}
-uint32_t NackTracker::EstimateTimestamp(uint16_t sequence_num) {
+uint32_t NackTracker::EstimateTimestamp(uint16_t sequence_num,
+ int samples_per_packet) {
uint16_t sequence_num_diff = sequence_num - sequence_num_last_received_rtp_;
- return sequence_num_diff * samples_per_packet_ + timestamp_last_received_rtp_;
+ return sequence_num_diff * samples_per_packet + timestamp_last_received_rtp_;
}
-void NackTracker::AddToList(uint16_t sequence_number_current_received_rtp) {
+void NackTracker::AddToList(uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp) {
RTC_DCHECK(!any_rtp_decoded_ ||
IsNewerSequenceNumber(sequence_number_current_received_rtp,
sequence_num_last_decoded_rtp_));
+ absl::optional<int> samples_per_packet = GetSamplesPerPacket(
+ sequence_number_current_received_rtp, timestamp_current_received_rtp);
+ if (!samples_per_packet) {
+ return;
+ }
+
// Packets with sequence numbers older than `upper_bound_missing` are
// considered missing, and the rest are considered late.
uint16_t upper_bound_missing =
@@ -152,7 +165,7 @@
for (uint16_t n = sequence_num_last_received_rtp_ + 1;
IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) {
bool is_missing = IsNewerSequenceNumber(upper_bound_missing, n);
- uint32_t timestamp = EstimateTimestamp(n);
+ uint32_t timestamp = EstimateTimestamp(n, *samples_per_packet);
NackElement nack_element(TimeToPlay(timestamp), timestamp, is_missing);
nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element));
}
@@ -211,7 +224,6 @@
timestamp_last_decoded_rtp_ = 0;
any_rtp_decoded_ = false;
sample_rate_khz_ = kDefaultSampleRateKhz;
- samples_per_packet_ = sample_rate_khz_ * kDefaultPacketSizeMs;
}
void NackTracker::SetMaxNackListSize(size_t max_nack_list_size) {
diff --git a/modules/audio_coding/neteq/nack_tracker.h b/modules/audio_coding/neteq/nack_tracker.h
index f3cce74..34e4de6 100644
--- a/modules/audio_coding/neteq/nack_tracker.h
+++ b/modules/audio_coding/neteq/nack_tracker.h
@@ -17,6 +17,7 @@
#include <map>
#include <vector>
+#include "absl/types/optional.h"
#include "modules/include/module_common_types_public.h"
#include "rtc_base/gtest_prod_util.h"
@@ -159,22 +160,24 @@
// Given the `sequence_number_current_received_rtp` of currently received RTP,
// recognize packets which are not arrive and add to the list.
- void AddToList(uint16_t sequence_number_current_received_rtp);
+ void AddToList(uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp);
// This function subtracts 10 ms of time-to-play for all packets in NACK list.
// This is called when 10 ms elapsed with no new RTP packet decoded.
void UpdateEstimatedPlayoutTimeBy10ms();
- // Given the `sequence_number_current_received_rtp` and
- // `timestamp_current_received_rtp` of currently received RTP update number
- // of samples per packet.
- void UpdateSamplesPerPacket(uint16_t sequence_number_current_received_rtp,
- uint32_t timestamp_current_received_rtp);
+ // Returns a valid number of samples per packet given the current received
+ // sequence number and timestamp or nullopt of none could be computed.
+ absl::optional<int> GetSamplesPerPacket(
+ uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp) const;
// Given the `sequence_number_current_received_rtp` of currently received RTP
// update the list. That is; some packets will change from late to missing,
// some packets are inserted as missing and some inserted as late.
- void UpdateList(uint16_t sequence_number_current_received_rtp);
+ void UpdateList(uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp);
// Packets which are considered late for too long (according to
// `nack_threshold_packets_`) are flagged as missing.
@@ -186,7 +189,7 @@
void LimitNackListSize();
// Estimate timestamp of a missing packet given its sequence number.
- uint32_t EstimateTimestamp(uint16_t sequence_number);
+ uint32_t EstimateTimestamp(uint16_t sequence_number, int samples_per_packet);
// Compute time-to-play given a timestamp.
int64_t TimeToPlay(uint32_t timestamp) const;
@@ -215,10 +218,6 @@
int sample_rate_khz_; // Sample rate in kHz.
- // Number of samples per packet. We update this every time we receive a
- // packet, not only for consecutive packets.
- int samples_per_packet_;
-
// A list of missing packets to be retransmitted. Components of the list
// contain the sequence number of missing packets and the estimated time that
// each pack is going to be played out.
diff --git a/modules/audio_coding/neteq/nack_tracker_unittest.cc b/modules/audio_coding/neteq/nack_tracker_unittest.cc
index 6ee8f2a..9fc3ae2 100644
--- a/modules/audio_coding/neteq/nack_tracker_unittest.cc
+++ b/modules/audio_coding/neteq/nack_tracker_unittest.cc
@@ -539,4 +539,19 @@
EXPECT_NEAR(nack->GetPacketLossRateForTest(), 1 << 28, (1 << 30) / 100);
}
+TEST(NackTrackerTest, DoNotNackAfterDtx) {
+ const int kNackListSize = 200;
+ std::unique_ptr<NackTracker> nack(NackTracker::Create(0));
+ nack->UpdateSampleRate(kSampleRateHz);
+ nack->SetMaxNackListSize(kNackListSize);
+ uint16_t seq_num = 0;
+ uint32_t timestamp = 0x87654321;
+ nack->UpdateLastReceivedPacket(seq_num, timestamp);
+ EXPECT_TRUE(nack->GetNackList(0).empty());
+ constexpr int kDtxPeriod = 400;
+ nack->UpdateLastReceivedPacket(seq_num + 2,
+ timestamp + kDtxPeriod * kSampleRateHz / 1000);
+ EXPECT_TRUE(nack->GetNackList(0).empty());
+}
+
} // namespace webrtc