ACM: Move NACK functionality inside NetEq

Negative acknowledgement (NACK) has up to now been implemented in
ACM. But, since NetEq is in charge of the actual packet buffer, it
makes more sense to have the NACK functionlaity in there.

This CL does the following:
- Move nack.{h,cc} and the unit tests from main/acm2 to neteq.
- Move the NACK related code in ACM into NetEq.
- NACK related functions in AcmReceiver are changed to simple
  forwarding APIs.
- Remove unused members in AcmReceiver.
- Remove unused API functions in NetEq.

BUG=webrtc:3520

Review URL: https://codereview.webrtc.org/1410073006

Cr-Commit-Position: refs/heads/master@{#10448}
diff --git a/webrtc/modules/audio_coding/BUILD.gn b/webrtc/modules/audio_coding/BUILD.gn
index 2c86b95..839a143 100644
--- a/webrtc/modules/audio_coding/BUILD.gn
+++ b/webrtc/modules/audio_coding/BUILD.gn
@@ -67,8 +67,6 @@
     "main/acm2/codec_owner.h",
     "main/acm2/initial_delay_manager.cc",
     "main/acm2/initial_delay_manager.h",
-    "main/acm2/nack.cc",
-    "main/acm2/nack.h",
     "main/include/audio_coding_module.h",
     "main/include/audio_coding_module_typedefs.h",
   ]
@@ -799,6 +797,8 @@
     "neteq/include/neteq.h",
     "neteq/merge.cc",
     "neteq/merge.h",
+    "neteq/nack.cc",
+    "neteq/nack.h",
     "neteq/neteq.cc",
     "neteq/neteq_impl.cc",
     "neteq/neteq_impl.h",
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
index 611b06a..80b7071 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -24,7 +24,6 @@
 #include "webrtc/modules/audio_coding/main/acm2/acm_common_defs.h"
 #include "webrtc/modules/audio_coding/main/acm2/acm_resampler.h"
 #include "webrtc/modules/audio_coding/main/acm2/call_statistics.h"
-#include "webrtc/modules/audio_coding/main/acm2/nack.h"
 #include "webrtc/modules/audio_coding/neteq/include/neteq.h"
 #include "webrtc/system_wrappers/include/clock.h"
 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
@@ -37,8 +36,6 @@
 
 namespace {
 
-const int kNackThresholdPackets = 2;
-
 // |vad_activity_| field of |audio_frame| is set to |previous_audio_activity_|
 // before the call to this function.
 void SetAudioFrameActivityAndType(bool vad_enabled,
@@ -130,8 +127,6 @@
       current_sample_rate_hz_(config.neteq_config.sample_rate_hz),
       audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
       last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
-      nack_(),
-      nack_enabled_(false),
       neteq_(NetEq::Create(config.neteq_config)),
       vad_enabled_(true),
       clock_(config.clock),
@@ -254,26 +249,11 @@
         // Therefore, either NetEq buffer is empty or will be flushed when this
         // packet is inserted.
         new_codec = true;
-
-        // Updating NACK'sampling rate is required, either first packet is
-        // received or codec is changed. Furthermore, reset is required if codec
-        // is changed (NetEq flushes its buffer so NACK should reset its list).
-        if (nack_enabled_) {
-          assert(nack_.get());
-          nack_->Reset();
-          nack_->UpdateSampleRate(sample_rate_hz);
-        }
         last_audio_decoder_ = decoder;
       }
       packet_type = InitialDelayManager::kAudioPacket;
     }
 
-    if (nack_enabled_) {
-      assert(nack_.get());
-      nack_->UpdateLastReceivedPacket(header->sequenceNumber,
-                                      header->timestamp);
-    }
-
     if (av_sync_) {
       assert(initial_delay_manager_.get());
       assert(missing_packets_sync_stream_.get());
@@ -344,16 +324,6 @@
     return -1;
   }
 
-  // Update NACK.
-  int decoded_sequence_num = 0;
-  uint32_t decoded_timestamp = 0;
-  bool update_nack = nack_enabled_ &&  // Update NACK only if it is enabled.
-      neteq_->DecodedRtpInfo(&decoded_sequence_num, &decoded_timestamp);
-  if (update_nack) {
-    assert(nack_.get());
-    nack_->UpdateLastDecodedPacket(decoded_sequence_num, decoded_timestamp);
-  }
-
   // NetEq always returns 10 ms of audio.
   current_sample_rate_hz_ = static_cast<int>(samples_per_channel * 100);
 
