Added a ParsePayload method to AudioDecoder.

It allows the decoder to split the input up into usable chunks before
they are put into NetEq's PacketBuffer. Eventually, all packet splitting
will move into ParsePayload.

There's currently a base implementation of ParsePayload. It will
generate a single Frame that calls the underlying AudioDecoder for
getting Duration() and to Decode.

BUG=webrtc:5805
BUG=chromium:428099

Review-Url: https://codereview.webrtc.org/2326953003
Cr-Commit-Position: refs/heads/master@{#14300}
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.cc b/webrtc/modules/audio_coding/codecs/audio_decoder.cc
index 8d4a2bc..9dbecd5 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder.cc
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.cc
@@ -12,6 +12,8 @@
 
 #include <assert.h>
 
+#include <utility>
+
 #include "webrtc/base/array_view.h"
 #include "webrtc/base/checks.h"
 #include "webrtc/base/sanitizer.h"
@@ -19,6 +21,76 @@
 
 namespace webrtc {
 
+namespace {
+class LegacyFrame final : public AudioDecoder::EncodedAudioFrame {
+ public:
+  LegacyFrame(AudioDecoder* decoder,
+              rtc::Buffer&& payload,
+              bool is_primary_payload)
+      : decoder_(decoder),
+        payload_(std::move(payload)),
+        is_primary_payload_(is_primary_payload) {}
+
+  size_t Duration() const override {
+    int ret;
+    if (is_primary_payload_) {
+      ret = decoder_->PacketDuration(payload_.data(), payload_.size());
+    } else {
+      ret = decoder_->PacketDurationRedundant(payload_.data(), payload_.size());
+    }
+    return (ret < 0) ? 0 : static_cast<size_t>(ret);
+  }
+
+  rtc::Optional<DecodeResult> Decode(
+      rtc::ArrayView<int16_t> decoded) const override {
+    AudioDecoder::SpeechType speech_type = AudioDecoder::kSpeech;
+    int ret;
+    if (is_primary_payload_) {
+      ret = decoder_->Decode(
+          payload_.data(), payload_.size(), decoder_->SampleRateHz(),
+          decoded.size() * sizeof(int16_t), decoded.data(), &speech_type);
+    } else {
+      ret = decoder_->DecodeRedundant(
+          payload_.data(), payload_.size(), decoder_->SampleRateHz(),
+          decoded.size() * sizeof(int16_t), decoded.data(), &speech_type);
+    }
+
+    if (ret < 0)
+      return rtc::Optional<DecodeResult>();
+
+    return rtc::Optional<DecodeResult>({static_cast<size_t>(ret), speech_type});
+  }
+
+ private:
+  AudioDecoder* const decoder_;
+  const rtc::Buffer payload_;
+  const bool is_primary_payload_;
+};
+}  // namespace
+
+AudioDecoder::ParseResult::ParseResult() = default;
+AudioDecoder::ParseResult::ParseResult(ParseResult&& b) = default;
+AudioDecoder::ParseResult::ParseResult(uint32_t timestamp,
+                                       bool primary,
+                                       std::unique_ptr<EncodedAudioFrame> frame)
+    : timestamp(timestamp), primary(primary), frame(std::move(frame)) {}
+
+AudioDecoder::ParseResult::~ParseResult() = default;
+
+AudioDecoder::ParseResult& AudioDecoder::ParseResult::operator=(
+    ParseResult&& b) = default;
+
+std::vector<AudioDecoder::ParseResult> AudioDecoder::ParsePayload(
+    rtc::Buffer&& payload,
+    uint32_t timestamp,
+    bool is_primary) {
+  std::vector<ParseResult> results;
+  std::unique_ptr<EncodedAudioFrame> frame(
+      new LegacyFrame(this, std::move(payload), is_primary));
+  results.emplace_back(timestamp, is_primary, std::move(frame));
+  return results;
+}
+
 int AudioDecoder::Decode(const uint8_t* encoded, size_t encoded_len,
                          int sample_rate_hz, size_t max_decoded_bytes,
                          int16_t* decoded, SpeechType* speech_type) {
diff --git a/webrtc/modules/audio_coding/codecs/audio_decoder.h b/webrtc/modules/audio_coding/codecs/audio_decoder.h
index 13581bc..9608c32 100644
--- a/webrtc/modules/audio_coding/codecs/audio_decoder.h
+++ b/webrtc/modules/audio_coding/codecs/audio_decoder.h
@@ -13,7 +13,13 @@
 
 #include <stdlib.h>  // NULL
 
+#include <memory>
+#include <vector>
+
+#include "webrtc/base/array_view.h"
+#include "webrtc/base/buffer.h"
 #include "webrtc/base/constructormagic.h"
+#include "webrtc/base/optional.h"
 #include "webrtc/typedefs.h"
 
 namespace webrtc {
@@ -33,6 +39,55 @@
   AudioDecoder() = default;
   virtual ~AudioDecoder() = default;
 
+  class EncodedAudioFrame {
+   public:
+    struct DecodeResult {
+      size_t num_decoded_samples;
+      SpeechType speech_type;
+    };
+
+    virtual ~EncodedAudioFrame() = default;
+
+    // Returns the duration in samples-per-channel of this audio frame.
+    // If no duration can be ascertained, returns zero.
+    virtual size_t Duration() const = 0;
+
+    // Decodes this frame of audio and writes the result in |decoded|.
+    // |decoded| must be large enough to store as many samples as indicated by a
+    // call to Duration() . On success, returns an rtc::Optional containing the
+    // total number of samples across all channels, as well as whether the
+    // decoder produced comfort noise or speech. On failure, returns an empty
+    // rtc::Optional. Decode may be called at most once per frame object.
+    virtual rtc::Optional<DecodeResult> Decode(
+        rtc::ArrayView<int16_t> decoded) const = 0;
+  };
+
+  struct ParseResult {
+    ParseResult();
+    ParseResult(uint32_t timestamp,
+                bool primary,
+                std::unique_ptr<EncodedAudioFrame> frame);
+    ParseResult(ParseResult&& b);
+    ~ParseResult();
+
+    ParseResult& operator=(ParseResult&& b);
+
+    // The timestamp of the frame is in samples per channel.
+    uint32_t timestamp;
+    bool primary;
+    std::unique_ptr<EncodedAudioFrame> frame;
+  };
+
+  // Let the decoder parse this payload and prepare zero or more decodable
+  // frames. Each frame must be between 10 ms and 120 ms long. The caller must
+  // ensure that the AudioDecoder object outlives any frame objects returned by
+  // this call. The decoder is free to swap or move the data from the |payload|
+  // buffer. |timestamp| is the input timestamp, in samples, corresponding to
+  // the start of the payload.
+  virtual std::vector<ParseResult> ParsePayload(rtc::Buffer&& payload,
+                                                uint32_t timestamp,
+                                                bool is_primary);
+
   // Decodes |encode_len| bytes from |encoded| and writes the result in
   // |decoded|. The maximum bytes allowed to be written into |decoded| is
   // |max_decoded_bytes|. Returns the total number of samples across all
diff --git a/webrtc/modules/audio_coding/neteq/decision_logic.cc b/webrtc/modules/audio_coding/neteq/decision_logic.cc
index 545d1d6..1c77914 100644
--- a/webrtc/modules/audio_coding/neteq/decision_logic.cc
+++ b/webrtc/modules/audio_coding/neteq/decision_logic.cc
@@ -108,24 +108,19 @@
                                       bool play_dtmf,
                                       size_t generated_noise_samples,
                                       bool* reset_decoder) {
-  if (prev_mode == kModeRfc3389Cng ||
-      prev_mode == kModeCodecInternalCng ||
-      prev_mode == kModeExpand) {
-    // If last mode was CNG (or Expand, since this could be covering up for
-    // a lost CNG packet), remember that CNG is on. This is needed if comfort
-    // noise is interrupted by DTMF.
-    if (prev_mode == kModeRfc3389Cng) {
-      cng_state_ = kCngRfc3389On;
-    } else if (prev_mode == kModeCodecInternalCng) {
-      cng_state_ = kCngInternalOn;
-    }
+  // If last mode was CNG (or Expand, since this could be covering up for
+  // a lost CNG packet), remember that CNG is on. This is needed if comfort
+  // noise is interrupted by DTMF.
+  if (prev_mode == kModeRfc3389Cng) {
+    cng_state_ = kCngRfc3389On;
+  } else if (prev_mode == kModeCodecInternalCng) {
+    cng_state_ = kCngInternalOn;
   }
 
   const size_t samples_left =
       sync_buffer.FutureLength() - expand.overlap_length();
   const size_t cur_size_samples =
-      samples_left + packet_buffer_.NumSamplesInBuffer(decoder_database_,
-                                                       decoder_frame_length);
+      samples_left + packet_buffer_.NumSamplesInBuffer(decoder_frame_length);
 
   prev_time_scale_ = prev_time_scale_ &&
       (prev_mode == kModeAccelerateSuccess ||
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index 9c4f580..d62d44f 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -14,6 +14,7 @@
 #include <memory.h>  // memset
 
 #include <algorithm>
+#include <utility>
 #include <vector>
 
 #include "webrtc/base/checks.h"
@@ -282,6 +283,7 @@
   rtc::CritScope lock(&crit_sect_);
   int ret = decoder_database_->Remove(rtp_payload_type);
   if (ret == DecoderDatabase::kOK) {
+    packet_buffer_->DiscardPacketsWithPayloadType(rtp_payload_type);
     return kOK;
   } else if (ret == DecoderDatabase::kDecoderNotFound) {
     error_code_ = kDecoderNotFound;
@@ -330,8 +332,7 @@
   // Sum up the samples in the packet buffer with the future length of the sync
   // buffer, and divide the sum by the sample rate.
   const size_t delay_samples =
-      packet_buffer_->NumSamplesInBuffer(decoder_database_.get(),
-                                         decoder_frame_length_) +
+      packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
       sync_buffer_->FutureLength();
   // The division below will truncate.
   const int delay_ms =
@@ -376,8 +377,7 @@
   rtc::CritScope lock(&crit_sect_);
   assert(decoder_database_.get());
   const size_t total_samples_in_buffers =
-      packet_buffer_->NumSamplesInBuffer(decoder_database_.get(),
-                                         decoder_frame_length_) +
+      packet_buffer_->NumSamplesInBuffer(decoder_frame_length_) +
       sync_buffer_->FutureLength();
   assert(delay_manager_.get());
   assert(decision_logic_.get());
@@ -662,29 +662,64 @@
                             receive_timestamp);
   }
 
+  PacketList parsed_packet_list;
+  while (!packet_list.empty()) {
+    std::unique_ptr<Packet> packet(packet_list.front());
+    packet_list.pop_front();
+    const DecoderDatabase::DecoderInfo* info =
+        decoder_database_->GetDecoderInfo(packet->header.payloadType);
+    if (!info) {
+      LOG(LS_WARNING) << "SplitAudio unknown payload type";
+      return kUnknownRtpPayloadType;
+    }
+
+    if (info->IsComfortNoise()) {
+      // Carry comfort noise packets along.
+      parsed_packet_list.push_back(packet.release());
+    } else {
+      std::vector<AudioDecoder::ParseResult> results =
+          info->GetDecoder()->ParsePayload(std::move(packet->payload),
+                                           packet->header.timestamp,
+                                           packet->primary);
+      const RTPHeader& original_header = packet->header;
+      for (auto& result : results) {
+        RTC_DCHECK(result.frame);
+        // Reuse the packet if possible
+        if (!packet) {
+          packet.reset(new Packet);
+          packet->header = original_header;
+        }
+        packet->header.timestamp = result.timestamp;
+        // TODO(ossu): Move from primary to some sort of priority level.
+        packet->primary = result.primary;
+        packet->frame = std::move(result.frame);
+        parsed_packet_list.push_back(packet.release());
+      }
+    }
+  }
+
   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);
+    nack_->UpdateLastReceivedPacket(
+        parsed_packet_list.front()->header.sequenceNumber,
+        parsed_packet_list.front()->header.timestamp);
   }
 
   // Insert packets in buffer.
   const size_t buffer_length_before_insert =
       packet_buffer_->NumPacketsInBuffer();
   ret = packet_buffer_->InsertPacketList(
-      &packet_list,
-      *decoder_database_,
-      &current_rtp_payload_type_,
+      &parsed_packet_list, *decoder_database_, &current_rtp_payload_type_,
       &current_cng_rtp_payload_type_);
   if (ret == PacketBuffer::kFlushed) {
     // Reset DSP timestamp etc. if packet buffer flushed.
     new_codec_ = true;
     update_sample_rate_and_channels = true;
   } else if (ret != PacketBuffer::kOK) {
-    PacketBuffer::DeleteAllPackets(&packet_list);
+    PacketBuffer::DeleteAllPackets(&parsed_packet_list);
     return kOtherError;
   }
 
@@ -1421,36 +1456,29 @@
            operation == kFastAccelerate || operation == kMerge ||
            operation == kPreemptiveExpand);
     packet_list->pop_front();
-    const size_t payload_length = packet->payload.size();
-    int decode_length;
-    if (!packet->primary) {
-      // This is a redundant payload; call the special decoder method.
-      decode_length = decoder->DecodeRedundant(
-          packet->payload.data(), packet->payload.size(), fs_hz_,
-          (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t),
-          &decoded_buffer_[*decoded_length], speech_type);
-    } else {
-      decode_length = decoder->Decode(
-          packet->payload.data(), packet->payload.size(), fs_hz_,
-          (decoded_buffer_length_ - *decoded_length) * sizeof(int16_t),
-          &decoded_buffer_[*decoded_length], speech_type);
-    }
-
+    auto opt_result = packet->frame->Decode(
+        rtc::ArrayView<int16_t>(&decoded_buffer_[*decoded_length],
+                                decoded_buffer_length_ - *decoded_length));
     delete packet;
     packet = NULL;
-    if (decode_length > 0) {
-      *decoded_length += decode_length;
-      // Update |decoder_frame_length_| with number of samples per channel.
-      decoder_frame_length_ =
-          static_cast<size_t>(decode_length) / decoder->Channels();
-    } else if (decode_length < 0) {
+    if (opt_result) {
+      const auto& result = *opt_result;
+      *speech_type = result.speech_type;
+      if (result.num_decoded_samples > 0) {
+        *decoded_length += rtc::checked_cast<int>(result.num_decoded_samples);
+        // Update |decoder_frame_length_| with number of samples per channel.
+        decoder_frame_length_ =
+            result.num_decoded_samples / decoder->Channels();
+      }
+    } else {
       // Error.
-      LOG(LS_WARNING) << "Decode " << decode_length << " " << payload_length;
+      // TODO(ossu): What to put here?
+      LOG(LS_WARNING) << "Decode error";
       *decoded_length = -1;
       PacketBuffer::DeleteAllPackets(packet_list);
       break;
     }
-    if (*decoded_length > static_cast<int>(decoded_buffer_length_)) {
+    if (*decoded_length > rtc::checked_cast<int>(decoded_buffer_length_)) {
       // Guard against overflow.
       LOG(LS_WARNING) << "Decoded too much.";
       PacketBuffer::DeleteAllPackets(packet_list);
@@ -1892,7 +1920,7 @@
     return -1;
   }
   uint32_t first_timestamp = header->timestamp;
-  int extracted_samples = 0;
+  size_t extracted_samples = 0;
 
   // Packet extraction loop.
   do {
@@ -1908,7 +1936,7 @@
     }
     stats_.PacketsDiscarded(discard_count);
     stats_.StoreWaitingTime(packet->waiting_time->ElapsedMs());
-    assert(!packet->payload.empty());
+    RTC_DCHECK(!packet->empty());
     packet_list->push_back(packet);  // Store packet in list.
 
     if (first_packet) {
@@ -1925,27 +1953,24 @@
     }
 
     // Store number of extracted samples.
-    int packet_duration = 0;
-    AudioDecoder* decoder = decoder_database_->GetDecoder(
-        packet->header.payloadType);
-    if (decoder) {
-      if (packet->primary) {
-        packet_duration = decoder->PacketDuration(packet->payload.data(),
-                                                  packet->payload.size());
-      } else {
-        packet_duration = decoder->PacketDurationRedundant(
-            packet->payload.data(), packet->payload.size());
-        stats_.SecondaryDecodedSamples(packet_duration);
+    size_t packet_duration = 0;
+    if (packet->frame) {
+      packet_duration = packet->frame->Duration();
+      // TODO(ossu): Is this the correct way to track samples decoded from a
+      // redundant packet?
+      if (packet_duration > 0 && !packet->primary) {
+        stats_.SecondaryDecodedSamples(rtc::checked_cast<int>(packet_duration));
       }
     } else if (!decoder_database_->IsComfortNoise(packet->header.payloadType)) {
       LOG(LS_WARNING) << "Unknown payload type "
                       << static_cast<int>(packet->header.payloadType);
-      assert(false);
+      RTC_NOTREACHED();
     }
-    if (packet_duration <= 0) {
+
+    if (packet_duration == 0) {
       // Decoder did not return a packet duration. Assume that the packet
       // contains the same number of samples as the previous one.
-      packet_duration = rtc::checked_cast<int>(decoder_frame_length_);
+      packet_duration = decoder_frame_length_;
     }
     extracted_samples = packet->header.timestamp - first_timestamp +
         packet_duration;
@@ -1964,8 +1989,7 @@
       }
       prev_sequence_number = header->sequenceNumber;
     }
-  } while (extracted_samples < rtc::checked_cast<int>(required_samples) &&
-           next_packet_available);
+  } while (extracted_samples < required_samples && next_packet_available);
 
   if (extracted_samples > 0) {
     // Delete old packets only when we are going to decode something. Otherwise,
@@ -1975,7 +1999,7 @@
     packet_buffer_->DiscardAllOldPackets(timestamp_);
   }
 
-  return extracted_samples;
+  return rtc::checked_cast<int>(extracted_samples);
 }
 
 void NetEqImpl::UpdatePlcComponents(int fs_hz, size_t channels) {
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
index c74342b..1b8ee82 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -791,50 +791,41 @@
   rtp_header.header.timestamp = 0x12345678;
   rtp_header.header.ssrc = 0x87654321;
 
-  class MockAudioDecoder : public AudioDecoder {
-   public:
-    // TODO(nisse): Valid overrides commented out, because the gmock
-    // methods don't use any override declarations, and we want to avoid
-    // warnings from -Winconsistent-missing-override. See
-    // http://crbug.com/428099.
-    void Reset() /* override */ {}
-    MOCK_CONST_METHOD2(PacketDuration, int(const uint8_t*, size_t));
-    MOCK_METHOD5(DecodeInternal, int(const uint8_t*, size_t, int, int16_t*,
-                                     SpeechType*));
-    int SampleRateHz() const /* override */ { return kSampleRateHz; }
-    size_t Channels() const /* override */ { return kChannels; }
-  } decoder_;
+  ::testing::NiceMock<MockAudioDecoder> decoder;
 
   const uint8_t kFirstPayloadValue = 1;
   const uint8_t kSecondPayloadValue = 2;
 
-  EXPECT_CALL(decoder_, PacketDuration(Pointee(kFirstPayloadValue),
-                                       kPayloadLengthBytes))
-    .Times(AtLeast(1))
-    .WillRepeatedly(Return(kNetEqMaxFrameSize + 1));
+  EXPECT_CALL(decoder,
+              PacketDuration(Pointee(kFirstPayloadValue), kPayloadLengthBytes))
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(kNetEqMaxFrameSize + 1));
 
-  EXPECT_CALL(decoder_,
-              DecodeInternal(Pointee(kFirstPayloadValue), _, _, _, _))
+  EXPECT_CALL(decoder, DecodeInternal(Pointee(kFirstPayloadValue), _, _, _, _))
       .Times(0);
 
-  EXPECT_CALL(decoder_, DecodeInternal(Pointee(kSecondPayloadValue),
-                                       kPayloadLengthBytes,
-                                       kSampleRateHz, _, _))
+  EXPECT_CALL(decoder, DecodeInternal(Pointee(kSecondPayloadValue),
+                                      kPayloadLengthBytes, kSampleRateHz, _, _))
       .Times(1)
-      .WillOnce(DoAll(SetArrayArgument<3>(dummy_output,
-                                          dummy_output +
-                                          kPayloadLengthSamples * kChannels),
-                      SetArgPointee<4>(AudioDecoder::kSpeech),
-                      Return(static_cast<int>(
-                          kPayloadLengthSamples * kChannels))));
+      .WillOnce(DoAll(
+          SetArrayArgument<3>(dummy_output,
+                              dummy_output + kPayloadLengthSamples * kChannels),
+          SetArgPointee<4>(AudioDecoder::kSpeech),
+          Return(static_cast<int>(kPayloadLengthSamples * kChannels))));
 
-  EXPECT_CALL(decoder_, PacketDuration(Pointee(kSecondPayloadValue),
-                                       kPayloadLengthBytes))
-    .Times(AtLeast(1))
-    .WillRepeatedly(Return(kNetEqMaxFrameSize));
+  EXPECT_CALL(decoder,
+              PacketDuration(Pointee(kSecondPayloadValue), kPayloadLengthBytes))
+      .Times(AtLeast(1))
+      .WillRepeatedly(Return(kNetEqMaxFrameSize));
+
+  EXPECT_CALL(decoder, SampleRateHz())
+      .WillRepeatedly(Return(kSampleRateHz));
+
+  EXPECT_CALL(decoder, Channels())
+      .WillRepeatedly(Return(kChannels));
 
   EXPECT_EQ(NetEq::kOK, neteq_->RegisterExternalDecoder(
-                            &decoder_, NetEqDecoder::kDecoderPCM16B,
+                            &decoder, NetEqDecoder::kDecoderPCM16B,
                             "dummy name", kPayloadType));
 
   // Insert one packet.
@@ -868,6 +859,10 @@
   EXPECT_EQ(NetEq::kOK, neteq_->GetAudio(&output, &muted));
   EXPECT_EQ(kExpectedOutputSize, output.samples_per_channel_ * kChannels);
   EXPECT_EQ(kChannels, output.num_channels_);
+
+  // Die isn't called through NiceMock (since it's called by the
+  // MockAudioDecoder constructor), so it needs to be mocked explicitly.
+  EXPECT_CALL(decoder, Die());
 }
 
 // This test inserts packets until the buffer is flushed. After that, it asks
diff --git a/webrtc/modules/audio_coding/neteq/packet.h b/webrtc/modules/audio_coding/neteq/packet.h
index 7119c80..4e17a88 100644
--- a/webrtc/modules/audio_coding/neteq/packet.h
+++ b/webrtc/modules/audio_coding/neteq/packet.h
@@ -15,6 +15,7 @@
 #include <memory>
 
 #include "webrtc/base/buffer.h"
+#include "webrtc/modules/audio_coding/codecs/audio_decoder.h"
 #include "webrtc/modules/audio_coding/neteq/tick_timer.h"
 #include "webrtc/modules/include/module_common_types.h"
 #include "webrtc/typedefs.h"
@@ -28,6 +29,7 @@
   rtc::Buffer payload;
   bool primary = true;  // Primary, i.e., not redundant payload.
   std::unique_ptr<TickTimer::Stopwatch> waiting_time;
+  std::unique_ptr<AudioDecoder::EncodedAudioFrame> frame;
 
   Packet();
   ~Packet();
@@ -60,6 +62,8 @@
   bool operator>(const Packet& rhs) const { return rhs.operator<(*this); }
   bool operator<=(const Packet& rhs) const { return !operator>(rhs); }
   bool operator>=(const Packet& rhs) const { return !operator<(rhs); }
+
+  bool empty() const { return !frame && payload.empty(); }
 };
 
 // A list of packets.
