Extract the parameters for the encoder stack from the CodecManager

BUG=webrtc:5028

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

Cr-Commit-Position: refs/heads/master@{#10750}
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
index 54cf13b..8022935 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.cc
@@ -108,17 +108,7 @@
 }  // namespace
 
 CodecManager::CodecManager()
-    : dtx_enabled_(false),
-      vad_mode_(VADNormal),
-      send_codec_inst_(kEmptyCodecInst),
-      red_enabled_(false),
-      codec_fec_enabled_(false),
-      encoder_is_opus_(false) {
-  // Register the default payload types for RED and CNG.
-  for (const CodecInst& ci : RentACodec::Database()) {
-    RentACodec::RegisterCngPayloadType(&cng_payload_types_, ci);
-    RentACodec::RegisterRedPayloadType(&red_payload_types_, ci);
-  }
+    : send_codec_inst_(kEmptyCodecInst), encoder_is_opus_(false) {
   thread_checker_.DetachFromThread();
 }
 
@@ -134,7 +124,8 @@
   }
 
   int dummy_id = 0;
-  switch (RentACodec::RegisterRedPayloadType(&red_payload_types_, send_codec)) {
+  switch (RentACodec::RegisterRedPayloadType(
+      &codec_stack_params_.red_payload_types, send_codec)) {
     case RentACodec::RegistrationResult::kOk:
       return 0;
     case RentACodec::RegistrationResult::kBadFreq:
@@ -145,7 +136,8 @@
     case RentACodec::RegistrationResult::kSkip:
       break;
   }
-  switch (RentACodec::RegisterCngPayloadType(&cng_payload_types_, send_codec)) {
+  switch (RentACodec::RegisterCngPayloadType(
+      &codec_stack_params_.cng_payload_types, send_codec)) {
     case RentACodec::RegistrationResult::kOk:
       return 0;
     case RentACodec::RegistrationResult::kBadFreq:
@@ -159,11 +151,11 @@
 
   // Set Stereo, and make sure VAD and DTX is turned off.
   if (send_codec.channels != 1) {
-    if (dtx_enabled_) {
+    if (codec_stack_params_.use_cng) {
       WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, dummy_id,
                    "VAD/DTX is turned off, not supported when sending stereo.");
     }
-    dtx_enabled_ = false;
+    codec_stack_params_.use_cng = false;
   }
 
   // Check if the codec is already registered as send codec.
@@ -175,10 +167,6 @@
     new_codec = !old_codec_id || *new_codec_id != *old_codec_id;
   }
 
-  if (RedPayloadType(send_codec.plfreq) == -1) {
-    red_enabled_ = false;
-  }
-
   encoder_is_opus_ = IsOpus(send_codec);
 
   if (new_codec) {
@@ -186,16 +174,17 @@
     RTC_DCHECK(CodecSupported(send_codec));
     if (IsOpus(send_codec)) {
       // VAD/DTX not supported.
-      dtx_enabled_ = false;
+      codec_stack_params_.use_cng = false;
     }
     AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
     if (!enc)
       return -1;
-    RentEncoderStack(enc, send_codec.plfreq);
+    rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
     RTC_DCHECK(CurrentEncoder());
 
-    codec_fec_enabled_ = codec_fec_enabled_ &&
-                         enc->SetFec(codec_fec_enabled_);
+    codec_stack_params_.use_codec_fec =
+        codec_stack_params_.use_codec_fec &&
+        enc->SetFec(codec_stack_params_.use_codec_fec);
 
     send_codec_inst_ = send_codec;
     return 0;
@@ -208,7 +197,7 @@
     AudioEncoder* enc = rent_a_codec_.RentEncoder(send_codec);
     if (!enc)
       return -1;
-    RentEncoderStack(enc, send_codec.plfreq);
+    rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
     RTC_DCHECK(CurrentEncoder());
   }
   send_codec_inst_.plfreq = send_codec.plfreq;
@@ -222,8 +211,9 @@
     send_codec_inst_.rate = send_codec.rate;
   }
 
-  codec_fec_enabled_ =
-      codec_fec_enabled_ && CurrentEncoder()->SetFec(codec_fec_enabled_);
+  codec_stack_params_.use_codec_fec =
+      codec_stack_params_.use_codec_fec &&
+      CurrentEncoder()->SetFec(codec_stack_params_.use_codec_fec);
 
   return 0;
 }
