diff options
Diffstat (limited to 'src/3rdparty/resonance-audio/resonance_audio/utils/buffer_partitioner_test.cc')
-rw-r--r-- | src/3rdparty/resonance-audio/resonance_audio/utils/buffer_partitioner_test.cc | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/src/3rdparty/resonance-audio/resonance_audio/utils/buffer_partitioner_test.cc b/src/3rdparty/resonance-audio/resonance_audio/utils/buffer_partitioner_test.cc new file mode 100644 index 000000000..a486b1f23 --- /dev/null +++ b/src/3rdparty/resonance-audio/resonance_audio/utils/buffer_partitioner_test.cc @@ -0,0 +1,241 @@ +/* +Copyright 2018 Google Inc. All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS-IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "utils/buffer_partitioner.h" + +#include <memory> + +#include "third_party/googletest/googletest/include/gtest/gtest.h" +#include "base/audio_buffer.h" +#include "base/constants_and_types.h" +#include "base/misc_math.h" +#include "utils/planar_interleaved_conversion.h" +#include "utils/test_util.h" + +namespace vraudio { + +const size_t kNumFramesPerBuffer = 64; + +using vraudio::AudioBuffer; + +class BufferPartitionerTest : public ::testing::Test { + public: + // Public validation method. This is called for every generated |AudioBuffer|. + AudioBuffer* ValidateAudioBufferCallback(AudioBuffer* audio_buffer) { + if (audio_buffer != nullptr) { + std::vector<float> received_buffer_interleaved; + FillExternalBuffer(*audio_buffer, &received_buffer_interleaved); + total_received_buffer_interleaved_.insert( + total_received_buffer_interleaved_.end(), + received_buffer_interleaved.begin(), + received_buffer_interleaved.end()); + + ++num_total_buffers_received_; + num_total_frames_received_ += audio_buffer->num_frames(); + } + ++num_total_callbacks_triggered_; + return &partitioned_buffer_; + } + + protected: + BufferPartitionerTest() + : partitioned_buffer_(kNumMonoChannels, kNumFramesPerBuffer), + partitioner_( + kNumMonoChannels, kNumFramesPerBuffer, + std::bind(&BufferPartitionerTest::ValidateAudioBufferCallback, this, + std::placeholders::_1)), + num_total_frames_received_(0), + num_total_buffers_received_(0), + num_total_callbacks_triggered_(0) {} + ~BufferPartitionerTest() override {} + + // Returns a section of an |AudioBuffer| in interleaved format. + template <typename T> + std::vector<T> GetInterleavedVectorFromAudioBufferSection( + const AudioBuffer& planar_buffer, size_t frame_offset, + size_t num_frames) { + CHECK_GE(planar_buffer.num_frames(), frame_offset + num_frames); + std::vector<T> return_vector(planar_buffer.num_channels() * num_frames); + + FillExternalBufferWithOffset( + planar_buffer, frame_offset, return_vector.data(), num_frames, + planar_buffer.num_channels(), 0 /* output_offset_frames */, num_frames); + + return return_vector; + } + + template <typename T> + void SmallBufferInputTest(float buffer_epsilon) { + ResetTest(); + + const size_t kNumInputBuffers = 8; + const size_t kNumFramesPerTestBuffer = + kNumFramesPerBuffer / kNumInputBuffers; + + AudioBuffer test_buffer(vraudio::kNumMonoChannels, kNumFramesPerBuffer); + GenerateSawToothSignal(kNumFramesPerBuffer, &test_buffer[0]); + + for (size_t i = 0; i < kNumInputBuffers; ++i) { + const std::vector<T> input_interleaved = + GetInterleavedVectorFromAudioBufferSection<T>( + test_buffer, kNumFramesPerTestBuffer * i, + kNumFramesPerTestBuffer); + + partitioner_.AddBuffer(input_interleaved.data(), kNumMonoChannels, + kNumFramesPerTestBuffer); + } + EXPECT_EQ(num_total_buffers_received_, 1U); + EXPECT_EQ(num_total_callbacks_triggered_, num_total_buffers_received_ + 1); + EXPECT_EQ(num_total_frames_received_, kNumFramesPerBuffer); + + AudioBuffer reconstructed_buffer(kNumMonoChannels, kNumFramesPerBuffer); + FillAudioBuffer(total_received_buffer_interleaved_, kNumMonoChannels, + &reconstructed_buffer); + + EXPECT_TRUE(CompareAudioBuffers(test_buffer[0], reconstructed_buffer[0], + buffer_epsilon)); + } + + template <typename T> + void LargeBufferTest(float buffer_epsilon) { + ResetTest(); + const size_t kNumOutputBuffers = 8; + const size_t kNumFramesPerTestBuffer = + kNumFramesPerBuffer * kNumOutputBuffers; + + AudioBuffer test_buffer(vraudio::kNumMonoChannels, kNumFramesPerTestBuffer); + GenerateSawToothSignal(kNumFramesPerTestBuffer, &test_buffer[0]); + + const std::vector<T> input_interleaved = + GetInterleavedVectorFromAudioBufferSection<T>(test_buffer, 0, + kNumFramesPerTestBuffer); + + partitioner_.AddBuffer(input_interleaved.data(), kNumMonoChannels, + kNumFramesPerTestBuffer); + + EXPECT_EQ(num_total_buffers_received_, kNumOutputBuffers); + EXPECT_EQ(num_total_callbacks_triggered_, num_total_buffers_received_ + 1); + EXPECT_EQ(num_total_frames_received_, kNumFramesPerTestBuffer); + + AudioBuffer reconstructed_buffer(kNumMonoChannels, kNumFramesPerTestBuffer); + FillAudioBuffer(total_received_buffer_interleaved_, kNumMonoChannels, + &reconstructed_buffer); + + EXPECT_TRUE(CompareAudioBuffers(test_buffer[0], reconstructed_buffer[0], + buffer_epsilon)); + } + + void ResetTest() { + num_total_frames_received_ = 0; + num_total_buffers_received_ = 0; + num_total_callbacks_triggered_ = 0; + total_received_buffer_interleaved_.clear(); + + partitioner_.Clear(); + } + + AudioBuffer partitioned_buffer_; + std::vector<float> total_received_buffer_interleaved_; + + BufferPartitioner partitioner_; + + // Stores the total number of frames received in + // |ValidateAudioBufferCallback|. + size_t num_total_frames_received_; + + // Stores the total number of buffers received in + // |ValidateAudioBufferCallback|. + size_t num_total_buffers_received_; + + // Stores the total number of callbacks being triggered in + // |ValidateAudioBufferCallback|. + size_t num_total_callbacks_triggered_; +}; + +// Tests the concatenation of multiple small buffers into a single +// |AudioBuffer|. +TEST_F(BufferPartitionerTest, TestSmallBufferInput) { + // int16 to float conversions introduce rounding errors. + SmallBufferInputTest<int16>(1e-4f /* buffer_epsilon */); + SmallBufferInputTest<float>(1e-6f /* buffer_epsilon */); +} + +// Tests the splitting of a large input buffer into multiple |AudioBuffer|s. +TEST_F(BufferPartitionerTest, TestLargeBufferInput) { + // int16 to float conversions introduce rounding errors. + LargeBufferTest<int16>(1e-4f /* buffer_epsilon */); + LargeBufferTest<float>(1e-6f /* buffer_epsilon */); +} + +// Tests the GetNumBufferedFramesTest() and +// GetNumGeneratedBuffersForNumInputFrames() methods. +TEST_F(BufferPartitionerTest, GetNumBufferedFramesTest) { + const std::vector<float> input_interleaved(1, 1.0f); + + EXPECT_EQ(partitioner_.GetNumGeneratedBuffersForNumInputFrames( + kNumFramesPerBuffer - 1), + 0U); + EXPECT_EQ( + partitioner_.GetNumGeneratedBuffersForNumInputFrames(kNumFramesPerBuffer), + 1U); + + for (size_t i = 0; i < kNumFramesPerBuffer * 2; ++i) { + EXPECT_EQ(partitioner_.GetNumBufferedFrames(), i % kNumFramesPerBuffer); + + const size_t large_random_frame_number = + i * 7 * kNumFramesPerBuffer + 13 * i; + // Expected number of generated buffers is based on + // |large_random_frame_number| and the internally stored remainder |i % + // kNumFramesPerBuffer|. + const size_t expected_num_generated_buffers = + (large_random_frame_number + partitioner_.GetNumBufferedFrames()) / + kNumFramesPerBuffer; + + EXPECT_EQ(partitioner_.GetNumGeneratedBuffersForNumInputFrames( + large_random_frame_number), + expected_num_generated_buffers); + + // Add single frame to |partinioner_|. + partitioner_.AddBuffer(input_interleaved.data(), kNumMonoChannels, 1); + } +} + +// Tests the Flush() method. +TEST_F(BufferPartitionerTest, FlushTest) { + AudioBuffer test_buffer(vraudio::kNumMonoChannels, kNumFramesPerBuffer); + GenerateDiracImpulseFilter(0, &test_buffer[0]); + + const std::vector<float> input_interleaved = + GetInterleavedVectorFromAudioBufferSection<float>( + test_buffer, 0 /* frame_offset */, kNumFramesPerBuffer); + + // Add only the first sample that contains the dirac impulse. + partitioner_.AddBuffer(input_interleaved.data(), kNumMonoChannels, 1); + partitioner_.Flush(); + + EXPECT_EQ(num_total_buffers_received_, 1U); + EXPECT_EQ(num_total_callbacks_triggered_, num_total_buffers_received_ + 1); + EXPECT_EQ(num_total_frames_received_, kNumFramesPerBuffer); + + AudioBuffer reconstructed_buffer(kNumMonoChannels, kNumFramesPerBuffer); + FillAudioBuffer(total_received_buffer_interleaved_, kNumMonoChannels, + &reconstructed_buffer); + + EXPECT_TRUE(CompareAudioBuffers(test_buffer[0], reconstructed_buffer[0], + kEpsilonFloat)); +} + +} // namespace vraudio |