@@ -640,45 +610,17 @@
 }
 
 int AcmReceiver::EnableNack(size_t max_nack_list_size) {
-  // Don't do anything if |max_nack_list_size| is out of range.
-  if (max_nack_list_size == 0 || max_nack_list_size > Nack::kNackListSizeLimit)
-    return -1;
-
-  CriticalSectionScoped lock(crit_sect_.get());
-  if (!nack_enabled_) {
-    nack_.reset(Nack::Create(kNackThresholdPackets));
-    nack_enabled_ = true;
-
-    // Sampling rate might need to be updated if we change from disable to
-    // enable. Do it if the receive codec is valid.
-    if (last_audio_decoder_) {
-      nack_->UpdateSampleRate(
-          ACMCodecDB::database_[last_audio_decoder_->acm_codec_id].plfreq);
-    }
-  }
-  return nack_->SetMaxNackListSize(max_nack_list_size);
+  neteq_->EnableNack(max_nack_list_size);
+  return 0;
 }
 
 void AcmReceiver::DisableNack() {
-  CriticalSectionScoped lock(crit_sect_.get());
-  nack_.reset();  // Memory is released.
-  nack_enabled_ = false;
+  neteq_->DisableNack();
 }
 
 std::vector<uint16_t> AcmReceiver::GetNackList(
     int64_t round_trip_time_ms) const {
-  CriticalSectionScoped lock(crit_sect_.get());
-  if (round_trip_time_ms < 0) {
-    WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, id_,
-                 "GetNackList: round trip time cannot be negative."
-                 " round_trip_time_ms=%" PRId64, round_trip_time_ms);
-  }
-  if (nack_enabled_ && round_trip_time_ms >= 0) {
-    assert(nack_.get());
-    return nack_->GetNackList(round_trip_time_ms);
-  }
-  std::vector<uint16_t> empty_list;
-  return empty_list;
+  return neteq_->GetNackList(round_trip_time_ms);
 }
 
 void AcmReceiver::ResetInitialDelay() {
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
index 823bf78..4775b8c 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
@@ -35,8 +35,6 @@
 
 namespace acm2 {
 
-class Nack;
-
 class AcmReceiver {
  public:
   struct Decoder {
@@ -321,8 +319,6 @@
   // TODO(henrik.lundin) Stack-allocate in GetAudio instead?
   rtc::scoped_ptr<int16_t[]> audio_buffer_ GUARDED_BY(crit_sect_);
   rtc::scoped_ptr<int16_t[]> last_audio_buffer_ GUARDED_BY(crit_sect_);
-  rtc::scoped_ptr<Nack> nack_ GUARDED_BY(crit_sect_);
-  bool nack_enabled_ GUARDED_BY(crit_sect_);
   CallStatistics call_stats_ GUARDED_BY(crit_sect_);
   NetEq* neteq_;
   // Decoders map is keyed by payload type
diff --git a/webrtc/modules/audio_coding/main/audio_coding_module.gypi b/webrtc/modules/audio_coding/main/audio_coding_module.gypi
index 811c614..6fb37d2 100644
--- a/webrtc/modules/audio_coding/main/audio_coding_module.gypi
+++ b/webrtc/modules/audio_coding/main/audio_coding_module.gypi
@@ -108,8 +108,6 @@
         'acm2/codec_owner.h',
         'acm2/initial_delay_manager.cc',
         'acm2/initial_delay_manager.h',
-        'acm2/nack.cc',
-        'acm2/nack.h',
         'include/audio_coding_module.h',
         'include/audio_coding_module_typedefs.h',
       ],
diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h
index 9cd4b57..4067ba5 100644
--- a/webrtc/modules/audio_coding/neteq/include/neteq.h
+++ b/webrtc/modules/audio_coding/neteq/include/neteq.h
@@ -272,10 +272,17 @@
   virtual void PacketBufferStatistics(int* current_num_packets,
                                       int* max_num_packets) const = 0;
 
-  // Get sequence number and timestamp of the latest RTP.
-  // This method is to facilitate NACK.
-  virtual int DecodedRtpInfo(int* sequence_number,
-                             uint32_t* timestamp) const = 0;
+  // Enables NACK and sets the maximum size of the NACK list, which should be
+  // positive and no larger than Nack::kNackListSizeLimit. If NACK is already
+  // enabled then the maximum NACK list size is modified accordingly.
+  virtual void EnableNack(size_t max_nack_list_size) = 0;
+
+  virtual void DisableNack() = 0;
+
+  // Returns a list of RTP sequence numbers corresponding to packets to be
+  // retransmitted, given an estimate of the round-trip time in milliseconds.
+  virtual std::vector<uint16_t> GetNackList(
+      int64_t round_trip_time_ms) const = 0;
 
  protected:
   NetEq() {}
diff --git a/webrtc/modules/audio_coding/main/acm2/nack.cc b/webrtc/modules/audio_coding/neteq/nack.cc
similarity index 82%
rename from webrtc/modules/audio_coding/main/acm2/nack.cc
rename to webrtc/modules/audio_coding/neteq/nack.cc
index d509045..fd3d762 100644
--- a/webrtc/modules/audio_coding/main/acm2/nack.cc
+++ b/webrtc/modules/audio_coding/neteq/nack.cc
@@ -8,19 +8,17 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "webrtc/modules/audio_coding/main/acm2/nack.h"
+#include "webrtc/modules/audio_coding/neteq/nack.h"
 
 #include <assert.h>  // For assert.
 
 #include <algorithm>  // For std::max.
 
+#include "webrtc/base/checks.h"
 #include "webrtc/modules/interface/module_common_types.h"
 #include "webrtc/system_wrappers/include/logging.h"
 
 namespace webrtc {
-
-namespace acm2 {
-
 namespace {
 
 const int kDefaultSampleRateKhz = 48;
@@ -89,10 +87,10 @@
 
 void Nack::UpdateSamplesPerPacket(uint16_t sequence_number_current_received_rtp,
                                   uint32_t timestamp_current_received_rtp) {
-  uint32_t timestamp_increase = timestamp_current_received_rtp -
-      timestamp_last_received_rtp_;
-  uint16_t sequence_num_increase = sequence_number_current_received_rtp -
-      sequence_num_last_received_rtp_;
+  uint32_t timestamp_increase =
+      timestamp_current_received_rtp - timestamp_last_received_rtp_;
+  uint16_t sequence_num_increase =
+      sequence_number_current_received_rtp - sequence_num_last_received_rtp_;
 
   samples_per_packet_ = timestamp_increase / sequence_num_increase;
 }
@@ -108,9 +106,9 @@
 
 void Nack::ChangeFromLateToMissing(
     uint16_t sequence_number_current_received_rtp) {
-  NackList::const_iterator lower_bound = nack_list_.lower_bound(
-      static_cast<uint16_t>(sequence_number_current_received_rtp -
-                            nack_threshold_packets_));
+  NackList::const_iterator lower_bound =
+      nack_list_.lower_bound(static_cast<uint16_t>(
+          sequence_number_current_received_rtp - nack_threshold_packets_));
 
   for (NackList::iterator it = nack_list_.begin(); it != lower_bound; ++it)
     it->second.is_missing = true;
@@ -122,16 +120,17 @@
 }
 
 void Nack::AddToList(uint16_t sequence_number_current_received_rtp) {
-  assert(!any_rtp_decoded_ || IsNewerSequenceNumber(
-      sequence_number_current_received_rtp, sequence_num_last_decoded_rtp_));
+  assert(!any_rtp_decoded_ ||
+         IsNewerSequenceNumber(sequence_number_current_received_rtp,
+                               sequence_num_last_decoded_rtp_));
 
   // Packets with sequence numbers older than |upper_bound_missing| are
   // considered missing, and the rest are considered late.
-  uint16_t upper_bound_missing = sequence_number_current_received_rtp -
-      nack_threshold_packets_;
+  uint16_t upper_bound_missing =
+      sequence_number_current_received_rtp - nack_threshold_packets_;
 
   for (uint16_t n = sequence_num_last_received_rtp_ + 1;
-      IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) {
+       IsNewerSequenceNumber(sequence_number_current_received_rtp, n); ++n) {
     bool is_missing = IsNewerSequenceNumber(upper_bound_missing, n);
     uint32_t timestamp = EstimateTimestamp(n);
     NackElement nack_element(TimeToPlay(timestamp), timestamp, is_missing);
@@ -141,7 +140,7 @@
 
 void Nack::UpdateEstimatedPlayoutTimeBy10ms() {
   while (!nack_list_.empty() &&
-      nack_list_.begin()->second.time_to_play_ms <= 10)
+         nack_list_.begin()->second.time_to_play_ms <= 10)
     nack_list_.erase(nack_list_.begin());
 
   for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end(); ++it)
@@ -157,12 +156,12 @@
     // Packets in the list with sequence numbers less than the
     // sequence number of the decoded RTP should be removed from the lists.
     // They will be discarded by the jitter buffer if they arrive.
-    nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(
-        sequence_num_last_decoded_rtp_));
+    nack_list_.erase(nack_list_.begin(),
+                     nack_list_.upper_bound(sequence_num_last_decoded_rtp_));
 
     // Update estimated time-to-play.
     for (NackList::iterator it = nack_list_.begin(); it != nack_list_.end();
-        ++it)
+         ++it)
       it->second.time_to_play_ms = TimeToPlay(it->second.estimated_timestamp);
   } else {
     assert(sequence_number == sequence_num_last_decoded_rtp_);
@@ -195,17 +194,19 @@
   samples_per_packet_ = sample_rate_khz_ * kDefaultPacketSizeMs;
 }
 
-int Nack::SetMaxNackListSize(size_t max_nack_list_size) {
-  if (max_nack_list_size == 0 || max_nack_list_size > kNackListSizeLimit)
-    return -1;
+void Nack::SetMaxNackListSize(size_t max_nack_list_size) {
+  RTC_CHECK_GT(max_nack_list_size, 0u);
+  // Ugly hack to get around the problem of passing static consts by reference.
+  const size_t kNackListSizeLimitLocal = Nack::kNackListSizeLimit;
+  RTC_CHECK_LE(max_nack_list_size, kNackListSizeLimitLocal);
+
   max_nack_list_size_ = max_nack_list_size;
   LimitNackListSize();
-  return 0;
 }
 
 void Nack::LimitNackListSize() {
   uint16_t limit = sequence_num_last_received_rtp_ -
-      static_cast<uint16_t>(max_nack_list_size_) - 1;
+                   static_cast<uint16_t>(max_nack_list_size_) - 1;
   nack_list_.erase(nack_list_.begin(), nack_list_.upper_bound(limit));
 }
 
@@ -216,9 +217,10 @@
 
 // We don't erase elements with time-to-play shorter than round-trip-time.
 std::vector<uint16_t> Nack::GetNackList(int64_t round_trip_time_ms) const {
+  RTC_DCHECK_GE(round_trip_time_ms, 0);
   std::vector<uint16_t> sequence_numbers;
   for (NackList::const_iterator it = nack_list_.begin(); it != nack_list_.end();
-      ++it) {
+       ++it) {
     if (it->second.is_missing &&
         it->second.time_to_play_ms > round_trip_time_ms)
       sequence_numbers.push_back(it->first);
@@ -226,6 +228,4 @@
   return sequence_numbers;
 }
 
-}  // namespace acm2
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/main/acm2/nack.h b/webrtc/modules/audio_coding/neteq/nack.h
similarity index 95%
rename from webrtc/modules/audio_coding/main/acm2/nack.h
rename to webrtc/modules/audio_coding/neteq/nack.h
index 4b22fa1..116b7e2 100644
--- a/webrtc/modules/audio_coding/main/acm2/nack.h
+++ b/webrtc/modules/audio_coding/neteq/nack.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_
-#define WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_
+#ifndef WEBRTC_MODULES_AUDIO_CODING_NETEQ_NACK_H_
+#define WEBRTC_MODULES_AUDIO_CODING_NETEQ_NACK_H_
 
 #include <vector>
 #include <map>
@@ -49,8 +49,6 @@
 //
 namespace webrtc {
 
-namespace acm2 {
-
 class Nack {
  public:
   // A limit for the size of the NACK list.
@@ -66,7 +64,7 @@
   // 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);
+  void SetMaxNackListSize(size_t max_nack_list_size);
 
   // Set the sampling rate.
   //
@@ -124,8 +122,8 @@
 
   class NackListCompare {
    public:
-    bool operator() (uint16_t sequence_number_old,
-                     uint16_t sequence_number_new) const {
+    bool operator()(uint16_t sequence_number_old,
+                    uint16_t sequence_number_new) const {
       return IsNewerSequenceNumber(sequence_number_new, sequence_number_old);
     }
   };
@@ -206,8 +204,6 @@
   size_t max_nack_list_size_;
 };
 
-}  // namespace acm2
-
 }  // namespace webrtc
 
-#endif  // WEBRTC_MODULES_AUDIO_CODING_MAIN_ACM2_NACK_H_
+#endif  // WEBRTC_MODULES_AUDIO_CODING_NETEQ_NACK_H_
diff --git a/webrtc/modules/audio_coding/main/acm2/nack_unittest.cc b/webrtc/modules/audio_coding/neteq/nack_unittest.cc
similarity index 91%
rename from webrtc/modules/audio_coding/main/acm2/nack_unittest.cc
rename to webrtc/modules/audio_coding/neteq/nack_unittest.cc
index cdbcbee..853af94 100644
--- a/webrtc/modules/audio_coding/main/acm2/nack_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/nack_unittest.cc
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "webrtc/modules/audio_coding/main/acm2/nack.h"
+#include "webrtc/modules/audio_coding/neteq/nack.h"
 
 #include <stdint.h>
 
@@ -20,9 +20,6 @@
 #include "webrtc/modules/audio_coding/main/include/audio_coding_module_typedefs.h"
 
 namespace webrtc {
-
-namespace acm2 {
-
 namespace {
 
 const int kNackThreshold = 3;
@@ -90,8 +87,9 @@
 
   // Push in reverse order
   while (num_late_packets > 0) {
-    nack->UpdateLastReceivedPacket(seq_num + num_late_packets, timestamp +
-                            num_late_packets * kTimestampIncrement);
+    nack->UpdateLastReceivedPacket(
+        seq_num + num_late_packets,
+        timestamp + num_late_packets * kTimestampIncrement);
     nack_list = nack->GetNackList(kShortRoundTripTimeMs);
     EXPECT_TRUE(nack_list.empty());
     num_late_packets--;
@@ -99,9 +97,9 @@
 }
 
 TEST(NackTest, LatePacketsMovedToNackThenNackListDoesNotChange) {
-  const uint16_t kSequenceNumberLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
+  const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9};
   static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
-      sizeof(kSequenceNumberLostPackets[0]);
+                                        sizeof(kSequenceNumberLostPackets[0]);
 
   for (int k = 0; k < 2; k++) {  // Two iteration with/without wrap around.
     rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
@@ -109,8 +107,9 @@
 
     uint16_t sequence_num_lost_packets[kNumAllLostPackets];
     for (int n = 0; n < kNumAllLostPackets; n++) {
-      sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] + k *
-          65531;  // Have wrap around in sequence numbers for |k == 1|.
+      sequence_num_lost_packets[n] =
+          kSequenceNumberLostPackets[n] +
+          k * 65531;  // Have wrap around in sequence numbers for |k == 1|.
     }
     uint16_t seq_num = sequence_num_lost_packets[0] - 1;
 
@@ -147,9 +146,9 @@
 }
 
 TEST(NackTest, ArrivedPacketsAreRemovedFromNackList) {
-  const uint16_t kSequenceNumberLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9 };
+  const uint16_t kSequenceNumberLostPackets[] = {2, 3, 4, 5, 6, 7, 8, 9};
   static const int kNumAllLostPackets = sizeof(kSequenceNumberLostPackets) /
-      sizeof(kSequenceNumberLostPackets[0]);
+                                        sizeof(kSequenceNumberLostPackets[0]);
 
   for (int k = 0; k < 2; ++k) {  // Two iteration with/without wrap around.
     rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
@@ -157,8 +156,8 @@
 
     uint16_t sequence_num_lost_packets[kNumAllLostPackets];
     for (int n = 0; n < kNumAllLostPackets; ++n) {
-      sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] + k *
-          65531;  // Wrap around for |k == 1|.
+      sequence_num_lost_packets[n] = kSequenceNumberLostPackets[n] +
+                                     k * 65531;  // Wrap around for |k == 1|.
     }
 
     uint16_t seq_num = sequence_num_lost_packets[0] - 1;
@@ -208,11 +207,10 @@
 // Assess if estimation of timestamps and time-to-play is correct. Introduce all
 // combinations that timestamps and sequence numbers might have wrap around.
 TEST(NackTest, EstimateTimestampAndTimeToPlay) {
-  const uint16_t kLostPackets[] = { 2, 3, 4, 5, 6, 7, 8, 9, 10,
-      11, 12, 13, 14, 15 };
-  static const int kNumAllLostPackets = sizeof(kLostPackets) /
-      sizeof(kLostPackets[0]);
-
+  const uint16_t kLostPackets[] = {2, 3,  4,  5,  6,  7,  8,
+                                   9, 10, 11, 12, 13, 14, 15};
+  static const int kNumAllLostPackets =
+      sizeof(kLostPackets) / sizeof(kLostPackets[0]);
 
   for (int k = 0; k < 4; ++k) {
     rtc::scoped_ptr<Nack> nack(Nack::Create(kNackThreshold));
@@ -222,14 +220,14 @@
     int seq_num_offset = (k < 2) ? 0 : 65531;
 
     // Timestamp wrap around if |k| is 1 or 3.
-    uint32_t timestamp_offset = (k & 0x1) ?
-        static_cast<uint32_t>(0xffffffff) - 6 : 0;
+    uint32_t timestamp_offset =
+        (k & 0x1) ? static_cast<uint32_t>(0xffffffff) - 6 : 0;
 
     uint32_t timestamp_lost_packets[kNumAllLostPackets];
     uint16_t seq_num_lost_packets[kNumAllLostPackets];
     for (int n = 0; n < kNumAllLostPackets; ++n) {
-      timestamp_lost_packets[n] = timestamp_offset + kLostPackets[n] *
-          kTimestampIncrement;
+      timestamp_lost_packets[n] =
+          timestamp_offset + kLostPackets[n] * kTimestampIncrement;
       seq_num_lost_packets[n] = seq_num_offset + kLostPackets[n];
     }
 
@@ -248,8 +246,8 @@
 
     // A packet after the last one which is supposed to be lost.
     seq_num = seq_num_lost_packets[kNumAllLostPackets - 1] + 1;
-    timestamp = timestamp_lost_packets[kNumAllLostPackets - 1] +
-        kTimestampIncrement;
+    timestamp =
+        timestamp_lost_packets[kNumAllLostPackets - 1] + kTimestampIncrement;
     nack->UpdateLastReceivedPacket(seq_num, timestamp);
 
     Nack::NackList nack_list = nack->GetNackList();
@@ -292,16 +290,16 @@
     // Two consecutive packets to have a correct estimate of timestamp increase.
     uint16_t seq_num = 0;
     nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
-      seq_num * kTimestampIncrement);
+                                   seq_num * kTimestampIncrement);
     seq_num++;
     nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
-      seq_num * kTimestampIncrement);
+                                   seq_num * kTimestampIncrement);
 
     // Skip 10 packets (larger than NACK threshold).
     const int kNumLostPackets = 10;
     seq_num += kNumLostPackets + 1;
     nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
-      seq_num * kTimestampIncrement);
+                                   seq_num * kTimestampIncrement);
 
     const size_t kExpectedListSize = kNumLostPackets - kNackThreshold;
     std::vector<uint16_t> nack_list = nack->GetNackList(kShortRoundTripTimeMs);
@@ -319,7 +317,7 @@
 
     // Decoding of the last received packet.
     nack->UpdateLastDecodedPacket(seq_num + seq_num_offset,
-      seq_num * kTimestampIncrement);
+                                  seq_num * kTimestampIncrement);
     nack_list = nack->GetNackList(kShortRoundTripTimeMs);
     EXPECT_TRUE(nack_list.empty());
 
@@ -329,7 +327,7 @@
     for (int n = 0; n < kNackThreshold + 10; ++n) {
       seq_num++;
       nack->UpdateLastReceivedPacket(seq_num_offset + seq_num,
-       seq_num * kTimestampIncrement);
+                                     seq_num * kTimestampIncrement);
       nack_list = nack->GetNackList(kShortRoundTripTimeMs);
       EXPECT_TRUE(nack_list.empty());
     }
@@ -481,6 +479,4 @@
   EXPECT_EQ(5, nack_list[1]);
 }
 
-}  // namespace acm2
-
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/neteq/neteq.gypi b/webrtc/modules/audio_coding/neteq/neteq.gypi
index 41b8fd0..e424ab5 100644
--- a/webrtc/modules/audio_coding/neteq/neteq.gypi
+++ b/webrtc/modules/audio_coding/neteq/neteq.gypi
@@ -96,6 +96,8 @@
         'expand.h',
         'merge.cc',
         'merge.h',
