blob: 4e74032d01875e0458f7ac299884bcdd61662766 [file] [log] [blame]
Tommid3807da2020-05-22 17:36:36 +02001/*
2 * Copyright (c) 2016 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
Markus Handell06a2bf02021-07-22 15:09:39 +020011#include "modules/video_coding/nack_requester.h"
Tommid3807da2020-05-22 17:36:36 +020012
13#include <algorithm>
14#include <limits>
15
Markus Handell0e62f7a2021-07-20 13:32:02 +020016#include "api/sequence_checker.h"
17#include "api/task_queue/task_queue_base.h"
Tommid3807da2020-05-22 17:36:36 +020018#include "api/units/timestamp.h"
Tommid3807da2020-05-22 17:36:36 +020019#include "rtc_base/checks.h"
20#include "rtc_base/experiments/field_trial_parser.h"
21#include "rtc_base/logging.h"
Tommid3807da2020-05-22 17:36:36 +020022
23namespace webrtc {
24
25namespace {
Erik Språng609aef32022-07-01 16:46:56 +020026constexpr int kMaxPacketAge = 10'000;
27constexpr int kMaxNackPackets = 1000;
28constexpr TimeDelta kDefaultRtt = TimeDelta::Millis(100);
29constexpr int kMaxNackRetries = 10;
30constexpr int kMaxReorderedPackets = 128;
31constexpr int kNumReorderingBuckets = 10;
32constexpr TimeDelta kDefaultSendNackDelay = TimeDelta::Zero();
Tommid3807da2020-05-22 17:36:36 +020033
Erik Språng609aef32022-07-01 16:46:56 +020034TimeDelta GetSendNackDelay(const FieldTrialsView& field_trials) {
Tommid3807da2020-05-22 17:36:36 +020035 int64_t delay_ms = strtol(
Jonas Orelande02f9ee2022-03-25 12:43:14 +010036 field_trials.Lookup("WebRTC-SendNackDelayMs").c_str(), nullptr, 10);
Tommid3807da2020-05-22 17:36:36 +020037 if (delay_ms > 0 && delay_ms <= 20) {
38 RTC_LOG(LS_INFO) << "SendNackDelay is set to " << delay_ms;
Erik Språng609aef32022-07-01 16:46:56 +020039 return TimeDelta::Millis(delay_ms);
Tommid3807da2020-05-22 17:36:36 +020040 }
Erik Språng609aef32022-07-01 16:46:56 +020041 return kDefaultSendNackDelay;
Tommid3807da2020-05-22 17:36:36 +020042}
43} // namespace
44
Markus Handell0e62f7a2021-07-20 13:32:02 +020045constexpr TimeDelta NackPeriodicProcessor::kUpdateInterval;
46
47NackPeriodicProcessor::NackPeriodicProcessor(TimeDelta update_interval)
48 : update_interval_(update_interval) {}
49
50NackPeriodicProcessor::~NackPeriodicProcessor() {}
51
Markus Handell06a2bf02021-07-22 15:09:39 +020052void NackPeriodicProcessor::RegisterNackModule(NackRequesterBase* module) {
Markus Handell0e62f7a2021-07-20 13:32:02 +020053 RTC_DCHECK_RUN_ON(&sequence_);
54 modules_.push_back(module);
55 if (modules_.size() != 1)
56 return;
57 repeating_task_ = RepeatingTaskHandle::DelayedStart(
58 TaskQueueBase::Current(), update_interval_, [this] {
59 RTC_DCHECK_RUN_ON(&sequence_);
60 ProcessNackModules();
61 return update_interval_;
62 });
63}
64
Markus Handell06a2bf02021-07-22 15:09:39 +020065void NackPeriodicProcessor::UnregisterNackModule(NackRequesterBase* module) {
Markus Handell0e62f7a2021-07-20 13:32:02 +020066 RTC_DCHECK_RUN_ON(&sequence_);
67 auto it = std::find(modules_.begin(), modules_.end(), module);
68 RTC_DCHECK(it != modules_.end());
69 modules_.erase(it);
70 if (modules_.empty())
71 repeating_task_.Stop();
72}
73
Markus Handell0e62f7a2021-07-20 13:32:02 +020074void NackPeriodicProcessor::ProcessNackModules() {
Danil Chapovalov6e7c2682022-07-25 15:58:28 +020075 RTC_DCHECK_RUN_ON(&sequence_);
Markus Handell06a2bf02021-07-22 15:09:39 +020076 for (NackRequesterBase* module : modules_)
Markus Handell0e62f7a2021-07-20 13:32:02 +020077 module->ProcessNacks();
78}
79
80ScopedNackPeriodicProcessorRegistration::
Markus Handell06a2bf02021-07-22 15:09:39 +020081 ScopedNackPeriodicProcessorRegistration(NackRequesterBase* module,
Markus Handell0e62f7a2021-07-20 13:32:02 +020082 NackPeriodicProcessor* processor)
83 : module_(module), processor_(processor) {
84 processor_->RegisterNackModule(module_);
85}
86
87ScopedNackPeriodicProcessorRegistration::
88 ~ScopedNackPeriodicProcessorRegistration() {
89 processor_->UnregisterNackModule(module_);
90}
Tommi63673fe2020-05-27 12:55:38 +020091
Markus Handell06a2bf02021-07-22 15:09:39 +020092NackRequester::NackInfo::NackInfo()
Erik Språng609aef32022-07-01 16:46:56 +020093 : seq_num(0),
94 send_at_seq_num(0),
95 created_at_time(Timestamp::MinusInfinity()),
96 sent_at_time(Timestamp::MinusInfinity()),
97 retries(0) {}
Tommid3807da2020-05-22 17:36:36 +020098
Markus Handell06a2bf02021-07-22 15:09:39 +020099NackRequester::NackInfo::NackInfo(uint16_t seq_num,
100 uint16_t send_at_seq_num,
Erik Språng609aef32022-07-01 16:46:56 +0200101 Timestamp created_at_time)
Tommid3807da2020-05-22 17:36:36 +0200102 : seq_num(seq_num),
103 send_at_seq_num(send_at_seq_num),
104 created_at_time(created_at_time),
Erik Språng609aef32022-07-01 16:46:56 +0200105 sent_at_time(Timestamp::MinusInfinity()),
Tommid3807da2020-05-22 17:36:36 +0200106 retries(0) {}
107
Markus Handell06a2bf02021-07-22 15:09:39 +0200108NackRequester::NackRequester(TaskQueueBase* current_queue,
109 NackPeriodicProcessor* periodic_processor,
110 Clock* clock,
111 NackSender* nack_sender,
Jonas Orelande02f9ee2022-03-25 12:43:14 +0100112 KeyFrameRequestSender* keyframe_request_sender,
Jonas Orelande62c2f22022-03-29 11:04:48 +0200113 const FieldTrialsView& field_trials)
Tommi63673fe2020-05-27 12:55:38 +0200114 : worker_thread_(current_queue),
Tommi63673fe2020-05-27 12:55:38 +0200115 clock_(clock),
Tommid3807da2020-05-22 17:36:36 +0200116 nack_sender_(nack_sender),
117 keyframe_request_sender_(keyframe_request_sender),
118 reordering_histogram_(kNumReorderingBuckets, kMaxReorderedPackets),
119 initialized_(false),
Erik Språng609aef32022-07-01 16:46:56 +0200120 rtt_(kDefaultRtt),
Tommid3807da2020-05-22 17:36:36 +0200121 newest_seq_num_(0),
Erik Språng609aef32022-07-01 16:46:56 +0200122 send_nack_delay_(GetSendNackDelay(field_trials)),
Markus Handell0e62f7a2021-07-20 13:32:02 +0200123 processor_registration_(this, periodic_processor) {
Tommid3807da2020-05-22 17:36:36 +0200124 RTC_DCHECK(clock_);
125 RTC_DCHECK(nack_sender_);
126 RTC_DCHECK(keyframe_request_sender_);
Tommi63673fe2020-05-27 12:55:38 +0200127 RTC_DCHECK(worker_thread_);
128 RTC_DCHECK(worker_thread_->IsCurrent());
Tommi63673fe2020-05-27 12:55:38 +0200129}
130
Markus Handell06a2bf02021-07-22 15:09:39 +0200131NackRequester::~NackRequester() {
Tommi63673fe2020-05-27 12:55:38 +0200132 RTC_DCHECK_RUN_ON(worker_thread_);
Markus Handell0e62f7a2021-07-20 13:32:02 +0200133}
134
Markus Handell06a2bf02021-07-22 15:09:39 +0200135void NackRequester::ProcessNacks() {
Markus Handell0e62f7a2021-07-20 13:32:02 +0200136 RTC_DCHECK_RUN_ON(worker_thread_);
137 std::vector<uint16_t> nack_batch = GetNackBatch(kTimeOnly);
138 if (!nack_batch.empty()) {
139 // This batch of NACKs is triggered externally; there is no external
140 // initiator who can batch them with other feedback messages.
141 nack_sender_->SendNack(nack_batch, /*buffering_allowed=*/false);
142 }
Tommid3807da2020-05-22 17:36:36 +0200143}
144
Markus Handell06a2bf02021-07-22 15:09:39 +0200145int NackRequester::OnReceivedPacket(uint16_t seq_num, bool is_keyframe) {
Tommi63673fe2020-05-27 12:55:38 +0200146 RTC_DCHECK_RUN_ON(worker_thread_);
Tommid3807da2020-05-22 17:36:36 +0200147 return OnReceivedPacket(seq_num, is_keyframe, false);
148}
149
Markus Handell06a2bf02021-07-22 15:09:39 +0200150int NackRequester::OnReceivedPacket(uint16_t seq_num,
151 bool is_keyframe,
152 bool is_recovered) {
Tommi63673fe2020-05-27 12:55:38 +0200153 RTC_DCHECK_RUN_ON(worker_thread_);
Tommid3807da2020-05-22 17:36:36 +0200154 // TODO(philipel): When the packet includes information whether it is
155 // retransmitted or not, use that value instead. For
156 // now set it to true, which will cause the reordering
157 // statistics to never be updated.
158 bool is_retransmitted = true;
159
160 if (!initialized_) {
161 newest_seq_num_ = seq_num;
162 if (is_keyframe)
163 keyframe_list_.insert(seq_num);
164 initialized_ = true;
165 return 0;
166 }
167
Artem Titovdcd7fc72021-08-09 13:02:57 +0200168 // Since the `newest_seq_num_` is a packet we have actually received we know
Tommid3807da2020-05-22 17:36:36 +0200169 // that packet has never been Nacked.
170 if (seq_num == newest_seq_num_)
171 return 0;
172
173 if (AheadOf(newest_seq_num_, seq_num)) {
174 // An out of order packet has been received.
175 auto nack_list_it = nack_list_.find(seq_num);
176 int nacks_sent_for_packet = 0;
177 if (nack_list_it != nack_list_.end()) {
178 nacks_sent_for_packet = nack_list_it->second.retries;
179 nack_list_.erase(nack_list_it);
180 }
181 if (!is_retransmitted)
182 UpdateReorderingStatistics(seq_num);
183 return nacks_sent_for_packet;
184 }
185
186 // Keep track of new keyframes.
187 if (is_keyframe)
188 keyframe_list_.insert(seq_num);
189
190 // And remove old ones so we don't accumulate keyframes.
191 auto it = keyframe_list_.lower_bound(seq_num - kMaxPacketAge);
192 if (it != keyframe_list_.begin())
193 keyframe_list_.erase(keyframe_list_.begin(), it);
194
195 if (is_recovered) {
196 recovered_list_.insert(seq_num);
197
198 // Remove old ones so we don't accumulate recovered packets.
199 auto it = recovered_list_.lower_bound(seq_num - kMaxPacketAge);
200 if (it != recovered_list_.begin())
201 recovered_list_.erase(recovered_list_.begin(), it);
202
203 // Do not send nack for packets recovered by FEC or RTX.
204 return 0;
205 }
206
207 AddPacketsToNack(newest_seq_num_ + 1, seq_num);
208 newest_seq_num_ = seq_num;
209
210 // Are there any nacks that are waiting for this seq_num.
211 std::vector<uint16_t> nack_batch = GetNackBatch(kSeqNumOnly);
212 if (!nack_batch.empty()) {
213 // This batch of NACKs is triggered externally; the initiator can
214 // batch them with other feedback messages.
215 nack_sender_->SendNack(nack_batch, /*buffering_allowed=*/true);
216 }
217
218 return 0;
219}
220
Markus Handell06a2bf02021-07-22 15:09:39 +0200221void NackRequester::ClearUpTo(uint16_t seq_num) {
Tommi63673fe2020-05-27 12:55:38 +0200222 // Called via RtpVideoStreamReceiver2::FrameContinuous on the network thread.
Danil Chapovalov0be8eba2022-07-06 13:17:54 +0200223 worker_thread_->PostTask(SafeTask(task_safety_.flag(), [seq_num, this]() {
Tommi63673fe2020-05-27 12:55:38 +0200224 RTC_DCHECK_RUN_ON(worker_thread_);
225 nack_list_.erase(nack_list_.begin(), nack_list_.lower_bound(seq_num));
226 keyframe_list_.erase(keyframe_list_.begin(),
227 keyframe_list_.lower_bound(seq_num));
228 recovered_list_.erase(recovered_list_.begin(),
229 recovered_list_.lower_bound(seq_num));
230 }));
Tommid3807da2020-05-22 17:36:36 +0200231}
232
Markus Handell06a2bf02021-07-22 15:09:39 +0200233void NackRequester::UpdateRtt(int64_t rtt_ms) {
Tommi63673fe2020-05-27 12:55:38 +0200234 RTC_DCHECK_RUN_ON(worker_thread_);
Erik Språng609aef32022-07-01 16:46:56 +0200235 rtt_ = TimeDelta::Millis(rtt_ms);
Tommid3807da2020-05-22 17:36:36 +0200236}
237
Markus Handell06a2bf02021-07-22 15:09:39 +0200238bool NackRequester::RemovePacketsUntilKeyFrame() {
Tommi63673fe2020-05-27 12:55:38 +0200239 // Called on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200240 while (!keyframe_list_.empty()) {
241 auto it = nack_list_.lower_bound(*keyframe_list_.begin());
242
243 if (it != nack_list_.begin()) {
244 // We have found a keyframe that actually is newer than at least one
245 // packet in the nack list.
246 nack_list_.erase(nack_list_.begin(), it);
247 return true;
248 }
249
250 // If this keyframe is so old it does not remove any packets from the list,
251 // remove it from the list of keyframes and try the next keyframe.
252 keyframe_list_.erase(keyframe_list_.begin());
253 }
254 return false;
255}
256
Markus Handell06a2bf02021-07-22 15:09:39 +0200257void NackRequester::AddPacketsToNack(uint16_t seq_num_start,
258 uint16_t seq_num_end) {
Tommi63673fe2020-05-27 12:55:38 +0200259 // Called on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200260 // Remove old packets.
261 auto it = nack_list_.lower_bound(seq_num_end - kMaxPacketAge);
262 nack_list_.erase(nack_list_.begin(), it);
263
264 // If the nack list is too large, remove packets from the nack list until
265 // the latest first packet of a keyframe. If the list is still too large,
266 // clear it and request a keyframe.
267 uint16_t num_new_nacks = ForwardDiff(seq_num_start, seq_num_end);
268 if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
269 while (RemovePacketsUntilKeyFrame() &&
270 nack_list_.size() + num_new_nacks > kMaxNackPackets) {
271 }
272
273 if (nack_list_.size() + num_new_nacks > kMaxNackPackets) {
274 nack_list_.clear();
275 RTC_LOG(LS_WARNING) << "NACK list full, clearing NACK"
276 " list and requesting keyframe.";
277 keyframe_request_sender_->RequestKeyFrame();
278 return;
279 }
280 }
281
282 for (uint16_t seq_num = seq_num_start; seq_num != seq_num_end; ++seq_num) {
283 // Do not send nack for packets that are already recovered by FEC or RTX
284 if (recovered_list_.find(seq_num) != recovered_list_.end())
285 continue;
286 NackInfo nack_info(seq_num, seq_num + WaitNumberOfPackets(0.5),
Erik Språng609aef32022-07-01 16:46:56 +0200287 clock_->CurrentTime());
Tommid3807da2020-05-22 17:36:36 +0200288 RTC_DCHECK(nack_list_.find(seq_num) == nack_list_.end());
289 nack_list_[seq_num] = nack_info;
290 }
291}
292
Markus Handell06a2bf02021-07-22 15:09:39 +0200293std::vector<uint16_t> NackRequester::GetNackBatch(NackFilterOptions options) {
Tommi63673fe2020-05-27 12:55:38 +0200294 // Called on worker_thread_.
295
Tommid3807da2020-05-22 17:36:36 +0200296 bool consider_seq_num = options != kTimeOnly;
297 bool consider_timestamp = options != kSeqNumOnly;
298 Timestamp now = clock_->CurrentTime();
299 std::vector<uint16_t> nack_batch;
300 auto it = nack_list_.begin();
301 while (it != nack_list_.end()) {
Erik Språng609aef32022-07-01 16:46:56 +0200302 bool delay_timed_out = now - it->second.created_at_time >= send_nack_delay_;
303 bool nack_on_rtt_passed = now - it->second.sent_at_time >= rtt_;
Tommid3807da2020-05-22 17:36:36 +0200304 bool nack_on_seq_num_passed =
Erik Språng609aef32022-07-01 16:46:56 +0200305 it->second.sent_at_time.IsInfinite() &&
Tommid3807da2020-05-22 17:36:36 +0200306 AheadOrAt(newest_seq_num_, it->second.send_at_seq_num);
307 if (delay_timed_out && ((consider_seq_num && nack_on_seq_num_passed) ||
308 (consider_timestamp && nack_on_rtt_passed))) {
309 nack_batch.emplace_back(it->second.seq_num);
310 ++it->second.retries;
Erik Språng609aef32022-07-01 16:46:56 +0200311 it->second.sent_at_time = now;
Tommid3807da2020-05-22 17:36:36 +0200312 if (it->second.retries >= kMaxNackRetries) {
313 RTC_LOG(LS_WARNING) << "Sequence number " << it->second.seq_num
314 << " removed from NACK list due to max retries.";
315 it = nack_list_.erase(it);
316 } else {
317 ++it;
318 }
319 continue;
320 }
321 ++it;
322 }
323 return nack_batch;
324}
325
Markus Handell06a2bf02021-07-22 15:09:39 +0200326void NackRequester::UpdateReorderingStatistics(uint16_t seq_num) {
Tommi63673fe2020-05-27 12:55:38 +0200327 // Running on worker_thread_.
Tommid3807da2020-05-22 17:36:36 +0200328 RTC_DCHECK(AheadOf(newest_seq_num_, seq_num));
329 uint16_t diff = ReverseDiff(newest_seq_num_, seq_num);
330 reordering_histogram_.Add(diff);
331}
332
Markus Handell06a2bf02021-07-22 15:09:39 +0200333int NackRequester::WaitNumberOfPackets(float probability) const {
Tommi63673fe2020-05-27 12:55:38 +0200334 // Called on worker_thread_;
Tommid3807da2020-05-22 17:36:36 +0200335 if (reordering_histogram_.NumValues() == 0)
336 return 0;
337 return reordering_histogram_.InverseCdf(probability);
338}
339
340} // namespace webrtc