@@ -242,19 +232,18 @@
   memcpy(send_codec_inst_.plname, kName, sizeof(kName));
 
   if (send_codec_inst_.channels != 1)
-    dtx_enabled_ = false;
-  if (codec_fec_enabled_) {
+    codec_stack_params_.use_cng = false;
+  if (codec_stack_params_.use_codec_fec) {
     // Switch FEC on. On failure, remember that FEC is off.
     if (!external_speech_encoder->SetFec(true))
-      codec_fec_enabled_ = false;
+      codec_stack_params_.use_codec_fec = false;
   } else {
     // Switch FEC off. This shouldn't fail.
     const bool success = external_speech_encoder->SetFec(false);
     RTC_DCHECK(success);
   }
 
-  RentEncoderStack(external_speech_encoder,
-                   external_speech_encoder->SampleRateHz());
+  rent_a_codec_.RentEncoderStack(external_speech_encoder, &codec_stack_params_);
 }
 
 rtc::Optional<CodecInst> CodecManager::GetCodecInst() const {
@@ -271,20 +260,23 @@
 }
 
 bool CodecManager::SetCopyRed(bool enable) {
-  if (enable && codec_fec_enabled_) {
+  if (enable && codec_stack_params_.use_codec_fec) {
     WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
                  "Codec internal FEC and RED cannot be co-enabled.");
     return false;
   }
-  if (enable && RedPayloadType(send_codec_inst_.plfreq) == -1) {
+  if (enable &&
+      codec_stack_params_.red_payload_types.count(send_codec_inst_.plfreq) <
+          1) {
     WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
                  "Cannot enable RED at %i Hz.", send_codec_inst_.plfreq);
     return false;
   }
-  if (red_enabled_ != enable) {
-    red_enabled_ = enable;
+  if (codec_stack_params_.use_red != enable) {
+    codec_stack_params_.use_red = enable;
     if (CurrentEncoder())
-      RentEncoderStack(rent_a_codec_.GetEncoder(), send_codec_inst_.plfreq);
+      rent_a_codec_.RentEncoderStack(rent_a_codec_.GetEncoder(),
+                                     &codec_stack_params_);
   }
   return true;
 }
@@ -301,22 +293,23 @@
   if (enable && stereo_send) {
     WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceAudioCoding, 0,
                  "VAD/DTX not supported for stereo sending");
-    dtx_enabled_ = false;
+    codec_stack_params_.use_cng = false;
     return -1;
   }
 
   // If a send codec is registered, set VAD/DTX for the codec.
   if (IsOpus(send_codec_inst_)) {
     // VAD/DTX not supported.
-    dtx_enabled_ = false;
+    codec_stack_params_.use_cng = false;
     return 0;
   }
 
-  if (dtx_enabled_ != enable || vad_mode_ != mode) {
-    dtx_enabled_ = enable;
-    vad_mode_ = mode;
+  if (codec_stack_params_.use_cng != enable ||
+      codec_stack_params_.vad_mode != mode) {
+    codec_stack_params_.use_cng = enable;
+    codec_stack_params_.vad_mode = mode;
     if (enc)
-      RentEncoderStack(enc, send_codec_inst_.plfreq);
+      rent_a_codec_.RentEncoderStack(enc, &codec_stack_params_);
   }
   return 0;
 }
