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