AcmReceiver: Look up last decoder in NetEq's table of decoders

AcmReceiver::decoders_ is now one step closer to being unused.

(This is a re-land of https://codereview.webrtc.org/2339953002.)

BUG=webrtc:5801

Review-Url: https://codereview.webrtc.org/2354453003
Cr-Commit-Position: refs/heads/master@{#14303}
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/acm2/acm_receiver.cc
index 417a346..641818d 100644
--- a/webrtc/modules/audio_coding/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/acm2/acm_receiver.cc
@@ -32,23 +32,8 @@
 
 namespace acm2 {
 
-namespace {
-
-// Is the given codec a CNG codec?
-// TODO(kwiberg): Move to RentACodec.
-bool IsCng(int codec_id) {
-  auto i = RentACodec::CodecIdFromIndex(codec_id);
-  return (i && (*i == RentACodec::CodecId::kCNNB ||
-                *i == RentACodec::CodecId::kCNWB ||
-                *i == RentACodec::CodecId::kCNSWB ||
-                *i == RentACodec::CodecId::kCNFB));
-}
-
-}  // namespace
-
 AcmReceiver::AcmReceiver(const AudioCodingModule::Config& config)
-    : last_audio_decoder_(nullptr),
-      last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
+    : last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
       neteq_(NetEq::Create(config.neteq_config, config.decoder_factory)),
       clock_(config.clock),
       resampled_last_output_frame_(true) {
@@ -95,29 +80,25 @@
   {
     rtc::CritScope lock(&crit_sect_);
 
-    const Decoder* decoder = RtpHeaderToDecoder(*header, incoming_payload[0]);
-    if (!decoder) {
+    const rtc::Optional<CodecInst> ci =
+        RtpHeaderToDecoder(*header, incoming_payload[0]);
+    if (!ci) {
       LOG_F(LS_ERROR) << "Payload-type "
                       << static_cast<int>(header->payloadType)
                       << " is not registered.";
       return -1;
     }
-    const int sample_rate_hz = [&decoder] {
-      const auto ci = RentACodec::CodecIdFromIndex(decoder->acm_codec_id);
-      return ci ? RentACodec::CodecInstById(*ci)->plfreq : -1;
-    }();
-    receive_timestamp = NowInTimestamp(sample_rate_hz);
+    receive_timestamp = NowInTimestamp(ci->plfreq);
 
-    // If this is a CNG while the audio codec is not mono, skip pushing in
-    // packets into NetEq.
-    if (IsCng(decoder->acm_codec_id) && last_audio_decoder_ &&
-        last_audio_decoder_->channels > 1)
+    if (STR_CASE_CMP(ci->plname, "cn") == 0) {
+      if (last_audio_decoder_ && last_audio_decoder_->channels > 1) {
+        // This is a CNG and the audio codec is not mono, so skip pushing in
+        // packets into NetEq.
         return 0;
-    if (!IsCng(decoder->acm_codec_id) &&
-        decoder->acm_codec_id !=
-            *RentACodec::CodecIndexFromId(RentACodec::CodecId::kAVT)) {
-      last_audio_decoder_ = decoder;
-      last_packet_sample_rate_hz_ = rtc::Optional<int>(decoder->sample_rate_hz);
+      }
+    } else {
+      last_audio_decoder_ = ci;
+      last_packet_sample_rate_hz_ = rtc::Optional<int>(ci->plfreq);
     }
 
   }  // |crit_sect_| is released.
@@ -283,7 +264,7 @@
   }
 
   // No codec is registered, invalidate last audio decoder.
-  last_audio_decoder_ = nullptr;
+  last_audio_decoder_ = rtc::Optional<CodecInst>();
   last_packet_sample_rate_hz_ = rtc::Optional<int>();
   return ret_val;
 }
@@ -298,8 +279,8 @@
     LOG(LERROR) << "AcmReceiver::RemoveCodec" << static_cast<int>(payload_type);
     return -1;
   }
-  if (last_audio_decoder_ == &it->second) {
-    last_audio_decoder_ = nullptr;
+  if (last_audio_decoder_ && payload_type == last_audio_decoder_->pltype) {
+    last_audio_decoder_ = rtc::Optional<CodecInst>();
     last_packet_sample_rate_hz_ = rtc::Optional<int>();
   }
   decoders_.erase(it);
@@ -319,11 +300,7 @@
   if (!last_audio_decoder_) {
     return -1;
   }
-  *codec = *RentACodec::CodecInstById(
-      *RentACodec::CodecIdFromIndex(last_audio_decoder_->acm_codec_id));
-  codec->pltype = last_audio_decoder_->payload_type;
-  codec->channels = last_audio_decoder_->channels;
-  codec->plfreq = last_audio_decoder_->sample_rate_hz;
+  *codec = *last_audio_decoder_;
   return 0;
 }
 
@@ -387,20 +364,17 @@
   // TODO(turajs): Should NetEq Buffer be flushed?
 }
 
-const AcmReceiver::Decoder* AcmReceiver::RtpHeaderToDecoder(
+const rtc::Optional<CodecInst> AcmReceiver::RtpHeaderToDecoder(
     const RTPHeader& rtp_header,
-    uint8_t payload_type) const {
-  auto it = decoders_.find(rtp_header.payloadType);
-  const auto red_index =
-      RentACodec::CodecIndexFromId(RentACodec::CodecId::kRED);
-  if (red_index &&  // This ensures that RED is defined in WebRTC.
-      it != decoders_.end() && it->second.acm_codec_id == *red_index) {
-    // This is a RED packet, get the payload of the audio codec.
-    it = decoders_.find(payload_type & 0x7F);
+    uint8_t first_payload_byte) const {
+  const rtc::Optional<CodecInst> ci =
+      neteq_->GetDecoder(rtp_header.payloadType);
+  if (ci && STR_CASE_CMP(ci->plname, "red") == 0) {
+    // This is a RED packet. Get the payload of the audio codec.
+    return neteq_->GetDecoder(first_payload_byte & 0x7f);
+  } else {
+    return ci;
   }
-
-  // Check if the payload is registered.
-  return it != decoders_.end() ? &it->second : nullptr;
 }
 
 uint32_t AcmReceiver::NowInTimestamp(int decoder_sampling_rate) const {
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.h b/webrtc/modules/audio_coding/acm2/acm_receiver.h
index e62e714..d39581e 100644
--- a/webrtc/modules/audio_coding/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/acm2/acm_receiver.h
@@ -39,15 +39,6 @@
 
 class AcmReceiver {
  public:
-  struct Decoder {
-    int acm_codec_id;
-    uint8_t payload_type;
-    // This field is meaningful for codecs where both mono and
-    // stereo versions are registered under the same ID.
-    size_t channels;
-    int sample_rate_hz;
-  };
-
   // Constructor of the class
   explicit AcmReceiver(const AudioCodingModule::Config& config);
 
@@ -262,14 +253,23 @@
   void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
 
  private:
-  const Decoder* RtpHeaderToDecoder(const RTPHeader& rtp_header,
-                                    uint8_t payload_type) const
-      EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
+  struct Decoder {
+    int acm_codec_id;
+    uint8_t payload_type;
+    // This field is meaningful for codecs where both mono and
+    // stereo versions are registered under the same ID.
+    size_t channels;
+    int sample_rate_hz;
+  };
+
+  const rtc::Optional<CodecInst> RtpHeaderToDecoder(
+      const RTPHeader& rtp_header,
+      uint8_t first_payload_byte) const EXCLUSIVE_LOCKS_REQUIRED(crit_sect_);
 
   uint32_t NowInTimestamp(int decoder_sampling_rate) const;
 
   rtc::CriticalSection crit_sect_;
-  const Decoder* last_audio_decoder_ GUARDED_BY(crit_sect_);
+  rtc::Optional<CodecInst> last_audio_decoder_ GUARDED_BY(crit_sect_);
   ACMResampler resampler_ GUARDED_BY(crit_sect_);
   std::unique_ptr<int16_t[]> last_audio_buffer_ GUARDED_BY(crit_sect_);
   CallStatistics call_stats_ GUARDED_BY(crit_sect_);
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc
index 81a57da..5622fc1 100644
--- a/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc
@@ -119,9 +119,9 @@
     for (auto id : ids) {
       const auto i = RentACodec::CodecIndexFromId(id);
       ASSERT_TRUE(i);
-      ASSERT_EQ(
-          0, receiver_->AddCodec(*i, codecs_[*i].pltype, codecs_[*i].channels,
-                                 codecs_[*i].plfreq, nullptr, ""));
+      ASSERT_EQ(0, receiver_->AddCodec(*i, codecs_[*i].pltype,
+                                       codecs_[*i].channels, codecs_[*i].plfreq,
+                                       nullptr, codecs_[*i].plname));
     }
   }
 
diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h
index cae56b3..22d994e 100644
--- a/webrtc/modules/audio_coding/neteq/include/neteq.h
+++ b/webrtc/modules/audio_coding/neteq/include/neteq.h
@@ -252,6 +252,10 @@
   // (Config::sample_rate_hz) is returned.
   virtual int last_output_sample_rate_hz() const = 0;
 
+  // Returns info about the decoder for the given payload type, or an empty
+  // value if we have no decoder for that payload type.
+  virtual rtc::Optional<CodecInst> GetDecoder(int payload_type) const = 0;
+
   // Not implemented.
   virtual int SetTargetNumberOfChannels() = 0;
 
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index d62d44f..27d47c1 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -431,6 +431,27 @@
   return last_output_sample_rate_hz_;
 }
 
+rtc::Optional<CodecInst> NetEqImpl::GetDecoder(int payload_type) const {
+  rtc::CritScope lock(&crit_sect_);
+  const DecoderDatabase::DecoderInfo* di =
+      decoder_database_->GetDecoderInfo(payload_type);
+  if (!di) {
+    return rtc::Optional<CodecInst>();
+  }
+
+  // Create a CodecInst with some fields set. The remaining fields are zeroed,
+  // but we tell MSan to consider them uninitialized.
+  CodecInst ci = {0};
+  rtc::MsanMarkUninitialized(rtc::MakeArrayView(&ci, 1));
+  ci.pltype = payload_type;
+  std::strncpy(ci.plname, di->name.c_str(), sizeof(ci.plname));
+  ci.plname[sizeof(ci.plname) - 1] = '\0';
+  ci.plfreq = di->IsRed() || di->IsDtmf() ? 8000 : di->SampleRateHz();
+  AudioDecoder* const decoder = di->GetDecoder();
+  ci.channels = decoder ? decoder->Channels() : 1;
+  return rtc::Optional<CodecInst>(ci);
+}
+
 int NetEqImpl::SetTargetNumberOfChannels() {
   return kNotImplemented;
 }
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h
index e74f090..8795ef5 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.h
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h
@@ -169,6 +169,8 @@
 
   int last_output_sample_rate_hz() const override;
 
+  rtc::Optional<CodecInst> GetDecoder(int payload_type) const override;
+
   int SetTargetNumberOfChannels() override;
 
   int SetTargetSampleRate() override;