NetEq: Add new method last_output_sample_rate_hz

This change moves the logics for keeping track of the last ouput
sample rate from AcmReceiver to NetEq, where it fits better. The
getter function AcmReceiver::current_sample_rate_hz() is renamed to
last_output_sample_rate_hz().

BUG=webrtc:3520

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

Cr-Commit-Position: refs/heads/master@{#10754}
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
index b4dfe3a..1775029 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.cc
@@ -123,7 +123,6 @@
       id_(config.id),
       last_audio_decoder_(nullptr),
       previous_audio_activity_(AudioFrame::kVadPassive),
-      current_sample_rate_hz_(config.neteq_config.sample_rate_hz),
       audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
       last_audio_buffer_(new int16_t[AudioFrame::kMaxDataSizeSamples]),
       neteq_(NetEq::Create(config.neteq_config)),
@@ -157,9 +156,8 @@
   return neteq_->LeastRequiredDelayMs();
 }
 
-int AcmReceiver::current_sample_rate_hz() const {
-  CriticalSectionScoped lock(crit_sect_.get());
-  return current_sample_rate_hz_;
+int AcmReceiver::last_output_sample_rate_hz() const {
+  return neteq_->last_output_sample_rate_hz();
 }
 
 int AcmReceiver::InsertPacket(const WebRtcRTPHeader& rtp_header,
@@ -224,23 +222,18 @@
     return -1;
   }
 
-  // NetEq always returns 10 ms of audio.
-  current_sample_rate_hz_ = static_cast<int>(samples_per_channel * 100);
+  const int current_sample_rate_hz = neteq_->last_output_sample_rate_hz();
 
   // Update if resampling is required.
-  bool need_resampling = (desired_freq_hz != -1) &&
-      (current_sample_rate_hz_ != desired_freq_hz);
+  const bool need_resampling =
+      (desired_freq_hz != -1) && (current_sample_rate_hz != desired_freq_hz);
 
   if (need_resampling && !resampled_last_output_frame_) {
     // Prime the resampler with the last frame.
     int16_t temp_output[AudioFrame::kMaxDataSizeSamples];
-    int samples_per_channel_int =
-        resampler_.Resample10Msec(last_audio_buffer_.get(),
-                                  current_sample_rate_hz_,
-                                  desired_freq_hz,
-                                  num_channels,
-                                  AudioFrame::kMaxDataSizeSamples,
-                                  temp_output);
+    int samples_per_channel_int = resampler_.Resample10Msec(
+        last_audio_buffer_.get(), current_sample_rate_hz, desired_freq_hz,
+        num_channels, AudioFrame::kMaxDataSizeSamples, temp_output);
     if (samples_per_channel_int < 0) {
       LOG(LERROR) << "AcmReceiver::GetAudio - "
                      "Resampling last_audio_buffer_ failed.";
@@ -254,13 +247,9 @@
   // TODO(henrik.lundin) Glitches in the output may appear if the output rate
   // from NetEq changes. See WebRTC issue 3923.
   if (need_resampling) {
-    int samples_per_channel_int =
-        resampler_.Resample10Msec(audio_buffer_.get(),
-                                  current_sample_rate_hz_,
-                                  desired_freq_hz,
-                                  num_channels,
-                                  AudioFrame::kMaxDataSizeSamples,
-                                  audio_frame->data_);
+    int samples_per_channel_int = resampler_.Resample10Msec(
+        audio_buffer_.get(), current_sample_rate_hz, desired_freq_hz,
+        num_channels, AudioFrame::kMaxDataSizeSamples, audio_frame->data_);
     if (samples_per_channel_int < 0) {
       LOG(LERROR) << "AcmReceiver::GetAudio - Resampling audio_buffer_ failed.";
       return -1;
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
index 7dc851a..f02605b 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver.h
@@ -154,12 +154,8 @@
   //
   void ResetInitialDelay();
 
-  //
-  // Get the current sampling frequency in Hz.
-  //
-  // Return value             : Sampling frequency in Hz.
-  //
-  int current_sample_rate_hz() const;
+  // Returns last_output_sample_rate_hz from the NetEq instance.
+  int last_output_sample_rate_hz() const;
 
   //
   // Get the current network statistics from NetEq.
@@ -287,7 +283,6 @@
   int id_;  // TODO(henrik.lundin) Make const.
   const Decoder* last_audio_decoder_ GUARDED_BY(crit_sect_);
   AudioFrame::VADActivity previous_audio_activity_ GUARDED_BY(crit_sect_);
-  int current_sample_rate_hz_ GUARDED_BY(crit_sect_);
   ACMResampler resampler_ GUARDED_BY(crit_sect_);
   // Used in GetAudio, declared as member to avoid allocating every 10ms.
   // TODO(henrik.lundin) Stack-allocate in GetAudio instead?
diff --git a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
index 37bb131..3bda116 100644
--- a/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
+++ b/webrtc/modules/audio_coding/main/acm2/acm_receiver_unittest_oldapi.cc
@@ -261,8 +261,7 @@
     for (int k = 0; k < num_10ms_frames; ++k) {
       EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame));
     }
-    EXPECT_EQ(std::min(32000, codec.inst.plfreq),
-              receiver_->current_sample_rate_hz());
+    EXPECT_EQ(codec.inst.plfreq, receiver_->last_output_sample_rate_hz());
   }
 }
 
diff --git a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
index d4d5853..19ae4cb 100644
--- a/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
+++ b/webrtc/modules/audio_coding/main/acm2/audio_coding_module_impl.cc
@@ -532,17 +532,14 @@
 
   auto codec_id = RentACodec::CodecIdFromIndex(receiver_.last_audio_codec_id());
   return codec_id ? RentACodec::CodecInstById(*codec_id)->plfreq
-                  : receiver_.current_sample_rate_hz();
+                  : receiver_.last_output_sample_rate_hz();
 }
 
 // Get current playout frequency.
 int AudioCodingModuleImpl::PlayoutFrequency() const {
   WEBRTC_TRACE(webrtc::kTraceStream, webrtc::kTraceAudioCoding, id_,
                "PlayoutFrequency()");
-
-  CriticalSectionScoped lock(acm_crit_sect_.get());
-
-  return receiver_.current_sample_rate_hz();
+  return receiver_.last_output_sample_rate_hz();
 }
 
 // Register possible receive codecs, can be called multiple times,