+        'nack.h',
+        'nack.cc',
         'neteq_impl.cc',
         'neteq_impl.h',
         'neteq.cc',
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index ead08f1..ecd1ad9 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -33,6 +33,7 @@
 #include "webrtc/modules/audio_coding/neteq/dtmf_tone_generator.h"
 #include "webrtc/modules/audio_coding/neteq/expand.h"
 #include "webrtc/modules/audio_coding/neteq/merge.h"
+#include "webrtc/modules/audio_coding/neteq/nack.h"
 #include "webrtc/modules/audio_coding/neteq/normal.h"
 #include "webrtc/modules/audio_coding/neteq/packet_buffer.h"
 #include "webrtc/modules/audio_coding/neteq/packet.h"
@@ -86,7 +87,7 @@
       new_codec_(false),
       timestamp_(0),
       reset_decoder_(false),
-      current_rtp_payload_type_(0xFF),  // Invalid RTP payload type.
+      current_rtp_payload_type_(0xFF),      // Invalid RTP payload type.
       current_cng_rtp_payload_type_(0xFF),  // Invalid RTP payload type.
       ssrc_(0),
       first_packet_(true),
@@ -95,8 +96,7 @@
       background_noise_mode_(config.background_noise_mode),
       playout_mode_(config.playout_mode),
       enable_fast_accelerate_(config.enable_fast_accelerate),
