Reland "WebRtcVoiceMediaChannel::AddRecvStream: Don't call SetRecPayloadType"

BUG=webrtc:5805

Review-Url: https://codereview.webrtc.org/2774833003
Cr-Commit-Position: refs/heads/master@{#17391}
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/acm2/acm_receiver.cc
index 21dbc74..4980d27 100644
--- a/webrtc/modules/audio_coding/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/acm2/acm_receiver.cc
@@ -179,6 +179,10 @@
   return 0;
 }
 
+void AcmReceiver::SetCodecs(const std::map<int, SdpAudioFormat>& codecs) {
+  neteq_->SetCodecs(codecs);
+}
+
 int32_t AcmReceiver::AddCodec(int acm_codec_id,
                               uint8_t payload_type,
                               size_t channels,
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver.h b/webrtc/modules/audio_coding/acm2/acm_receiver.h
index 63ed43d..8f0963f 100644
--- a/webrtc/modules/audio_coding/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/acm2/acm_receiver.h
@@ -79,6 +79,9 @@
   //
   int GetAudio(int desired_freq_hz, AudioFrame* audio_frame, bool* muted);
 
+  // Replace the current set of decoders with the specified set.
+  void SetCodecs(const std::map<int, SdpAudioFormat>& codecs);
+
   //
   // Adds a new codec to the NetEq codec database.
   //
diff --git a/webrtc/modules/audio_coding/acm2/audio_coding_module.cc b/webrtc/modules/audio_coding/acm2/audio_coding_module.cc
index daeea35..bc814f6 100644
--- a/webrtc/modules/audio_coding/acm2/audio_coding_module.cc
+++ b/webrtc/modules/audio_coding/acm2/audio_coding_module.cc
@@ -121,6 +121,8 @@
   // Get current playout frequency.
   int PlayoutFrequency() const override;
 
+  void SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) override;
+
   bool RegisterReceiveCodec(int rtp_payload_type,
                             const SdpAudioFormat& audio_format) override;
 
@@ -318,16 +320,6 @@
           webrtc::AudioEncoder::CodecType::kMaxLoggedAudioCodecTypes));
 }
 
-// TODO(turajs): the same functionality is used in NetEq. If both classes
-// need them, make it a static function in ACMCodecDB.
-bool IsCodecRED(const CodecInst& codec) {
-  return (STR_CASE_CMP(codec.plname, "RED") == 0);
-}
-
-bool IsCodecCN(const CodecInst& codec) {
-  return (STR_CASE_CMP(codec.plname, "CN") == 0);
-}
-
 // Stereo-to-mono can be used as in-place.
 int DownMix(const AudioFrame& frame,
             size_t length_out_buff,
@@ -956,19 +948,6 @@
   receiver_.SetMaximumDelay(0);
   receiver_.FlushBuffers();
 
-  // Register RED and CN.
-  auto db = acm2::RentACodec::Database();
-  for (size_t i = 0; i < db.size(); i++) {
-    if (IsCodecRED(db[i]) || IsCodecCN(db[i])) {
-      if (receiver_.AddCodec(static_cast<int>(i),
-                             static_cast<uint8_t>(db[i].pltype), 1,
-                             db[i].plfreq, nullptr, db[i].plname) < 0) {
-        WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, id_,
-                     "Cannot register master codec.");
-        return -1;
-      }
-    }
-  }
   receiver_initialized_ = true;
   return 0;
 }
@@ -987,6 +966,12 @@
   return receiver_.last_output_sample_rate_hz();
 }
 
