ACM2 integration with NetEq 4.
nack{.cc, .h, _unittest.cc} are basically copies from main/source/ folder, with cpplint warning cleaned up.
BUG=
R=andrew@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/2190009
git-svn-id: http://webrtc.googlecode.com/svn/trunk@4736 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/main/acm2/nack.h b/webrtc/modules/audio_coding/main/acm2/nack.h
new file mode 100644
index 0000000..ddafbcd
--- /dev/null
+++ b/webrtc/modules/audio_coding/main/acm2/nack.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_NACK_H_
+#define WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_NACK_H_
+
+#include <vector>
+#include <map>
+
+#include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h"
+#include "webrtc/system_wrappers/interface/scoped_ptr.h"
+#include "webrtc/test/testsupport/gtest_prod_util.h"
+
+//
+// The Nack class keeps track of the lost packets, an estimate of time-to-play
+// for each packet is also given.
+//
+// Every time a packet is pushed into NetEq, LastReceivedPacket() has to be
+// called to update the NACK list.
+//
+// Every time 10ms audio is pulled from NetEq LastDecodedPacket() should be
+// called, and time-to-play is updated at that moment.
+//
+// If packet N is received, any packet prior to |N - NackThreshold| which is not
+// arrived is considered lost, and should be labeled as "missing" (the size of
+// the list might be limited and older packet eliminated from the list). Packets
+// |N - NackThreshold|, |N - NackThreshold + 1|, ..., |N - 1| are considered
+// "late." A "late" packet with sequence number K is changed to "missing" any
+// time a packet with sequence number newer than |K + NackList| is arrived.
+//
+// The Nack class has to know about the sample rate of the packets to compute
+// time-to-play. So sample rate should be set as soon as the first packet is
+// received. If there is a change in the receive codec (sender changes codec)
+// then Nack should be reset. This is because NetEQ would flush its buffer and
+// re-transmission is meaning less for old packet. Therefore, in that case,
+// after reset the sampling rate has to be updated.
+//
+// Thread Safety
+// =============
+// Please note that this class in not thread safe. The class must be protected
+// if different APIs are called from different threads.
+//
+namespace webrtc {
+
+class Nack {
+ public:
+ // A limit for the size of the NACK list.
+ static const size_t kNackListSizeLimit = 500; // 10 seconds for 20 ms frame
+ // packets.
+ // Factory method.
+ static Nack* Create(int nack_threshold_packets);
+
+ ~Nack() {}
+
+ // Set a maximum for the size of the NACK list. If the last received packet
+ // has sequence number of N, then NACK list will not contain any element
+ // with sequence number earlier than N - |max_nack_list_size|.
+ //
+ // The largest maximum size is defined by |kNackListSizeLimit|
+ int SetMaxNackListSize(size_t max_nack_list_size);
+
+ // Set the sampling rate.
+ //
+ // If associated sampling rate of the received packets is changed, call this
+ // function to update sampling rate. Note that if there is any change in
+ // received codec then NetEq will flush its buffer and NACK has to be reset.
+ // After Reset() is called sampling rate has to be set.
+ void UpdateSampleRate(int sample_rate_hz);
+
+ // Update the sequence number and the timestamp of the last decoded RTP. This
+ // API should be called every time 10 ms audio is pulled from NetEq.
+ void UpdateLastDecodedPacket(uint16_t sequence_number, uint32_t timestamp);
+
+ // Update the sequence number and the timestamp of the last received RTP. This
+ // API should be called every time a packet pushed into ACM.
+ void UpdateLastReceivedPacket(uint16_t sequence_number, uint32_t timestamp);
+
+ // Get a list of "missing" packets which have expected time-to-play larger
+ // than the given round-trip-time (in milliseconds).
+ // Note: Late packets are not included.
+ std::vector<uint16_t> GetNackList(int round_trip_time_ms) const;
+
+ // Reset to default values. The NACK list is cleared.
+ // |nack_threshold_packets_| & |max_nack_list_size_| preserve their values.
+ void Reset();
+
+ private:
+ // This test need to access the private method GetNackList().
+ FRIEND_TEST_ALL_PREFIXES(NackTest, EstimateTimestampAndTimeToPlay);
+
+ struct NackElement {
+ NackElement(int initial_time_to_play_ms,
+ uint32_t initial_timestamp,
+ bool missing)
+ : time_to_play_ms(initial_time_to_play_ms),
+ estimated_timestamp(initial_timestamp),
+ is_missing(missing) {}
+
+ // Estimated time (ms) left for this packet to be decoded. This estimate is
+ // updated every time jitter buffer decodes a packet.
+ int time_to_play_ms;
+
+ // A guess about the timestamp of the missing packet, it is used for
+ // estimation of |time_to_play_ms|. The estimate might be slightly wrong if
+ // there has been frame-size change since the last received packet and the
+ // missing packet. However, the risk of this is low, and in case of such
+ // errors, there will be a minor misestimation in time-to-play of missing
+ // packets. This will have a very minor effect on NACK performance.
+ uint32_t estimated_timestamp;
+
+ // True if the packet is considered missing. Otherwise indicates packet is
+ // late.
+ bool is_missing;
+ };
+
+ class NackListCompare {
+ public:
+ bool operator() (uint16_t sequence_number_old,
+ uint16_t sequence_number_new) const {
+ return IsNewerSequenceNumber(sequence_number_new, sequence_number_old);
+ }
+ };
+
+ typedef std::map<uint16_t, NackElement, NackListCompare> NackList;
+
+ // Constructor.
+ explicit Nack(int nack_threshold_packets);
+
+ // This API is used only for testing to assess whether time-to-play is
+ // computed correctly.
+ NackList GetNackList() const;
+
+ // Given the |sequence_number_current_received_rtp| of currently received RTP,
+ // recognize packets which are not arrive and add to the list.
+ void AddToList(uint16_t sequence_number_current_received_rtp);
+
+ // This function subtracts 10 ms of time-to-play for all packets in NACK list.
+ // This is called when 10 ms elapsed with no new RTP packet decoded.
+ void UpdateEstimatedPlayoutTimeBy10ms();
+
+ // Given the |sequence_number_current_received_rtp| and
+ // |timestamp_current_received_rtp| of currently received RTP update number
+ // of samples per packet.
+ void UpdateSamplesPerPacket(uint16_t sequence_number_current_received_rtp,
+ uint32_t timestamp_current_received_rtp);
+
+ // Given the |sequence_number_current_received_rtp| of currently received RTP
+ // update the list. That is; some packets will change from late to missing,
+ // some packets are inserted as missing and some inserted as late.
+ void UpdateList(uint16_t sequence_number_current_received_rtp);
+
+ // Packets which are considered late for too long (according to
+ // |nack_threshold_packets_|) are flagged as missing.
+ void ChangeFromLateToMissing(uint16_t sequence_number_current_received_rtp);
+
+ // Packets which have sequence number older that
+ // |sequence_num_last_received_rtp_| - |max_nack_list_size_| are removed
+ // from the NACK list.
+ void LimitNackListSize();
+
+ // Estimate timestamp of a missing packet given its sequence number.
+ uint32_t EstimateTimestamp(uint16_t sequence_number);
+
+ // Compute time-to-play given a timestamp.
+ int TimeToPlay(uint32_t timestamp) const;
+
+ // If packet N is arrived, any packet prior to N - |nack_threshold_packets_|
+ // which is not arrived is considered missing, and should be in NACK list.
+ // Also any packet in the range of N-1 and N - |nack_threshold_packets_|,
+ // exclusive, which is not arrived is considered late, and should should be
+ // in the list of late packets.
+ const int nack_threshold_packets_;
+
+ // Valid if a packet is received.
+ uint16_t sequence_num_last_received_rtp_;
+ uint32_t timestamp_last_received_rtp_;
+ bool any_rtp_received_; // If any packet received.
+
+ // Valid if a packet is decoded.
+ uint16_t sequence_num_last_decoded_rtp_;
+ uint32_t timestamp_last_decoded_rtp_;
+ bool any_rtp_decoded_; // If any packet decoded.
+
+ int sample_rate_khz_; // Sample rate in kHz.
+
+ // Number of samples per packet. We update this every time we receive a
+ // packet, not only for consecutive packets.
+ int samples_per_packet_;
+
+ // A list of missing packets to be retransmitted. Components of the list
+ // contain the sequence number of missing packets and the estimated time that
+ // each pack is going to be played out.
+ NackList nack_list_;
+
+ // NACK list will not keep track of missing packets prior to
+ // |sequence_num_last_received_rtp_| - |max_nack_list_size_|.
+ size_t max_nack_list_size_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_MODULES_AUDIO_CODING_MAIN_SOURCE_NACK_H_