Change how background noise mode in NetEq is set

This change prepares for switching default background noise (bgn) mode
from on to off. The actual switch will be done later.

In this change, the bgn mode is included as a setting in NetEq's config
struct. We're also removing the connection between playout modes and
bgn modes in ACM. In practice this means that bgn mode will change from
off to on for streaming mode, but since the playout modes are not used
it does not matter.

BUG=3519
R=tina.legrand@webrtc.org

Review URL: https://webrtc-codereview.appspot.com/21749004

git-svn-id: http://webrtc.googlecode.com/svn/trunk@6843 4adac7df-926f-26a2-2b94-8c16560cd09d
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
index f40250f..0c7e6c7 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -210,29 +210,25 @@
 
 // TODO(turajs): use one set of enumerators, e.g. the one defined in
 // common_types.h
+// TODO(henrik.lundin): This method is not used any longer. The call hierarchy
+// stops in voe::Channel::SetNetEQPlayoutMode(). Remove it.
 void AcmReceiver::SetPlayoutMode(AudioPlayoutMode mode) {
   enum NetEqPlayoutMode playout_mode = kPlayoutOn;
-  enum NetEqBackgroundNoiseMode bgn_mode = kBgnOn;
   switch (mode) {
     case voice:
       playout_mode = kPlayoutOn;
-      bgn_mode = kBgnOn;
       break;
     case fax:  // No change to background noise mode.
       playout_mode = kPlayoutFax;
-      bgn_mode = neteq_->BackgroundNoiseMode();
       break;
     case streaming:
       playout_mode = kPlayoutStreaming;
-      bgn_mode = kBgnOff;
       break;
     case off:
       playout_mode = kPlayoutOff;
-      bgn_mode = kBgnOff;
       break;
   }
   neteq_->SetPlayoutMode(playout_mode);
-  neteq_->SetBackgroundNoiseMode(bgn_mode);
 }
 
 AudioPlayoutMode AcmReceiver::PlayoutMode() const {
@@ -800,10 +796,6 @@
   return true;
 }
 
-NetEqBackgroundNoiseMode AcmReceiver::BackgroundNoiseModeForTest() const {
-  return neteq_->BackgroundNoiseMode();
-}
-
 int AcmReceiver::RtpHeaderToCodecIndex(
     const RTPHeader &rtp_header, const uint8_t* payload) const {
   uint8_t payload_type = rtp_header.payloadType;
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
index dd6de52..180b4ba 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
@@ -308,12 +308,6 @@
   std::vector<uint16_t> GetNackList(int round_trip_time_ms) const;
 
   //
-  // Returns the background noise mode. This is only for testing and ACM is not
-  // calling this function. Used in acm_receiver_unittest.cc.
-  //
-  NetEqBackgroundNoiseMode BackgroundNoiseModeForTest() const;
-
-  //
   // Get statistics of calls to GetAudio().
   void GetDecodingCallStatistics(AudioDecodingCallStats* stats) const;
 
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest.cc
index 4234f14..81c97e5 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest.cc
@@ -247,34 +247,19 @@
   }
 }
 
