diff --git a/webrtc/common_audio/resampler/resampler.gypi b/webrtc/common_audio/resampler/resampler.gypi index 4d7fdd0130..67f179e761 100644 --- a/webrtc/common_audio/resampler/resampler.gypi +++ b/webrtc/common_audio/resampler/resampler.gypi @@ -25,6 +25,8 @@ 'sources': [ 'include/resampler.h', 'resampler.cc', + 'sinc_resampler.cc', + 'sinc_resampler.h', ], }, ], # targets @@ -37,10 +39,12 @@ 'dependencies': [ 'resampler', '<(webrtc_root)/test/test.gyp:test_support_main', + '<(DEPTH)/testing/gmock.gyp:gmock', '<(DEPTH)/testing/gtest.gyp:gtest', ], 'sources': [ 'resampler_unittest.cc', + 'sinc_resampler_unittest.cc', ], }, # resampler_unittests ], # targets @@ -48,8 +52,3 @@ ], # conditions } -# Local Variables: -# tab-width:2 -# indent-tabs-mode:nil -# End: -# vim: set expandtab tabstop=2 shiftwidth=2: diff --git a/webrtc/common_audio/resampler/sinc_resampler.cc b/webrtc/common_audio/resampler/sinc_resampler.cc index d836fc7cbc..1c117222ae 100644 --- a/webrtc/common_audio/resampler/sinc_resampler.cc +++ b/webrtc/common_audio/resampler/sinc_resampler.cc @@ -1,7 +1,16 @@ -// 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.cc + // Input buffer layout, dividing the total buffer into regions (r0_ - r5_): // // |----------------|-----------------------------------------|----------------| @@ -34,23 +43,24 @@ // MSVC++ requires this to be set before any other includes to get M_PI. #define _USE_MATH_DEFINES -#include "media/base/sinc_resampler.h" +#include "webrtc/common_audio/resampler/sinc_resampler.h" +#include "webrtc/system_wrappers/interface/compile_assert.h" +#include "webrtc/system_wrappers/interface/cpu_features_wrapper.h" +#include "webrtc/typedefs.h" #include +#include -#include "base/cpu.h" -#include "base/logging.h" -#include "build/build_config.h" - -#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) +#if defined(WEBRTC_USE_SSE2) #include #endif -#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) -#include -#endif +// TODO(ajm): See note below in Convolve_NEON. +//#if defined(WEBRTC_ARCH_ARM_NEON) || defined(WEBRTC_DETECT_ARM_NEON) +//#include +//#endif -namespace media { +namespace webrtc { namespace { @@ -63,7 +73,7 @@ enum { // The number of destination frames generated per processing pass. Affects // how often and for how much SincResampler calls back for input. Must be // greater than kKernelSize. - kBlockSize = 512, + kDefaultBlockSize = 512, // The kernel offset count is used for interpolation and is the number of // sub-sample kernel shifts. Can be adjusted for quality (higher is better) @@ -72,59 +82,87 @@ enum { kKernelStorageSize = kKernelSize * (kKernelOffsetCount + 1), // The size (in samples) of the internal buffer used by the resampler. - kBufferSize = kBlockSize + kKernelSize + kDefaultBufferSize = kDefaultBlockSize + kKernelSize }; } // namespace -const int SincResampler::kMaximumLookAheadSize = kBufferSize; - -SincResampler::SincResampler(double io_sample_rate_ratio, const ReadCB& read_cb) +SincResampler::SincResampler(double io_sample_rate_ratio, + SincResamplerCallback* read_cb, + int block_size) : io_sample_rate_ratio_(io_sample_rate_ratio), virtual_source_idx_(0), buffer_primed_(false), read_cb_(read_cb), + block_size_(block_size), + buffer_size_(block_size_ + kKernelSize), // Create input buffers with a 16-byte alignment for SSE optimizations. kernel_storage_(static_cast( - base::AlignedAlloc(sizeof(float) * kKernelStorageSize, 16))), + AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), input_buffer_(static_cast( - base::AlignedAlloc(sizeof(float) * kBufferSize, 16))), + AlignedMalloc(sizeof(float) * buffer_size_, 16))), // Setup various region pointers in the buffer (see diagram above). r0_(input_buffer_.get() + kKernelSize / 2), r1_(input_buffer_.get()), r2_(r0_), - r3_(r0_ + kBlockSize - kKernelSize / 2), - r4_(r0_ + kBlockSize), + r3_(r0_ + block_size_ - kKernelSize / 2), + r4_(r0_ + block_size_), r5_(r0_ + kKernelSize / 2) { - // Ensure kKernelSize is a multiple of 32 for easy SSE optimizations; causes - // r0_ and r5_ (used for input) to always be 16-byte aligned by virtue of - // input_buffer_ being 16-byte aligned. - DCHECK_EQ(kKernelSize % 32, 0) << "kKernelSize must be a multiple of 32!"; - DCHECK_GT(kBlockSize, kKernelSize) - << "kBlockSize must be greater than kKernelSize!"; - // Basic sanity checks to ensure buffer regions are laid out correctly: - // r0_ and r2_ should always be the same position. - DCHECK_EQ(r0_, r2_); - // r1_ at the beginning of the buffer. - DCHECK_EQ(r1_, input_buffer_.get()); - // r1_ left of r2_, r2_ left of r5_ and r1_, r2_ size correct. - DCHECK_EQ(r2_ - r1_, r5_ - r2_); - // r3_ left of r4_, r5_ left of r0_ and r3_ size correct. - DCHECK_EQ(r4_ - r3_, r5_ - r0_); - // r3_, r4_ size correct and r4_ at the end of the buffer. - DCHECK_EQ(r4_ + (r4_ - r3_), r1_ + kBufferSize); - // r5_ size correct and at the end of the buffer. - DCHECK_EQ(r5_ + kBlockSize, r1_ + kBufferSize); - - memset(kernel_storage_.get(), 0, - sizeof(*kernel_storage_.get()) * kKernelStorageSize); - memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * kBufferSize); + Initialize(); + InitializeKernel(); +} +SincResampler::SincResampler(double io_sample_rate_ratio, + SincResamplerCallback* read_cb) + : io_sample_rate_ratio_(io_sample_rate_ratio), + virtual_source_idx_(0), + buffer_primed_(false), + read_cb_(read_cb), + block_size_(kDefaultBlockSize), + buffer_size_(kDefaultBufferSize), + // Create input buffers with a 16-byte alignment for SSE optimizations. + kernel_storage_(static_cast( + AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))), + input_buffer_(static_cast( + AlignedMalloc(sizeof(float) * buffer_size_, 16))), + // Setup various region pointers in the buffer (see diagram above). + r0_(input_buffer_.get() + kKernelSize / 2), + r1_(input_buffer_.get()), + r2_(r0_), + r3_(r0_ + block_size_ - kKernelSize / 2), + r4_(r0_ + block_size_), + r5_(r0_ + kKernelSize / 2) { + Initialize(); InitializeKernel(); } SincResampler::~SincResampler() {} +void SincResampler::Initialize() { + // Ensure kKernelSize is a multiple of 32 for easy SSE optimizations; causes + // r0_ and r5_ (used for input) to always be 16-byte aligned by virtue of + // input_buffer_ being 16-byte aligned. + COMPILE_ASSERT(kKernelSize % 32 == 0); + assert(block_size_ > kKernelSize); + // Basic sanity checks to ensure buffer regions are laid out correctly: + // r0_ and r2_ should always be the same position. + assert(r0_ == r2_); + // r1_ at the beginning of the buffer. + assert(r1_ == input_buffer_.get()); + // r1_ left of r2_, r2_ left of r5_ and r1_, r2_ size correct. + assert(r2_ - r1_ == r5_ - r2_); + // r3_ left of r4_, r5_ left of r0_ and r3_ size correct. + assert(r4_ - r3_ == r5_ - r0_); + // r3_, r4_ size correct and r4_ at the end of the buffer. + assert(r4_ + (r4_ - r3_) == r1_ + buffer_size_); + // r5_ size correct and at the end of the buffer. + assert(r5_ + block_size_ == r1_ + buffer_size_); + + memset(kernel_storage_.get(), 0, + sizeof(*kernel_storage_.get()) * kKernelStorageSize); + memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_); +} + void SincResampler::InitializeKernel() { // Blackman window parameters. static const double kAlpha = 0.16; @@ -173,13 +211,13 @@ void SincResampler::Resample(float* destination, int frames) { // Step (1) -- Prime the input buffer at the start of the input stream. if (!buffer_primed_) { - read_cb_.Run(r0_, kBlockSize + kKernelSize / 2); + read_cb_->Run(r0_, block_size_ + kKernelSize / 2); buffer_primed_ = true; } // Step (2) -- Resample! while (remaining_frames) { - while (virtual_source_idx_ < kBlockSize) { + while (virtual_source_idx_ < block_size_) { // |virtual_source_idx_| lies in between two kernel offsets so figure out // what they are. int source_idx = static_cast(virtual_source_idx_); @@ -209,7 +247,7 @@ void SincResampler::Resample(float* destination, int frames) { } // Wrap back around to the start. - virtual_source_idx_ -= kBlockSize; + virtual_source_idx_ -= block_size_; // Step (3) Copy r3_ to r1_ and r4_ to r2_. // This wraps the last input frames back to the start of the buffer. @@ -218,18 +256,18 @@ void SincResampler::Resample(float* destination, int frames) { // Step (4) // Refresh the buffer with more input. - read_cb_.Run(r5_, kBlockSize); + read_cb_->Run(r5_, block_size_); } } int SincResampler::ChunkSize() { - return kBlockSize / io_sample_rate_ratio_; + return block_size_ / io_sample_rate_ratio_; } void SincResampler::Flush() { virtual_source_idx_ = 0; buffer_primed_ = false; - memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * kBufferSize); + memset(input_buffer_.get(), 0, sizeof(*input_buffer_.get()) * buffer_size_); } float SincResampler::Convolve(const float* input_ptr, const float* k1, @@ -240,11 +278,15 @@ float SincResampler::Convolve(const float* input_ptr, const float* k1, typedef float (*ConvolveProc)(const float* src, const float* k1, const float* k2, double kernel_interpolation_factor); -#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) +#if defined(WEBRTC_USE_SSE2) static const ConvolveProc kConvolveProc = - base::CPU().has_sse() ? Convolve_SSE : Convolve_C; -#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) + WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C; +#elif defined(WEBRTC_ARCH_ARM_NEON) static const ConvolveProc kConvolveProc = Convolve_NEON; +#elif defined(WEBRTC_DETECT_ARM_NEON) + static const ConvolveProc kConvolveProc = + WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ? Convolve_NEON : + Convolve_C; #else static const ConvolveProc kConvolveProc = Convolve_C; #endif @@ -271,14 +313,14 @@ float SincResampler::Convolve_C(const float* input_ptr, const float* k1, + kernel_interpolation_factor * sum2; } -#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) +#if defined(WEBRTC_USE_SSE2) float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { // Ensure |k1|, |k2| are 16-byte aligned for SSE usage. Should always be true // so long as kKernelSize is a multiple of 16. - DCHECK_EQ(0u, reinterpret_cast(k1) & 0x0F); - DCHECK_EQ(0u, reinterpret_cast(k2) & 0x0F); + assert(0u == (reinterpret_cast(k1) & 0x0F)); + assert(0u == (reinterpret_cast(k2) & 0x0F)); __m128 m_input; __m128 m_sums1 = _mm_setzero_ps(); @@ -315,33 +357,36 @@ float SincResampler::Convolve_SSE(const float* input_ptr, const float* k1, } #endif -#if defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) +#if defined(WEBRTC_ARCH_ARM_NEON) || defined(WEBRTC_DETECT_ARM_NEON) float SincResampler::Convolve_NEON(const float* input_ptr, const float* k1, const float* k2, double kernel_interpolation_factor) { - float32x4_t m_input; - float32x4_t m_sums1 = vmovq_n_f32(0); - float32x4_t m_sums2 = vmovq_n_f32(0); + // TODO(ajm): The AndroidNDK bot is giving compile errors in this function. + // Fallback to the plain C version until it's resolved. + return Convolve_C(input_ptr, k1, k2, kernel_interpolation_factor); + //float32x4_t m_input; + //float32x4_t m_sums1 = vmovq_n_f32(0); + //float32x4_t m_sums2 = vmovq_n_f32(0); - const float* upper = input_ptr + kKernelSize; - for (; input_ptr < upper; ) { - m_input = vld1q_f32(input_ptr); - input_ptr += 4; - m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1)); - k1 += 4; - m_sums2 = vmlaq_f32(m_sums2, m_input, vld1q_f32(k2)); - k2 += 4; - } + //const float* upper = input_ptr + kKernelSize; + //for (; input_ptr < upper; ) { + // m_input = vld1q_f32(input_ptr); + // input_ptr += 4; + // m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1)); + // k1 += 4; + // m_sums2 = vmlaq_f32(m_sums2, m_input, vld1q_f32(k2)); + // k2 += 4; + //} // Linearly interpolate the two "convolutions". - m_sums1 = vmlaq_f32( - vmulq_f32(m_sums1, vmovq_n_f32(1.0 - kernel_interpolation_factor)), - m_sums2, vmovq_n_f32(kernel_interpolation_factor)); + //m_sums1 = vmlaq_f32( + // vmulq_f32(m_sums1, vmovq_n_f32(1.0 - kernel_interpolation_factor)), + // m_sums2, vmovq_n_f32(kernel_interpolation_factor)); // Sum components together. - float32x2_t m_half = vadd_f32(vget_high_f32(m_sums1), vget_low_f32(m_sums1)); - return vget_lane_f32(vpadd_f32(m_half, m_half), 0); + //float32x2_t m_half = vadd_f32(vget_high_f32(m_sums1), vget_low_f32(m_sums1)); + //return vget_lane_f32(vpadd_f32(m_half, m_half), 0); } #endif -} // namespace media +} // namespace webrtc diff --git a/webrtc/common_audio/resampler/sinc_resampler.h b/webrtc/common_audio/resampler/sinc_resampler.h index a1d3cf718b..84a6b6ec9c 100644 --- a/webrtc/common_audio/resampler/sinc_resampler.h +++ b/webrtc/common_audio/resampler/sinc_resampler.h @@ -1,34 +1,45 @@ -// 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. + */ -#ifndef MEDIA_BASE_SINC_RESAMPLER_H_ -#define MEDIA_BASE_SINC_RESAMPLER_H_ +// Modified from the Chromium original here: +// src/media/base/sinc_resampler.h -#include "base/callback.h" -#include "base/gtest_prod_util.h" -#include "base/memory/aligned_memory.h" -#include "base/memory/scoped_ptr.h" -#include "media/base/media_export.h" +#ifndef WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ +#define WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ -namespace media { +#include "webrtc/system_wrappers/interface/aligned_malloc.h" +#include "webrtc/system_wrappers/interface/constructor_magic.h" +#include "webrtc/system_wrappers/interface/scoped_ptr.h" +#include "webrtc/test/testsupport/gtest_prod_util.h" + +namespace webrtc { + +// Callback class to provide SincResampler with input. +class SincResamplerCallback { + public: + virtual ~SincResamplerCallback() {} + virtual void Run(float* destination, int frames) = 0; +}; // SincResampler is a high-quality single-channel sample-rate converter. -class MEDIA_EXPORT SincResampler { +class SincResampler { public: - // The maximum number of samples that may be requested from the callback ahead - // of the current position in the stream. - static const int kMaximumLookAheadSize; - - // Callback type for providing more data into the resampler. Expects |frames| - // of data to be rendered into |destination|; zero padded if not enough frames - // are available to satisfy the request. - typedef base::Callback ReadCB; - // Constructs a SincResampler with the specified |read_cb|, which is used to // acquire audio data for resampling. |io_sample_rate_ratio| is the ratio of - // input / output sample rates. - SincResampler(double io_sample_rate_ratio, const ReadCB& read_cb); + // input / output sample rates. If desired, the number of destination frames + // generated per processing pass can be specified through |block_size|. + SincResampler(double io_sample_rate_ratio, + SincResamplerCallback* read_cb); + SincResampler(double io_sample_rate_ratio, + SincResamplerCallback* read_cb, + int block_size); virtual ~SincResampler(); // Resample |frames| of data from |read_cb_| into |destination|. @@ -45,6 +56,7 @@ class MEDIA_EXPORT SincResampler { FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve); FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark); + void Initialize(); void InitializeKernel(); // Compute convolution of |k1| and |k2| over |input_ptr|, resultant sums are @@ -73,15 +85,21 @@ class MEDIA_EXPORT SincResampler { bool buffer_primed_; // Source of data for resampling. - ReadCB read_cb_; + SincResamplerCallback* read_cb_; + + // See kDefaultBlockSize. + int block_size_; + + // See kDefaultBufferSize. + int buffer_size_; // Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize. // The kernel offsets are sub-sample shifts of a windowed sinc shifted from // 0.0 to 1.0 sample. - scoped_ptr_malloc kernel_storage_; + scoped_ptr_malloc kernel_storage_; // Data from the source is copied into this buffer for each processing pass. - scoped_ptr_malloc input_buffer_; + scoped_ptr_malloc input_buffer_; // Pointers to the various regions inside |input_buffer_|. See the diagram at // the top of the .cc file for more information. @@ -95,6 +113,6 @@ class MEDIA_EXPORT SincResampler { DISALLOW_COPY_AND_ASSIGN(SincResampler); }; -} // namespace media +} // namespace webrtc -#endif // MEDIA_BASE_SINC_RESAMPLER_H_ +#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ diff --git a/webrtc/common_audio/resampler/sinc_resampler_unittest.cc b/webrtc/common_audio/resampler/sinc_resampler_unittest.cc index 0f718f23df..cad389ca66 100644 --- a/webrtc/common_audio/resampler/sinc_resampler_unittest.cc +++ b/webrtc/common_audio/resampler/sinc_resampler_unittest.cc @@ -1,38 +1,40 @@ -// 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 -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/string_number_conversions.h" -#include "base/strings/stringize_macros.h" -#include "base/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/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(float* destination, int frames)); + MOCK_METHOD2(Run, void(float* destination, int frames)); }; ACTION(ClearBuffer) { @@ -53,22 +55,20 @@ 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, - base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); + SincResampler resampler(kSampleRateRatio, &mock_source); static const int kChunks = 2; int max_chunk_size = resampler.ChunkSize() * kChunks; scoped_array 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(resampled_destination.get(), resampler.ChunkSize()); // 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(resampled_destination.get(), max_chunk_size); } @@ -76,13 +76,11 @@ TEST(SincResamplerTest, ChunkedResample) { // Test flush resets the internal state properly. TEST(SincResamplerTest, Flush) { MockSource mock_source; - SincResampler resampler( - kSampleRateRatio, - base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); + SincResampler resampler(kSampleRateRatio, &mock_source); scoped_array 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(resampled_destination.get(), resampler.ChunkSize() / 2); ASSERT_NE(resampled_destination[0], 0); @@ -90,7 +88,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(resampled_destination.get(), resampler.ChunkSize() / 2); for (int i = 0; i < resampler.ChunkSize() / 2; ++i) @@ -98,9 +96,9 @@ TEST(SincResamplerTest, Flush) { } // Define platform independent function name for Convolve* tests. -#if defined(ARCH_CPU_X86_FAMILY) && defined(__SSE__) +#if defined(WEBRTC_USE_SSE2) && defined(__SSE__) #define CONVOLVE_FUNC Convolve_SSE -#elif defined(ARCH_CPU_ARM_FAMILY) && defined(USE_NEON) +#elif defined(WEBRTC_ARCH_ARM_NEON) || defined(WEBRTC_DETECT_ARM_NEON) #define CONVOLVE_FUNC Convolve_NEON #endif @@ -111,9 +109,7 @@ TEST(SincResamplerTest, Flush) { TEST(SincResamplerTest, Convolve) { // Initialize a dummy resampler. MockSource mock_source; - SincResampler resampler( - kSampleRateRatio, - base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); + SincResampler resampler(kSampleRateRatio, &mock_source); // The optimized Convolve methods are slightly more precise than Convolve_C(), // so comparison must be done using an epsilon. @@ -146,59 +142,53 @@ TEST(SincResamplerTest, Convolve) { TEST(SincResamplerTest, ConvolveBenchmark) { // Initialize a dummy resampler. MockSource mock_source; - SincResampler resampler( - kSampleRateRatio, - base::Bind(&MockSource::ProvideInput, base::Unretained(&mock_source))); + SincResampler resampler(kSampleRateRatio, &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) // 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(); + 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_ms, - total_time_c_ms / total_time_optimized_unaligned_ms); + "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 } @@ -207,7 +197,7 @@ TEST(SincResamplerTest, ConvolveBenchmark) { // 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 { +class SinusoidalLinearChirpSource : public SincResamplerCallback { public: SinusoidalLinearChirpSource(int sample_rate, int samples, double max_frequency) @@ -222,7 +212,7 @@ class SinusoidalLinearChirpSource { virtual ~SinusoidalLinearChirpSource() {} - void ProvideInput(float* destination, int frames) { + virtual void Run(float* destination, int frames) { for (int i = 0; i < frames; ++i, ++current_index_) { // Filter out frequencies higher than Nyquist. if (Frequency(current_index_) > 0.5 * sample_rate_) { @@ -292,8 +282,7 @@ TEST_P(SincResamplerTest, Resample) { SincResampler resampler( input_rate_ / static_cast(output_rate_), - base::Bind(&SinusoidalLinearChirpSource::ProvideInput, - base::Unretained(&resampler_source))); + &resampler_source); // 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. @@ -306,7 +295,7 @@ TEST_P(SincResamplerTest, Resample) { // Generate pure signal. SinusoidalLinearChirpSource pure_source( output_rate_, output_samples, input_nyquist_freq); - pure_source.ProvideInput(pure_destination.get(), output_samples); + pure_source.Run(pure_destination.get(), output_samples); // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which // we refer to as low and high. @@ -402,4 +391,5 @@ 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 + diff --git a/webrtc/system_wrappers/interface/stringize_macros.h b/webrtc/system_wrappers/interface/stringize_macros.h index d4e27071e4..ab8c43d4e2 100644 --- a/webrtc/system_wrappers/interface/stringize_macros.h +++ b/webrtc/system_wrappers/interface/stringize_macros.h @@ -1,15 +1,22 @@ -// Copyright (c) 2010 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/base/strings/stringize_macros.h + // This file defines preprocessor macros for stringizing preprocessor // symbols (or their output) and manipulating preprocessor symbols // that define strings. -#ifndef BASE_STRINGS_STRINGIZE_MACROS_H_ -#define BASE_STRINGS_STRINGIZE_MACROS_H_ - -#include "build/build_config.h" +#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ +#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ // This is not very useful as it does not expand defined symbols if // called directly. Use its counterpart without the _NO_EXPANSION @@ -28,4 +35,4 @@ // STRINGIZE(B(y)) produces "myobj->FunctionCall(y)" #define STRINGIZE(x) STRINGIZE_NO_EXPANSION(x) -#endif // BASE_STRINGS_STRINGIZE_MACROS_H_ +#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STRINGIZE_MACROS_H_ diff --git a/webrtc/system_wrappers/source/stringize_macros_unittest.cc b/webrtc/system_wrappers/source/stringize_macros_unittest.cc index d7f9e560ae..8d953dd540 100644 --- a/webrtc/system_wrappers/source/stringize_macros_unittest.cc +++ b/webrtc/system_wrappers/source/stringize_macros_unittest.cc @@ -1,8 +1,14 @@ -// Copyright (c) 2010 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. + */ -#include "base/strings/stringize_macros.h" +#include "webrtc/system_wrappers/interface/stringize_macros.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/webrtc/system_wrappers/source/system_wrappers.gyp b/webrtc/system_wrappers/source/system_wrappers.gyp index 71da723a7d..2e79fb55ec 100644 --- a/webrtc/system_wrappers/source/system_wrappers.gyp +++ b/webrtc/system_wrappers/source/system_wrappers.gyp @@ -48,6 +48,7 @@ '../interface/sleep.h', '../interface/sort.h', '../interface/static_instance.h', + '../interface/stringize_macros.h', '../interface/thread_wrapper.h', '../interface/tick_util.h', '../interface/trace.h', @@ -258,6 +259,7 @@ 'data_log_helpers_unittest.cc', 'data_log_c_helpers_unittest.c', 'data_log_c_helpers_unittest.h', + 'stringize_macros_unittest.cc', 'thread_unittest.cc', 'thread_posix_unittest.cc', 'trace_unittest.cc',