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

Unified Diff: chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.cc

Issue 2937123005: Add a general PostProcessorUnittest. (Closed)
Patch Set: rename test to test_support Created 3 years, 6 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: chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.cc
diff --git a/chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.cc b/chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..bba39b88a13f1f54b30210e960e4aa370b409f63
--- /dev/null
+++ b/chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chromecast/media/cma/backend/alsa/post_processors/post_processor_unittest.h"
+
+#include <algorithm>
+#include <cmath>
+#include <limits>
+
+#include "base/logging.h"
+
+namespace chromecast {
+namespace media {
+
+namespace {
+
+const float kEpsilon = std::numeric_limits<float>::epsilon();
+
+} // namespace
+
+namespace post_processor_test {
+
+void TestDelay(AudioPostProcessor* pp, int sample_rate) {
+ EXPECT_TRUE(pp->SetSampleRate(sample_rate));
+
+ const int kNumFrames = GetMaximumFrames(sample_rate);
+ const int kSinFreq = 2000;
+ std::vector<float> data = GetSineData(kNumFrames, kSinFreq, sample_rate);
+ std::vector<float> expected = GetSineData(kNumFrames, kSinFreq, sample_rate);
+
+ int delay_frames = pp->ProcessFrames(data.data(), kNumFrames, 1.0);
+ int delayed_frames = 0;
+
+ // PostProcessors that run in dedicated threads may need to delay
+ // until they get data processed asyncronously.
+ while (delay_frames >= delayed_frames + kNumFrames) {
+ delayed_frames += kNumFrames;
+ for (int i = 0; i < kNumFrames * kNumChannels; ++i) {
+ EXPECT_EQ(0.0f, data[i]) << i;
+ }
+ std::vector<float> data = GetSineData(kNumFrames, kSinFreq, sample_rate);
+ delay_frames = pp->ProcessFrames(data.data(), kNumFrames, 1.0);
+
+ ASSERT_GE(delay_frames, delayed_frames);
+ }
+
+ for (int ch = 0; ch < kNumChannels; ++ch) {
+ ASSERT_NE(expected[ch], 0.0);
+
+ int nonzero_frame = delay_frames - delayed_frames;
+ for (int f = 0; f < nonzero_frame; ++f) {
+ EXPECT_EQ(0.0f, data[f * kNumChannels + ch]) << ch << " " << f;
+ }
+ EXPECT_NE(0.0f, data[nonzero_frame * kNumChannels + ch])
+ << ch << " " << nonzero_frame;
+ }
+}
+
+void TestRingingTime(AudioPostProcessor* pp, int sample_rate) {
+ EXPECT_TRUE(pp->SetSampleRate(sample_rate));
+
+ const int kNumFrames = GetMaximumFrames(sample_rate);
+ const int kSinFreq = 200;
+ int ringing_time_frames = pp->GetRingingTimeInFrames();
+ std::vector<float> data;
+
+ // Send a second of data to excite the filter.
+ for (int i = 0; i < sample_rate; i += kNumFrames) {
+ data = GetSineData(kNumFrames, kSinFreq, sample_rate);
+ pp->ProcessFrames(data.data(), kNumFrames, 1.0);
+ }
+ // Compute the amplitude of the last buffer
+ float original_amplitude = SineAmplitude(data, kNumChannels);
+
+ EXPECT_GE(original_amplitude, 0)
+ << "Output of nonzero data is 0; cannot test ringing";
+
+ // Feed |ringing_time_frames| of silence.
+ if (ringing_time_frames > 0) {
+ int frames_remaining = ringing_time_frames;
+ int frames_to_process = std::min(ringing_time_frames, kNumFrames);
+ while (frames_remaining > 0) {
+ frames_to_process = std::min(frames_to_process, frames_remaining);
+ data.assign(frames_to_process * kNumChannels, 0);
+ pp->ProcessFrames(data.data(), frames_to_process, 1.0);
+ frames_remaining -= frames_to_process;
+ }
+ }
+
+ // Send a little more data and ensure the amplitude is < 1% the original.
+ const int probe_frames = 100;
+ data.assign(probe_frames * kNumChannels, 0);
+ pp->ProcessFrames(data.data(), probe_frames, 1.0);
+
+ EXPECT_LE(SineAmplitude(data, probe_frames * kNumChannels),
+ original_amplitude * 0.01);
+}
+
+void TestPassthrough(AudioPostProcessor* pp, int sample_rate) {
+ EXPECT_TRUE(pp->SetSampleRate(sample_rate));
+
+ const int kNumFrames = GetMaximumFrames(sample_rate);
+ const int kSinFreq = 2000;
+ std::vector<float> data = GetSineData(kNumFrames, kSinFreq, sample_rate);
+ std::vector<float> expected = GetSineData(kNumFrames, kSinFreq, sample_rate);
+
+ int delay_frames = pp->ProcessFrames(data.data(), kNumFrames, 1.0);
+ int delayed_frames = 0;
+
+ // PostProcessors that run in dedicated threads may need to delay
+ // until they get data processed asyncronously.
+ while (delay_frames >= delayed_frames + kNumFrames) {
+ delayed_frames += kNumFrames;
+ for (int i = 0; i < kNumFrames * kNumChannels; ++i) {
+ EXPECT_EQ(0.0f, data[i]) << i;
+ }
+ std::vector<float> data = GetSineData(kNumFrames, kSinFreq, sample_rate);
+ delay_frames = pp->ProcessFrames(data.data(), kNumFrames, 1.0);
+
+ ASSERT_GE(delay_frames, delayed_frames);
+ }
+
+ int delay_samples = (delay_frames - delayed_frames) * kNumChannels;
+ ASSERT_LE(delay_samples, static_cast<int>(data.size()));
+
+ CheckArraysEqual(expected.data(), data.data() + delay_samples,
+ data.size() - delay_samples);
+}
+
+int GetMaximumFrames(int sample_rate) {
+ return kMaxAudioWriteTimeMilliseconds * sample_rate / 1000;
+}
+
+template <typename T>
+void CheckArraysEqual(T* expected, T* actual, size_t size) {
+ std::vector<int> differing_values = CompareArray(expected, actual, size);
+ if (differing_values.empty()) {
+ return;
+ }
+
+ size_t size_to_print =
+ std::min(static_cast<size_t>(differing_values[0] + 8), size);
+ EXPECT_EQ(differing_values.size(), 0u)
+ << "Arrays differ at indices "
+ << ::testing::PrintToString(differing_values)
+ << "\n Expected: " << ArrayToString(expected, size_to_print)
+ << "\n Actual: " << ArrayToString(actual, size_to_print);
+}
+
+template <typename T>
+std::vector<int> CompareArray(T* expected, T* actual, size_t size) {
+ std::vector<int> diffs;
+ for (size_t i = 0; i < size; ++i) {
+ if (std::abs(expected[i] - actual[i]) > kEpsilon) {
+ diffs.push_back(i);
+ }
+ }
+ return diffs;
+}
+
+template <typename T>
+std::string ArrayToString(T* array, size_t size) {
+ std::string result;
+ for (size_t i = 0; i < size; ++i) {
+ result += ::testing::PrintToString(array[i]) + " ";
+ }
+ return result;
+}
+
+template <typename T>
+float SineAmplitude(std::vector<T> data, int num_channels) {
+ double max_power = 0;
+ int frames = data.size() / num_channels;
+ for (int ch = 0; ch < kNumChannels; ++ch) {
+ double power = 0;
+ for (int f = 0; f < frames; ++f) {
+ power += std::pow(data[f * num_channels + ch], 2);
+ }
+ max_power = std::max(max_power, power);
+ }
+ return std::sqrt(max_power / frames) * sqrt(2);
+}
+
+std::vector<float> GetSineData(size_t frames,
+ float frequency,
+ int sample_rate) {
+ std::vector<float> sine(frames * kNumChannels);
+ for (size_t i = 0; i < frames; ++i) {
+ // Offset by a little so that first value is non-zero
+ sine[i * 2] =
+ sin(static_cast<float>(i + 1) * frequency * 2 * M_PI / sample_rate);
+ sine[i * 2 + 1] =
+ cos(static_cast<float>(i) * frequency * 2 * M_PI / sample_rate);
+ }
+ return sine;
+}
+
+PostProcessorTest::PostProcessorTest() : sample_rate_(GetParam()) {}
+PostProcessorTest::~PostProcessorTest() = default;
+
+INSTANTIATE_TEST_CASE_P(SampleRates,
+ PostProcessorTest,
+ ::testing::Values(44100, 48000));
+
+} // namespace post_processor_test
+} // namespace media
+} // namespace chromecast

Powered by Google App Engine
This is Rietveld 408576698