/* * Copyright (c) 2012 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 "webrtc/modules/audio_coding/neteq/audio_vector.h" #include #include #include #include "testing/gtest/include/gtest/gtest.h" #include "webrtc/typedefs.h" namespace webrtc { class AudioVectorTest : public ::testing::Test { protected: virtual void SetUp() { // Populate test array. for (size_t i = 0; i < array_length(); ++i) { array_[i] = i; } } size_t array_length() const { return sizeof(array_) / sizeof(array_[0]); } int16_t array_[10]; }; // Create and destroy AudioVector objects, both empty and with a predefined // length. TEST_F(AudioVectorTest, CreateAndDestroy) { AudioVector vec1; EXPECT_TRUE(vec1.Empty()); EXPECT_EQ(0u, vec1.Size()); size_t initial_size = 17; AudioVector vec2(initial_size); EXPECT_FALSE(vec2.Empty()); EXPECT_EQ(initial_size, vec2.Size()); } // Test the subscript operator [] for getting and setting. TEST_F(AudioVectorTest, SubscriptOperator) { AudioVector vec(array_length()); for (size_t i = 0; i < array_length(); ++i) { vec[i] = static_cast(i); const int16_t& value = vec[i]; // Make sure to use the const version. EXPECT_EQ(static_cast(i), value); } } // Test the PushBack method and the CopyFrom method. The Clear method is also // invoked. TEST_F(AudioVectorTest, PushBackAndCopy) { AudioVector vec; AudioVector vec_copy; vec.PushBack(array_, array_length()); vec.CopyTo(&vec_copy); // Copy from |vec| to |vec_copy|. ASSERT_EQ(array_length(), vec.Size()); ASSERT_EQ(array_length(), vec_copy.Size()); for (size_t i = 0; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[i]); EXPECT_EQ(array_[i], vec_copy[i]); } // Clear |vec| and verify that it is empty. vec.Clear(); EXPECT_TRUE(vec.Empty()); // Now copy the empty vector and verify that the copy becomes empty too. vec.CopyTo(&vec_copy); EXPECT_TRUE(vec_copy.Empty()); } // Try to copy to a NULL pointer. Nothing should happen. TEST_F(AudioVectorTest, CopyToNull) { AudioVector vec; AudioVector* vec_copy = NULL; vec.PushBack(array_, array_length()); vec.CopyTo(vec_copy); } // Test the PushBack method with another AudioVector as input argument. TEST_F(AudioVectorTest, PushBackVector) { static const size_t kLength = 10; AudioVector vec1(kLength); AudioVector vec2(kLength); // Set the first vector to [0, 1, ..., kLength - 1]. // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1]. for (size_t i = 0; i < kLength; ++i) { vec1[i] = static_cast(i); vec2[i] = static_cast(i + kLength); } // Append vec2 to the back of vec1. vec1.PushBack(vec2); ASSERT_EQ(2 * kLength, vec1.Size()); for (size_t i = 0; i < 2 * kLength; ++i) { EXPECT_EQ(static_cast(i), vec1[i]); } } // Test the PushFront method. TEST_F(AudioVectorTest, PushFront) { AudioVector vec; vec.PushFront(array_, array_length()); ASSERT_EQ(array_length(), vec.Size()); for (size_t i = 0; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[i]); } } // Test the PushFront method with another AudioVector as input argument. TEST_F(AudioVectorTest, PushFrontVector) { static const size_t kLength = 10; AudioVector vec1(kLength); AudioVector vec2(kLength); // Set the first vector to [0, 1, ..., kLength - 1]. // Set the second vector to [kLength, kLength + 1, ..., 2 * kLength - 1]. for (size_t i = 0; i < kLength; ++i) { vec1[i] = static_cast(i); vec2[i] = static_cast(i + kLength); } // Prepend vec1 to the front of vec2. vec2.PushFront(vec1); ASSERT_EQ(2 * kLength, vec2.Size()); for (size_t i = 0; i < 2 * kLength; ++i) { EXPECT_EQ(static_cast(i), vec2[i]); } } // Test the PopFront method. TEST_F(AudioVectorTest, PopFront) { AudioVector vec; vec.PushBack(array_, array_length()); vec.PopFront(1); // Remove one element. EXPECT_EQ(array_length() - 1u, vec.Size()); for (size_t i = 0; i < array_length() - 1; ++i) { EXPECT_EQ(static_cast(i + 1), vec[i]); } vec.PopFront(array_length()); // Remove more elements than vector size. EXPECT_EQ(0u, vec.Size()); } // Test the PopBack method. TEST_F(AudioVectorTest, PopBack) { AudioVector vec; vec.PushBack(array_, array_length()); vec.PopBack(1); // Remove one element. EXPECT_EQ(array_length() - 1u, vec.Size()); for (size_t i = 0; i < array_length() - 1; ++i) { EXPECT_EQ(static_cast(i), vec[i]); } vec.PopBack(array_length()); // Remove more elements than vector size. EXPECT_EQ(0u, vec.Size()); } // Test the Extend method. TEST_F(AudioVectorTest, Extend) { AudioVector vec; vec.PushBack(array_, array_length()); vec.Extend(5); // Extend with 5 elements, which should all be zeros. ASSERT_EQ(array_length() + 5u, vec.Size()); // Verify that all are zero. for (size_t i = array_length(); i < array_length() + 5; ++i) { EXPECT_EQ(0, vec[i]); } } // Test the InsertAt method with an insert position in the middle of the vector. TEST_F(AudioVectorTest, InsertAt) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } int insert_position = 5; vec.InsertAt(new_array, kNewLength, insert_position); // Verify that the vector looks as follows: // {0, 1, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, // |insert_position|, |insert_position| + 1, ..., kLength - 1}. size_t pos = 0; for (int i = 0; i < insert_position; ++i) { EXPECT_EQ(array_[i], vec[pos]); ++pos; } for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } for (size_t i = insert_position; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[pos]); ++pos; } } // Test the InsertZerosAt method with an insert position in the middle of the // vector. Use the InsertAt method as reference. TEST_F(AudioVectorTest, InsertZerosAt) { AudioVector vec; AudioVector vec_ref; vec.PushBack(array_, array_length()); vec_ref.PushBack(array_, array_length()); static const int kNewLength = 5; int insert_position = 5; vec.InsertZerosAt(kNewLength, insert_position); int16_t new_array[kNewLength] = {0}; // All zero elements. vec_ref.InsertAt(new_array, kNewLength, insert_position); // Verify that the vectors are identical. ASSERT_EQ(vec_ref.Size(), vec.Size()); for (size_t i = 0; i < vec.Size(); ++i) { EXPECT_EQ(vec_ref[i], vec[i]); } } // Test the InsertAt method with an insert position at the start of the vector. TEST_F(AudioVectorTest, InsertAtBeginning) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } int insert_position = 0; vec.InsertAt(new_array, kNewLength, insert_position); // Verify that the vector looks as follows: // {100, 101, ..., 100 + kNewLength - 1, // 0, 1, ..., kLength - 1}. size_t pos = 0; for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } for (size_t i = insert_position; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[pos]); ++pos; } } // Test the InsertAt method with an insert position at the end of the vector. TEST_F(AudioVectorTest, InsertAtEnd) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } int insert_position = array_length(); vec.InsertAt(new_array, kNewLength, insert_position); // Verify that the vector looks as follows: // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }. size_t pos = 0; for (size_t i = 0; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[pos]); ++pos; } for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } } // Test the InsertAt method with an insert position beyond the end of the // vector. Verify that a position beyond the end of the vector does not lead to // an error. The expected outcome is the same as if the vector end was used as // input position. That is, the input position should be capped at the maximum // allowed value. TEST_F(AudioVectorTest, InsertBeyondEnd) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } int insert_position = array_length() + 10; // Too large. vec.InsertAt(new_array, kNewLength, insert_position); // Verify that the vector looks as follows: // {0, 1, ..., kLength - 1, 100, 101, ..., 100 + kNewLength - 1 }. size_t pos = 0; for (size_t i = 0; i < array_length(); ++i) { EXPECT_EQ(array_[i], vec[pos]); ++pos; } for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } } // Test the OverwriteAt method with a position such that all of the new values // fit within the old vector. TEST_F(AudioVectorTest, OverwriteAt) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } size_t insert_position = 2; vec.OverwriteAt(new_array, kNewLength, insert_position); // Verify that the vector looks as follows: // {0, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, // |insert_position|, |insert_position| + 1, ..., kLength - 1}. size_t pos = 0; for (pos = 0; pos < insert_position; ++pos) { EXPECT_EQ(array_[pos], vec[pos]); } for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } for (; pos < array_length(); ++pos) { EXPECT_EQ(array_[pos], vec[pos]); } } // Test the OverwriteAt method with a position such that some of the new values // extend beyond the end of the current vector. This is valid, and the vector is // expected to expand to accommodate the new values. TEST_F(AudioVectorTest, OverwriteBeyondEnd) { AudioVector vec; vec.PushBack(array_, array_length()); static const int kNewLength = 5; int16_t new_array[kNewLength]; // Set array elements to {100, 101, 102, ... }. for (int i = 0; i < kNewLength; ++i) { new_array[i] = 100 + i; } int insert_position = array_length() - 2; vec.OverwriteAt(new_array, kNewLength, insert_position); ASSERT_EQ(array_length() - 2u + kNewLength, vec.Size()); // Verify that the vector looks as follows: // {0, ..., |insert_position| - 1, 100, 101, ..., 100 + kNewLength - 1, // |insert_position|, |insert_position| + 1, ..., kLength - 1}. int pos = 0; for (pos = 0; pos < insert_position; ++pos) { EXPECT_EQ(array_[pos], vec[pos]); } for (int i = 0; i < kNewLength; ++i) { EXPECT_EQ(new_array[i], vec[pos]); ++pos; } // Verify that we checked to the end of |vec|. EXPECT_EQ(vec.Size(), static_cast(pos)); } TEST_F(AudioVectorTest, CrossFade) { static const size_t kLength = 100; static const size_t kFadeLength = 10; AudioVector vec1(kLength); AudioVector vec2(kLength); // Set all vector elements to 0 in |vec1| and 100 in |vec2|. for (size_t i = 0; i < kLength; ++i) { vec1[i] = 0; vec2[i] = 100; } vec1.CrossFade(vec2, kFadeLength); ASSERT_EQ(2 * kLength - kFadeLength, vec1.Size()); // First part untouched. for (size_t i = 0; i < kLength - kFadeLength; ++i) { EXPECT_EQ(0, vec1[i]); } // Check mixing zone. for (size_t i = 0 ; i < kFadeLength; ++i) { EXPECT_NEAR((i + 1) * 100 / (kFadeLength + 1), vec1[kLength - kFadeLength + i], 1); } // Second part untouched. for (size_t i = kLength; i < vec1.Size(); ++i) { EXPECT_EQ(100, vec1[i]); } } } // namespace webrtc