diff --git a/webrtc/modules/audio_coding/neteq/packet_buffer.cc b/webrtc/modules/audio_coding/neteq/packet_buffer.cc
index 1c8713c..c5b23dc 100644
--- a/webrtc/modules/audio_coding/neteq/packet_buffer.cc
+++ b/webrtc/modules/audio_coding/neteq/packet_buffer.cc
@@ -68,7 +68,7 @@
 }
 
 int PacketBuffer::InsertPacket(Packet* packet) {
-  if (!packet || packet->payload.empty()) {
+  if (!packet || packet->empty()) {
     if (packet) {
       delete packet;
     }
@@ -209,7 +209,7 @@
 
   Packet* packet = buffer_.front();
   // Assert that the packet sanity checks in InsertPacket method works.
-  assert(packet && !packet->payload.empty());
+  RTC_DCHECK(packet && !packet->empty());
   buffer_.pop_front();
 
   // Discard other packets with the same timestamp. These are duplicates or
@@ -237,8 +237,8 @@
     return kBufferEmpty;
   }
   // Assert that the packet sanity checks in InsertPacket method works.
-  assert(buffer_.front());
-  assert(!buffer_.front()->payload.empty());
+  RTC_DCHECK(buffer_.front());
+  RTC_DCHECK(!buffer_.front()->empty());
   DeleteFirstPacket(&buffer_);
   return kOK;
 }
@@ -260,26 +260,32 @@
   return DiscardOldPackets(timestamp_limit, 0);
 }
 
