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(
RateShifterInfo* rate_info = &rate_shifter_info_.front();
// Bypass rate shifter if the rate is 1.0, and there are no frames queued
// 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 &&
rate_shifter_info_.size() == 1) {
DCHECK_EQ(rate_info->output_frames, rate_info->input_frames);
......@@ -518,7 +518,7 @@ void AudioDecoderAndroid::CheckBufferComplete() {
// 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
// rate shifter entirely.
rate_shifter_queue_full = (rate_shifter_->frames_buffered() > 0 ||
rate_shifter_queue_full = (rate_shifter_->BufferedFrames() > 0 ||
pending_output_frames_ != kNoPendingOutput);
}
......@@ -615,7 +615,7 @@ void AudioDecoderAndroid::PushRateShifted() {
// been logically played; once we switch to passthrough mode (rate == 1.0),
// that old data needs to be cleared out.
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);
if (extra_frames > 0) {
// Clear out extra buffered data.
......@@ -625,7 +625,7 @@ void AudioDecoderAndroid::PushRateShifted() {
rate_shifter_->FillBuffer(dropped.get(), 0, extra_frames, 1.0f);
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) {
const int frames_needed_to_scale =
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,
audio_fifo_input_bus_->frames(),
playback_rate_)) {
......
......@@ -13,7 +13,6 @@
#include "media/base/audio_bus.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/limits.h"
#include "media/base/multi_channel_resampler.h"
#include "media/filters/wsola_internals.h"
namespace media {
......@@ -263,6 +262,12 @@ int AudioRendererAlgorithm::FillBuffer(AudioBus* dest,
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
// chunk of memory. ~56kB for stereo 48kHz, up to ~765kB for 7.1 192kHz.
if (!ola_window_) {
......@@ -398,7 +403,12 @@ void AudioRendererAlgorithm::IncreasePlaybackThreshold() {
}
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 {
......
......@@ -32,11 +32,11 @@
#include "media/base/audio_buffer_queue.h"
#include "media/base/audio_parameters.h"
#include "media/base/media_log.h"
#include "media/base/multi_channel_resampler.h"
namespace media {
class AudioBus;
class MultiChannelResampler;
class MEDIA_EXPORT AudioRendererAlgorithm {
public:
......@@ -114,13 +114,14 @@ class MEDIA_EXPORT AudioRendererAlgorithm {
// Returns an estimate of the amount of memory (in bytes) used for frames.
int64_t GetMemoryUsage() const;
// Returns the number of frames left in |audio_buffer_|, which may be larger
// than QueueCapacity() in the event that EnqueueBuffer() delivered more data
// than |audio_buffer_| was intending to hold.
int frames_buffered() { return audio_buffer_.frames(); }
// Returns the total number of frames in |audio_buffer_| as well as
// unconsumed input frames in the |resampler_|. The returned value may be
// larger than QueueCapacity() in the event that EnqueueBuffer() delivered
// more data than |audio_buffer_| was intending to hold.
int BufferedFrames() const;
// 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_; }
......
......@@ -125,7 +125,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
}
base::TimeDelta BufferedTime() {
return AudioTimestampHelper::FramesToTime(algorithm_.frames_buffered(),
return AudioTimestampHelper::FramesToTime(algorithm_.BufferedFrames(),
samples_per_second_);
}
......@@ -200,7 +200,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
int ComputeConsumedFrames(int initial_frames_enqueued,
int initial_frames_buffered) {
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;
CHECK_GE(consumed, 0);
return consumed;
......@@ -220,7 +220,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
int total_frames_requested,
int dest_offset) {
int initial_frames_enqueued = frames_enqueued_;
int initial_frames_buffered = algorithm_.frames_buffered();
int initial_frames_buffered = algorithm_.BufferedFrames();
std::unique_ptr<AudioBus> bus =
AudioBus::Create(channels_, buffer_size_in_frames);
......@@ -256,7 +256,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
FillAlgorithmQueueUntilFull();
}
EXPECT_EQ(algorithm_.frames_buffered() * channels_ * sizeof(float),
EXPECT_EQ(algorithm_.BufferedFrames() * channels_ * sizeof(float),
static_cast<size_t>(algorithm_.GetMemoryUsage()));
int frames_consumed =
......@@ -311,7 +311,7 @@ class AudioRendererAlgorithmTest : public testing::Test {
bus.get(), 0, buffer_size_in_frames, playback_rate);
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;
......@@ -861,7 +861,7 @@ TEST_F(AudioRendererAlgorithmTest, FillBuffer_ChannelMask) {
// |latency_hint_| is set.
TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) {
// Queue is initially empty. Capacity is unset.
EXPECT_EQ(algorithm_.frames_buffered(), 0);
EXPECT_EQ(algorithm_.BufferedFrames(), 0);
EXPECT_EQ(algorithm_.QueueCapacity(), 0);
// Initialize sets capacity fills queue.
......@@ -875,21 +875,21 @@ TEST_F(AudioRendererAlgorithmTest, NoLatencyHint) {
// one frame below the capacity limit.
std::unique_ptr<AudioBus> bus = AudioBus::Create(channels_, kFrameSize);
int requested_frames =
(algorithm_.frames_buffered() - algorithm_.QueueCapacity()) + 1;
(algorithm_.BufferedFrames() - algorithm_.QueueCapacity()) + 1;
const int frames_filled =
algorithm_.FillBuffer(bus.get(), 0, requested_frames, 1);
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_.IsQueueAdequateForPlayback());
// 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);
algorithm_.EnqueueBuffer(MakeBuffer(1));
EXPECT_TRUE(algorithm_.IsQueueFull());
EXPECT_TRUE(algorithm_.IsQueueAdequateForPlayback());
EXPECT_EQ(algorithm_.frames_buffered(), algorithm_.QueueCapacity());
EXPECT_EQ(algorithm_.BufferedFrames(), algorithm_.QueueCapacity());
// Increasing playback threshold should also increase capacity.
int orig_capacity = algorithm_.QueueCapacity();
......@@ -1079,7 +1079,7 @@ TEST_F(AudioRendererAlgorithmTest, ClampLatencyHint) {
// well above the hinted value.
EXPECT_EQ(algorithm_.QueueCapacity(), default_capacity);
FillAlgorithmQueueUntilAdequate();
EXPECT_EQ(algorithm_.frames_buffered(), 2 * kBufferSize);
EXPECT_EQ(algorithm_.BufferedFrames(), 2 * kBufferSize);
}
} // namespace media
......@@ -1040,7 +1040,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
return 0;
}
if (is_passthrough_ && algorithm_->frames_buffered() > 0) {
if (is_passthrough_ && algorithm_->BufferedFrames() > 0) {
// TODO(tsunghung): For compressed bitstream formats, play zeroed buffer
// won't generate delay. It could be discarded immediately. Need another
// way to generate audio delay.
......@@ -1059,7 +1059,7 @@ int AudioRendererImpl::Render(base::TimeDelta delay,
// bitstream cases. Fix |frames_requested| to avoid incorrent time
// calculation of |audio_clock_| below.
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
// timestamp yet; this can occur if the video starts before the audio.
CHECK_NE(first_packet_timestamp_, kNoTimestamp);
......
......@@ -464,7 +464,7 @@ class AudioRendererImplTest : public ::testing::Test, public RendererClient {
}
OutputFrames frames_buffered() {
return OutputFrames(renderer_->algorithm_->frames_buffered());
return OutputFrames(renderer_->algorithm_->BufferedFrames());
}
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