-// Changing playout mode to FAX should not change the background noise mode.
-TEST_F(AcmReceiverTest,
-       DISABLED_ON_ANDROID(PlayoutModeAndBackgroundNoiseMode)) {
-  EXPECT_EQ(kBgnOn, receiver_->BackgroundNoiseModeForTest());  // Default
-
+// Verify that the playout mode is set correctly.
+TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(PlayoutMode)) {
   receiver_->SetPlayoutMode(voice);
   EXPECT_EQ(voice, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOn, receiver_->BackgroundNoiseModeForTest());
 
   receiver_->SetPlayoutMode(streaming);
   EXPECT_EQ(streaming, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOff, receiver_->BackgroundNoiseModeForTest());
 
   receiver_->SetPlayoutMode(fax);
   EXPECT_EQ(fax, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOff, receiver_->BackgroundNoiseModeForTest());
 
   receiver_->SetPlayoutMode(off);
   EXPECT_EQ(off, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOff, receiver_->BackgroundNoiseModeForTest());
-
-  // Change to voice then to FAX.
-  receiver_->SetPlayoutMode(voice);
-  EXPECT_EQ(voice, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOn, receiver_->BackgroundNoiseModeForTest());
-  receiver_->SetPlayoutMode(fax);
-  EXPECT_EQ(fax, receiver_->PlayoutMode());
-  EXPECT_EQ(kBgnOn, receiver_->BackgroundNoiseModeForTest());
 }
 
 TEST_F(AcmReceiverTest, DISABLED_ON_ANDROID(PostdecodingVad)) {
diff --git a/webrtc/modules/audio_coding/neteq/background_noise.cc b/webrtc/modules/audio_coding/neteq/background_noise.cc
index e00c4f6..8d5a293 100644
--- a/webrtc/modules/audio_coding/neteq/background_noise.cc
+++ b/webrtc/modules/audio_coding/neteq/background_noise.cc
@@ -24,7 +24,7 @@
 BackgroundNoise::BackgroundNoise(size_t num_channels)
     : num_channels_(num_channels),
       channel_parameters_(new ChannelParameters[num_channels_]),
-      mode_(kBgnOn) {
+      mode_(NetEq::kBgnOn) {
   Reset();
 }
 
diff --git a/webrtc/modules/audio_coding/neteq/background_noise.h b/webrtc/modules/audio_coding/neteq/background_noise.h
index 8fb310e..5c9f39b 100644
--- a/webrtc/modules/audio_coding/neteq/background_noise.h
+++ b/webrtc/modules/audio_coding/neteq/background_noise.h
@@ -68,11 +68,11 @@
 
   // Accessors.
   bool initialized() const { return initialized_; }
-  NetEqBackgroundNoiseMode mode() const { return mode_; }
+  NetEq::BackgroundNoiseMode mode() const { return mode_; }
 
   // Sets the mode of the background noise playout for cases when there is long
   // duration of packet loss.
-  void set_mode(NetEqBackgroundNoiseMode mode) { mode_ = mode; }
+  void set_mode(NetEq::BackgroundNoiseMode mode) { mode_ = mode; }
 
  private:
   static const int kThresholdIncrement = 229;  // 0.0035 in Q16.
@@ -128,7 +128,7 @@
   size_t num_channels_;
   scoped_ptr<ChannelParameters[]> channel_parameters_;
   bool initialized_;
-  NetEqBackgroundNoiseMode mode_;
+  NetEq::BackgroundNoiseMode mode_;
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundNoise);
 };
