|  | /* | 
|  | *  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 "modules/audio_coding/neteq/sync_buffer.h" | 
|  |  | 
|  | #include <cstddef> | 
|  | #include <cstdint> | 
|  |  | 
|  | #include "api/audio/audio_frame.h" | 
|  | #include "modules/audio_coding/neteq/audio_multi_vector.h" | 
|  | #include "rtc_base/numerics/safe_conversions.h" | 
|  | #include "test/gtest.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | TEST(SyncBuffer, CreateAndDestroy) { | 
|  | // Create a SyncBuffer with two channels and 10 samples each. | 
|  | static const size_t kLen = 10; | 
|  | static const size_t kChannels = 2; | 
|  | SyncBuffer sync_buffer(kChannels, kLen); | 
|  | EXPECT_EQ(kChannels, sync_buffer.Channels()); | 
|  | EXPECT_EQ(kLen, sync_buffer.Size()); | 
|  | // When the buffer is empty, the next index to play out is at the end. | 
|  | EXPECT_EQ(kLen, sync_buffer.next_index()); | 
|  | // Verify that all elements are zero. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kLen; ++i) { | 
|  | EXPECT_EQ(0, sync_buffer[channel][i]); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(SyncBuffer, SetNextIndex) { | 
|  | // Create a SyncBuffer with two channels and 100 samples each. | 
|  | static const size_t kLen = 100; | 
|  | static const size_t kChannels = 2; | 
|  | SyncBuffer sync_buffer(kChannels, kLen); | 
|  | sync_buffer.set_next_index(0); | 
|  | EXPECT_EQ(0u, sync_buffer.next_index()); | 
|  | sync_buffer.set_next_index(kLen / 2); | 
|  | EXPECT_EQ(kLen / 2, sync_buffer.next_index()); | 
|  | sync_buffer.set_next_index(kLen); | 
|  | EXPECT_EQ(kLen, sync_buffer.next_index()); | 
|  | // Try to set larger than the buffer size; should cap at buffer size. | 
|  | sync_buffer.set_next_index(kLen + 1); | 
|  | EXPECT_EQ(kLen, sync_buffer.next_index()); | 
|  | } | 
|  |  | 
|  | TEST(SyncBuffer, PushBackAndFlush) { | 
|  | // Create a SyncBuffer with two channels and 100 samples each. | 
|  | static const size_t kLen = 100; | 
|  | static const size_t kChannels = 2; | 
|  | SyncBuffer sync_buffer(kChannels, kLen); | 
|  | static const size_t kNewLen = 10; | 
|  | AudioMultiVector new_data(kChannels, kNewLen); | 
|  | // Populate `new_data`. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kNewLen; ++i) { | 
|  | new_data[channel][i] = checked_cast<int16_t>(i); | 
|  | } | 
|  | } | 
|  | // Push back `new_data` into `sync_buffer`. This operation should pop out | 
|  | // data from the front of `sync_buffer`, so that the size of the buffer | 
|  | // remains the same. The `next_index_` should also move with the same length. | 
|  | sync_buffer.PushBack(new_data); | 
|  | ASSERT_EQ(kLen, sync_buffer.Size()); | 
|  | // Verify that `next_index_` moved accordingly. | 
|  | EXPECT_EQ(kLen - kNewLen, sync_buffer.next_index()); | 
|  | // Verify the new contents. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kNewLen; ++i) { | 
|  | EXPECT_EQ(new_data[channel][i], | 
|  | sync_buffer[channel][sync_buffer.next_index() + i]); | 
|  | } | 
|  | } | 
|  |  | 
|  | // Now flush the buffer, and verify that it is all zeros, and that next_index | 
|  | // points to the end. | 
|  | sync_buffer.Flush(); | 
|  | ASSERT_EQ(kLen, sync_buffer.Size()); | 
|  | EXPECT_EQ(kLen, sync_buffer.next_index()); | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kLen; ++i) { | 
|  | EXPECT_EQ(0, sync_buffer[channel][i]); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(SyncBuffer, PushFrontZeros) { | 
|  | // Create a SyncBuffer with two channels and 100 samples each. | 
|  | static const size_t kLen = 100; | 
|  | static const size_t kChannels = 2; | 
|  | SyncBuffer sync_buffer(kChannels, kLen); | 
|  | static const size_t kNewLen = 10; | 
|  | AudioMultiVector new_data(kChannels, kNewLen); | 
|  | // Populate `new_data`. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kNewLen; ++i) { | 
|  | new_data[channel][i] = checked_cast<int16_t>(1000 + i); | 
|  | } | 
|  | } | 
|  | sync_buffer.PushBack(new_data); | 
|  | EXPECT_EQ(kLen, sync_buffer.Size()); | 
|  |  | 
|  | // Push `kNewLen` - 1 zeros into each channel in the front of the SyncBuffer. | 
|  | sync_buffer.PushFrontZeros(kNewLen - 1); | 
|  | EXPECT_EQ(kLen, sync_buffer.Size());  // Size should remain the same. | 
|  | // Verify that `next_index_` moved accordingly. Should be at the end - 1. | 
|  | EXPECT_EQ(kLen - 1, sync_buffer.next_index()); | 
|  | // Verify the zeros. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kNewLen - 1; ++i) { | 
|  | EXPECT_EQ(0, sync_buffer[channel][i]); | 
|  | } | 
|  | } | 
|  | // Verify that the correct data is at the end of the SyncBuffer. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | EXPECT_EQ(1000, sync_buffer[channel][sync_buffer.next_index()]); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(SyncBuffer, GetNextAudioInterleaved) { | 
|  | // Create a SyncBuffer with two channels and 100 samples each. | 
|  | static const size_t kLen = 100; | 
|  | static const size_t kChannels = 2; | 
|  | SyncBuffer sync_buffer(kChannels, kLen); | 
|  | static const size_t kNewLen = 10; | 
|  | AudioMultiVector new_data(kChannels, kNewLen); | 
|  | // Populate `new_data`. | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | for (size_t i = 0; i < kNewLen; ++i) { | 
|  | new_data[channel][i] = checked_cast<int16_t>(i); | 
|  | } | 
|  | } | 
|  | // Push back `new_data` into `sync_buffer`. This operation should pop out | 
|  | // data from the front of `sync_buffer`, so that the size of the buffer | 
|  | // remains the same. The `next_index_` should also move with the same length. | 
|  | sync_buffer.PushBack(new_data); | 
|  |  | 
|  | // Read to interleaved output. Read in two batches, where each read operation | 
|  | // should automatically update the `net_index_` in the SyncBuffer. | 
|  | // `samples` is the number of samples read from each channel. | 
|  | // That is, the number of samples written to `output` is `samples` * | 
|  | // `kChannels`. | 
|  | const size_t samples = kNewLen / 2; | 
|  | AudioFrame output1; | 
|  | EXPECT_TRUE(sync_buffer.GetNextAudioInterleaved( | 
|  | output1.mutable_data(samples, kChannels))); | 
|  |  | 
|  | AudioFrame output2; | 
|  | EXPECT_TRUE(sync_buffer.GetNextAudioInterleaved( | 
|  | output2.mutable_data(samples, kChannels))); | 
|  |  | 
|  | // Verify the data. | 
|  | const int16_t* output_ptr = output1.data(); | 
|  | for (size_t i = 0; i < samples; ++i) { | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | EXPECT_EQ(new_data[channel][i], *output_ptr); | 
|  | ++output_ptr; | 
|  | } | 
|  | } | 
|  | output_ptr = output2.data(); | 
|  | for (size_t i = kNewLen / 2; i < kNewLen; ++i) { | 
|  | for (size_t channel = 0; channel < kChannels; ++channel) { | 
|  | EXPECT_EQ(new_data[channel][i], *output_ptr); | 
|  | ++output_ptr; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace webrtc |