Commit a7a38b3f authored by scherkus@chromium.org's avatar scherkus@chromium.org

Improve media::AudioRendererImplTest correctness via helper types.

While writing some new tests I ran into some hard to track down failures
that were a result of:
  1) Using AudioBufferConverter due to different input/output rates
  2) Using "int" for all input/output frame counts

For example, DeliverRemainingAudio() would actually over-deliver since
it didn't take the ratio of input/output rates into account.

To help make things better, use the type system to differentiate between
input and output frame counts. In addition, use simpler input/output
rates to make it easier to calculate expected time and frame values.

BUG=370634

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@284529 0039d316-1c4b-4281-b951-d872f2087c98
parent 6a6b5899
...@@ -23,17 +23,32 @@ using ::testing::SaveArg; ...@@ -23,17 +23,32 @@ using ::testing::SaveArg;
namespace media { namespace media {
namespace {
// Since AudioBufferConverter is used due to different input/output sample
// rates, define some helper types to differentiate between the two.
struct InputFrames {
explicit InputFrames(int value) : value(value) {}
int value;
};
struct OutputFrames {
explicit OutputFrames(int value) : value(value) {}
int value;
};
} // namespace
// Constants to specify the type of audio data used. // Constants to specify the type of audio data used.
static AudioCodec kCodec = kCodecVorbis; static AudioCodec kCodec = kCodecVorbis;
static SampleFormat kSampleFormat = kSampleFormatPlanarF32; static SampleFormat kSampleFormat = kSampleFormatPlanarF32;
static ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO; static ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
static int kChannelCount = 2; static int kChannelCount = 2;
static int kChannels = ChannelLayoutToChannelCount(kChannelLayout); static int kChannels = ChannelLayoutToChannelCount(kChannelLayout);
static int kSamplesPerSecond = 44100;
// Use a different output sample rate so the AudioBufferConverter is invoked.
static int kOutputSamplesPerSecond = 48000;
static const int kDataSize = 1024; // Use a different output sample rate so the AudioBufferConverter is invoked.
static int kInputSamplesPerSecond = 5000;
static int kOutputSamplesPerSecond = 10000;
ACTION_P(EnterPendingDecoderInitStateAction, test) { ACTION_P(EnterPendingDecoderInitStateAction, test) {
test->EnterPendingDecoderInitState(arg1); test->EnterPendingDecoderInitState(arg1);
...@@ -52,7 +67,7 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -52,7 +67,7 @@ class AudioRendererImplTest : public ::testing::Test {
AudioDecoderConfig audio_config(kCodec, AudioDecoderConfig audio_config(kCodec,
kSampleFormat, kSampleFormat,
kChannelLayout, kChannelLayout,
kSamplesPerSecond, kInputSamplesPerSecond,
NULL, NULL,
0, 0,
false); false);
...@@ -132,8 +147,7 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -132,8 +147,7 @@ class AudioRendererImplTest : public ::testing::Test {
RunCallback<1>(PIPELINE_OK))); RunCallback<1>(PIPELINE_OK)));
InitializeWithStatus(PIPELINE_OK); InitializeWithStatus(PIPELINE_OK);
next_timestamp_.reset(new AudioTimestampHelper( next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond));
hardware_config_.GetOutputConfig().sample_rate()));
} }
void InitializeWithStatus(PipelineStatus expected) { void InitializeWithStatus(PipelineStatus expected) {
...@@ -189,7 +203,7 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -189,7 +203,7 @@ class AudioRendererImplTest : public ::testing::Test {
SCOPED_TRACE("FlushDuringPendingRead()"); SCOPED_TRACE("FlushDuringPendingRead()");
WaitableMessageLoopEvent flush_event; WaitableMessageLoopEvent flush_event;
renderer_->Flush(flush_event.GetClosure()); renderer_->Flush(flush_event.GetClosure());
SatisfyPendingRead(kDataSize); SatisfyPendingRead(InputFrames(256));
flush_event.RunAndWait(); flush_event.RunAndWait();
EXPECT_FALSE(IsReadPending()); EXPECT_FALSE(IsReadPending());
...@@ -241,21 +255,21 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -241,21 +255,21 @@ class AudioRendererImplTest : public ::testing::Test {
DCHECK(wait_for_pending_decode_cb_.is_null()); DCHECK(wait_for_pending_decode_cb_.is_null());
} }
// Delivers |size| frames with value kPlayingAudio to |renderer_|. // Delivers decoded frames to |renderer_|.
void SatisfyPendingRead(int size) { void SatisfyPendingRead(InputFrames frames) {
CHECK_GT(size, 0); CHECK_GT(frames.value, 0);
CHECK(!decode_cb_.is_null()); CHECK(!decode_cb_.is_null());
scoped_refptr<AudioBuffer> buffer = scoped_refptr<AudioBuffer> buffer =
MakeAudioBuffer<float>(kSampleFormat, MakeAudioBuffer<float>(kSampleFormat,
kChannelLayout, kChannelLayout,
kChannelCount, kChannelCount,
kSamplesPerSecond, kInputSamplesPerSecond,
1.0f, 1.0f,
0.0f, 0.0f,
size, frames.value,
next_timestamp_->GetTimestamp()); next_timestamp_->GetTimestamp());
next_timestamp_->AddFrames(size); next_timestamp_->AddFrames(frames.value);
DeliverBuffer(AudioDecoder::kOk, buffer); DeliverBuffer(AudioDecoder::kOk, buffer);
} }
...@@ -285,43 +299,46 @@ class AudioRendererImplTest : public ::testing::Test { ...@@ -285,43 +299,46 @@ class AudioRendererImplTest : public ::testing::Test {
// Delivers frames until |renderer_|'s internal buffer is full and no longer // Delivers frames until |renderer_|'s internal buffer is full and no longer
// has pending reads. // has pending reads.
void DeliverRemainingAudio() { void DeliverRemainingAudio() {
SatisfyPendingRead(frames_remaining_in_buffer()); while (frames_remaining_in_buffer().value > 0) {
SatisfyPendingRead(InputFrames(256));
}
} }
// Attempts to consume |requested_frames| frames from |renderer_|'s internal // Attempts to consume |requested_frames| frames from |renderer_|'s internal
// buffer. Returns true if and only if all of |requested_frames| were able // buffer. Returns true if and only if all of |requested_frames| were able
// to be consumed. // to be consumed.
bool ConsumeBufferedData(int requested_frames) { bool ConsumeBufferedData(OutputFrames requested_frames) {
scoped_ptr<AudioBus> bus = scoped_ptr<AudioBus> bus =
AudioBus::Create(kChannels, std::max(requested_frames, 1)); AudioBus::Create(kChannels, requested_frames.value);
int frames_read = 0; int frames_read = 0;
EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read)); EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
return frames_read == requested_frames; return frames_read == requested_frames.value;
} }
int frames_buffered() { OutputFrames frames_buffered() {
return renderer_->algorithm_->frames_buffered(); return OutputFrames(renderer_->algorithm_->frames_buffered());
} }
int buffer_capacity() { OutputFrames buffer_capacity() {
return renderer_->algorithm_->QueueCapacity(); return OutputFrames(renderer_->algorithm_->QueueCapacity());
} }
int frames_remaining_in_buffer() { OutputFrames frames_remaining_in_buffer() {
// This can happen if too much data was delivered, in which case the buffer // This can happen if too much data was delivered, in which case the buffer
// will accept the data but not increase capacity. // will accept the data but not increase capacity.
if (frames_buffered() > buffer_capacity()) { if (frames_buffered().value > buffer_capacity().value) {
return 0; return OutputFrames(0);
} }
return buffer_capacity() - frames_buffered(); return OutputFrames(buffer_capacity().value - frames_buffered().value);
} }
void force_config_change() { void force_config_change() {
renderer_->OnConfigChange(); renderer_->OnConfigChange();
} }
int converter_input_frames_left() const { InputFrames converter_input_frames_left() const {
return renderer_->buffer_converter_->input_frames_left_for_testing(); return InputFrames(
renderer_->buffer_converter_->input_frames_left_for_testing());
} }
bool splicer_has_next_buffer() const { bool splicer_has_next_buffer() const {
...@@ -449,7 +466,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) { ...@@ -449,7 +466,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) {
WaitForPendingRead(); WaitForPendingRead();
// Forcefully trigger underflow. // Forcefully trigger underflow.
EXPECT_FALSE(ConsumeBufferedData(1)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
// Fulfill the read with an end-of-stream buffer. Doing so should change our // Fulfill the read with an end-of-stream buffer. Doing so should change our
...@@ -462,7 +479,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) { ...@@ -462,7 +479,7 @@ TEST_F(AudioRendererImplTest, EndOfStream) {
EXPECT_FALSE(ended()); EXPECT_FALSE(ended());
// Ended should trigger on next render call. // Ended should trigger on next render call.
EXPECT_FALSE(ConsumeBufferedData(1)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
EXPECT_TRUE(ended()); EXPECT_TRUE(ended());
} }
...@@ -478,18 +495,18 @@ TEST_F(AudioRendererImplTest, Underflow) { ...@@ -478,18 +495,18 @@ TEST_F(AudioRendererImplTest, Underflow) {
// Verify the next FillBuffer() call triggers a buffering state change // Verify the next FillBuffer() call triggers a buffering state change
// update. // update.
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
EXPECT_FALSE(ConsumeBufferedData(kDataSize)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
// Verify we're still not getting audio data. // Verify we're still not getting audio data.
EXPECT_EQ(0, frames_buffered()); EXPECT_EQ(0, frames_buffered().value);
EXPECT_FALSE(ConsumeBufferedData(kDataSize)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
// Deliver enough data to have enough for buffering. // Deliver enough data to have enough for buffering.
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
DeliverRemainingAudio(); DeliverRemainingAudio();
// Verify we're getting audio data. // Verify we're getting audio data.
EXPECT_TRUE(ConsumeBufferedData(kDataSize)); EXPECT_TRUE(ConsumeBufferedData(OutputFrames(1)));
} }
TEST_F(AudioRendererImplTest, Underflow_CapacityResetsAfterFlush) { TEST_F(AudioRendererImplTest, Underflow_CapacityResetsAfterFlush) {
...@@ -503,16 +520,16 @@ TEST_F(AudioRendererImplTest, Underflow_CapacityResetsAfterFlush) { ...@@ -503,16 +520,16 @@ TEST_F(AudioRendererImplTest, Underflow_CapacityResetsAfterFlush) {
// Verify the next FillBuffer() call triggers the underflow callback // Verify the next FillBuffer() call triggers the underflow callback
// since the decoder hasn't delivered any data after it was drained. // since the decoder hasn't delivered any data after it was drained.
int initial_capacity = buffer_capacity(); OutputFrames initial_capacity = buffer_capacity();
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
EXPECT_FALSE(ConsumeBufferedData(kDataSize)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
// Verify that the buffer capacity increased as a result of underflowing. // Verify that the buffer capacity increased as a result of underflowing.
EXPECT_GT(buffer_capacity(), initial_capacity); EXPECT_GT(buffer_capacity().value, initial_capacity.value);
// Verify that the buffer capacity is restored to the |initial_capacity|. // Verify that the buffer capacity is restored to the |initial_capacity|.
FlushDuringPendingRead(); FlushDuringPendingRead();
EXPECT_EQ(buffer_capacity(), initial_capacity); EXPECT_EQ(buffer_capacity().value, initial_capacity.value);
} }
TEST_F(AudioRendererImplTest, Underflow_Flush) { TEST_F(AudioRendererImplTest, Underflow_Flush) {
...@@ -524,7 +541,7 @@ TEST_F(AudioRendererImplTest, Underflow_Flush) { ...@@ -524,7 +541,7 @@ TEST_F(AudioRendererImplTest, Underflow_Flush) {
EXPECT_TRUE(ConsumeBufferedData(frames_buffered())); EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
WaitForPendingRead(); WaitForPendingRead();
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
EXPECT_FALSE(ConsumeBufferedData(kDataSize)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
WaitForPendingRead(); WaitForPendingRead();
StopRendering(); StopRendering();
...@@ -539,7 +556,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Flush) { ...@@ -539,7 +556,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Flush) {
StartRendering(); StartRendering();
// Partially drain internal buffer so we get a pending read. // Partially drain internal buffer so we get a pending read.
EXPECT_TRUE(ConsumeBufferedData(frames_buffered() / 2)); EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
WaitForPendingRead(); WaitForPendingRead();
StopRendering(); StopRendering();
...@@ -561,7 +578,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Stop) { ...@@ -561,7 +578,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Stop) {
StartRendering(); StartRendering();
// Partially drain internal buffer so we get a pending read. // Partially drain internal buffer so we get a pending read.
EXPECT_TRUE(ConsumeBufferedData(frames_buffered() / 2)); EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
WaitForPendingRead(); WaitForPendingRead();
StopRendering(); StopRendering();
...@@ -572,7 +589,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Stop) { ...@@ -572,7 +589,7 @@ TEST_F(AudioRendererImplTest, PendingRead_Stop) {
renderer_->Stop(stop_event.GetClosure()); renderer_->Stop(stop_event.GetClosure());
needs_stop_ = false; needs_stop_ = false;
SatisfyPendingRead(kDataSize); SatisfyPendingRead(InputFrames(256));
stop_event.RunAndWait(); stop_event.RunAndWait();
...@@ -586,7 +603,7 @@ TEST_F(AudioRendererImplTest, PendingFlush_Stop) { ...@@ -586,7 +603,7 @@ TEST_F(AudioRendererImplTest, PendingFlush_Stop) {
StartRendering(); StartRendering();
// Partially drain internal buffer so we get a pending read. // Partially drain internal buffer so we get a pending read.
EXPECT_TRUE(ConsumeBufferedData(frames_buffered() / 2)); EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
WaitForPendingRead(); WaitForPendingRead();
StopRendering(); StopRendering();
...@@ -598,7 +615,7 @@ TEST_F(AudioRendererImplTest, PendingFlush_Stop) { ...@@ -598,7 +615,7 @@ TEST_F(AudioRendererImplTest, PendingFlush_Stop) {
renderer_->Flush(flush_event.GetClosure()); renderer_->Flush(flush_event.GetClosure());
EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING)); EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
SatisfyPendingRead(kDataSize); SatisfyPendingRead(InputFrames(256));
WaitableMessageLoopEvent event; WaitableMessageLoopEvent event;
renderer_->Stop(event.GetClosure()); renderer_->Stop(event.GetClosure());
...@@ -625,15 +642,15 @@ TEST_F(AudioRendererImplTest, ConfigChangeDrainsConverter) { ...@@ -625,15 +642,15 @@ TEST_F(AudioRendererImplTest, ConfigChangeDrainsConverter) {
// Deliver a little bit of data. Use an odd data size to ensure there is data // Deliver a little bit of data. Use an odd data size to ensure there is data
// left in the AudioBufferConverter. Ensure no buffers are in the splicer. // left in the AudioBufferConverter. Ensure no buffers are in the splicer.
SatisfyPendingRead(2053); SatisfyPendingRead(InputFrames(2053));
EXPECT_FALSE(splicer_has_next_buffer()); EXPECT_FALSE(splicer_has_next_buffer());
EXPECT_GT(converter_input_frames_left(), 0); EXPECT_GT(converter_input_frames_left().value, 0);
// Force a config change and then ensure all buffered data has been put into // Force a config change and then ensure all buffered data has been put into
// the splicer. // the splicer.
force_config_change(); force_config_change();
EXPECT_TRUE(splicer_has_next_buffer()); EXPECT_TRUE(splicer_has_next_buffer());
EXPECT_EQ(0, converter_input_frames_left()); EXPECT_EQ(0, converter_input_frames_left().value);
} }
TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) { TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) {
...@@ -645,7 +662,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) { ...@@ -645,7 +662,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) {
EXPECT_EQ(kNoTimestamp(), last_time_update()); EXPECT_EQ(kNoTimestamp(), last_time_update());
// Preroll() should be buffered some data, consume half of it now. // Preroll() should be buffered some data, consume half of it now.
int frames_to_consume = frames_buffered() / 2; OutputFrames frames_to_consume(frames_buffered().value / 2);
EXPECT_TRUE(ConsumeBufferedData(frames_to_consume)); EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
WaitForPendingRead(); WaitForPendingRead();
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
...@@ -653,7 +670,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) { ...@@ -653,7 +670,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) {
// ConsumeBufferedData() uses an audio delay of zero, so ensure we received // ConsumeBufferedData() uses an audio delay of zero, so ensure we received
// a time update that's equal to |kFramesToConsume| from above. // a time update that's equal to |kFramesToConsume| from above.
timestamp_helper.SetBaseTimestamp(base::TimeDelta()); timestamp_helper.SetBaseTimestamp(base::TimeDelta());
timestamp_helper.AddFrames(frames_to_consume); timestamp_helper.AddFrames(frames_to_consume.value);
EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update()); EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update());
// The next time update should match the remaining frames_buffered(), but only // The next time update should match the remaining frames_buffered(), but only
...@@ -663,7 +680,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) { ...@@ -663,7 +680,7 @@ TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) {
EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update()); EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update());
base::RunLoop().RunUntilIdle(); base::RunLoop().RunUntilIdle();
timestamp_helper.AddFrames(frames_to_consume); timestamp_helper.AddFrames(frames_to_consume.value);
EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update()); EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update());
} }
...@@ -680,7 +697,7 @@ TEST_F(AudioRendererImplTest, ImmediateEndOfStream) { ...@@ -680,7 +697,7 @@ TEST_F(AudioRendererImplTest, ImmediateEndOfStream) {
// Read a single frame. We shouldn't be able to satisfy it. // Read a single frame. We shouldn't be able to satisfy it.
EXPECT_FALSE(ended()); EXPECT_FALSE(ended());
EXPECT_FALSE(ConsumeBufferedData(1)); EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
EXPECT_TRUE(ended()); EXPECT_TRUE(ended());
} }
......
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