blob: 14ba2166d1539977bd2d4cccfc8ac9302f917e2c [file] [log] [blame]
turaj@webrtc.org7959e162013-09-12 18:30:26 +00001/*
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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#ifndef MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
12#define MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_
turaj@webrtc.org7959e162013-09-12 18:30:26 +000013
Yves Gerey988cc082018-10-23 12:03:01 +020014#include <stddef.h>
15#include <stdint.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020016
turaj@webrtc.org7959e162013-09-12 18:30:26 +000017#include <map>
Yves Gerey665174f2018-06-19 15:03:05 +020018#include <vector>
turaj@webrtc.org7959e162013-09-12 18:30:26 +000019
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +020020#include "absl/types/optional.h"
Yves Gerey988cc082018-10-23 12:03:01 +020021#include "modules/include/module_common_types_public.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/gtest_prod_util.h"
turaj@webrtc.org7959e162013-09-12 18:30:26 +000023
24//
henrik.lundin91951862016-06-08 06:43:41 -070025// The NackTracker class keeps track of the lost packets, an estimate of
26// time-to-play for each packet is also given.
turaj@webrtc.org7959e162013-09-12 18:30:26 +000027//
28// Every time a packet is pushed into NetEq, LastReceivedPacket() has to be
29// called to update the NACK list.
30//
31// Every time 10ms audio is pulled from NetEq LastDecodedPacket() should be
32// called, and time-to-play is updated at that moment.
33//
Ivo Creusenbc503c92021-09-14 15:17:23 +000034// If packet N is received, any packet prior to N which has not arrived is
35// considered lost, and should be labeled as "missing" (the size of
36// the list might be limited and older packet eliminated from the list).
turaj@webrtc.org7959e162013-09-12 18:30:26 +000037//
henrik.lundin91951862016-06-08 06:43:41 -070038// The NackTracker class has to know about the sample rate of the packets to
39// compute time-to-play. So sample rate should be set as soon as the first
40// packet is received. If there is a change in the receive codec (sender changes
41// codec) then NackTracker should be reset. This is because NetEQ would flush
42// its buffer and re-transmission is meaning less for old packet. Therefore, in
43// that case, after reset the sampling rate has to be updated.
turaj@webrtc.org7959e162013-09-12 18:30:26 +000044//
45// Thread Safety
46// =============
47// Please note that this class in not thread safe. The class must be protected
48// if different APIs are called from different threads.
49//
50namespace webrtc {
51
henrik.lundin91951862016-06-08 06:43:41 -070052class NackTracker {
turaj@webrtc.org7959e162013-09-12 18:30:26 +000053 public:
54 // A limit for the size of the NACK list.
55 static const size_t kNackListSizeLimit = 500; // 10 seconds for 20 ms frame
56 // packets.
Ivo Creusenbc503c92021-09-14 15:17:23 +000057 NackTracker();
henrik.lundin91951862016-06-08 06:43:41 -070058 ~NackTracker();
turaj@webrtc.org7959e162013-09-12 18:30:26 +000059
60 // Set a maximum for the size of the NACK list. If the last received packet
61 // has sequence number of N, then NACK list will not contain any element
Artem Titovd00ce742021-07-28 20:00:17 +020062 // with sequence number earlier than N - `max_nack_list_size`.
turaj@webrtc.org7959e162013-09-12 18:30:26 +000063 //
Artem Titovd00ce742021-07-28 20:00:17 +020064 // The largest maximum size is defined by `kNackListSizeLimit`
henrik.lundin48ed9302015-10-29 05:36:24 -070065 void SetMaxNackListSize(size_t max_nack_list_size);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000066
67 // Set the sampling rate.
68 //
69 // If associated sampling rate of the received packets is changed, call this
70 // function to update sampling rate. Note that if there is any change in
71 // received codec then NetEq will flush its buffer and NACK has to be reset.
72 // After Reset() is called sampling rate has to be set.
73 void UpdateSampleRate(int sample_rate_hz);
74
75 // Update the sequence number and the timestamp of the last decoded RTP. This
76 // API should be called every time 10 ms audio is pulled from NetEq.
77 void UpdateLastDecodedPacket(uint16_t sequence_number, uint32_t timestamp);
78
79 // Update the sequence number and the timestamp of the last received RTP. This
80 // API should be called every time a packet pushed into ACM.
81 void UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp);
82
83 // Get a list of "missing" packets which have expected time-to-play larger
84 // than the given round-trip-time (in milliseconds).
85 // Note: Late packets are not included.
Ivo Creusen3a9640a2021-09-10 11:45:47 +000086 // Calling this method multiple times may give different results, since the
87 // internal nack list may get flushed if never_nack_multiple_times_ is true.
88 std::vector<uint16_t> GetNackList(int64_t round_trip_time_ms);
turaj@webrtc.org7959e162013-09-12 18:30:26 +000089
90 // Reset to default values. The NACK list is cleared.
Ivo Creusenbc503c92021-09-14 15:17:23 +000091 // `max_nack_list_size_` preserves its value.
turaj@webrtc.org7959e162013-09-12 18:30:26 +000092 void Reset();
93
Ivo Creusen3a9640a2021-09-10 11:45:47 +000094 // Returns the estimated packet loss rate in Q30, for testing only.
95 uint32_t GetPacketLossRateForTest() { return packet_loss_rate_; }
96
turaj@webrtc.org7959e162013-09-12 18:30:26 +000097 private:
98 // This test need to access the private method GetNackList().
henrik.lundin91951862016-06-08 06:43:41 -070099 FRIEND_TEST_ALL_PREFIXES(NackTrackerTest, EstimateTimestampAndTimeToPlay);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000100
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000101 // Options that can be configured via field trial.
102 struct Config {
103 Config();
104
105 // The exponential decay factor used to estimate the packet loss rate.
106 double packet_loss_forget_factor = 0.996;
107 // How many additional ms we are willing to wait (at most) for nacked
108 // packets for each additional percentage of packet loss.
109 int ms_per_loss_percent = 20;
110 // If true, never nack packets more than once.
111 bool never_nack_multiple_times = false;
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100112 // Only nack if the RTT is valid.
113 bool require_valid_rtt = false;
Jakob Ivarsson4d5eb652022-03-30 16:26:19 +0200114 // Default RTT to use unless `require_valid_rtt` is set.
115 int default_rtt_ms = 100;
Jakob Ivarssone1bbef12021-11-25 15:34:57 +0100116 // Do not nack if the loss rate is above this value.
117 double max_loss_rate = 1.0;
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000118 };
119
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000120 struct NackElement {
Ivo Creusenbc503c92021-09-14 15:17:23 +0000121 NackElement(int64_t initial_time_to_play_ms, uint32_t initial_timestamp)
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000122 : time_to_play_ms(initial_time_to_play_ms),
Ivo Creusenbc503c92021-09-14 15:17:23 +0000123 estimated_timestamp(initial_timestamp) {}
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000124
125 // Estimated time (ms) left for this packet to be decoded. This estimate is
126 // updated every time jitter buffer decodes a packet.
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000127 int64_t time_to_play_ms;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000128
129 // A guess about the timestamp of the missing packet, it is used for
Artem Titovd00ce742021-07-28 20:00:17 +0200130 // estimation of `time_to_play_ms`. The estimate might be slightly wrong if
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000131 // there has been frame-size change since the last received packet and the
132 // missing packet. However, the risk of this is low, and in case of such
133 // errors, there will be a minor misestimation in time-to-play of missing
134 // packets. This will have a very minor effect on NACK performance.
135 uint32_t estimated_timestamp;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000136 };
137
138 class NackListCompare {
139 public:
henrik.lundin48ed9302015-10-29 05:36:24 -0700140 bool operator()(uint16_t sequence_number_old,
141 uint16_t sequence_number_new) const {
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000142 return IsNewerSequenceNumber(sequence_number_new, sequence_number_old);
143 }
144 };
145
146 typedef std::map<uint16_t, NackElement, NackListCompare> NackList;
147
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000148 // This API is used only for testing to assess whether time-to-play is
149 // computed correctly.
150 NackList GetNackList() const;
151
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000152 // This function subtracts 10 ms of time-to-play for all packets in NACK list.
153 // This is called when 10 ms elapsed with no new RTP packet decoded.
154 void UpdateEstimatedPlayoutTimeBy10ms();
155
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200156 // Returns a valid number of samples per packet given the current received
157 // sequence number and timestamp or nullopt of none could be computed.
158 absl::optional<int> GetSamplesPerPacket(
159 uint16_t sequence_number_current_received_rtp,
160 uint32_t timestamp_current_received_rtp) const;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000161
Artem Titovd00ce742021-07-28 20:00:17 +0200162 // Given the `sequence_number_current_received_rtp` of currently received RTP
Ivo Creusenbc503c92021-09-14 15:17:23 +0000163 // update the list. Packets that are older than the received packet are added
164 // to the nack list.
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200165 void UpdateList(uint16_t sequence_number_current_received_rtp,
166 uint32_t timestamp_current_received_rtp);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000167
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000168 // Packets which have sequence number older that
Artem Titovd00ce742021-07-28 20:00:17 +0200169 // `sequence_num_last_received_rtp_` - `max_nack_list_size_` are removed
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000170 // from the NACK list.
171 void LimitNackListSize();
172
173 // Estimate timestamp of a missing packet given its sequence number.
Jakob Ivarsson018cd3d2021-09-13 16:06:28 +0200174 uint32_t EstimateTimestamp(uint16_t sequence_number, int samples_per_packet);
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000175
176 // Compute time-to-play given a timestamp.
pkasting@chromium.org16825b12015-01-12 21:51:21 +0000177 int64_t TimeToPlay(uint32_t timestamp) const;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000178
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000179 // Updates the estimated packet lost rate.
180 void UpdatePacketLossRate(int packets_lost);
181
182 const Config config_;
183
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000184 // Valid if a packet is received.
185 uint16_t sequence_num_last_received_rtp_;
186 uint32_t timestamp_last_received_rtp_;
187 bool any_rtp_received_; // If any packet received.
188
189 // Valid if a packet is decoded.
190 uint16_t sequence_num_last_decoded_rtp_;
191 uint32_t timestamp_last_decoded_rtp_;
192 bool any_rtp_decoded_; // If any packet decoded.
193
194 int sample_rate_khz_; // Sample rate in kHz.
195
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000196 // A list of missing packets to be retransmitted. Components of the list
197 // contain the sequence number of missing packets and the estimated time that
198 // each pack is going to be played out.
199 NackList nack_list_;
200
201 // NACK list will not keep track of missing packets prior to
Artem Titovd00ce742021-07-28 20:00:17 +0200202 // `sequence_num_last_received_rtp_` - `max_nack_list_size_`.
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000203 size_t max_nack_list_size_;
Ivo Creusen3a9640a2021-09-10 11:45:47 +0000204
205 // Current estimate of the packet loss rate in Q30.
206 uint32_t packet_loss_rate_ = 0;
turaj@webrtc.org7959e162013-09-12 18:30:26 +0000207};
208
209} // namespace webrtc
210
Mirko Bonadei92ea95e2017-09-15 06:47:31 +0200211#endif // MODULES_AUDIO_CODING_NETEQ_NACK_TRACKER_H_