-      decoded_packet_sequence_number_(-1),
-      decoded_packet_timestamp_(0) {
+      nack_enabled_(false) {
   LOG(LS_INFO) << "NetEq config: " << config.ToString();
   int fs = config.sample_rate_hz;
   if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
@@ -405,13 +405,30 @@
   packet_buffer_->BufferStat(current_num_packets, max_num_packets);
 }
 
-int NetEqImpl::DecodedRtpInfo(int* sequence_number, uint32_t* timestamp) const {
+void NetEqImpl::EnableNack(size_t max_nack_list_size) {
   CriticalSectionScoped lock(crit_sect_.get());
-  if (decoded_packet_sequence_number_ < 0)
-    return -1;
-  *sequence_number = decoded_packet_sequence_number_;
-  *timestamp = decoded_packet_timestamp_;
-  return 0;
+  if (!nack_enabled_) {
+    const int kNackThresholdPackets = 2;
+    nack_.reset(Nack::Create(kNackThresholdPackets));
+    nack_enabled_ = true;
+    nack_->UpdateSampleRate(fs_hz_);
+  }
+  nack_->SetMaxNackListSize(max_nack_list_size);
+}
+
+void NetEqImpl::DisableNack() {
+  CriticalSectionScoped lock(crit_sect_.get());
+  nack_.reset();
+  nack_enabled_ = false;
+}
+
+std::vector<uint16_t> NetEqImpl::GetNackList(int64_t round_trip_time_ms) const {
+  CriticalSectionScoped lock(crit_sect_.get());
+  if (!nack_enabled_) {
+    return std::vector<uint16_t>();
+  }
+  RTC_DCHECK(nack_.get());
+  return nack_->GetNackList(round_trip_time_ms);
 }
 
 const SyncBuffer* NetEqImpl::sync_buffer_for_test() const {
@@ -611,6 +628,15 @@
                             receive_timestamp);
   }
 
+  if (nack_enabled_) {
+    RTC_DCHECK(nack_);
+    if (update_sample_rate_and_channels) {
+      nack_->Reset();
+    }
+    nack_->UpdateLastReceivedPacket(packet_list.front()->header.sequenceNumber,
+                                    packet_list.front()->header.timestamp);
+  }
+
   // Insert packets in buffer.
   const size_t buffer_length_before_insert =
       packet_buffer_->NumPacketsInBuffer();
@@ -658,8 +684,14 @@
         decoder_database_->GetDecoderInfo(payload_type);
     assert(decoder_info);
     if (decoder_info->fs_hz != fs_hz_ ||
-        decoder->Channels() != algorithm_buffer_->Channels())
+        decoder->Channels() != algorithm_buffer_->Channels()) {
       SetSampleRateAndChannels(decoder_info->fs_hz, decoder->Channels());
+    }
+    if (nack_enabled_) {
+      RTC_DCHECK(nack_);
+      // Update the sample rate even if the rate is not new, because of Reset().
+      nack_->UpdateSampleRate(fs_hz_);
+    }
   }
 
   // TODO(hlundin): Move this code to DelayManager class.