+void PacketBuffer::DiscardPacketsWithPayloadType(uint8_t payload_type) {
+  for (auto it = buffer_.begin(); it != buffer_.end(); /* */) {
+    Packet *packet = *it;
+    if (packet->header.payloadType == payload_type) {
+      delete packet;
+      it = buffer_.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
 size_t PacketBuffer::NumPacketsInBuffer() const {
   return buffer_.size();
 }
 
-size_t PacketBuffer::NumSamplesInBuffer(DecoderDatabase* decoder_database,
-                                        size_t last_decoded_length) const {
-  PacketList::const_iterator it;
+size_t PacketBuffer::NumSamplesInBuffer(size_t last_decoded_length) const {
   size_t num_samples = 0;
   size_t last_duration = last_decoded_length;
-  for (it = buffer_.begin(); it != buffer_.end(); ++it) {
-    Packet* packet = (*it);
-    AudioDecoder* decoder =
-        decoder_database->GetDecoder(packet->header.payloadType);
-    if (decoder) {
+  for (Packet* packet : buffer_) {
+    if (packet->frame) {
       if (!packet->primary) {
         continue;
       }
-      int duration = decoder->PacketDuration(packet->payload.data(),
-                                             packet->payload.size());
-      if (duration >= 0) {
+      size_t duration = packet->frame->Duration();
+      if (duration > 0) {
         last_duration = duration;  // Save the most up-to-date (valid) duration.
       }
     }
diff --git a/webrtc/modules/audio_coding/neteq/packet_buffer.h b/webrtc/modules/audio_coding/neteq/packet_buffer.h
index be2eceb..ee8c378 100644
--- a/webrtc/modules/audio_coding/neteq/packet_buffer.h
+++ b/webrtc/modules/audio_coding/neteq/packet_buffer.h
@@ -109,14 +109,16 @@
   // Discards all packets that are (strictly) older than timestamp_limit.
   virtual int DiscardAllOldPackets(uint32_t timestamp_limit);
 
+  // Removes all packets with a specific payload type from the buffer.
+  virtual void DiscardPacketsWithPayloadType(uint8_t payload_type);
+
   // Returns the number of packets in the buffer, including duplicates and
   // redundant packets.
   virtual size_t NumPacketsInBuffer() const;
 
   // Returns the number of samples in the buffer, including samples carried in
   // duplicate and redundant packets.
-  virtual size_t NumSamplesInBuffer(DecoderDatabase* decoder_database,
-                                    size_t last_decoded_length) const;
+  virtual size_t NumSamplesInBuffer(size_t last_decoded_length) const;
 
   virtual void BufferStat(int* num_packets, int* max_num_packets) const;