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.