+void AudioCodingModuleImpl::SetReceiveCodecs(
+    const std::map<int, SdpAudioFormat>& codecs) {
+  rtc::CritScope lock(&acm_crit_sect_);
+  receiver_.SetCodecs(codecs);
+}
+
 bool AudioCodingModuleImpl::RegisterReceiveCodec(
     int rtp_payload_type,
     const SdpAudioFormat& audio_format) {
diff --git a/webrtc/modules/audio_coding/include/audio_coding_module.h b/webrtc/modules/audio_coding/include/audio_coding_module.h
index 1893b62..b5cbff2 100644
--- a/webrtc/modules/audio_coding/include/audio_coding_module.h
+++ b/webrtc/modules/audio_coding/include/audio_coding_module.h
@@ -485,6 +485,10 @@
   //
   virtual int32_t PlayoutFrequency() const = 0;
 
+  // Replace any existing decoders with the given payload type -> decoder map.
+  virtual void SetReceiveCodecs(
+      const std::map<int, SdpAudioFormat>& codecs) = 0;
+
   // Registers a decoder for the given payload type. Returns true iff
   // successful.
   virtual bool RegisterReceiveCodec(int rtp_payload_type,
diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.cc b/webrtc/modules/audio_coding/neteq/decoder_database.cc
index d147d67..8cd4386 100644
--- a/webrtc/modules/audio_coding/neteq/decoder_database.cc
+++ b/webrtc/modules/audio_coding/neteq/decoder_database.cc
@@ -123,6 +123,38 @@
   active_cng_decoder_type_ = -1;
 }
 
+std::vector<int> DecoderDatabase::SetCodecs(
+    const std::map<int, SdpAudioFormat>& codecs) {
+  // First collect all payload types that we'll remove or reassign, then remove
+  // them from the database.
+  std::vector<int> changed_payload_types;
+  for (const std::pair<uint8_t, const DecoderInfo&> kv : decoders_) {
+    auto i = codecs.find(kv.first);
+    if (i == codecs.end() || i->second != kv.second.GetFormat()) {
+      changed_payload_types.push_back(kv.first);
+    }
+  }
+  for (int pl_type : changed_payload_types) {
+    Remove(pl_type);
+  }
+
+  // Enter the new and changed payload type mappings into the database.
+  for (const auto& kv : codecs) {
+    const int& rtp_payload_type = kv.first;
+    const SdpAudioFormat& audio_format = kv.second;
+    RTC_DCHECK_GE(rtp_payload_type, 0);
+    RTC_DCHECK_LE(rtp_payload_type, 0x7f);
+    if (decoders_.count(rtp_payload_type) == 0) {
+      decoders_.insert(std::make_pair(
+          rtp_payload_type, DecoderInfo(audio_format, decoder_factory_.get())));
+    } else {
+      // The mapping for this payload type hasn't changed.
+    }
+  }
+
+  return changed_payload_types;
+}
+
 int DecoderDatabase::RegisterPayload(uint8_t rtp_payload_type,
                                      NetEqDecoder codec_type,
                                      const std::string& name) {
diff --git a/webrtc/modules/audio_coding/neteq/decoder_database.h b/webrtc/modules/audio_coding/neteq/decoder_database.h
index ec470f8..35d1d0d 100644
--- a/webrtc/modules/audio_coding/neteq/decoder_database.h
+++ b/webrtc/modules/audio_coding/neteq/decoder_database.h
@@ -149,6 +149,11 @@
   // using InsertExternal().
   virtual void Reset();
 
+  // Replaces the existing set of decoders with the given set. Returns the
+  // payload types that were reassigned or removed while doing so.
+  virtual std::vector<int> SetCodecs(
+      const std::map<int, SdpAudioFormat>& codecs);
+
   // Registers |rtp_payload_type| as a decoder of type |codec_type|. The |name|
   // is only used to populate the name field in the DecoderInfo struct in the
   // database, and can be arbitrary (including empty). Returns kOK on success;
diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h
index ea05940..450318e 100644
--- a/webrtc/modules/audio_coding/neteq/include/neteq.h
+++ b/webrtc/modules/audio_coding/neteq/include/neteq.h
@@ -157,6 +157,9 @@
   // Returns kOK on success, or kFail in case of an error.
   virtual int GetAudio(AudioFrame* audio_frame, bool* muted) = 0;
 
+  // Replaces the current set of decoders with the given one.
+  virtual void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) = 0;
+
   // Associates |rtp_payload_type| with |codec| and |codec_name|, and stores the
   // information in the codec database. Returns 0 on success, -1 on failure.
   // The name is only used to provide information back to the caller about the
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index 5015b7e..501e567 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -212,6 +212,15 @@
   return kOK;
 }
 