@@ -1863,9 +1895,14 @@
 
     if (first_packet) {
       first_packet = false;
-      decoded_packet_sequence_number_ = prev_sequence_number =
-          packet->header.sequenceNumber;
-      decoded_packet_timestamp_ = prev_timestamp = packet->header.timestamp;
+      if (nack_enabled_) {
+        RTC_DCHECK(nack_);
+        // TODO(henrik.lundin): Should we update this for all decoded packets?
+        nack_->UpdateLastDecodedPacket(packet->header.sequenceNumber,
+                                       packet->header.timestamp);
+      }
+      prev_sequence_number = packet->header.sequenceNumber;
+      prev_timestamp = packet->header.timestamp;
       prev_payload_type = packet->header.payloadType;
     }
 
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h
index bb93b32..4f253bd 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.h
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h
@@ -39,6 +39,7 @@
 class DtmfToneGenerator;
 class Expand;
 class Merge;
+class Nack;
 class Normal;
 class PacketBuffer;
 class PayloadSplitter;
@@ -187,9 +188,11 @@
   void PacketBufferStatistics(int* current_num_packets,
                               int* max_num_packets) const override;
 
-  // Get sequence number and timestamp of the latest RTP.
-  // This method is to facilitate NACK.
-  int DecodedRtpInfo(int* sequence_number, uint32_t* timestamp) const override;
+  void EnableNack(size_t max_nack_list_size) override;
+
+  void DisableNack() override;
+
+  std::vector<uint16_t> GetNackList(int64_t round_trip_time_ms) const override;
 
   // This accessor method is only intended for testing purposes.
   const SyncBuffer* sync_buffer_for_test() const;