@@ -324,55 +317,26 @@
 void CodecManager::VAD(bool* dtx_enabled,
                        bool* vad_enabled,
                        ACMVADMode* mode) const {
-  *dtx_enabled = dtx_enabled_;
-  *vad_enabled = dtx_enabled_;
-  *mode = vad_mode_;
+  *dtx_enabled = *vad_enabled = codec_stack_params_.use_cng;
+  *mode = codec_stack_params_.vad_mode;
 }
 
 int CodecManager::SetCodecFEC(bool enable_codec_fec) {
-  if (enable_codec_fec == true && red_enabled_ == true) {
+  if (enable_codec_fec && codec_stack_params_.use_red) {
     WEBRTC_TRACE(webrtc::kTraceWarning, webrtc::kTraceAudioCoding, 0,
                  "Codec internal FEC and RED cannot be co-enabled.");
     return -1;
   }
 
   RTC_CHECK(CurrentEncoder());
-  codec_fec_enabled_ =
+  codec_stack_params_.use_codec_fec =
       CurrentEncoder()->SetFec(enable_codec_fec) && enable_codec_fec;
-  return codec_fec_enabled_ == enable_codec_fec ? 0 : -1;
+  return codec_stack_params_.use_codec_fec == enable_codec_fec ? 0 : -1;
 }
 
 AudioDecoder* CodecManager::GetAudioDecoder(const CodecInst& codec) {
   return IsIsac(codec) ? rent_a_codec_.RentIsacDecoder() : nullptr;
 }
 
-int CodecManager::CngPayloadType(int rtp_timestamp_rate_hz) const {
-  RTC_CHECK(rtp_timestamp_rate_hz == 8000 || rtp_timestamp_rate_hz == 16000 ||
-            rtp_timestamp_rate_hz == 32000 || rtp_timestamp_rate_hz == 48000)
-      << rtp_timestamp_rate_hz << " Hz is not supported";
-  auto it = cng_payload_types_.find(rtp_timestamp_rate_hz);
-  return it == cng_payload_types_.end() ? -1 : it->second;
-}
-
-int CodecManager::RedPayloadType(int rtp_timestamp_rate_hz) const {
-  RTC_CHECK(rtp_timestamp_rate_hz == 8000 || rtp_timestamp_rate_hz == 16000 ||
-            rtp_timestamp_rate_hz == 32000 || rtp_timestamp_rate_hz == 48000)
-      << rtp_timestamp_rate_hz << " Hz is not supported";
-  auto it = red_payload_types_.find(rtp_timestamp_rate_hz);
-  return it == red_payload_types_.end() ? -1 : it->second;
-}
-
-void CodecManager::RentEncoderStack(AudioEncoder* speech_encoder,
-                                    int sample_rate_hz) {
-  auto cng_config =
-      dtx_enabled_ ? rtc::Optional<RentACodec::CngConfig>(RentACodec::CngConfig{
-                         CngPayloadType(sample_rate_hz), vad_mode_})
-                   : rtc::Optional<RentACodec::CngConfig>();
-  auto red_pt = red_enabled_
-                    ? rtc::Optional<int>(RedPayloadType(sample_rate_hz))
-                    : rtc::Optional<int>();
-  rent_a_codec_.RentEncoderStack(speech_encoder, cng_config, red_pt);
-}
-
 }  // namespace acm2
 }  // namespace webrtc
diff --git a/webrtc/modules/audio_coding/main/acm2/codec_manager.h b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
index 3cf3030..7670bbd 100644
--- a/webrtc/modules/audio_coding/main/acm2/codec_manager.h
+++ b/webrtc/modules/audio_coding/main/acm2/codec_manager.h
@@ -54,9 +54,9 @@
   // null.
   AudioDecoder* GetAudioDecoder(const CodecInst& codec);
 
-  bool red_enabled() const { return red_enabled_; }
+  bool red_enabled() const { return codec_stack_params_.use_red; }
 
-  bool codec_fec_enabled() const { return codec_fec_enabled_; }
+  bool codec_fec_enabled() const { return codec_stack_params_.use_codec_fec; }
 
   AudioEncoder* CurrentEncoder() { return rent_a_codec_.GetEncoderStack(); }
   const AudioEncoder* CurrentEncoder() const {
@@ -66,21 +66,10 @@
   bool CurrentEncoderIsOpus() const { return encoder_is_opus_; }
 
  private:
-  int CngPayloadType(int sample_rate_hz) const;
-  int RedPayloadType(int sample_rate_hz) const;
-  void RentEncoderStack(AudioEncoder* speech_encoder, int sample_rate_hz);
-
   rtc::ThreadChecker thread_checker_;
-  bool dtx_enabled_;
-  ACMVADMode vad_mode_;
   CodecInst send_codec_inst_;
-  bool red_enabled_;
-  bool codec_fec_enabled_;
   RentACodec rent_a_codec_;
-
-  // Maps from RTP timestamp rate (in Hz) to payload type.
-  std::map<int, int> cng_payload_types_;
-  std::map<int, int> red_payload_types_;
+  RentACodec::StackParameters codec_stack_params_;
 
   bool encoder_is_opus_;
 
diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc
index c2a4024..3281814 100644
--- a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc
+++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.cc
@@ -187,14 +187,14 @@
 #endif
 }
 
