• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "modules/audio_coding/neteq/nack_tracker.h"
12 
13 #include <cstdint>
14 #include <utility>
15 
16 #include "rtc_base/checks.h"
17 #include "rtc_base/experiments/struct_parameters_parser.h"
18 #include "rtc_base/logging.h"
19 #include "system_wrappers/include/field_trial.h"
20 
21 namespace webrtc {
22 namespace {
23 
24 const int kDefaultSampleRateKhz = 48;
25 const int kMaxPacketSizeMs = 120;
26 constexpr char kNackTrackerConfigFieldTrial[] =
27     "WebRTC-Audio-NetEqNackTrackerConfig";
28 
29 }  // namespace
30 
Config()31 NackTracker::Config::Config() {
32   auto parser = StructParametersParser::Create(
33       "packet_loss_forget_factor", &packet_loss_forget_factor,
34       "ms_per_loss_percent", &ms_per_loss_percent, "never_nack_multiple_times",
35       &never_nack_multiple_times, "require_valid_rtt", &require_valid_rtt,
36       "max_loss_rate", &max_loss_rate);
37   parser->Parse(
38       webrtc::field_trial::FindFullName(kNackTrackerConfigFieldTrial));
39   RTC_LOG(LS_INFO) << "Nack tracker config:"
40                       " packet_loss_forget_factor="
41                    << packet_loss_forget_factor
42                    << " ms_per_loss_percent=" << ms_per_loss_percent
43                    << " never_nack_multiple_times=" << never_nack_multiple_times
44                    << " require_valid_rtt=" << require_valid_rtt
45                    << " max_loss_rate=" << max_loss_rate;
46 }
47 
NackTracker()48 NackTracker::NackTracker()
49     : sequence_num_last_received_rtp_(0),
50       timestamp_last_received_rtp_(0),
51       any_rtp_received_(false),
52       sequence_num_last_decoded_rtp_(0),
53       timestamp_last_decoded_rtp_(0),
54       any_rtp_decoded_(false),
55       sample_rate_khz_(kDefaultSampleRateKhz),
56       max_nack_list_size_(kNackListSizeLimit) {}
57 
58 NackTracker::~NackTracker() = default;
59 
UpdateSampleRate(int sample_rate_hz)60 void NackTracker::UpdateSampleRate(int sample_rate_hz) {
61   RTC_DCHECK_GT(sample_rate_hz, 0);
62   sample_rate_khz_ = sample_rate_hz / 1000;
63 }
64 
UpdateLastReceivedPacket(uint16_t sequence_number,uint32_t timestamp)65 void NackTracker::UpdateLastReceivedPacket(uint16_t sequence_number,
66                                            uint32_t timestamp) {
67   // Just record the value of sequence number and timestamp if this is the
68   // first packet.
69   if (!any_rtp_received_) {
70     sequence_num_last_received_rtp_ = sequence_number;
71     timestamp_last_received_rtp_ = timestamp;
72     any_rtp_received_ = true;
73     // If no packet is decoded, to have a reasonable estimate of time-to-play
74     // use the given values.
75     if (!any_rtp_decoded_) {
76       sequence_num_last_decoded_rtp_ = sequence_number;
77       timestamp_last_decoded_rtp_ = timestamp;
78     }
79     return;
80   }
81 
82   if (sequence_number == sequence_num_last_received_rtp_)
83     return;
84 
85   // Received RTP should not be in the list.
86   nack_list_.erase(sequence_number);
87 
88   // If this is an old sequence number, no more action is required, return.
89   if (IsNewerSequenceNumber(sequence_num_last_received_rtp_, sequence_number))
90     return;
91 
92   UpdatePacketLossRate(sequence_number - sequence_num_last_received_rtp_ - 1);
93 
94   UpdateList(sequence_number, timestamp);
95 
96   sequence_num_last_received_rtp_ = sequence_number;
97   timestamp_last_received_rtp_ = timestamp;
98   LimitNackListSize();
99 }
100 
GetSamplesPerPacket(uint16_t sequence_number_current_received_rtp,uint32_t timestamp_current_received_rtp) const101 absl::optional<int> NackTracker::GetSamplesPerPacket(
102     uint16_t sequence_number_current_received_rtp,
103     uint32_t timestamp_current_received_rtp) const {
104   uint32_t timestamp_increase =
105       timestamp_current_received_rtp - timestamp_last_received_rtp_;
106   uint16_t sequence_num_increase =
107       sequence_number_current_received_rtp - sequence_num_last_received_rtp_;
108 
109   int samples_per_packet = timestamp_increase / sequence_num_increase;
110   if (samples_per_packet == 0 ||
111       samples_per_packet > kMaxPacketSizeMs * sample_rate_khz_) {
112     // Not a valid samples per packet.
113     return absl::nullopt;
114   }
115   return samples_per_packet;
116 }
117 
UpdateList(uint16_t sequence_number_current_received_rtp,uint32_t timestamp_current_received_rtp)118 void NackTracker::UpdateList(uint16_t sequence_number_current_received_rtp,
119                              uint32_t timestamp_current_received_rtp) {
120   if (!IsNewerSequenceNumber(sequence_number_current_received_rtp,
121                              sequence_num_last_received_rtp_ + 1)) {
122     return;
123   }
124   RTC_DCHECK(!any_rtp_decoded_ ||
125              IsNewerSequenceNumber(sequence_number_current_received_rtp,
126                                    sequence_num_last_decoded_rtp_));
127 
128   absl::optional<int> samples_per_packet = GetSamplesPerPacket(
129       sequence_number_current_received_rtp, timestamp_current_received_rtp);
130   if (!samples_per_packet) {
131     return;
132   }
133 
134   for (uint16_t n = sequence_num_last_received_rtp_ + 1;
135        IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) {
136     uint32_t timestamp = EstimateTimestamp(n, *samples_per_packet);
137     NackElement nack_element(TimeToPlay(timestamp), timestamp);
138     nack_list_.insert(nack_list_.end(), std::make_pair(n, nack_element));
139   }
140 }
141 
EstimateTimestamp(uint16_t sequence_num,int samples_per_packet)142 uint32_t NackTracker::EstimateTimestamp(uint16_t sequence_num,
143                                         int samples_per_packet) {
144   uint16_t sequence_num_diff = sequence_num - sequence_num_last_received_rtp_;
145   return sequence_num_diff * samples_per_packet + timestamp_last_received_rtp_;
146 }
147 
UpdateEstimatedPlayoutTimeBy10ms()148 void NackTracker::UpdateEstimatedPlayoutTimeBy10ms() {
149   while (!nack_list_.empty() &&
150          nack_list_.begin()->second.time_to_play_ms <= 10)
151     nack_list_.erase(nack_list_.begin());
152 
153   for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end(); ++it)
154     it->second.time_to_play_ms -= 10;
155 }
156 
UpdateLastDecodedPacket(uint16_t sequence_number,uint32_t timestamp)157 void NackTracker::UpdateLastDecodedPacket(uint16_t sequence_number,
158                                           uint32_t timestamp) {
159   if (IsNewerSequenceNumber(sequence_number, sequence_num_last_decoded_rtp_) ||
160       !any_rtp_decoded_) {
161     sequence_num_last_decoded_rtp_ = sequence_number;
162     timestamp_last_decoded_rtp_ = timestamp;
163     // Packets in the list with sequence numbers less than the
164     // sequence number of the decoded RTP should be removed from the lists.
165     // They will be discarded by the jitter buffer if they arrive.
166     nack_list_.erase(nack_list_.begin(),
167                      nack_list_.upper_bound(sequence_num_last_decoded_rtp_));
168 
169     // Update estimated time-to-play.
170     for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end();
171          ++it)
172       it->second.time_to_play_ms = TimeToPlay(it->second.estimated_timestamp);
173   } else {
174     RTC_DCHECK_EQ(sequence_number, sequence_num_last_decoded_rtp_);
175 
176     // Same sequence number as before. 10 ms is elapsed, update estimations for
177     // time-to-play.
178     UpdateEstimatedPlayoutTimeBy10ms();
179 
180     // Update timestamp for better estimate of time-to-play, for packets which
181     // are added to NACK list later on.
182     timestamp_last_decoded_rtp_ += sample_rate_khz_ * 10;
183   }
184   any_rtp_decoded_ = true;
185 }
186 
GetNackList() const187 NackTracker::NackList NackTracker::GetNackList() const {
188   return nack_list_;
189 }
190 
Reset()191 void NackTracker::Reset() {
192   nack_list_.clear();
193 
194   sequence_num_last_received_rtp_ = 0;
195   timestamp_last_received_rtp_ = 0;
196   any_rtp_received_ = false;
197   sequence_num_last_decoded_rtp_ = 0;
198   timestamp_last_decoded_rtp_ = 0;
199   any_rtp_decoded_ = false;
200   sample_rate_khz_ = kDefaultSampleRateKhz;
201 }
202 
SetMaxNackListSize(size_t max_nack_list_size)203 void NackTracker::SetMaxNackListSize(size_t max_nack_list_size) {
204   RTC_CHECK_GT(max_nack_list_size, 0);
205   // Ugly hack to get around the problem of passing static consts by reference.
206   const size_t kNackListSizeLimitLocal = NackTracker::kNackListSizeLimit;
207   RTC_CHECK_LE(max_nack_list_size, kNackListSizeLimitLocal);
208 
209   max_nack_list_size_ = max_nack_list_size;
210   LimitNackListSize();
211 }
212 
LimitNackListSize()213 void NackTracker::LimitNackListSize() {
214   uint16_t limit = sequence_num_last_received_rtp_ -
215                    static_cast<uint16_t>(max_nack_list_size_) - 1;
216   nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit));
217 }
218 
TimeToPlay(uint32_t timestamp) const219 int64_t NackTracker::TimeToPlay(uint32_t timestamp) const {
220   uint32_t timestamp_increase = timestamp - timestamp_last_decoded_rtp_;
221   return timestamp_increase / sample_rate_khz_;
222 }
223 
224 // We don't erase elements with time-to-play shorter than round-trip-time.
GetNackList(int64_t round_trip_time_ms)225 std::vector<uint16_t> NackTracker::GetNackList(int64_t round_trip_time_ms) {
226   RTC_DCHECK_GE(round_trip_time_ms, 0);
227   std::vector<uint16_t> sequence_numbers;
228   if (round_trip_time_ms == 0) {
229     if (config_.require_valid_rtt) {
230       return sequence_numbers;
231     } else {
232       round_trip_time_ms = config_.default_rtt_ms;
233     }
234   }
235   if (packet_loss_rate_ >
236       static_cast<uint32_t>(config_.max_loss_rate * (1 << 30))) {
237     return sequence_numbers;
238   }
239   // The estimated packet loss is between 0 and 1, so we need to multiply by 100
240   // here.
241   int max_wait_ms =
242       100.0 * config_.ms_per_loss_percent * packet_loss_rate_ / (1 << 30);
243   for (NackList::const_iterator it = nack_list_.begin(); it != nack_list_.end();
244        ++it) {
245     int64_t time_since_packet_ms =
246         (timestamp_last_received_rtp_ - it->second.estimated_timestamp) /
247         sample_rate_khz_;
248     if (it->second.time_to_play_ms > round_trip_time_ms ||
249         time_since_packet_ms + round_trip_time_ms < max_wait_ms)
250       sequence_numbers.push_back(it->first);
251   }
252   if (config_.never_nack_multiple_times) {
253     nack_list_.clear();
254   }
255   return sequence_numbers;
256 }
257 
UpdatePacketLossRate(int packets_lost)258 void NackTracker::UpdatePacketLossRate(int packets_lost) {
259   const uint64_t alpha_q30 = (1 << 30) * config_.packet_loss_forget_factor;
260   // Exponential filter.
261   packet_loss_rate_ = (alpha_q30 * packet_loss_rate_) >> 30;
262   for (int i = 0; i < packets_lost; ++i) {
263     packet_loss_rate_ =
264         ((alpha_q30 * packet_loss_rate_) >> 30) + ((1 << 30) - alpha_q30);
265   }
266 }
267 }  // namespace webrtc
268