Remove muted_ and playback_rate_ from media::AudioRendererAlgorithm.

We don't need to hold onto the state as playback rate is only used when
calling FillBuffer().

BUG=370634

Review URL: https://codereview.chromium.org/411683002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284802 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/media/cast/test/fake_media_source.cc b/media/cast/test/fake_media_source.cc
index 07baebe..f3ebd9c 100644
--- a/media/cast/test/fake_media_source.cc
+++ b/media/cast/test/fake_media_source.cc
@@ -207,7 +207,7 @@
   }
 
   // Send transcoding streams.
-  audio_algo_.Initialize(playback_rate_, audio_params_);
+  audio_algo_.Initialize(audio_params_);
   audio_algo_.FlushBuffers();
   audio_fifo_input_bus_ =
       AudioBus::Create(
@@ -476,7 +476,8 @@
       kAudioPacketsPerSecond;
   while (frames_needed_to_scale <= audio_algo_.frames_buffered()) {
     if (!audio_algo_.FillBuffer(audio_fifo_input_bus_.get(),
-                                audio_fifo_input_bus_->frames())) {
+                                audio_fifo_input_bus_->frames(),
+                                playback_rate_)) {
       // Nothing can be scaled. Decode some more.
       return;
     }
diff --git a/media/filters/audio_renderer_algorithm.cc b/media/filters/audio_renderer_algorithm.cc
index e73ce65..fb5cf74 100644
--- a/media/filters/audio_renderer_algorithm.cc
+++ b/media/filters/audio_renderer_algorithm.cc
@@ -42,7 +42,7 @@
 // 6) Update:
 //    |target_block_| = |optimal_index| + |ola_window_size_| / 2.
 //    |output_index_| = |output_index_| + |ola_window_size_| / 2,
-//    |search_block_center_offset_| = |output_index_| * |playback_rate_|, and
+//    |search_block_center_offset_| = |output_index_| * |playback_rate|, and
 //    |search_block_index_| = |search_block_center_offset_| -
 //        |search_block_center_offset_|.
 
@@ -56,7 +56,7 @@
 static const int kOlaWindowSizeMs = 20;
 
 // Size of search interval in milliseconds. The search interval is
-// [-delta delta] around |output_index_| * |playback_rate_|. So the search
+// [-delta delta] around |output_index_| * |playback_rate|. So the search
 // interval is 2 * delta.
 static const int kWsolaSearchIntervalMs = 30;
 
@@ -75,8 +75,6 @@
 AudioRendererAlgorithm::AudioRendererAlgorithm()
     : channels_(0),
       samples_per_second_(0),
-      playback_rate_(0),
-      muted_(false),
       muted_partial_frame_(0),
       capacity_(kStartingBufferSizeInFrames),
       output_time_(0.0),
@@ -91,13 +89,11 @@
 
 AudioRendererAlgorithm::~AudioRendererAlgorithm() {}
 
-void AudioRendererAlgorithm::Initialize(float initial_playback_rate,
-                                        const AudioParameters& params) {
+void AudioRendererAlgorithm::Initialize(const AudioParameters& params) {
   CHECK(params.IsValid());
 
   channels_ = params.channels();
   samples_per_second_ = params.sample_rate();
-  SetPlaybackRate(initial_playback_rate);
   num_candidate_blocks_ = (kWsolaSearchIntervalMs * samples_per_second_) / 1000;
   ola_window_size_ = kOlaWindowSizeMs * samples_per_second_ / 1000;
 
@@ -145,24 +141,26 @@
   target_block_ = AudioBus::Create(channels_, ola_window_size_);
 }
 
-int AudioRendererAlgorithm::FillBuffer(AudioBus* dest, int requested_frames) {
-  if (playback_rate_ == 0)
+int AudioRendererAlgorithm::FillBuffer(AudioBus* dest,
+                                       int requested_frames,
+                                       float playback_rate) {
+  if (playback_rate == 0)
     return 0;
 
   DCHECK_EQ(channels_, dest->channels());
 
-  // Optimize the |muted_| case to issue a single clear instead of performing
+  // Optimize the muted case to issue a single clear instead of performing
   // the full crossfade and clearing each crossfaded frame.
-  if (muted_) {
+  if (playback_rate < kMinPlaybackRate || playback_rate > kMaxPlaybackRate) {
     int frames_to_render =
-        std::min(static_cast<int>(audio_buffer_.frames() / playback_rate_),
+        std::min(static_cast<int>(audio_buffer_.frames() / playback_rate),
                  requested_frames);
 
     // Compute accurate number of frames to actually skip in the source data.
     // Includes the leftover partial frame from last request. However, we can
     // only skip over complete frames, so a partial frame may remain for next
     // time.
-    muted_partial_frame_ += frames_to_render * playback_rate_;
+    muted_partial_frame_ += frames_to_render * playback_rate;
     int seek_frames = static_cast<int>(muted_partial_frame_);
     dest->ZeroFrames(frames_to_render);
     audio_buffer_.SeekFrames(seek_frames);
@@ -176,10 +174,10 @@
     return frames_to_render;
   }
 
-  int slower_step = ceil(ola_window_size_ * playback_rate_);
-  int faster_step = ceil(ola_window_size_ / playback_rate_);
+  int slower_step = ceil(ola_window_size_ * playback_rate);
+  int faster_step = ceil(ola_window_size_ / playback_rate);
 
-  // Optimize the most common |playback_rate_| ~= 1 case to use a single copy
+  // Optimize the most common |playback_rate| ~= 1 case to use a single copy
   // instead of copying frame by frame.
   if (ola_window_size_ <= faster_step && slower_step >= ola_window_size_) {
     const int frames_to_copy =
@@ -193,17 +191,11 @@
   do {
     rendered_frames += WriteCompletedFramesTo(
         requested_frames - rendered_frames, rendered_frames, dest);
-  } while (rendered_frames < requested_frames && RunOneWsolaIteration());
+  } while (rendered_frames < requested_frames &&
+           RunOneWsolaIteration(playback_rate));
   return rendered_frames;
 }
 
-void AudioRendererAlgorithm::SetPlaybackRate(float new_rate) {
-  DCHECK_GE(new_rate, 0);
-  playback_rate_ = new_rate;
-  muted_ =
-      playback_rate_ < kMinPlaybackRate || playback_rate_ > kMaxPlaybackRate;
-}
-
 void AudioRendererAlgorithm::FlushBuffers() {
   // Clear the queue of decoded packets (releasing the buffers).
   audio_buffer_.Clear();
@@ -246,7 +238,7 @@
       search_block_index_ + search_block_size <= frames;
 }
 
-bool AudioRendererAlgorithm::RunOneWsolaIteration() {
+bool AudioRendererAlgorithm::RunOneWsolaIteration(float playback_rate) {
   if (!CanPerformWsola())
     return false;
 
@@ -267,20 +259,21 @@
   }
 
   num_complete_frames_ += ola_hop_size_;
-  UpdateOutputTime(ola_hop_size_);
-  RemoveOldInputFrames();
+  UpdateOutputTime(playback_rate, ola_hop_size_);
+  RemoveOldInputFrames(playback_rate);
   return true;
 }
 
-void AudioRendererAlgorithm::UpdateOutputTime(double time_change) {
+void AudioRendererAlgorithm::UpdateOutputTime(float playback_rate,
+                                              double time_change) {
   output_time_ += time_change;
   // Center of the search region, in frames.
   const int search_block_center_index = static_cast<int>(
-      output_time_ * playback_rate_ + 0.5);
+      output_time_ * playback_rate + 0.5);
   search_block_index_ = search_block_center_index - search_block_center_offset_;
 }
 
-void AudioRendererAlgorithm::RemoveOldInputFrames() {
+void AudioRendererAlgorithm::RemoveOldInputFrames(float playback_rate) {
   const int earliest_used_index = std::min(target_block_index_,
                                            search_block_index_);
   if (earliest_used_index <= 0)
@@ -292,9 +285,9 @@
 
   // Adjust output index.
   double output_time_change = static_cast<double>(earliest_used_index) /
-      playback_rate_;
+      playback_rate;
   CHECK_GE(output_time_, output_time_change);
-  UpdateOutputTime(-output_time_change);
+  UpdateOutputTime(playback_rate, -output_time_change);
 }
 
 int AudioRendererAlgorithm::WriteCompletedFramesTo(
diff --git a/media/filters/audio_renderer_algorithm.h b/media/filters/audio_renderer_algorithm.h
index 39e4db6..b36eb08 100644
--- a/media/filters/audio_renderer_algorithm.h
+++ b/media/filters/audio_renderer_algorithm.h
@@ -4,10 +4,7 @@
 
 // AudioRendererAlgorithm buffers and transforms audio data. The owner of
 // this object provides audio data to the object through EnqueueBuffer() and
-// requests data from the buffer via FillBuffer(). The owner also sets the
-// playback rate, and the AudioRendererAlgorithm will stretch or compress the
-// buffered audio as necessary to match the playback rate when fulfilling
-// FillBuffer() requests.
+// requests data from the buffer via FillBuffer().
 //
 // This class is *not* thread-safe. Calls to enqueue and retrieve data must be
 // locked if called from multiple threads.
@@ -20,7 +17,6 @@
 // description of the algorithm.
 //
 // Audio at very low or very high playback rates are muted to preserve quality.
-//
 
 #ifndef MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_H_
 #define MEDIA_FILTERS_AUDIO_RENDERER_ALGORITHM_H_
@@ -41,17 +37,16 @@
   ~AudioRendererAlgorithm();
 
   // Initializes this object with information about the audio stream.
-  void Initialize(float initial_playback_rate, const AudioParameters& params);
+  void Initialize(const AudioParameters& params);
 
   // Tries to fill |requested_frames| frames into |dest| with possibly scaled
-  // data from our |audio_buffer_|. Data is scaled based on the playback rate,
+  // data from our |audio_buffer_|. Data is scaled based on |playback_rate|,
   // using a variation of the Overlap-Add method to combine sample windows.
   //
   // Data from |audio_buffer_| is consumed in proportion to the playback rate.
   //
-  // Returns the number of frames copied into |dest|. May request more reads via
-  // |request_read_cb_| before returning.
-  int FillBuffer(AudioBus* dest, int requested_frames);
+  // Returns the number of frames copied into |dest|.
+  int FillBuffer(AudioBus* dest, int requested_frames, float playback_rate);
 
   // Clears |audio_buffer_|.
   void FlushBuffers();
@@ -64,9 +59,6 @@
   // read completes.
   void EnqueueBuffer(const scoped_refptr<AudioBuffer>& buffer_in);
 
-  float playback_rate() const { return playback_rate_; }
-  void SetPlaybackRate(float new_rate);
-
   // Returns true if |audio_buffer_| is at or exceeds capacity.
   bool IsQueueFull();
 
@@ -84,9 +76,6 @@
   // Returns the samples per second for this audio stream.
   int samples_per_second() { return samples_per_second_; }
 
-  // Is the sound currently muted?
-  bool is_muted() { return muted_; }
-
  private:
   // Within |search_block_|, find the block of data that is most similar to
   // |target_block_|, and write it in |optimal_block_|. This method assumes that
@@ -111,15 +100,15 @@
   // Run one iteration of WSOLA, if there are sufficient frames. This will
   // overlap-and-add one block to |wsola_output_|, hence, |num_complete_frames_|
   // is incremented by |ola_hop_size_|.
-  bool RunOneWsolaIteration();
+  bool RunOneWsolaIteration(float playback_rate);
 
   // Seek |audio_buffer_| forward to remove frames from input that are not used
   // any more. State of the WSOLA will be updated accordingly.
-  void RemoveOldInputFrames();
+  void RemoveOldInputFrames(float playback_rate);
 
   // Update |output_time_| by |time_change|. In turn |search_block_index_| is
   // updated.
-  void UpdateOutputTime(double time_change);
+  void UpdateOutputTime(float playback_rate, double time_change);
 
   // Is |target_block_| fully within |search_block_|? If so, we don't need to
   // perform the search.
@@ -134,15 +123,9 @@
   // Sample rate of audio stream.
   int samples_per_second_;
 
-  // Used by algorithm to scale output.
-  float playback_rate_;
-
   // Buffered audio data.
   AudioBufferQueue audio_buffer_;
 
-  // True if the audio should be muted.
-  bool muted_;
-
   // If muted, keep track of partial frames that should have been skipped over.
   double muted_partial_frame_;
 
diff --git a/media/filters/audio_renderer_algorithm_unittest.cc b/media/filters/audio_renderer_algorithm_unittest.cc
index 0f63922..b5f895c 100644
--- a/media/filters/audio_renderer_algorithm_unittest.cc
+++ b/media/filters/audio_renderer_algorithm_unittest.cc
@@ -94,7 +94,7 @@
                            samples_per_second,
                            bytes_per_sample_ * 8,
                            samples_per_second / 100);
-    algorithm_.Initialize(1, params);
+    algorithm_.Initialize(params);
     FillAlgorithmQueue();
   }
 
@@ -145,14 +145,14 @@
     }
   }
 
-  void CheckFakeData(AudioBus* audio_data, int frames_written) {
-    // Check each channel individually.
+  bool AudioDataIsMuted(AudioBus* audio_data, int frames_written) {
     for (int ch = 0; ch < channels_; ++ch) {
-      bool all_zero = true;
-      for (int i = 0; i < frames_written && all_zero; ++i)
-        all_zero = audio_data->channel(ch)[i] == 0.0f;
-      ASSERT_EQ(algorithm_.is_muted(), all_zero) << " for channel " << ch;
+      for (int i = 0; i < frames_written; ++i) {
+        if (audio_data->channel(ch)[i] != 0.0f)
+          return false;
+      }
     }
+    return true;
   }
 
   int ComputeConsumedFrames(int initial_frames_enqueued,
@@ -178,22 +178,24 @@
                         int total_frames_requested) {
     int initial_frames_enqueued = frames_enqueued_;
     int initial_frames_buffered = algorithm_.frames_buffered();
-    algorithm_.SetPlaybackRate(static_cast<float>(playback_rate));
 
     scoped_ptr<AudioBus> bus =
         AudioBus::Create(channels_, buffer_size_in_frames);
     if (playback_rate == 0.0) {
-      int frames_written =
-          algorithm_.FillBuffer(bus.get(), buffer_size_in_frames);
+      int frames_written = algorithm_.FillBuffer(
+          bus.get(), buffer_size_in_frames, playback_rate);
       EXPECT_EQ(0, frames_written);
       return;
     }
 
+    bool expect_muted = (playback_rate < 0.5 || playback_rate > 4);
+
     int frames_remaining = total_frames_requested;
     bool first_fill_buffer = true;
     while (frames_remaining > 0) {
       int frames_requested = std::min(buffer_size_in_frames, frames_remaining);
-      int frames_written = algorithm_.FillBuffer(bus.get(), frames_requested);
+      int frames_written =
+          algorithm_.FillBuffer(bus.get(), frames_requested, playback_rate);
       ASSERT_GT(frames_written, 0) << "Requested: " << frames_requested
                                    << ", playing at " << playback_rate;
 
@@ -203,7 +205,7 @@
       // if at very first buffer-fill only one frame is written, that is zero
       // which might cause exception in CheckFakeData().
       if (!first_fill_buffer || frames_written > 1)
-        CheckFakeData(bus.get(), frames_written);
+        ASSERT_EQ(expect_muted, AudioDataIsMuted(bus.get(), frames_written));
       first_fill_buffer = false;
       frames_remaining -= frames_written;
 
@@ -242,7 +244,7 @@
     channels_ = ChannelLayoutToChannelCount(kChannelLayout);
     AudioParameters params(AudioParameters::AUDIO_PCM_LINEAR, kChannelLayout,
                            kSampleRateHz, kBytesPerSample * 8, kNumFrames);
-    algorithm_.Initialize(playback_rate, params);
+    algorithm_.Initialize(params);
 
     // A pulse is 6 milliseconds (even number of samples).
     const int kPulseWidthSamples = 6 * kSampleRateHz / 1000;
@@ -279,7 +281,7 @@
     for (int n = 0; n < kNumRequestedPulses; ++n) {
       int num_buffered_frames = 0;
       while (num_buffered_frames < kPulseWidthSamples) {
-        int num_samples = algorithm_.FillBuffer(output.get(), 1);
+        int num_samples = algorithm_.FillBuffer(output.get(), 1, playback_rate);
         ASSERT_LE(num_samples, 1);
         if (num_samples > 0) {
           output->CopyPartialFramesTo(0, num_samples, num_buffered_frames,
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc
index 44536de..231db85 100644
--- a/media/filters/audio_renderer_impl.cc
+++ b/media/filters/audio_renderer_impl.cc
@@ -52,6 +52,7 @@
                                                  decoders.Pass(),
                                                  set_decryptor_ready_cb)),
       hardware_config_(hardware_config),
+      playback_rate_(0),
       state_(kUninitialized),
       buffering_state_(BUFFERING_HAVE_NOTHING),
       rendering_(false),
@@ -86,7 +87,7 @@
 
   base::AutoLock auto_lock(lock_);
   // Wait for an eventual call to SetPlaybackRate() to start rendering.
-  if (algorithm_->playback_rate() == 0) {
+  if (playback_rate_ == 0) {
     DCHECK(!sink_playing_);
     return;
   }
@@ -99,7 +100,7 @@
   DCHECK(task_runner_->BelongsToCurrentThread());
   DCHECK_EQ(state_, kPlaying);
   DCHECK(!sink_playing_);
-  DCHECK_NE(algorithm_->playback_rate(), 0);
+  DCHECK_NE(playback_rate_, 0);
   lock_.AssertAcquired();
 
   sink_playing_ = true;
@@ -116,7 +117,7 @@
 
   base::AutoLock auto_lock(lock_);
   // Rendering should have already been stopped with a zero playback rate.
-  if (algorithm_->playback_rate() == 0) {
+  if (playback_rate_ == 0) {
     DCHECK(!sink_playing_);
     return;
   }
@@ -326,7 +327,7 @@
   // We're all good! Continue initializing the rest of the audio renderer
   // based on the decoder format.
   algorithm_.reset(new AudioRendererAlgorithm());
-  algorithm_->Initialize(0, audio_parameters_);
+  algorithm_->Initialize(audio_parameters_);
 
   ChangeState_Locked(kFlushed);
 
@@ -509,8 +510,8 @@
   // We have two cases here:
   // Play: current_playback_rate == 0 && playback_rate != 0
   // Pause: current_playback_rate != 0 && playback_rate == 0
-  float current_playback_rate = algorithm_->playback_rate();
-  algorithm_->SetPlaybackRate(playback_rate);
+  float current_playback_rate = playback_rate_;
+  playback_rate_ = playback_rate;
 
   if (!rendering_)
     return;
@@ -551,8 +552,7 @@
       return 0;
     }
 
-    float playback_rate = algorithm_->playback_rate();
-    if (playback_rate == 0) {
+    if (playback_rate_ == 0) {
       audio_clock_->WroteSilence(requested_frames, delay_frames);
       return 0;
     }
@@ -578,9 +578,10 @@
     const base::TimeDelta media_timestamp_before_filling =
         audio_clock_->CurrentMediaTimestamp(base::TimeDelta());
     if (algorithm_->frames_buffered() > 0) {
-      frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
+      frames_written =
+          algorithm_->FillBuffer(audio_bus, requested_frames, playback_rate_);
       audio_clock_->WroteAudio(
-          frames_written, delay_frames, playback_rate, algorithm_->GetTime());
+          frames_written, delay_frames, playback_rate_, algorithm_->GetTime());
     }
     audio_clock_->WroteSilence(requested_frames - frames_written, delay_frames);
 
diff --git a/media/filters/audio_renderer_impl.h b/media/filters/audio_renderer_impl.h
index 837dd73..423063b 100644
--- a/media/filters/audio_renderer_impl.h
+++ b/media/filters/audio_renderer_impl.h
@@ -226,6 +226,7 @@
   base::Lock lock_;
 
   // Algorithm for scaling audio.
+  float playback_rate_;
   scoped_ptr<AudioRendererAlgorithm> algorithm_;
 
   // Simple state tracking variable.