-rtc::scoped_ptr<AudioEncoder> CreateCngEncoder(
-    AudioEncoder* encoder,
-    RentACodec::CngConfig cng_config) {
+rtc::scoped_ptr<AudioEncoder> CreateCngEncoder(AudioEncoder* encoder,
+                                               int payload_type,
+                                               ACMVADMode vad_mode) {
   AudioEncoderCng::Config config;
   config.num_channels = encoder->NumChannels();
-  config.payload_type = cng_config.cng_payload_type;
+  config.payload_type = payload_type;
   config.speech_encoder = encoder;
-  switch (cng_config.vad_mode) {
+  switch (vad_mode) {
     case VADNormal:
       config.vad_mode = Vad::kVadNormal;
       break;
@@ -239,26 +239,45 @@
   return speech_encoder_.get();
 }
 
-AudioEncoder* RentACodec::RentEncoderStack(
-    AudioEncoder* speech_encoder,
-    rtc::Optional<CngConfig> cng_config,
-    rtc::Optional<int> red_payload_type) {
+RentACodec::StackParameters::StackParameters() {
+  // Register the default payload types for RED and CNG.
+  for (const CodecInst& ci : RentACodec::Database()) {
+    RentACodec::RegisterCngPayloadType(&cng_payload_types, ci);
+    RentACodec::RegisterRedPayloadType(&red_payload_types, ci);
+  }
+}
+
+RentACodec::StackParameters::~StackParameters() = default;
+
+AudioEncoder* RentACodec::RentEncoderStack(AudioEncoder* speech_encoder,
+                                           StackParameters* param) {
   RTC_DCHECK(speech_encoder);
-  if (cng_config || red_payload_type) {
+
+  auto pt = [&speech_encoder](const std::map<int, int>& m) {
+    auto it = m.find(speech_encoder->SampleRateHz());
+    return it == m.end() ? rtc::Optional<int>()
+                         : rtc::Optional<int>(it->second);
+  };
+  auto cng_pt = pt(param->cng_payload_types);
+  param->use_cng = param->use_cng && cng_pt;
+  auto red_pt = pt(param->red_payload_types);
+  param->use_red = param->use_red && red_pt;
+
+  if (param->use_cng || param->use_red) {
     // The RED and CNG encoders need to be in sync with the speech encoder, so
     // reset the latter to ensure its buffer is empty.
     speech_encoder->Reset();
   }
   encoder_stack_ = speech_encoder;
-  if (red_payload_type) {
-    red_encoder_ = CreateRedEncoder(encoder_stack_, *red_payload_type);
+  if (param->use_red) {
+    red_encoder_ = CreateRedEncoder(encoder_stack_, *red_pt);
     if (red_encoder_)
       encoder_stack_ = red_encoder_.get();
   } else {
     red_encoder_.reset();
   }
-  if (cng_config) {
-    cng_encoder_ = CreateCngEncoder(encoder_stack_, *cng_config);
+  if (param->use_cng) {
+    cng_encoder_ = CreateCngEncoder(encoder_stack_, *cng_pt, param->vad_mode);
     encoder_stack_ = cng_encoder_.get();
   } else {
     cng_encoder_.reset();
diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h
index db728ae..45d46bb 100644
--- a/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h
+++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec.h
@@ -200,18 +200,27 @@
   // successful call to this function, or until the Rent-A-Codec is destroyed.
   AudioEncoder* RentEncoder(const CodecInst& codec_inst);
 
-  // Creates and returns an audio encoder stack where the given speech encoder
-  // is augmented with the specified CNG/VAD and RED encoders. Leave either
-  // optional field blank if you don't want the corresponding gizmo in the
-  // stack. The returned encoder is live until the next successful call to this
-  // function, or until the Rent-A-Codec is destroyed.
-  struct CngConfig {
-    int cng_payload_type;
-    ACMVADMode vad_mode;
+  struct StackParameters {
+    StackParameters();
+    ~StackParameters();
+
+    bool use_codec_fec = false;
+    bool use_red = false;
+    bool use_cng = false;
+    ACMVADMode vad_mode = VADNormal;
+
+    // Maps from RTP timestamp rate (in Hz) to payload type.
+    std::map<int, int> cng_payload_types;
+    std::map<int, int> red_payload_types;
   };
+
+  // Creates and returns an audio encoder stack constructed to the given
+  // specification. If the specification isn't compatible with the encoder, it
+  // will be changed to match (things will be switched off). The returned
+  // encoder is live until the next successful call to this function, or until
+  // the Rent-A-Codec is destroyed.
   AudioEncoder* RentEncoderStack(AudioEncoder* speech_encoder,
-                                 rtc::Optional<CngConfig> cng_config,
-                                 rtc::Optional<int> red_payload_type);
+                                 StackParameters* param);
 
   // Get the last return values of RentEncoder and RentEncoderStack, or null if
   // they haven't been called.
diff --git a/webrtc/modules/audio_coding/main/acm2/rent_a_codec_unittest.cc b/webrtc/modules/audio_coding/main/acm2/rent_a_codec_unittest.cc
index 6938051..d2f40ed 100644
--- a/webrtc/modules/audio_coding/main/acm2/rent_a_codec_unittest.cc
+++ b/webrtc/modules/audio_coding/main/acm2/rent_a_codec_unittest.cc
@@ -32,10 +32,9 @@
   void CreateCodec() {
     speech_encoder_ = rent_a_codec_.RentEncoder(kDefaultCodecInst);
     ASSERT_TRUE(speech_encoder_);
-    encoder_ = rent_a_codec_.RentEncoderStack(
-        speech_encoder_, rtc::Optional<RentACodec::CngConfig>(
-                             RentACodec::CngConfig{kCngPt, VADNormal}),
-        rtc::Optional<int>());
+    RentACodec::StackParameters param;
+    param.use_cng = true;
+    encoder_ = rent_a_codec_.RentEncoderStack(speech_encoder_, &param);
   }
 
   void EncodeAndVerify(size_t expected_out_length,
@@ -104,10 +103,8 @@
 TEST(RentACodecTest, ExternalEncoder) {
   MockAudioEncoder external_encoder;
   RentACodec rac;
-  EXPECT_EQ(&external_encoder,
-            rac.RentEncoderStack(&external_encoder,
-                                 rtc::Optional<RentACodec::CngConfig>(),
-                                 rtc::Optional<int>()));
+  RentACodec::StackParameters param;
+  EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, &param));
   const int kSampleRateHz = 8000;
   const int kPacketSizeSamples = kSampleRateHz / 100;
   int16_t audio[kPacketSizeSamples] = {0};
@@ -143,19 +140,14 @@
   codec_inst.pacsize = kPacketSizeSamples;
   AudioEncoder* enc = rac.RentEncoder(codec_inst);
   ASSERT_TRUE(enc);
-  EXPECT_EQ(enc,
-            rac.RentEncoderStack(enc, rtc::Optional<RentACodec::CngConfig>(),
-                                 rtc::Optional<int>()));
+  EXPECT_EQ(enc, rac.RentEncoderStack(enc, &param));
 
   // Don't expect any more calls to the external encoder.
   info = rac.GetEncoderStack()->Encode(1, audio, arraysize(encoded), encoded);
   external_encoder.Mark("B");
 
   // Change back to external encoder again.
-  EXPECT_EQ(&external_encoder,
-            rac.RentEncoderStack(&external_encoder,
-                                 rtc::Optional<RentACodec::CngConfig>(),
-                                 rtc::Optional<int>()));
+  EXPECT_EQ(&external_encoder, rac.RentEncoderStack(&external_encoder, &param));
   info = rac.GetEncoderStack()->Encode(2, audio, arraysize(encoded), encoded);
   EXPECT_EQ(2u, info.encoded_timestamp);
 }
@@ -177,16 +169,14 @@
     EXPECT_CALL(speech_encoder, Die());
   }
 
-  auto cng_cfg = use_cng ? rtc::Optional<RentACodec::CngConfig>(
-                               RentACodec::CngConfig{17, VADNormal})
-                         : rtc::Optional<RentACodec::CngConfig>();
-  auto red_pt = use_red ? rtc::Optional<int>(19) : rtc::Optional<int>();
+  RentACodec::StackParameters param1, param2;
+  param2.use_cng = use_cng;
+  param2.use_red = use_red;
   speech_encoder.Mark("disabled");
   RentACodec rac;
-  rac.RentEncoderStack(&speech_encoder, rtc::Optional<RentACodec::CngConfig>(),
-                       rtc::Optional<int>());
+  rac.RentEncoderStack(&speech_encoder, &param1);
   speech_encoder.Mark("enabled");
-  rac.RentEncoderStack(&speech_encoder, cng_cfg, red_pt);
+  rac.RentEncoderStack(&speech_encoder, &param2);
 }
 
 TEST(RentACodecTest, CngResetsSpeechEncoder) {