+void NetEqImpl::SetCodecs(const std::map<int, SdpAudioFormat>& codecs) {
+  rtc::CritScope lock(&crit_sect_);
+  const std::vector<int> changed_payload_types =
+      decoder_database_->SetCodecs(codecs);
+  for (const int pt : changed_payload_types) {
+    packet_buffer_->DiscardPacketsWithPayloadType(pt);
+  }
+}
+
 int NetEqImpl::RegisterPayloadType(NetEqDecoder codec,
                                    const std::string& name,
                                    uint8_t rtp_payload_type) {
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h
index a8c3462..88c0308 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.h
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h
@@ -111,6 +111,8 @@
 
   int GetAudio(AudioFrame* audio_frame, bool* muted) override;
 
+  void SetCodecs(const std::map<int, SdpAudioFormat>& codecs) override;
+
   int RegisterPayloadType(NetEqDecoder codec,
                           const std::string& codec_name,
                           uint8_t rtp_payload_type) override;
diff --git a/webrtc/modules/rtp_rtcp/BUILD.gn b/webrtc/modules/rtp_rtcp/BUILD.gn
index 541edd9..c1d69e0 100644
--- a/webrtc/modules/rtp_rtcp/BUILD.gn
+++ b/webrtc/modules/rtp_rtcp/BUILD.gn
@@ -168,6 +168,7 @@
   deps = [
     "../..:webrtc_common",
     "../../api:transport_api",
+    "../../api/audio_codecs:audio_codecs_api",
     "../../base:gtest_prod",
     "../../base:rtc_base_approved",
     "../../base:rtc_task_queue",
@@ -175,6 +176,7 @@
     "../../common_video",
     "../../logging:rtc_event_log_api",
     "../../system_wrappers",
+    "../audio_coding:audio_format_conversion",
     "../remote_bitrate_estimator",
   ]
 
diff --git a/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h b/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h
index 767bd07..029de5d 100644
--- a/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h
+++ b/webrtc/modules/rtp_rtcp/include/rtp_payload_registry.h
@@ -15,6 +15,7 @@
 #include <memory>
 #include <set>
 
+#include "webrtc/api/audio_codecs/audio_format.h"
 #include "webrtc/base/criticalsection.h"
 #include "webrtc/base/deprecation.h"
 #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_strategy.h"
@@ -43,6 +44,10 @@
 
   // TODO(magjed): Split RTPPayloadRegistry into separate Audio and Video class
   // and simplify the code. http://crbug/webrtc/6743.
+
+  // Replace all audio receive payload types with the given map.
+  void SetAudioReceivePayloads(std::map<int, SdpAudioFormat> codecs);
+
   int32_t RegisterReceivePayload(const CodecInst& audio_codec,
                                  bool* created_new_payload_type);
   int32_t RegisterReceivePayload(const VideoCodec& video_codec);
diff --git a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
index 1023bf8..234fd7f 100644
--- a/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
+++ b/webrtc/modules/rtp_rtcp/source/rtp_payload_registry.cc
@@ -16,6 +16,7 @@
 #include "webrtc/base/logging.h"
 #include "webrtc/base/stringutils.h"
 #include "webrtc/common_types.h"
+#include "webrtc/modules/audio_coding/codecs/audio_format_conversion.h"
 #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
 
 namespace webrtc {
@@ -119,6 +120,31 @@
 
 RTPPayloadRegistry::~RTPPayloadRegistry() = default;
 
+void RTPPayloadRegistry::SetAudioReceivePayloads(
+    std::map<int, SdpAudioFormat> codecs) {
+  rtc::CritScope cs(&crit_sect_);
+
+#if RTC_DCHECK_IS_ON
+  RTC_DCHECK(!used_for_video_);
+  used_for_audio_ = true;
+#endif
+
+  payload_type_map_.clear();
+  for (const auto& kv : codecs) {
+    const int& rtp_payload_type = kv.first;
+    const SdpAudioFormat& audio_format = kv.second;
+    const CodecInst ci = SdpToCodecInst(rtp_payload_type, audio_format);
+    RTC_DCHECK(IsPayloadTypeValid(rtp_payload_type));
+    payload_type_map_.insert(
+        std::make_pair(rtp_payload_type, CreatePayloadType(ci)));
+  }
+
+  // Clear the value of last received payload type since it might mean
+  // something else now.
+  last_received_payload_type_ = -1;
+  last_received_media_payload_type_ = -1;
+}
+
 int32_t RTPPayloadRegistry::RegisterReceivePayload(const CodecInst& audio_codec,
                                                    bool* created_new_payload) {
   rtc::CritScope cs(&crit_sect_);