Index: media/base/sinc_resampler_unittest.cc |
diff --git a/media/base/sinc_resampler_unittest.cc b/media/base/sinc_resampler_unittest.cc |
index 8b89a5d3808034ab4d5ad705b8f0c6fd311cde41..b228f3d419a049320ce6e00285ab5816e0c9181b 100644 |
--- a/media/base/sinc_resampler_unittest.cc |
+++ b/media/base/sinc_resampler_unittest.cc |
@@ -1,39 +1,42 @@ |
-// Copyright (c) 2012 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. |
+/* |
+ * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
+ * |
+ * Use of this source code is governed by a BSD-style license |
+ * that can be found in the LICENSE file in the root of the source |
+ * tree. An additional intellectual property rights grant can be found |
+ * in the file PATENTS. All contributing project authors may |
+ * be found in the AUTHORS file in the root of the source tree. |
+ */ |
+ |
+// Modified from the Chromium original: |
+// src/media/base/sinc_resampler_unittest.cc |
// MSVC++ requires this to be set before any other includes to get M_PI. |
#define _USE_MATH_DEFINES |
#include <cmath> |
-#include "base/bind.h" |
-#include "base/bind_helpers.h" |
-#include "base/command_line.h" |
-#include "base/cpu.h" |
-#include "base/logging.h" |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/stringize_macros.h" |
-#include "base/time/time.h" |
-#include "build/build_config.h" |
-#include "media/base/sinc_resampler.h" |
#include "testing/gmock/include/gmock/gmock.h" |
#include "testing/gtest/include/gtest/gtest.h" |
+#include "webrtc/common_audio/resampler/sinc_resampler.h" |
+#include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h" |
+#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h" |
+#include "webrtc/system_wrappers/interface/scoped_ptr.h" |
+#include "webrtc/system_wrappers/interface/stringize_macros.h" |
+#include "webrtc/system_wrappers/interface/tick_util.h" |
+#include "webrtc/test/test_suite.h" |
using testing::_; |
-namespace media { |
+namespace webrtc { |
static const double kSampleRateRatio = 192000.0 / 44100.0; |
static const double kKernelInterpolationFactor = 0.5; |
-// Command line switch for runtime adjustment of ConvolveBenchmark iterations. |
-static const char kConvolveIterations[] = "convolve-iterations"; |
- |
// Helper class to ensure ChunkedResample() functions properly. |
-class MockSource { |
+class MockSource : public SincResamplerCallback { |
public: |
- MOCK_METHOD2(ProvideInput, void(int frames, float* destination)); |
+ MOCK_METHOD2(Run, void(int frames, float* destination)); |
}; |
ACTION(ClearBuffer) { |
@@ -54,22 +57,21 @@ TEST(SincResamplerTest, ChunkedResample) { |
// Choose a high ratio of input to output samples which will result in quick |
// exhaustion of SincResampler's internal buffers. |
- SincResampler resampler( |
- kSampleRateRatio, SincResampler::kDefaultRequestSize, |
- base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, |
+ &mock_source); |
static const int kChunks = 2; |
int max_chunk_size = resampler.ChunkSize() * kChunks; |
- scoped_ptr<float[]> resampled_destination(new float[max_chunk_size]); |
+ scoped_array<float> resampled_destination(new float[max_chunk_size]); |
// Verify requesting ChunkSize() frames causes a single callback. |
- EXPECT_CALL(mock_source, ProvideInput(_, _)) |
+ EXPECT_CALL(mock_source, Run(_, _)) |
.Times(1).WillOnce(ClearBuffer()); |
resampler.Resample(resampler.ChunkSize(), resampled_destination.get()); |
// Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks. |
testing::Mock::VerifyAndClear(&mock_source); |
- EXPECT_CALL(mock_source, ProvideInput(_, _)) |
+ EXPECT_CALL(mock_source, Run(_, _)) |
.Times(kChunks).WillRepeatedly(ClearBuffer()); |
resampler.Resample(max_chunk_size, resampled_destination.get()); |
} |
@@ -77,13 +79,12 @@ TEST(SincResamplerTest, ChunkedResample) { |
// Test flush resets the internal state properly. |
TEST(SincResamplerTest, Flush) { |
MockSource mock_source; |
- SincResampler resampler( |
- kSampleRateRatio, SincResampler::kDefaultRequestSize, |
- base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
- scoped_ptr<float[]> resampled_destination(new float[resampler.ChunkSize()]); |
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, |
+ &mock_source); |
+ scoped_array<float> resampled_destination(new float[resampler.ChunkSize()]); |
// Fill the resampler with junk data. |
- EXPECT_CALL(mock_source, ProvideInput(_, _)) |
+ EXPECT_CALL(mock_source, Run(_, _)) |
.Times(1).WillOnce(FillBuffer()); |
resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); |
ASSERT_NE(resampled_destination[0], 0); |
@@ -91,7 +92,7 @@ TEST(SincResamplerTest, Flush) { |
// Flush and request more data, which should all be zeros now. |
resampler.Flush(); |
testing::Mock::VerifyAndClear(&mock_source); |
- EXPECT_CALL(mock_source, ProvideInput(_, _)) |
+ EXPECT_CALL(mock_source, Run(_, _)) |
.Times(1).WillOnce(ClearBuffer()); |
resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); |
for (int i = 0; i < resampler.ChunkSize() / 2; ++i) |
@@ -101,23 +102,21 @@ TEST(SincResamplerTest, Flush) { |
// Test flush resets the internal state properly. |
TEST(SincResamplerTest, DISABLED_SetRatioBench) { |
MockSource mock_source; |
- SincResampler resampler( |
- kSampleRateRatio, SincResampler::kDefaultRequestSize, |
- base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, |
+ &mock_source); |
- base::TimeTicks start = base::TimeTicks::HighResNow(); |
+ TickTime start = TickTime::Now(); |
for (int i = 1; i < 10000; ++i) |
resampler.SetRatio(1.0 / i); |
- double total_time_c_ms = |
- (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
- printf("SetRatio() took %.2fms.\n", total_time_c_ms); |
+ double total_time_c_us = (TickTime::Now() - start).Microseconds(); |
+ printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000); |
} |
// Define platform independent function name for Convolve* tests. |
-#if defined(ARCH_CPU_X86_FAMILY) |
+#if defined(WEBRTC_ARCH_X86_FAMILY) |
#define CONVOLVE_FUNC Convolve_SSE |
-#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) |
+#elif defined(WEBRTC_ARCH_ARM_V7) |
#define CONVOLVE_FUNC Convolve_NEON |
#endif |
@@ -126,15 +125,16 @@ TEST(SincResamplerTest, DISABLED_SetRatioBench) { |
// will be tested by the parameterized SincResampler tests below. |
#if defined(CONVOLVE_FUNC) |
TEST(SincResamplerTest, Convolve) { |
-#if defined(ARCH_CPU_X86_FAMILY) |
- ASSERT_TRUE(base::CPU().has_sse()); |
+#if defined(WEBRTC_ARCH_X86_FAMILY) |
+ ASSERT_TRUE(WebRtc_GetCPUInfo(kSSE2)); |
+#elif defined(WEBRTC_ARCH_ARM_V7) |
+ ASSERT_TRUE(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON); |
#endif |
// Initialize a dummy resampler. |
MockSource mock_source; |
- SincResampler resampler( |
- kSampleRateRatio, SincResampler::kDefaultRequestSize, |
- base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, |
+ &mock_source); |
// The optimized Convolve methods are slightly more precise than Convolve_C(), |
// so comparison must be done using an epsilon. |
@@ -167,121 +167,65 @@ TEST(SincResamplerTest, Convolve) { |
TEST(SincResamplerTest, ConvolveBenchmark) { |
// Initialize a dummy resampler. |
MockSource mock_source; |
- SincResampler resampler( |
- kSampleRateRatio, SincResampler::kDefaultRequestSize, |
- base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); |
+ SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, |
+ &mock_source); |
// Retrieve benchmark iterations from command line. |
- int convolve_iterations = 10; |
- std::string iterations(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
- kConvolveIterations)); |
- if (!iterations.empty()) |
- base::StringToInt(iterations, &convolve_iterations); |
+ // TODO(ajm): Reintroduce this as a command line option. |
+ const int kConvolveIterations = 1000000; |
- printf("Benchmarking %d iterations:\n", convolve_iterations); |
+ printf("Benchmarking %d iterations:\n", kConvolveIterations); |
// Benchmark Convolve_C(). |
- base::TimeTicks start = base::TimeTicks::HighResNow(); |
- for (int i = 0; i < convolve_iterations; ++i) { |
+ TickTime start = TickTime::Now(); |
+ for (int i = 0; i < kConvolveIterations; ++i) { |
resampler.Convolve_C( |
resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), |
resampler.kernel_storage_.get(), kKernelInterpolationFactor); |
} |
- double total_time_c_ms = |
- (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
- printf("Convolve_C took %.2fms.\n", total_time_c_ms); |
+ double total_time_c_us = (TickTime::Now() - start).Microseconds(); |
+ printf("Convolve_C took %.2fms.\n", total_time_c_us / 1000); |
#if defined(CONVOLVE_FUNC) |
-#if defined(ARCH_CPU_X86_FAMILY) |
- ASSERT_TRUE(base::CPU().has_sse()); |
+#if defined(WEBRTC_ARCH_X86_FAMILY) |
+ ASSERT_TRUE(WebRtc_GetCPUInfo(kSSE2)); |
+#elif defined(WEBRTC_ARCH_ARM_V7) |
+ ASSERT_TRUE(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON); |
#endif |
// Benchmark with unaligned input pointer. |
- start = base::TimeTicks::HighResNow(); |
- for (int j = 0; j < convolve_iterations; ++j) { |
+ start = TickTime::Now(); |
+ for (int j = 0; j < kConvolveIterations; ++j) { |
resampler.CONVOLVE_FUNC( |
resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), |
resampler.kernel_storage_.get(), kKernelInterpolationFactor); |
} |
- double total_time_optimized_unaligned_ms = |
- (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
- printf(STRINGIZE(CONVOLVE_FUNC) " (unaligned) took %.2fms; which is %.2fx " |
- "faster than Convolve_C.\n", total_time_optimized_unaligned_ms, |
- total_time_c_ms / total_time_optimized_unaligned_ms); |
+ double total_time_optimized_unaligned_us = |
+ (TickTime::Now() - start).Microseconds(); |
+ printf(STRINGIZE(CONVOLVE_FUNC) "(unaligned) took %.2fms; which is %.2fx " |
+ "faster than Convolve_C.\n", total_time_optimized_unaligned_us / 1000, |
+ total_time_c_us / total_time_optimized_unaligned_us); |
// Benchmark with aligned input pointer. |
- start = base::TimeTicks::HighResNow(); |
- for (int j = 0; j < convolve_iterations; ++j) { |
+ start = TickTime::Now(); |
+ for (int j = 0; j < kConvolveIterations; ++j) { |
resampler.CONVOLVE_FUNC( |
resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), |
resampler.kernel_storage_.get(), kKernelInterpolationFactor); |
} |
- double total_time_optimized_aligned_ms = |
- (base::TimeTicks::HighResNow() - start).InMillisecondsF(); |
+ double total_time_optimized_aligned_us = |
+ (TickTime::Now() - start).Microseconds(); |
printf(STRINGIZE(CONVOLVE_FUNC) " (aligned) took %.2fms; which is %.2fx " |
"faster than Convolve_C and %.2fx faster than " |
STRINGIZE(CONVOLVE_FUNC) " (unaligned).\n", |
- total_time_optimized_aligned_ms, |
- total_time_c_ms / total_time_optimized_aligned_ms, |
- total_time_optimized_unaligned_ms / total_time_optimized_aligned_ms); |
+ total_time_optimized_aligned_us / 1000, |
+ total_time_c_us / total_time_optimized_aligned_us, |
+ total_time_optimized_unaligned_us / total_time_optimized_aligned_us); |
#endif |
} |
#undef CONVOLVE_FUNC |
-// Fake audio source for testing the resampler. Generates a sinusoidal linear |
-// chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the |
-// resampler for the specific sample rate conversion being used. |
-class SinusoidalLinearChirpSource { |
- public: |
- SinusoidalLinearChirpSource(int sample_rate, |
- int samples, |
- double max_frequency) |
- : sample_rate_(sample_rate), |
- total_samples_(samples), |
- max_frequency_(max_frequency), |
- current_index_(0) { |
- // Chirp rate. |
- double duration = static_cast<double>(total_samples_) / sample_rate_; |
- k_ = (max_frequency_ - kMinFrequency) / duration; |
- } |
- |
- virtual ~SinusoidalLinearChirpSource() {} |
- |
- void ProvideInput(int frames, float* destination) { |
- for (int i = 0; i < frames; ++i, ++current_index_) { |
- // Filter out frequencies higher than Nyquist. |
- if (Frequency(current_index_) > 0.5 * sample_rate_) { |
- destination[i] = 0; |
- } else { |
- // Calculate time in seconds. |
- double t = static_cast<double>(current_index_) / sample_rate_; |
- |
- // Sinusoidal linear chirp. |
- destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t)); |
- } |
- } |
- } |
- |
- double Frequency(int position) { |
- return kMinFrequency + position * (max_frequency_ - kMinFrequency) |
- / total_samples_; |
- } |
- |
- private: |
- enum { |
- kMinFrequency = 5 |
- }; |
- |
- double sample_rate_; |
- int total_samples_; |
- double max_frequency_; |
- double k_; |
- int current_index_; |
- |
- DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource); |
-}; |
- |
typedef std::tr1::tuple<int, int, double, double> SincResamplerTestData; |
class SincResamplerTest |
: public testing::TestWithParam<SincResamplerTestData> { |
@@ -306,25 +250,23 @@ class SincResamplerTest |
TEST_P(SincResamplerTest, Resample) { |
// Make comparisons using one second of data. |
static const double kTestDurationSecs = 1; |
- int input_samples = kTestDurationSecs * input_rate_; |
- int output_samples = kTestDurationSecs * output_rate_; |
+ const int input_samples = kTestDurationSecs * input_rate_; |
+ const int output_samples = kTestDurationSecs * output_rate_; |
// Nyquist frequency for the input sampling rate. |
- double input_nyquist_freq = 0.5 * input_rate_; |
+ const double input_nyquist_freq = 0.5 * input_rate_; |
// Source for data to be resampled. |
SinusoidalLinearChirpSource resampler_source( |
- input_rate_, input_samples, input_nyquist_freq); |
+ input_rate_, input_samples, input_nyquist_freq, 0); |
const double io_ratio = input_rate_ / static_cast<double>(output_rate_); |
- SincResampler resampler( |
- io_ratio, SincResampler::kDefaultRequestSize, |
- base::Bind(&SinusoidalLinearChirpSource::ProvideInput, |
- base::Unretained(&resampler_source))); |
+ SincResampler resampler(io_ratio, SincResampler::kDefaultRequestSize, |
+ &resampler_source); |
// Force an update to the sample rate ratio to ensure dyanmic sample rate |
// changes are working correctly. |
- scoped_ptr<float[]> kernel(new float[SincResampler::kKernelStorageSize]); |
+ scoped_array<float> kernel(new float[SincResampler::kKernelStorageSize]); |
memcpy(kernel.get(), resampler.get_kernel_for_testing(), |
SincResampler::kKernelStorageSize); |
resampler.SetRatio(M_PI); |
@@ -336,16 +278,16 @@ TEST_P(SincResamplerTest, Resample) { |
// TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to |
// allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. |
- scoped_ptr<float[]> resampled_destination(new float[output_samples]); |
- scoped_ptr<float[]> pure_destination(new float[output_samples]); |
+ scoped_array<float> resampled_destination(new float[output_samples]); |
+ scoped_array<float> pure_destination(new float[output_samples]); |
// Generate resampled signal. |
resampler.Resample(output_samples, resampled_destination.get()); |
// Generate pure signal. |
SinusoidalLinearChirpSource pure_source( |
- output_rate_, output_samples, input_nyquist_freq); |
- pure_source.ProvideInput(output_samples, pure_destination.get()); |
+ output_rate_, output_samples, input_nyquist_freq, 0); |
+ pure_source.Run(output_samples, pure_destination.get()); |
// Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which |
// we refer to as low and high. |
@@ -441,4 +383,4 @@ INSTANTIATE_TEST_CASE_P( |
std::tr1::make_tuple(96000, 192000, kResamplingRMSError, -73.52), |
std::tr1::make_tuple(192000, 192000, kResamplingRMSError, -73.52))); |
-} // namespace media |
+} // namespace webrtc |