@@ -393,16 +396,8 @@
   const BackgroundNoiseMode background_noise_mode_ GUARDED_BY(crit_sect_);
   NetEqPlayoutMode playout_mode_ GUARDED_BY(crit_sect_);
   bool enable_fast_accelerate_ GUARDED_BY(crit_sect_);
-
-  // These values are used by NACK module to estimate time-to-play of
-  // a missing packet. Occasionally, NetEq might decide to decode more
-  // than one packet. Therefore, these values store sequence number and
-  // timestamp of the first packet pulled from the packet buffer. In
-  // such cases, these values do not exactly represent the sequence number
-  // or timestamp associated with a 10ms audio pulled from NetEq. NACK
-  // module is designed to compensate for this.
-  int decoded_packet_sequence_number_ GUARDED_BY(crit_sect_);
-  uint32_t decoded_packet_timestamp_ GUARDED_BY(crit_sect_);
+  rtc::scoped_ptr<Nack> nack_ GUARDED_BY(crit_sect_);
+  bool nack_enabled_ GUARDED_BY(crit_sect_);
 
  private:
   RTC_DISALLOW_COPY_AND_ASSIGN(NetEqImpl);
diff --git a/webrtc/modules/modules.gyp b/webrtc/modules/modules.gyp
index 68cf53e..2bf0ac8 100644
--- a/webrtc/modules/modules.gyp
+++ b/webrtc/modules/modules.gyp
@@ -103,7 +103,6 @@
             'audio_coding/main/acm2/call_statistics_unittest.cc',
             'audio_coding/main/acm2/codec_owner_unittest.cc',
             'audio_coding/main/acm2/initial_delay_manager_unittest.cc',
-            'audio_coding/main/acm2/nack_unittest.cc',
             'audio_coding/codecs/cng/cng_unittest.cc',
             'audio_coding/codecs/isac/fix/source/filters_unittest.cc',
             'audio_coding/codecs/isac/fix/source/filterbanks_unittest.cc',
@@ -130,6 +129,7 @@
             'audio_coding/neteq/dtmf_tone_generator_unittest.cc',
             'audio_coding/neteq/expand_unittest.cc',
             'audio_coding/neteq/merge_unittest.cc',
+            'audio_coding/neteq/nack_unittest.cc',
             'audio_coding/neteq/neteq_external_decoder_unittest.cc',
             'audio_coding/neteq/neteq_impl_unittest.cc',
             'audio_coding/neteq/neteq_network_stats_unittest.cc',