Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Unified Diff: media/filters/audio_renderer_algorithm_base_unittest.cc

Issue 9395057: Fix muted audio when playback rate != 1.0 or 0.0 (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: media/filters/audio_renderer_algorithm_base_unittest.cc
diff --git a/media/filters/audio_renderer_algorithm_base_unittest.cc b/media/filters/audio_renderer_algorithm_base_unittest.cc
index 75d8c52cd3be9819fe6d76d269eb9eec81ac5bfc..917bcca2e2f86ad858c85cfb8584edbfcae2a6af 100644
--- a/media/filters/audio_renderer_algorithm_base_unittest.cc
+++ b/media/filters/audio_renderer_algorithm_base_unittest.cc
@@ -12,132 +12,209 @@
#include "base/callback.h"
#include "media/base/data_buffer.h"
#include "media/filters/audio_renderer_algorithm_base.h"
-#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
-using ::testing::AnyNumber;
+static const size_t kRawDataSize = 1024;
+static const int kSamplesPerSecond = 1234;
namespace media {
-static const int kChannels = 1;
-static const int kSampleRate = 1000;
-static const int kSampleBits = 8;
-
-TEST(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) {
- // When playback rate == 1.0f: straight copy of whatever is in |queue_|.
- AudioRendererAlgorithmBase algorithm;
- algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 1.0f,
- base::Bind(&base::DoNothing));
-
- // Enqueue a buffer of any size since it doesn't matter.
- const size_t kDataSize = 1024;
- algorithm.EnqueueBuffer(new DataBuffer(
- scoped_array<uint8>(new uint8[kDataSize]), kDataSize));
- EXPECT_EQ(kDataSize, algorithm.bytes_buffered());
-
- // Read the same sized amount.
- scoped_array<uint8> data(new uint8[kDataSize]);
- EXPECT_EQ(kDataSize, algorithm.FillBuffer(data.get(), kDataSize));
- EXPECT_EQ(0u, algorithm.bytes_buffered());
-}
+class AudioRendererAlgorithmBaseTest : public testing::Test {
+ public:
+ AudioRendererAlgorithmBaseTest()
+ : bytes_enqueued_(0),
+ bytes_per_frame_(0) {
+ }
+
+ ~AudioRendererAlgorithmBaseTest() {}
-TEST(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) {
- // When playback rate > 1.0f: input is read faster than output is written.
- AudioRendererAlgorithmBase algorithm;
- algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 2.0f,
- base::Bind(&base::DoNothing));
-
- // First parameter is the input buffer size, second parameter is how much data
- // we expect to consume in order to have no data left in the |algorithm|.
- //
- // For rate == 0.5f, reading half the input size should consume all enqueued
- // data.
- const size_t kBufferSize = 16 * 1024;
- scoped_array<uint8> data(new uint8[kBufferSize]);
- const size_t kTestData[][2] = {
- { algorithm.window_size(), algorithm.window_size() / 2},
- { algorithm.window_size() / 2, algorithm.window_size() / 4},
- { 4u, 2u },
- { 0u, 0u },
- };
-
- for (size_t i = 0u; i < arraysize(kTestData); ++i) {
- const size_t kDataSize = kTestData[i][0];
- algorithm.EnqueueBuffer(new DataBuffer(
- scoped_array<uint8>(new uint8[kDataSize]), kDataSize));
- EXPECT_EQ(kDataSize, algorithm.bytes_buffered());
-
- const size_t kExpectedSize = kTestData[i][1];
- ASSERT_LE(kExpectedSize, kBufferSize);
- EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize));
- EXPECT_EQ(0u, algorithm.bytes_buffered());
+ void Initialize() {
+ static const int kDefaultChannels = 2;
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Any reason not to put these up with the const
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Nah, I just figured I'd put them close to where th
+ static const int kDefaultSampleBits = 16;
+
+ Initialize(kDefaultChannels, kDefaultSampleBits);
}
-}
-TEST(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) {
- // When playback rate < 1.0f: input is read slower than output is written.
- AudioRendererAlgorithmBase algorithm;
- algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.5f,
- base::Bind(&base::DoNothing));
-
- // First parameter is the input buffer size, second parameter is how much data
- // we expect to consume in order to have no data left in the |algorithm|.
- //
- // For rate == 0.5f, reading double the input size should consume all enqueued
- // data.
- const size_t kBufferSize = 16 * 1024;
- scoped_array<uint8> data(new uint8[kBufferSize]);
- const size_t kTestData[][2] = {
- { algorithm.window_size(), algorithm.window_size() * 2 },
- { algorithm.window_size() / 2, algorithm.window_size() },
- { 2u, 4u },
- { 0u, 0u },
- };
-
- for (size_t i = 0u; i < arraysize(kTestData); ++i) {
- const size_t kDataSize = kTestData[i][0];
- algorithm.EnqueueBuffer(new DataBuffer(
- scoped_array<uint8>(new uint8[kDataSize]), kDataSize));
- EXPECT_EQ(kDataSize, algorithm.bytes_buffered());
-
- const size_t kExpectedSize = kTestData[i][1];
- ASSERT_LE(kExpectedSize, kBufferSize);
- EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize));
- EXPECT_EQ(0u, algorithm.bytes_buffered());
+ void Initialize(int channels, int bits_per_sample) {
+ bytes_per_frame_ = channels * (bits_per_sample / 8);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Perhaps add a protected accessor method to al
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
+ algorithm_.Initialize(
+ channels, kSamplesPerSecond, bits_per_sample, 1.0f,
+ base::Bind(&AudioRendererAlgorithmBaseTest::EnqueueData,
+ base::Unretained(this)));
+ EnqueueData();
}
-}
-TEST(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) {
- // When playback rate is very low the audio is simply muted.
- AudioRendererAlgorithmBase algorithm;
- algorithm.Initialize(kChannels, kSampleRate, kSampleBits, 0.25f,
- base::Bind(&base::DoNothing));
-
- // First parameter is the input buffer size, second parameter is how much data
- // we expect to consume in order to have no data left in the |algorithm|.
- //
- // For rate == 0.25f, reading four times the input size should consume all
- // enqueued data but without executing OLA.
- const size_t kBufferSize = 16 * 1024;
- scoped_array<uint8> data(new uint8[kBufferSize]);
- const size_t kTestData[][2] = {
- { algorithm.window_size(), algorithm.window_size() * 4},
- { algorithm.window_size() / 2, algorithm.window_size() * 2},
- { 1u, 4u },
- { 0u, 0u },
- };
-
- for (size_t i = 0u; i < arraysize(kTestData); ++i) {
- const size_t kDataSize = kTestData[i][0];
- algorithm.EnqueueBuffer(new DataBuffer(scoped_array<uint8>(
- new uint8[kDataSize]), kDataSize));
- EXPECT_EQ(kDataSize, algorithm.bytes_buffered());
-
- const size_t kExpectedSize = kTestData[i][1];
- ASSERT_LE(kExpectedSize, kBufferSize);
- EXPECT_EQ(kExpectedSize, algorithm.FillBuffer(data.get(), kBufferSize));
- EXPECT_EQ(0u, algorithm.bytes_buffered());
+ void EnqueueData() {
+ algorithm_.EnqueueBuffer(new DataBuffer(
+ scoped_array<uint8>(new uint8[kRawDataSize]), kRawDataSize));
+ bytes_enqueued_ += kRawDataSize;
+ }
+
+ int ComputeConsumedBytes(int initial_bytes_enqueued,
+ int initial_bytes_buffered) {
+ int byte_delta = bytes_enqueued_ - initial_bytes_enqueued;
+ int buffered_delta = algorithm_.bytes_buffered() - initial_bytes_buffered;
+ int consumed = byte_delta - buffered_delta;
+ CHECK_GE(consumed, 0);
+ return consumed;
+ }
+
+ void TestPlaybackRate(float playback_rate) {
+ algorithm_.SetPlaybackRate(playback_rate);
+ static const int kDefaultBufferSize = kSamplesPerSecond / 2;
+ static const int kDefaultFramesRequested = 10 * kSamplesPerSecond;
+
+ TestPlaybackRate(
+ playback_rate, kDefaultBufferSize, kDefaultFramesRequested);
}
+
+ void TestPlaybackRate(float playback_rate,
+ int buffer_size_in_frames,
+ int total_frames_requested) {
+ int initial_bytes_enqueued = bytes_enqueued_;
+ int initial_bytes_buffered = algorithm_.bytes_buffered();
+
+ algorithm_.SetPlaybackRate(playback_rate);
+
+ scoped_array<uint8> buffer(
+ new uint8[buffer_size_in_frames * bytes_per_frame_]);
+ int frames_remaining = total_frames_requested;
+
+ while (frames_remaining > 0) {
+ int frames_requested = std::min(buffer_size_in_frames, frames_remaining);
+ int frames_written =
+ algorithm_.FillBuffer(buffer.get(), frames_requested);
+ if (playback_rate == 0.0) {
+ EXPECT_EQ(0, frames_written);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: I think it might be clearer to just move this
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
+ return;
+ }
+ frames_remaining -= frames_written;
+ }
+
+ int bytes_requested = total_frames_requested * bytes_per_frame_;
+ int bytes_consumed = ComputeConsumedBytes(initial_bytes_enqueued,
+ initial_bytes_buffered);
+
+ // If playing back at normal speed, we should always get back the same
+ // number of bytes requested.
+ if (playback_rate == 1.0) {
+ EXPECT_EQ(bytes_requested, bytes_consumed);
+ return;
+ }
+
+ // Otherwise, allow |kMaxAcceptableDelta| difference between the target and
+ // actual playback rate.
+ static const float kMaxAcceptableDelta = 0.05;
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Is the error bound really constant? I thought
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
+ float actual_playback_rate = 1.0 * bytes_consumed / bytes_requested;
+
+ // Calculate the percentage difference from the target |playback_rate| as a
+ // fraction from 0.0 to 1.0.
+ float delta = 1.0 - (actual_playback_rate / playback_rate);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: std::abs() instead of if below?
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Ooh d'oh! Originally I tried this and it converted
+ if (delta < 0.0)
+ delta *= -1.0;
+
+ EXPECT_LE(delta, kMaxAcceptableDelta);
+ }
+
+ protected:
+ AudioRendererAlgorithmBase algorithm_;
+ int bytes_enqueued_;
+ int bytes_per_frame_;
+};
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_NormalRate) {
+ Initialize();
+ TestPlaybackRate(1.0);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAQuarterRate) {
+ Initialize();
+ TestPlaybackRate(1.25);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_OneAndAHalfRate) {
+ Initialize();
+ TestPlaybackRate(1.5);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_DoubleRate) {
+ Initialize();
+ TestPlaybackRate(2.0);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_ThreeQuartersRate) {
+ Initialize();
+ TestPlaybackRate(0.75);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HalfRate) {
+ Initialize();
+ TestPlaybackRate(0.5);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_QuarterRate) {
+ Initialize();
+ TestPlaybackRate(0.25);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_Pause) {
+ Initialize();
+ TestPlaybackRate(0.0);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SlowDown) {
+ Initialize();
+ TestPlaybackRate(3.0);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Should add a case above kMaxPlaybackRate (ie
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
+ TestPlaybackRate(2.0);
+ TestPlaybackRate(1.0);
+ TestPlaybackRate(0.5);
+ TestPlaybackRate(0.25);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SpeedUp) {
+ Initialize();
+ TestPlaybackRate(0.25);
+ TestPlaybackRate(0.5);
+ TestPlaybackRate(1.0);
+ TestPlaybackRate(2.0);
+ TestPlaybackRate(3.0);
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 nit: Should add a case above kMaxPlaybackRate (ie
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done.
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_JumpAroundSpeeds) {
+ Initialize();
+ TestPlaybackRate(2.1);
+ TestPlaybackRate(0.9);
+ TestPlaybackRate(0.6);
+ TestPlaybackRate(1.4);
+ TestPlaybackRate(0.3);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_SmallBufferSize) {
+ Initialize();
+ static const int kBufferSizeInFrames = 1;
+ static const int kFramesRequested= kSamplesPerSecond;
+
+ TestPlaybackRate(1.0, kBufferSizeInFrames, kFramesRequested);
+ TestPlaybackRate(0.5, kBufferSizeInFrames, kFramesRequested);
+ TestPlaybackRate(1.5, kBufferSizeInFrames, kFramesRequested);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_LowerQualityAudio) {
+ static const int kChannels = 1;
+ static const int kSampleBits = 8;
+ Initialize(kChannels, kSampleBits);
+ TestPlaybackRate(1.0);
+ TestPlaybackRate(0.5);
+ TestPlaybackRate(1.5);
+}
+
+TEST_F(AudioRendererAlgorithmBaseTest, FillBuffer_HigherQualityAudio) {
+ static const int kChannels = 2;
+ static const int kSampleBits = 32;
+ Initialize(kChannels, kSampleBits);
+ TestPlaybackRate(1.0);
+ TestPlaybackRate(0.5);
+ TestPlaybackRate(1.5);
}
acolwell GONE FROM CHROMIUM 2012/02/27 21:00:08 Should we add tests to verify sound is output betw
vrk (LEFT CHROMIUM) 2012/02/28 23:40:32 Done - but it took more code than I thought! I had
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698