diff --git a/webrtc/modules/audio_coding/neteq/include/neteq.h b/webrtc/modules/audio_coding/neteq/include/neteq.h
index 9a1bc17..88677d8 100644
--- a/webrtc/modules/audio_coding/neteq/include/neteq.h
+++ b/webrtc/modules/audio_coding/neteq/include/neteq.h
@@ -251,6 +251,11 @@
   // Returns true if the RTP timestamp is valid, otherwise false.
   virtual bool GetPlayoutTimestamp(uint32_t* timestamp) = 0;
 
+  // Returns the sample rate in Hz of the audio produced in the last GetAudio
+  // call. If GetAudio has not been called yet, the configured sample rate
+  // (Config::sample_rate_hz) is returned.
+  virtual int last_output_sample_rate_hz() 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 5fa2cbd..ed0c83f 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.cc
@@ -106,6 +106,7 @@
   }
   fs_hz_ = fs;
   fs_mult_ = fs / 8000;
+  last_output_sample_rate_hz_ = fs;
   output_size_samples_ = static_cast<size_t>(kOutputSizeMs * 8 * fs_mult_);
   decoder_frame_length_ = 3 * output_size_samples_;
   WebRtcSpl_Init();
@@ -160,6 +161,13 @@
   if (type) {
     *type = LastOutputType();
   }
+  last_output_sample_rate_hz_ =
+      rtc::checked_cast<int>(*samples_per_channel * 100);
+  RTC_DCHECK(last_output_sample_rate_hz_ == 8000 ||
+             last_output_sample_rate_hz_ == 16000 ||
+             last_output_sample_rate_hz_ == 32000 ||
+             last_output_sample_rate_hz_ == 48000)
+      << "Unexpected sample rate " << last_output_sample_rate_hz_;
   return kOK;
 }
 
@@ -359,6 +367,11 @@
   return true;
 }
 
+int NetEqImpl::last_output_sample_rate_hz() const {
+  CriticalSectionScoped lock(crit_sect_.get());
+  return last_output_sample_rate_hz_;
+}
+
 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 60c846d..0fc204f 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl.h
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl.h
@@ -168,6 +168,8 @@
 
   bool GetPlayoutTimestamp(uint32_t* timestamp) override;
 
+  int last_output_sample_rate_hz() const override;
+
   int SetTargetNumberOfChannels() override;
 
   int SetTargetSampleRate() override;
@@ -375,6 +377,7 @@
   StatisticsCalculator stats_ GUARDED_BY(crit_sect_);
   int fs_hz_ GUARDED_BY(crit_sect_);
   int fs_mult_ GUARDED_BY(crit_sect_);
+  int last_output_sample_rate_hz_ GUARDED_BY(crit_sect_);
   size_t output_size_samples_ GUARDED_BY(crit_sect_);
   size_t decoder_frame_length_ GUARDED_BY(crit_sect_);
   Modes last_mode_ GUARDED_BY(crit_sect_);
diff --git a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
index 11fdfe9..5d1dc0c 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_impl_unittest.cc
@@ -1230,4 +1230,13 @@
   EXPECT_CALL(mock_decoder, Die());
 }
 
+// Tests that the return value from last_output_sample_rate_hz() is equal to the
+// configured inital sample rate.
+TEST_F(NetEqImplTest, InitialLastOutputSampleRate) {
+  UseNoMocks();
+  config_.sample_rate_hz = 48000;
+  CreateInstance();
+  EXPECT_EQ(48000, neteq_->last_output_sample_rate_hz());
+}
+
 }// namespace webrtc
diff --git a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
index 2088cd1..5d75a4f 100644
--- a/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
+++ b/webrtc/modules/audio_coding/neteq/neteq_unittest.cc
@@ -362,6 +362,7 @@
               (*out_len == kBlockSize16kHz) ||
               (*out_len == kBlockSize32kHz));
   output_sample_rate_ = static_cast<int>(*out_len / 10 * 1000);
+  EXPECT_EQ(output_sample_rate_, neteq_->last_output_sample_rate_hz());
 
   // Increase time.
   sim_clock_ += kTimeStepMs;
@@ -895,6 +896,8 @@
     SCOPED_TRACE(ss.str());  // Print out the parameter values on failure.
     EXPECT_EQ(0, out_data_[i]);
   }
+  // Verify that the sample rate did not change from the initial configuration.
+  EXPECT_EQ(config_.sample_rate_hz, neteq_->last_output_sample_rate_hz());
 }
 
 class NetEqBgnTest : public NetEqDecodingTest {
diff --git a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
index dcf5f61..13b4185 100644
--- a/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
+++ b/webrtc/modules/audio_coding/neteq/tools/neteq_external_decoder_test.cc
@@ -56,6 +56,7 @@
   EXPECT_EQ(channels_, num_channels);
   EXPECT_EQ(static_cast<size_t>(kOutputLengthMs * sample_rate_hz_ / 1000),
             samples_per_channel);
+  EXPECT_EQ(sample_rate_hz_, neteq_->last_output_sample_rate_hz());
   return samples_per_channel;
 }