diff --git a/webrtc/modules/audio_coding/neteq/expand.cc b/webrtc/modules/audio_coding/neteq/expand.cc
index 14a7798..3f7ed24 100644
--- a/webrtc/modules/audio_coding/neteq/expand.cc
+++ b/webrtc/modules/audio_coding/neteq/expand.cc
@@ -806,7 +806,7 @@
                                      int16_t* buffer) {
   static const int kNoiseLpcOrder = BackgroundNoise::kMaxLpcOrder;
   int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
-  assert(kMaxSampleRate / 8000 * 125 >= (int)num_noise_samples);
+  assert(static_cast<size_t>(kMaxSampleRate / 8000 * 125) >= num_noise_samples);
   int16_t* noise_samples = &buffer[kNoiseLpcOrder];
   if (background_noise_->initialized()) {
     // Use background noise parameters.
@@ -838,8 +838,9 @@
 
     // Unmute the background noise.
     int16_t bgn_mute_factor = background_noise_->MuteFactor(channel);
-    NetEqBackgroundNoiseMode bgn_mode = background_noise_->mode();
-    if (bgn_mode == kBgnFade && too_many_expands && bgn_mute_factor > 0) {
+    NetEq::BackgroundNoiseMode bgn_mode = background_noise_->mode();
+    if (bgn_mode == NetEq::kBgnFade && too_many_expands &&
+        bgn_mute_factor > 0) {
       // Fade BGN to zero.
       // Calculate muting slope, approximately -2^18 / fs_hz.
       int16_t mute_slope;
@@ -862,8 +863,8 @@
     } else if (bgn_mute_factor < 16384) {
       // If mode is kBgnOff, or if kBgnFade has started fading,
       // Use regular |mute_slope|.
-      if (!stop_muting_ && bgn_mode != kBgnOff &&
-          !(bgn_mode == kBgnFade && too_many_expands)) {
+      if (!stop_muting_ && bgn_mode != NetEq::kBgnOff &&
+          !(bgn_mode == NetEq::kBgnFade && too_many_expands)) {
         DspHelper::UnmuteSignal(noise_samples,
                                 static_cast<int>(num_noise_samples),
                                 &bgn_mute_factor,
@@ -893,7 +894,7 @@
   // just as good to generate all of the vector in one call.
   size_t samples_generated = 0;
   const size_t kMaxRandSamples = RandomVector::kRandomTableSize;
-  while(samples_generated < length) {
+  while (samples_generated < length) {
     size_t rand_length = std::min(length - samples_generated, kMaxRandSamples);
     random_vector_->IncreaseSeedIncrement(seed_increment);
     random_vector_->Generate(rand_length, &random_vector[samples_generated]);
diff --git a/webrtc/modules/audio_coding/neteq/interface/neteq.h b/webrtc/modules/audio_coding/neteq/interface/neteq.h
index c67ab12..fdd000a 100644
--- a/webrtc/modules/audio_coding/neteq/interface/neteq.h
+++ b/webrtc/modules/audio_coding/neteq/interface/neteq.h
@@ -58,27 +58,29 @@
   kPlayoutStreaming
 };
 
-enum NetEqBackgroundNoiseMode {
-  kBgnOn,    // Default behavior with eternal noise.
-  kBgnFade,  // Noise fades to zero after some time.
-  kBgnOff    // Background noise is always zero.
-};
-
 // This is the interface class for NetEq.
 class NetEq {
  public:
+  enum BackgroundNoiseMode {
+    kBgnOn,    // Default behavior with eternal noise.
+    kBgnFade,  // Noise fades to zero after some time.
+    kBgnOff    // Background noise is always zero.
+  };
+
   struct Config {
     Config()
         : sample_rate_hz(16000),
           enable_audio_classifier(false),
           max_packets_in_buffer(50),
           // |max_delay_ms| has the same effect as calling SetMaximumDelay().
-          max_delay_ms(2000) {}
+          max_delay_ms(2000),
+          background_noise_mode(kBgnOn) {}
 
     int sample_rate_hz;  // Initial vale. Will change with input data.
     bool enable_audio_classifier;
     int max_packets_in_buffer;
     int max_delay_ms;
+    BackgroundNoiseMode background_noise_mode;
   };
 
   enum ReturnCodes {
@@ -259,12 +261,6 @@
   virtual int DecodedRtpInfo(int* sequence_number,
                              uint32_t* timestamp) const = 0;
 
-  // Sets the background noise mode.
-  virtual void SetBackgroundNoiseMode(NetEqBackgroundNoiseMode mode) = 0;
-
-  // Gets the background noise mode.
-  virtual NetEqBackgroundNoiseMode BackgroundNoiseMode() const = 0;
-
  protected:
   NetEq() {}
 
diff --git a/webrtc/modules/audio_coding/neteq/neteq.cc b/webrtc/modules/audio_coding/neteq/neteq.cc
index 7edacde..420165b 100644
--- a/webrtc/modules/audio_coding/neteq/neteq.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq.cc
@@ -44,7 +44,7 @@
   ExpandFactory* expand_factory = new ExpandFactory;
   PreemptiveExpandFactory* preemptive_expand_factory =
       new PreemptiveExpandFactory;
-  return new NetEqImpl(config.sample_rate_hz,
+  return new NetEqImpl(config,
                        buffer_level_filter,
                        decoder_database,
                        delay_manager,
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.cc b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
index 64a8660..a184fc3 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -49,7 +49,7 @@
 
 namespace webrtc {
 
-NetEqImpl::NetEqImpl(int fs,
+NetEqImpl::NetEqImpl(const NetEq::Config& config,
                      BufferLevelFilter* buffer_level_filter,
                      DecoderDatabase* decoder_database,
                      DelayManager* delay_manager,
@@ -90,8 +90,10 @@
       first_packet_(true),
       error_code_(0),
       decoder_error_code_(0),
+      background_noise_mode_(config.background_noise_mode),
       decoded_packet_sequence_number_(-1),
       decoded_packet_timestamp_(0) {
+  int fs = config.sample_rate_hz;
   if (fs != 8000 && fs != 16000 && fs != 32000 && fs != 48000) {
     LOG(LS_ERROR) << "Sample rate " << fs << " Hz not supported. " <<
         "Changing to 8000 Hz.";
@@ -384,18 +386,6 @@
   return 0;
 }
 
-void NetEqImpl::SetBackgroundNoiseMode(NetEqBackgroundNoiseMode mode) {
-  CriticalSectionScoped lock(crit_sect_.get());
-  assert(background_noise_.get());
-  background_noise_->set_mode(mode);
-}
-
-NetEqBackgroundNoiseMode NetEqImpl::BackgroundNoiseMode() const {
-  CriticalSectionScoped lock(crit_sect_.get());
-  assert(background_noise_.get());
-  return background_noise_->mode();
-}
-
 const SyncBuffer* NetEqImpl::sync_buffer_for_test() const {
   CriticalSectionScoped lock(crit_sect_.get());
   return sync_buffer_.get();
@@ -1873,14 +1863,9 @@
   // Delete sync buffer and create a new one.
   sync_buffer_.reset(new SyncBuffer(channels, kSyncBufferSize * fs_mult_));
 
-
-  // Delete BackgroundNoise object and create a new one, while preserving its
-  // mode.
-  NetEqBackgroundNoiseMode current_mode = kBgnOn;
-  if (background_noise_.get())
-    current_mode = background_noise_->mode();
+  // Delete BackgroundNoise object and create a new one.
   background_noise_.reset(new BackgroundNoise(channels));
-  background_noise_->set_mode(current_mode);
+  background_noise_->set_mode(background_noise_mode_);
 
   // Reset random vector.
   random_vector_.Reset();
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl.h b/webrtc/modules/audio_coding/neteq/neteq_impl.h
index e92babd..bc7734b 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.h
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h
@@ -58,7 +58,7 @@
  public:
   // Creates a new NetEqImpl object. The object will assume ownership of all
   // injected dependencies, and will delete them when done.
-  NetEqImpl(int fs,
+  NetEqImpl(const NetEq::Config& config,
             BufferLevelFilter* buffer_level_filter,
             DecoderDatabase* decoder_database,
             DelayManager* delay_manager,
@@ -191,12 +191,6 @@
   // This method is to facilitate NACK.
   virtual int DecodedRtpInfo(int* sequence_number, uint32_t* timestamp) const;
 
-  // Sets background noise mode.
-  virtual void SetBackgroundNoiseMode(NetEqBackgroundNoiseMode mode);
-
-  // Gets background noise mode.
-  virtual NetEqBackgroundNoiseMode BackgroundNoiseMode() const;
-
   // This accessor method is only intended for testing purposes.
   virtual const SyncBuffer* sync_buffer_for_test() const;
 
@@ -387,6 +381,7 @@
   bool first_packet_ GUARDED_BY(crit_sect_);
   int error_code_ GUARDED_BY(crit_sect_);  // Store last error code.
   int decoder_error_code_ GUARDED_BY(crit_sect_);
+  const BackgroundNoiseMode background_noise_mode_ 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
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 2e66487..402d79d 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -140,7 +140,7 @@
     PreemptiveExpandFactory* preemptive_expand_factory =
         new PreemptiveExpandFactory;
 
-    neteq_ = new NetEqImpl(config_.sample_rate_hz,
+    neteq_ = new NetEqImpl(config_,
                            buffer_level_filter_,
                            decoder_database_,
                            delay_manager_,
diff --git a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
index 0233e19..317c7b5 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
@@ -214,8 +214,6 @@
                           uint8_t* payload,
                           int* payload_len);
 
-  void CheckBgnOff(int sampling_rate, NetEqBackgroundNoiseMode bgn_mode);
-
   void WrapTest(uint16_t start_seq_no, uint32_t start_timestamp,
                 const std::set<uint16_t>& drop_seq_numbers,
                 bool expect_seq_no_wrap, bool expect_timestamp_wrap);
@@ -231,6 +229,7 @@
   uint32_t PlayoutTimestamp();
 
   NetEq* neteq_;
+  NetEq::Config config_;
   FILE* rtp_fp_;
   unsigned int sim_clock_;
   int16_t out_data_[kMaxBlockSize];
@@ -248,17 +247,17 @@
 
 NetEqDecodingTest::NetEqDecodingTest()
     : neteq_(NULL),
+      config_(),
       rtp_fp_(NULL),
       sim_clock_(0),
       output_sample_rate_(kInitSampleRateHz),
       algorithmic_delay_ms_(0) {
+  config_.sample_rate_hz = kInitSampleRateHz;
   memset(out_data_, 0, sizeof(out_data_));
 }
 
 void NetEqDecodingTest::SetUp() {
-  NetEq::Config config;
-  config.sample_rate_hz = kInitSampleRateHz;
-  neteq_ = NetEq::Create(config);
+  neteq_ = NetEq::Create(config_);
   NetEqNetworkStatistics stat;
   ASSERT_EQ(0, neteq_->NetworkStatistics(&stat));
   algorithmic_delay_ms_ = stat.current_buffer_size_ms;
@@ -425,107 +424,6 @@
   *payload_len = 1;  // Only noise level, no spectral parameters.
 }
 
-void NetEqDecodingTest::CheckBgnOff(int sampling_rate_hz,
-                                    NetEqBackgroundNoiseMode bgn_mode) {
-  int expected_samples_per_channel = 0;
-  uint8_t payload_type = 0xFF;  // Invalid.
-  if (sampling_rate_hz == 8000) {
-    expected_samples_per_channel = kBlockSize8kHz;
-    payload_type = 93;  // PCM 16, 8 kHz.
-  } else if (sampling_rate_hz == 16000) {
-    expected_samples_per_channel = kBlockSize16kHz;
-    payload_type = 94;  // PCM 16, 16 kHZ.
-  } else if (sampling_rate_hz == 32000) {
-    expected_samples_per_channel = kBlockSize32kHz;
-    payload_type = 95;  // PCM 16, 32 kHz.
-  } else {
-    ASSERT_TRUE(false);  // Unsupported test case.
-  }
-
-  NetEqOutputType type;
-  int16_t output[kBlockSize32kHz];  // Maximum size is chosen.
-  int16_t input[kBlockSize32kHz];  // Maximum size is chosen.
-
-  // Payload of 10 ms of PCM16 32 kHz.
-  uint8_t payload[kBlockSize32kHz * sizeof(int16_t)];
-
-  // Random payload.
-  for (int n = 0; n < expected_samples_per_channel; ++n) {
-    input[n] = (rand() & ((1 << 10) - 1)) - ((1 << 5) - 1);
-  }
-  int enc_len_bytes = WebRtcPcm16b_EncodeW16(
-      input, expected_samples_per_channel, reinterpret_cast<int16_t*>(payload));
-  ASSERT_EQ(enc_len_bytes, expected_samples_per_channel * 2);
-
-  WebRtcRTPHeader rtp_info;
-  PopulateRtpInfo(0, 0, &rtp_info);
-  rtp_info.header.payloadType = payload_type;
-
-  int number_channels = 0;
-  int samples_per_channel = 0;
-
-  uint32_t receive_timestamp = 0;
-  for (int n = 0; n < 10; ++n) {  // Insert few packets and get audio.
-    number_channels = 0;
-    samples_per_channel = 0;
-    ASSERT_EQ(0, neteq_->InsertPacket(
-        rtp_info, payload, enc_len_bytes, receive_timestamp));
-    ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
-                                  &number_channels, &type));
-    ASSERT_EQ(1, number_channels);
-    ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
-    ASSERT_EQ(kOutputNormal, type);
-
-    // Next packet.
-    rtp_info.header.timestamp += expected_samples_per_channel;
-    rtp_info.header.sequenceNumber++;
-    receive_timestamp += expected_samples_per_channel;
-  }
-
-  number_channels = 0;
-  samples_per_channel = 0;
-
-  // Get audio without inserting packets, expecting PLC and PLC-to-CNG. Pull one
-  // frame without checking speech-type. This is the first frame pulled without
-  // inserting any packet, and might not be labeled as PCL.
-  ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
-                                &number_channels, &type));
-  ASSERT_EQ(1, number_channels);
-  ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
-
-  // To be able to test the fading of background noise we need at lease to pull
-  // 611 frames.
-  const int kFadingThreshold = 611;
-
-  // Test several CNG-to-PLC packet for the expected behavior. The number 20 is
-  // arbitrary, but sufficiently large to test enough number of frames.
-  const int kNumPlcToCngTestFrames = 20;
-  bool plc_to_cng = false;
-  for (int n = 0; n < kFadingThreshold + kNumPlcToCngTestFrames; ++n) {
-    number_channels = 0;
-    samples_per_channel = 0;
-    memset(output, 1, sizeof(output));  // Set to non-zero.
-    ASSERT_EQ(0, neteq_->GetAudio(kBlockSize32kHz, output, &samples_per_channel,
-                                  &number_channels, &type));
-    ASSERT_EQ(1, number_channels);
-    ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
-    if (type == kOutputPLCtoCNG) {
-      plc_to_cng = true;
-      double sum_squared = 0;
-      for (int k = 0; k < number_channels * samples_per_channel; ++k)
-        sum_squared += output[k] * output[k];
-      if (bgn_mode == kBgnOn) {
-        EXPECT_NE(0, sum_squared);
-      } else if (bgn_mode == kBgnOff || n > kFadingThreshold) {
-        EXPECT_EQ(0, sum_squared);
-      }
-    } else {
-      EXPECT_EQ(kOutputPLC, type);
-    }
-  }
-  EXPECT_TRUE(plc_to_cng);  // Just to be sure that PLC-to-CNG has occurred.
-}
-
 TEST_F(NetEqDecodingTest, DISABLED_ON_ANDROID(TestBitExactness)) {
   const std::string input_rtp_file = webrtc::test::ProjectRootPath() +
       "resources/audio_coding/neteq_universal_new.rtp";
@@ -993,26 +891,143 @@
   }
 }
 
-TEST_F(NetEqDecodingTest, BackgroundNoise) {
-  neteq_->SetBackgroundNoiseMode(kBgnOn);
-  CheckBgnOff(8000, kBgnOn);
-  CheckBgnOff(16000, kBgnOn);
-  CheckBgnOff(32000, kBgnOn);
-  EXPECT_EQ(kBgnOn, neteq_->BackgroundNoiseMode());
+class NetEqBgnTest
+    : public NetEqDecodingTest,
+      public ::testing::WithParamInterface<NetEq::BackgroundNoiseMode> {
+ protected:
+  NetEqBgnTest() : NetEqDecodingTest() {
+    config_.background_noise_mode = GetParam();
+  }
 
-  neteq_->SetBackgroundNoiseMode(kBgnOff);
-  CheckBgnOff(8000, kBgnOff);
-  CheckBgnOff(16000, kBgnOff);
-  CheckBgnOff(32000, kBgnOff);
-  EXPECT_EQ(kBgnOff, neteq_->BackgroundNoiseMode());
+  void CheckBgnOff(int sampling_rate_hz) {
+    int expected_samples_per_channel = 0;
+    uint8_t payload_type = 0xFF;  // Invalid.
+    if (sampling_rate_hz == 8000) {
+      expected_samples_per_channel = kBlockSize8kHz;
+      payload_type = 93;  // PCM 16, 8 kHz.
+    } else if (sampling_rate_hz == 16000) {
+      expected_samples_per_channel = kBlockSize16kHz;
+      payload_type = 94;  // PCM 16, 16 kHZ.
+    } else if (sampling_rate_hz == 32000) {
+      expected_samples_per_channel = kBlockSize32kHz;
+      payload_type = 95;  // PCM 16, 32 kHz.
+    } else {
+      ASSERT_TRUE(false);  // Unsupported test case.
+    }
 
-  neteq_->SetBackgroundNoiseMode(kBgnFade);
-  CheckBgnOff(8000, kBgnFade);
-  CheckBgnOff(16000, kBgnFade);
-  CheckBgnOff(32000, kBgnFade);
-  EXPECT_EQ(kBgnFade, neteq_->BackgroundNoiseMode());
+    NetEqOutputType type;
+    int16_t output[kBlockSize32kHz];  // Maximum size is chosen.
+    int16_t input[kBlockSize32kHz];   // Maximum size is chosen.
+
+    // Payload of 10 ms of PCM16 32 kHz.
+    uint8_t payload[kBlockSize32kHz * sizeof(int16_t)];
+
+    // Random payload.
+    for (int n = 0; n < expected_samples_per_channel; ++n) {
+      input[n] = (rand() & ((1 << 10) - 1)) - ((1 << 5) - 1);
+    }
+    int enc_len_bytes =
+        WebRtcPcm16b_EncodeW16(input,
+                               expected_samples_per_channel,
+                               reinterpret_cast<int16_t*>(payload));
+    ASSERT_EQ(enc_len_bytes, expected_samples_per_channel * 2);
+
+    WebRtcRTPHeader rtp_info;
+    PopulateRtpInfo(0, 0, &rtp_info);
+    rtp_info.header.payloadType = payload_type;
+
+    int number_channels = 0;
+    int samples_per_channel = 0;
+
+    uint32_t receive_timestamp = 0;
+    for (int n = 0; n < 10; ++n) {  // Insert few packets and get audio.
+      number_channels = 0;
+      samples_per_channel = 0;
+      ASSERT_EQ(0,
+                neteq_->InsertPacket(
+                    rtp_info, payload, enc_len_bytes, receive_timestamp));
+      ASSERT_EQ(0,
+                neteq_->GetAudio(kBlockSize32kHz,
+                                 output,
+                                 &samples_per_channel,
+                                 &number_channels,
+                                 &type));
+      ASSERT_EQ(1, number_channels);
+      ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
+      ASSERT_EQ(kOutputNormal, type);
+
+      // Next packet.
+      rtp_info.header.timestamp += expected_samples_per_channel;
+      rtp_info.header.sequenceNumber++;
+      receive_timestamp += expected_samples_per_channel;
+    }
+
+    number_channels = 0;
+    samples_per_channel = 0;
+
+    // Get audio without inserting packets, expecting PLC and PLC-to-CNG. Pull
+    // one frame without checking speech-type. This is the first frame pulled
+    // without inserting any packet, and might not be labeled as PLC.
+    ASSERT_EQ(0,
+              neteq_->GetAudio(kBlockSize32kHz,
+                               output,
+                               &samples_per_channel,
+                               &number_channels,
+                               &type));
+    ASSERT_EQ(1, number_channels);
+    ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
+
+    // To be able to test the fading of background noise we need at lease to
+    // pull 611 frames.
+    const int kFadingThreshold = 611;
+
+    // Test several CNG-to-PLC packet for the expected behavior. The number 20
+    // is arbitrary, but sufficiently large to test enough number of frames.
+    const int kNumPlcToCngTestFrames = 20;
+    bool plc_to_cng = false;
+    for (int n = 0; n < kFadingThreshold + kNumPlcToCngTestFrames; ++n) {
+      number_channels = 0;
+      samples_per_channel = 0;
+      memset(output, 1, sizeof(output));  // Set to non-zero.
+      ASSERT_EQ(0,
+                neteq_->GetAudio(kBlockSize32kHz,
+                                 output,
+                                 &samples_per_channel,
+                                 &number_channels,
+                                 &type));
+      ASSERT_EQ(1, number_channels);
+      ASSERT_EQ(expected_samples_per_channel, samples_per_channel);
+      if (type == kOutputPLCtoCNG) {
+        plc_to_cng = true;
+        double sum_squared = 0;
+        for (int k = 0; k < number_channels * samples_per_channel; ++k)
+          sum_squared += output[k] * output[k];
+        if (config_.background_noise_mode == NetEq::kBgnOn) {
+          EXPECT_NE(0, sum_squared);
+        } else if (config_.background_noise_mode == NetEq::kBgnOff ||
+                   n > kFadingThreshold) {
+          EXPECT_EQ(0, sum_squared);
+        }
+      } else {
+        EXPECT_EQ(kOutputPLC, type);
+      }
+    }
+    EXPECT_TRUE(plc_to_cng);  // Just to be sure that PLC-to-CNG has occurred.
+  }
+};
+
+TEST_P(NetEqBgnTest, BackgroundNoise) {
+  CheckBgnOff(8000);
+  CheckBgnOff(16000);
+  CheckBgnOff(32000);
 }
 
+INSTANTIATE_TEST_CASE_P(BgnModes,
+                        NetEqBgnTest,
+                        ::testing::Values(NetEq::kBgnOn,
+                                          NetEq::kBgnOff,
+                                          NetEq::kBgnFade));
+
 TEST_F(NetEqDecodingTest, SyncPacketInsert) {
   WebRtcRTPHeader rtp_info;
   uint32_t receive_timestamp = 0;