Commit 6af71a8d authored by Sergey Ulanov's avatar Sergey Ulanov Committed by Commit Bot

Fix AudioRendererAlgorithm to account for resampler buffers.

AudioRendererAlgorithm may use resampler depending on playback rate.
When using the resampler audio samples may be buffered in
AudioRendererAlgorithm itself as well as in the resampler.
frames_buffered() was returning only number of frames buffered
internally, without accounting for the buffers in the resampler.
Replaced it with BufferedFrames() that adds the buffers in the
resampler.

Bug: b/150247610
Change-Id: Iacc5e8914f086f5298ecc7120ab369bd32ea5a29
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2113808
Auto-Submit: Sergey Ulanov <sergeyu@chromium.org>
Reviewed-by: default avatarKenneth MacKay <kmackay@chromium.org>
Reviewed-by: default avatarThomas Guilbert <tguilbert@chromium.org>
Commit-Queue: Kenneth MacKay <kmackay@chromium.org>
Cr-Commit-Position: refs/heads/master@{#752720}
parent 0cf813f1
...@@ -467,7 +467,7 @@ void AudioDecoderAndroid::OnBufferDecoded( ...@@ -467,7 +467,7 @@ void AudioDecoderAndroid::OnBufferDecoded(
RateShifterInfo* rate_info = &rate_shifter_info_.front(); RateShifterInfo* rate_info = &rate_shifter_info_.front();
// Bypass rate shifter if the rate is 1.0, and there are no frames queued // Bypass rate shifter if the rate is 1.0, and there are no frames queued
// in the rate shifter. // in the rate shifter.
if (rate_info->rate == 1.0 && rate_shifter_->frames_buffered() == 0 && if (rate_info->rate == 1.0 && rate_shifter_->BufferedFrames() == 0 &&
pending_output_frames_ == kNoPendingOutput && pending_output_frames_ == kNoPendingOutput &&
rate_shifter_info_.size() == 1) { rate_shifter_info_.size() == 1) {
DCHECK_EQ(rate_info->output_frames, rate_info->input_frames); DCHECK_EQ(rate_info->output_frames, rate_info->input_frames);
...@@ -518,7 +518,7 @@ void AudioDecoderAndroid::CheckBufferComplete() { ...@@ -518,7 +518,7 @@ void AudioDecoderAndroid::CheckBufferComplete() {
// If the current rate is 1.0, drain any data in the rate shifter before // If the current rate is 1.0, drain any data in the rate shifter before
// calling PushBufferComplete, so that the next PushBuffer call can skip the // calling PushBufferComplete, so that the next PushBuffer call can skip the
// rate shifter entirely. // rate shifter entirely.
rate_shifter_queue_full = (rate_shifter_->frames_buffered() > 0 || rate_shifter_queue_full = (rate_shifter_->BufferedFrames() > 0 ||
pending_output_frames_ != kNoPendingOutput); pending_output_frames_ != kNoPendingOutput);
} }
...@@ -615,7 +615,7 @@ void AudioDecoderAndroid::PushRateShifted() { ...@@ -615,7 +615,7 @@ void AudioDecoderAndroid::PushRateShifted() {
// been logically played; once we switch to passthrough mode (rate == 1.0), // been logically played; once we switch to passthrough mode (rate == 1.0),
// that old data needs to be cleared out. // that old data needs to be cleared out.
if (rate_info->rate == 1.0) { if (rate_info->rate == 1.0) {
int extra_frames = rate_shifter_->frames_buffered() - int extra_frames = rate_shifter_->BufferedFrames() -
static_cast<int>(rate_info->input_frames); static_cast<int>(rate_info->input_frames);
if (extra_frames > 0) { if (extra_frames > 0) {
// Clear out extra buffered data. // Clear out extra buffered data.
...@@ -625,7 +625,7 @@ void AudioDecoderAndroid::PushRateShifted() { ...@@ -625,7 +625,7 @@ void AudioDecoderAndroid::PushRateShifted() {
rate_shifter_->FillBuffer(dropped.get(), 0, extra_frames, 1.0f); rate_shifter_->FillBuffer(dropped.get(), 0, extra_frames, 1.0f);
DCHECK_EQ(extra_frames, cleared_frames); DCHECK_EQ(extra_frames, cleared_frames);
} }
rate_info->input_frames = rate_shifter_->frames_buffered(); rate_info->input_frames = rate_shifter_->BufferedFrames();
} }
} }
} }
......
...@@ -461,7 +461,7 @@ void FakeMediaSource::DecodeAudio(ScopedAVPacket packet) { ...@@ -461,7 +461,7 @@ void FakeMediaSource::DecodeAudio(ScopedAVPacket packet) {
const int frames_needed_to_scale = const int frames_needed_to_scale =
playback_rate_ * av_audio_context_->sample_rate / kAudioPacketsPerSecond; playback_rate_ * av_audio_context_->sample_rate / kAudioPacketsPerSecond;
while (frames_needed_to_scale <= audio_algo_.frames_buffered()) { while (frames_needed_to_scale <= audio_algo_.BufferedFrames()) {
if (!audio_algo_.FillBuffer(audio_fifo_input_bus_.get(), 0, if (!audio_algo_.FillBuffer(audio_fifo_input_bus_.get(), 0,
audio_fifo_input_bus_->frames(), audio_fifo_input_bus_->frames(),
playback_rate_)) { playback_rate_)) {
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include "media/base/audio_bus.h" #include "media/base/audio_bus.h"
#include "media/base/audio_timestamp_helper.h" #include "media/base/audio_timestamp_helper.h"
#include "media/base/limits.h" #include "media/base/limits.h"
#include "media/base/multi_channel_resampler.h"
#include "media/filters/wsola_internals.h" #include "media/filters/wsola_internals.h"
namespace media { namespace media {
...@@ -263,6 +262,12 @@ int AudioRendererAlgorithm::FillBuffer(AudioBus* dest, ...@@ -263,6 +262,12 @@ int AudioRendererAlgorithm::FillBuffer(AudioBus* dest,
return ResampleAndFill(dest, dest_offset, requested_frames, playback_rate); return ResampleAndFill(dest, dest_offset, requested_frames, playback_rate);
} }
// Destroy the resampler if it was used before, but it's no longer needed
// (e.g. before playback rate has changed). This ensures that we don't try to
// play later any samples still buffered in the resampler.
if (resampler_)
resampler_.reset();
// Allocate structures on first non-1.0 playback rate; these can eat a fair // Allocate structures on first non-1.0 playback rate; these can eat a fair
// chunk of memory. ~56kB for stereo 48kHz, up to ~765kB for 7.1 192kHz. // chunk of memory. ~56kB for stereo 48kHz, up to ~765kB for 7.1 192kHz.
if (!ola_window_) { if (!ola_window_) {
...@@ -398,7 +403,12 @@ void AudioRendererAlgorithm::IncreasePlaybackThreshold() { ...@@ -398,7 +403,12 @@ void AudioRendererAlgorithm::IncreasePlaybackThreshold() {
} }
int64_t AudioRendererAlgorithm::GetMemoryUsage() const { int64_t AudioRendererAlgorithm::GetMemoryUsage() const {
return audio_buffer_.frames() * channels_ * sizeof(float); return BufferedFrames() * channels_ * sizeof(float);
}
int AudioRendererAlgorithm::BufferedFrames() const {
return audio_buffer_.frames() +
(resampler_ ? static_cast<int>(resampler_->BufferedFrames()) : 0);
} }
bool AudioRendererAlgorithm::CanPerformWsola() const { bool AudioRendererAlgorithm::CanPerformWsola() const {
......
...@@ -32,11 +32,11 @@ ...@@ -32,11 +32,11 @@
#include "media/base/audio_buffer_queue.h" #include "media/base/audio_buffer_queue.h"
#include "media/base/audio_parameters.h" #include "media/base/audio_parameters.h"
#include "media/base/media_log.h" #include "media/base/media_log.h"
#include "media/base/multi_channel_resampler.h"
namespace media { namespace media {
class AudioBus; class AudioBus;
class MultiChannelResampler;
class MEDIA_EXPORT AudioRendererAlgorithm { class MEDIA_EXPORT AudioRendererAlgorithm {
public: public:
...@@ -114,13 +114,14 @@ class MEDIA_EXPORT AudioRendererAlgorithm { ...@@ -114,13 +114,14 @@ class MEDIA_EXPORT AudioRendererAlgorithm {
// Returns an estimate of the amount of memory (in bytes) used for frames. // Returns an estimate of the amount of memory (in bytes) used for frames.
int64_t GetMemoryUsage() const; int64_t GetMemoryUsage() const;
// Returns the number of frames left in |audio_buffer_|, which may be larger // Returns the total number of frames in |audio_buffer_| as well as
// than QueueCapacity() in the event that EnqueueBuffer() delivered more data // unconsumed input frames in the |resampler_|. The returned value may be
// than |audio_buffer_| was intending to hold. // larger than QueueCapacity() in the event that EnqueueBuffer() delivered
int frames_buffered() { return audio_buffer_.frames(); } // more data than |audio_buffer_| was intending to hold.
int BufferedFrames() const;
// Returns the samples per second for this audio stream. // Returns the samples per second for this audio stream.
int samples_per_second() { return samples_per_second_; } int samples_per_second() const { return samples_per_second_; }
std::vector<bool> channel_mask_for_testing() { return channel_mask_; } std::vector<bool> channel_mask_for_testing() { return channel_mask_; }
......
...@@ -125,7 +125,7 @@ class AudioRendererAlgorithmTest : public testing::Test { ...@@ -125,7 +125,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
} }
base::TimeDelta BufferedTime() { base::TimeDelta BufferedTime() {
return AudioTimestampHelper::FramesToTime(algorithm_.frames_buffered(), return AudioTimestampHelper::FramesToTime(algorithm_.BufferedFrames(),
samples_per_second_); samples_per_second_);
} }
...@@ -200,7 +200,7 @@ class AudioRendererAlgorithmTest : public testing::Test { ...@@ -200,7 +200,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
int ComputeConsumedFrames(int initial_frames_enqueued, int ComputeConsumedFrames(int initial_frames_enqueued,
int initial_frames_buffered) { int initial_frames_buffered) {
int frame_delta = frames_enqueued_ - initial_frames_enqueued; int frame_delta = frames_enqueued_ - initial_frames_enqueued;
int buffered_delta = algorithm_.frames_buffered() - initial_frames_buffered; int buffered_delta = algorithm_.BufferedFrames() - initial_frames_buffered;
int consumed = frame_delta - buffered_delta; int consumed = frame_delta - buffered_delta;
CHECK_GE(consumed, 0); CHECK_GE(consumed, 0);
return consumed; return consumed;
...@@ -220,7 +220,7 @@ class AudioRendererAlgorithmTest : public testing::Test { ...@@ -220,7 +220,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
int total_frames_requested, int total_frames_requested,
int dest_offset) { int dest_offset) {
int initial_frames_enqueued = frames_enqueued_; int initial_frames_enqueued = frames_enqueued_;
int initial_frames_buffered = algorithm_.frames_buffered(); int initial_frames_buffered = algorithm_.BufferedFrames();
std::unique_ptr<AudioBus> bus = std::unique_ptr<AudioBus> bus =
AudioBus::Create(channels_, buffer_size_in_frames); AudioBus::Create(channels_, buffer_size_in_frames);
...@@ -256,7 +256,7 @@ class AudioRendererAlgorithmTest : public testing::Test { ...@@ -256,7 +256,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
FillAlgorithmQueueUntilFull(); FillAlgorithmQueueUntilFull();
} }
EXPECT_EQ(algorithm_.frames_buffered() * channels_ * sizeof(float), EXPECT_EQ(algorithm_.BufferedFrames() * channels_ * sizeof(float),
static_cast<size_t>(algorithm_.GetMemoryUsage())); static_cast<size_t>(algorithm_.GetMemoryUsage()));
int frames_consumed = int frames_consumed =
...@@ -311,7 +311,7 @@ class AudioRendererAlgorithmTest : public testing::Test { ...@@ -311,7 +311,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
bus.get(), 0, buffer_size_in_frames, playback_rate); bus.get(), 0, buffer_size_in_frames, playback_rate);
total_frames_written += frames_written; total_frames_written += frames_written;
} while (frames_written && algorithm_.frames_buffered() > 0); } while (frames_written && algorithm_.BufferedFrames() > 0);
int input_frames_enqueued = frames_enqueued_ - initial_frames_enqueued; int input_frames_enqueued = frames_enqueued_ - initial_frames_enqueued;
...@@ -861,7 +861,7 @@ TEST_F(AudioRendererAlgorithmTest, FillBuffer_ChannelMask) { ...@@ -861,7 +861,7 @@ TEST_F(AudioRendererAlgorithmTest, FillBuffer_ChannelMask) {
// |latency_hint_| is set. // |latency_hint_| is set.
TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) { TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) {
// Queue is initially empty. Capacity is unset. // Queue is initially empty. Capacity is unset.
EXPECT_EQ(algorithm_.frames_buffered(), 0); EXPECT_EQ(algorithm_.BufferedFrames(), 0);
EXPECT_EQ(algorithm_.QueueCapacity(), 0); EXPECT_EQ(algorithm_.QueueCapacity(), 0);
// Initialize sets capacity fills queue. // Initialize sets capacity fills queue.
...@@ -875,21 +875,21 @@ TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) { ...@@ -875,21 +875,21 @@ TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) {
// one frame below the capacity limit. // one frame below the capacity limit.
std::unique_ptr<AudioBus> bus = AudioBus::Create(channels_, kFrameSize); std::unique_ptr<AudioBus> bus = AudioBus::Create(channels_, kFrameSize);
int requested_frames = int requested_frames =
(algorithm_.frames_buffered() - algorithm_.QueueCapacity()) + 1; (algorithm_.BufferedFrames() - algorithm_.QueueCapacity()) + 1;
const int frames_filled = const int frames_filled =
algorithm_.FillBuffer(bus.get(), 0, requested_frames, 1); algorithm_.FillBuffer(bus.get(), 0, requested_frames, 1);
EXPECT_EQ(frames_filled, requested_frames); EXPECT_EQ(frames_filled, requested_frames);
EXPECT_EQ(algorithm_.frames_buffered(), algorithm_.QueueCapacity() - 1); EXPECT_EQ(algorithm_.BufferedFrames(), algorithm_.QueueCapacity() - 1);
EXPECT_FALSE(algorithm_.IsQueueFull()); EXPECT_FALSE(algorithm_.IsQueueFull());
EXPECT_FALSE(algorithm_.IsQueueAdequateForPlayback()); EXPECT_FALSE(algorithm_.IsQueueAdequateForPlayback());
// Queue should again be "adequate for playback" and "full" it we add a single // Queue should again be "adequate for playback" and "full" it we add a single
// frame such that frames_buffered() == QueueCapacity(). // frame such that BufferedFrames() == QueueCapacity().
DCHECK_EQ(sample_format_, kSampleFormatS16); DCHECK_EQ(sample_format_, kSampleFormatS16);
algorithm_.EnqueueBuffer(MakeBuffer(1)); algorithm_.EnqueueBuffer(MakeBuffer(1));
EXPECT_TRUE(algorithm_.IsQueueFull()); EXPECT_TRUE(algorithm_.IsQueueFull());
EXPECT_TRUE(algorithm_.IsQueueAdequateForPlayback()); EXPECT_TRUE(algorithm_.IsQueueAdequateForPlayback());
EXPECT_EQ(algorithm_.frames_buffered(), algorithm_.QueueCapacity()); EXPECT_EQ(algorithm_.BufferedFrames(), algorithm_.QueueCapacity());
// Increasing playback threshold should also increase capacity. // Increasing playback threshold should also increase capacity.
int orig_capacity = algorithm_.QueueCapacity(); int orig_capacity = algorithm_.QueueCapacity();
...@@ -1079,7 +1079,7 @@ TEST_F(AudioRendererAlgorithmTest, ClampLatencyHint) { ...@@ -1079,7 +1079,7 @@ TEST_F(AudioRendererAlgorithmTest, ClampLatencyHint) {
// well above the hinted value. // well above the hinted value.
EXPECT_EQ(algorithm_.QueueCapacity(), default_capacity); EXPECT_EQ(algorithm_.QueueCapacity(), default_capacity);
FillAlgorithmQueueUntilAdequate(); FillAlgorithmQueueUntilAdequate();
EXPECT_EQ(algorithm_.frames_buffered(), 2 * kBufferSize); EXPECT_EQ(algorithm_.BufferedFrames(), 2 * kBufferSize);
} }
} // namespace media } // namespace media
...@@ -1040,7 +1040,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay, ...@@ -1040,7 +1040,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
return 0; return 0;
} }
if (is_passthrough_ && algorithm_->frames_buffered() > 0) { if (is_passthrough_ && algorithm_->BufferedFrames() > 0) {
// TODO(tsunghung): For compressed bitstream formats, play zeroed buffer // TODO(tsunghung): For compressed bitstream formats, play zeroed buffer
// won't generate delay. It could be discarded immediately. Need another // won't generate delay. It could be discarded immediately. Need another
// way to generate audio delay. // way to generate audio delay.
...@@ -1059,7 +1059,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay, ...@@ -1059,7 +1059,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
// bitstream cases. Fix |frames_requested| to avoid incorrent time // bitstream cases. Fix |frames_requested| to avoid incorrent time
// calculation of |audio_clock_| below. // calculation of |audio_clock_| below.
frames_requested = frames_written; frames_requested = frames_written;
} else if (algorithm_->frames_buffered() > 0) { } else if (algorithm_->BufferedFrames() > 0) {
// Delay playback by writing silence if we haven't reached the first // Delay playback by writing silence if we haven't reached the first
// timestamp yet; this can occur if the video starts before the audio. // timestamp yet; this can occur if the video starts before the audio.
CHECK_NE(first_packet_timestamp_, kNoTimestamp); CHECK_NE(first_packet_timestamp_, kNoTimestamp);
......
...@@ -464,7 +464,7 @@ class AudioRendererImplTest : public ::testing::Test, public RendererClient { ...@@ -464,7 +464,7 @@ class AudioRendererImplTest : public ::testing::Test, public RendererClient {
} }
OutputFrames frames_buffered() { OutputFrames frames_buffered() {
return OutputFrames(renderer_->algorithm_->frames_buffered()); return OutputFrames(renderer_->algorithm_->BufferedFrames());
} }
OutputFrames buffer_playback_threshold() { OutputFrames buffer_playback_threshold() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment