turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 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 | |
turaj@webrtc.org | 48af652 | 2013-09-13 23:06:59 +0000 | [diff] [blame] | 11 | #ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_ |
| 12 | #define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_ |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 13 | |
| 14 | #include <vector> |
| 15 | #include <map> |
| 16 | |
| 17 | #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h" |
| 18 | #include "webrtc/system_wrappers/interface/scoped_ptr.h" |
| 19 | #include "webrtc/test/testsupport/gtest_prod_util.h" |
| 20 | |
| 21 | // |
| 22 | // The Nack class keeps track of the lost packets, an estimate of time-to-play |
| 23 | // for each packet is also given. |
| 24 | // |
| 25 | // Every time a packet is pushed into NetEq, LastReceivedPacket() has to be |
| 26 | // called to update the NACK list. |
| 27 | // |
| 28 | // Every time 10ms audio is pulled from NetEq LastDecodedPacket() should be |
| 29 | // called, and time-to-play is updated at that moment. |
| 30 | // |
| 31 | // If packet N is received, any packet prior to |N - NackThreshold| which is not |
| 32 | // arrived is considered lost, and should be labeled as "missing" (the size of |
| 33 | // the list might be limited and older packet eliminated from the list). Packets |
| 34 | // |N - NackThreshold|, |N - NackThreshold + 1|, ..., |N - 1| are considered |
| 35 | // "late." A "late" packet with sequence number K is changed to "missing" any |
| 36 | // time a packet with sequence number newer than |K + NackList| is arrived. |
| 37 | // |
| 38 | // The Nack class has to know about the sample rate of the packets to compute |
| 39 | // time-to-play. So sample rate should be set as soon as the first packet is |
| 40 | // received. If there is a change in the receive codec (sender changes codec) |
| 41 | // then Nack should be reset. This is because NetEQ would flush its buffer and |
| 42 | // re-transmission is meaning less for old packet. Therefore, in that case, |
| 43 | // after reset the sampling rate has to be updated. |
| 44 | // |
| 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 | // |
| 50 | namespace webrtc { |
| 51 | |
turaj@webrtc.org | 6d5d248 | 2013-10-06 04:47:28 +0000 | [diff] [blame] | 52 | namespace acm2 { |
| 53 | |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 54 | class Nack { |
| 55 | public: |
| 56 | // A limit for the size of the NACK list. |
| 57 | static const size_t kNackListSizeLimit = 500; // 10 seconds for 20 ms frame |
| 58 | // packets. |
| 59 | // Factory method. |
| 60 | static Nack* Create(int nack_threshold_packets); |
| 61 | |
| 62 | ~Nack() {} |
| 63 | |
| 64 | // Set a maximum for the size of the NACK list. If the last received packet |
| 65 | // has sequence number of N, then NACK list will not contain any element |
| 66 | // with sequence number earlier than N - |max_nack_list_size|. |
| 67 | // |
| 68 | // The largest maximum size is defined by |kNackListSizeLimit| |
| 69 | int SetMaxNackListSize(size_t max_nack_list_size); |
| 70 | |
| 71 | // Set the sampling rate. |
| 72 | // |
| 73 | // If associated sampling rate of the received packets is changed, call this |
| 74 | // function to update sampling rate. Note that if there is any change in |
| 75 | // received codec then NetEq will flush its buffer and NACK has to be reset. |
| 76 | // After Reset() is called sampling rate has to be set. |
| 77 | void UpdateSampleRate(int sample_rate_hz); |
| 78 | |
| 79 | // Update the sequence number and the timestamp of the last decoded RTP. This |
| 80 | // API should be called every time 10 ms audio is pulled from NetEq. |
| 81 | void UpdateLastDecodedPacket(uint16_t sequence_number, uint32_t timestamp); |
| 82 | |
| 83 | // Update the sequence number and the timestamp of the last received RTP. This |
| 84 | // API should be called every time a packet pushed into ACM. |
| 85 | void UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp); |
| 86 | |
| 87 | // Get a list of "missing" packets which have expected time-to-play larger |
| 88 | // than the given round-trip-time (in milliseconds). |
| 89 | // Note: Late packets are not included. |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 +0000 | [diff] [blame^] | 90 | std::vector<uint16_t> GetNackList(int64_t round_trip_time_ms) const; |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 91 | |
| 92 | // Reset to default values. The NACK list is cleared. |
| 93 | // |nack_threshold_packets_| & |max_nack_list_size_| preserve their values. |
| 94 | void Reset(); |
| 95 | |
| 96 | private: |
| 97 | // This test need to access the private method GetNackList(). |
| 98 | FRIEND_TEST_ALL_PREFIXES(NackTest, EstimateTimestampAndTimeToPlay); |
| 99 | |
| 100 | struct NackElement { |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 +0000 | [diff] [blame^] | 101 | NackElement(int64_t initial_time_to_play_ms, |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 102 | uint32_t initial_timestamp, |
| 103 | bool missing) |
| 104 | : time_to_play_ms(initial_time_to_play_ms), |
| 105 | estimated_timestamp(initial_timestamp), |
| 106 | is_missing(missing) {} |
| 107 | |
| 108 | // Estimated time (ms) left for this packet to be decoded. This estimate is |
| 109 | // updated every time jitter buffer decodes a packet. |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 +0000 | [diff] [blame^] | 110 | int64_t time_to_play_ms; |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 111 | |
| 112 | // A guess about the timestamp of the missing packet, it is used for |
| 113 | // estimation of |time_to_play_ms|. The estimate might be slightly wrong if |
| 114 | // there has been frame-size change since the last received packet and the |
| 115 | // missing packet. However, the risk of this is low, and in case of such |
| 116 | // errors, there will be a minor misestimation in time-to-play of missing |
| 117 | // packets. This will have a very minor effect on NACK performance. |
| 118 | uint32_t estimated_timestamp; |
| 119 | |
| 120 | // True if the packet is considered missing. Otherwise indicates packet is |
| 121 | // late. |
| 122 | bool is_missing; |
| 123 | }; |
| 124 | |
| 125 | class NackListCompare { |
| 126 | public: |
| 127 | bool operator() (uint16_t sequence_number_old, |
| 128 | uint16_t sequence_number_new) const { |
| 129 | return IsNewerSequenceNumber(sequence_number_new, sequence_number_old); |
| 130 | } |
| 131 | }; |
| 132 | |
| 133 | typedef std::map<uint16_t, NackElement, NackListCompare> NackList; |
| 134 | |
| 135 | // Constructor. |
| 136 | explicit Nack(int nack_threshold_packets); |
| 137 | |
| 138 | // This API is used only for testing to assess whether time-to-play is |
| 139 | // computed correctly. |
| 140 | NackList GetNackList() const; |
| 141 | |
| 142 | // Given the |sequence_number_current_received_rtp| of currently received RTP, |
| 143 | // recognize packets which are not arrive and add to the list. |
| 144 | void AddToList(uint16_t sequence_number_current_received_rtp); |
| 145 | |
| 146 | // This function subtracts 10 ms of time-to-play for all packets in NACK list. |
| 147 | // This is called when 10 ms elapsed with no new RTP packet decoded. |
| 148 | void UpdateEstimatedPlayoutTimeBy10ms(); |
| 149 | |
| 150 | // Given the |sequence_number_current_received_rtp| and |
| 151 | // |timestamp_current_received_rtp| of currently received RTP update number |
| 152 | // of samples per packet. |
| 153 | void UpdateSamplesPerPacket(uint16_t sequence_number_current_received_rtp, |
| 154 | uint32_t timestamp_current_received_rtp); |
| 155 | |
| 156 | // Given the |sequence_number_current_received_rtp| of currently received RTP |
| 157 | // update the list. That is; some packets will change from late to missing, |
| 158 | // some packets are inserted as missing and some inserted as late. |
| 159 | void UpdateList(uint16_t sequence_number_current_received_rtp); |
| 160 | |
| 161 | // Packets which are considered late for too long (according to |
| 162 | // |nack_threshold_packets_|) are flagged as missing. |
| 163 | void ChangeFromLateToMissing(uint16_t sequence_number_current_received_rtp); |
| 164 | |
| 165 | // Packets which have sequence number older that |
| 166 | // |sequence_num_last_received_rtp_| - |max_nack_list_size_| are removed |
| 167 | // from the NACK list. |
| 168 | void LimitNackListSize(); |
| 169 | |
| 170 | // Estimate timestamp of a missing packet given its sequence number. |
| 171 | uint32_t EstimateTimestamp(uint16_t sequence_number); |
| 172 | |
| 173 | // Compute time-to-play given a timestamp. |
pkasting@chromium.org | 16825b1 | 2015-01-12 21:51:21 +0000 | [diff] [blame^] | 174 | int64_t TimeToPlay(uint32_t timestamp) const; |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 175 | |
| 176 | // If packet N is arrived, any packet prior to N - |nack_threshold_packets_| |
| 177 | // which is not arrived is considered missing, and should be in NACK list. |
| 178 | // Also any packet in the range of N-1 and N - |nack_threshold_packets_|, |
| 179 | // exclusive, which is not arrived is considered late, and should should be |
| 180 | // in the list of late packets. |
| 181 | const int nack_threshold_packets_; |
| 182 | |
| 183 | // Valid if a packet is received. |
| 184 | uint16_t sequence_num_last_received_rtp_; |
| 185 | uint32_t timestamp_last_received_rtp_; |
| 186 | bool any_rtp_received_; // If any packet received. |
| 187 | |
| 188 | // Valid if a packet is decoded. |
| 189 | uint16_t sequence_num_last_decoded_rtp_; |
| 190 | uint32_t timestamp_last_decoded_rtp_; |
| 191 | bool any_rtp_decoded_; // If any packet decoded. |
| 192 | |
| 193 | int sample_rate_khz_; // Sample rate in kHz. |
| 194 | |
| 195 | // Number of samples per packet. We update this every time we receive a |
| 196 | // packet, not only for consecutive packets. |
| 197 | int samples_per_packet_; |
| 198 | |
| 199 | // A list of missing packets to be retransmitted. Components of the list |
| 200 | // contain the sequence number of missing packets and the estimated time that |
| 201 | // each pack is going to be played out. |
| 202 | NackList nack_list_; |
| 203 | |
| 204 | // NACK list will not keep track of missing packets prior to |
| 205 | // |sequence_num_last_received_rtp_| - |max_nack_list_size_|. |
| 206 | size_t max_nack_list_size_; |
| 207 | }; |
| 208 | |
turaj@webrtc.org | 6d5d248 | 2013-10-06 04:47:28 +0000 | [diff] [blame] | 209 | } // namespace acm2 |
| 210 | |
turaj@webrtc.org | 7959e16 | 2013-09-12 18:30:26 +0000 | [diff] [blame] | 211 | } // namespace webrtc |
| 212 | |
turaj@webrtc.org | 48af652 | 2013-09-13 23:06:59 +0000 | [diff] [blame] | 213 | #endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_ |