audio_view_unittest.cc (6950B)
1 /* 2 * Copyright 2024 The WebRTC Project Authors. All rights reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 #include "api/audio/audio_view.h" 12 13 #include <array> 14 #include <cstddef> 15 #include <cstdint> 16 #include <vector> 17 18 #include "api/array_view.h" 19 #include "test/gtest.h" 20 21 namespace webrtc { 22 23 namespace { 24 25 constexpr const float kFloatStepIncrease = 0.5f; 26 constexpr const int16_t kIntStepIncrease = 1; 27 28 template <typename T> 29 void Increment(float& t) { 30 t += kFloatStepIncrease; 31 } 32 33 template <typename T> 34 void Increment(int16_t& t) { 35 t += kIntStepIncrease; 36 } 37 38 // Fills a given buffer with monotonically increasing values. 39 template <typename T> 40 void FillBuffer(ArrayView<T> buffer) { 41 T value = {}; 42 for (T& t : buffer) { 43 Increment<T>(value); 44 t = value; 45 } 46 } 47 48 } // namespace 49 50 TEST(AudioViewTest, MonoView) { 51 const size_t kArraySize = 100u; 52 int16_t arr[kArraySize]; 53 FillBuffer(ArrayView<int16_t>(arr)); 54 55 MonoView<int16_t> mono(arr); 56 MonoView<const int16_t> const_mono(arr); 57 EXPECT_EQ(mono.size(), kArraySize); 58 EXPECT_EQ(const_mono.size(), kArraySize); 59 EXPECT_EQ(&mono[0], &const_mono[0]); 60 EXPECT_EQ(mono[0], arr[0]); 61 62 EXPECT_EQ(1u, NumChannels(mono)); 63 EXPECT_EQ(1u, NumChannels(const_mono)); 64 EXPECT_EQ(100u, SamplesPerChannel(mono)); 65 EXPECT_TRUE(IsMono(mono)); 66 EXPECT_TRUE(IsMono(const_mono)); 67 } 68 69 TEST(AudioViewTest, InterleavedView) { 70 const size_t kArraySize = 100u; 71 int16_t arr[kArraySize]; 72 FillBuffer(ArrayView<int16_t>(arr)); 73 74 InterleavedView<int16_t> interleaved(arr, kArraySize, 1); 75 EXPECT_EQ(NumChannels(interleaved), 1u); 76 EXPECT_TRUE(IsMono(interleaved)); 77 EXPECT_EQ(SamplesPerChannel(interleaved), kArraySize); 78 EXPECT_EQ(interleaved.AsMono().size(), kArraySize); 79 EXPECT_EQ(&interleaved.AsMono()[0], &arr[0]); 80 EXPECT_EQ(interleaved.AsMono(), interleaved.data()); 81 82 // Basic iterator test. 83 int i = 0; 84 for (auto s : interleaved) { 85 EXPECT_EQ(s, arr[i++]); 86 } 87 88 interleaved = InterleavedView<int16_t>(arr, kArraySize / 2, 2); 89 InterleavedView<const int16_t> const_interleaved(arr, 50, 2); 90 EXPECT_EQ(NumChannels(interleaved), 2u); 91 EXPECT_EQ(NumChannels(const_interleaved), 2u); 92 EXPECT_EQ(&const_interleaved[0], &interleaved[0]); 93 EXPECT_TRUE(!IsMono(interleaved)); 94 EXPECT_TRUE(!IsMono(const_interleaved)); 95 EXPECT_EQ(SamplesPerChannel(interleaved), 50u); 96 EXPECT_EQ(SamplesPerChannel(const_interleaved), 50u); 97 98 interleaved = InterleavedView<int16_t>(arr, 4); 99 EXPECT_EQ(NumChannels(interleaved), 4u); 100 InterleavedView<const int16_t> const_interleaved2(interleaved); 101 EXPECT_EQ(NumChannels(const_interleaved2), 4u); 102 EXPECT_EQ(SamplesPerChannel(interleaved), 25u); 103 104 const_interleaved2 = interleaved; 105 EXPECT_EQ(NumChannels(const_interleaved2), 4u); 106 EXPECT_EQ(&const_interleaved2[0], &interleaved[0]); 107 } 108 109 TEST(AudioViewTest, DeinterleavedView) { 110 const size_t kArraySize = 100u; 111 int16_t arr[kArraySize] = {}; 112 DeinterleavedView<int16_t> di(arr, 10, 10); 113 DeinterleavedView<const int16_t> const_di(arr, 10, 10); 114 EXPECT_EQ(NumChannels(di), 10u); 115 EXPECT_EQ(SamplesPerChannel(di), 10u); 116 EXPECT_TRUE(!IsMono(di)); 117 EXPECT_EQ(const_di[5][1], di[5][1]); // Spot check. 118 // For deinterleaved views, although they may hold multiple channels, 119 // the AsMono() method is still available and returns the first channel 120 // in the view. 121 auto mono_ch = di.AsMono(); 122 EXPECT_EQ(NumChannels(mono_ch), 1u); 123 EXPECT_EQ(SamplesPerChannel(mono_ch), 10u); 124 EXPECT_EQ(di[0], mono_ch); // first channel should be same as mono. 125 126 di = DeinterleavedView<int16_t>(arr, 50, 2); 127 // Test assignment. 128 const_di = di; 129 EXPECT_EQ(&di.AsMono()[0], &const_di.AsMono()[0]); 130 131 // Access the second channel in the deinterleaved view. 132 // The start of the second channel should be directly after the first channel. 133 // The memory width of each channel is held by the `stride()` member which 134 // by default is the same value as samples per channel. 135 mono_ch = di[1]; 136 EXPECT_EQ(SamplesPerChannel(mono_ch), 50u); 137 EXPECT_EQ(&mono_ch[0], &arr[di.samples_per_channel()]); 138 } 139 140 TEST(AudioViewTest, CopySamples) { 141 const size_t kArraySize = 100u; 142 int16_t source_arr[kArraySize] = {}; 143 int16_t dest_arr[kArraySize] = {}; 144 FillBuffer(ArrayView<int16_t>(source_arr)); 145 146 InterleavedView<const int16_t> source(source_arr, 2); 147 InterleavedView<int16_t> destination(dest_arr, 2); 148 149 static_assert(IsInterleavedView(source) == IsInterleavedView(destination), 150 ""); 151 152 // Values in `dest_arr` should all be 0, none of the values in `source_arr` 153 // should be 0. 154 for (size_t i = 0; i < kArraySize; ++i) { 155 ASSERT_EQ(dest_arr[i], 0); 156 ASSERT_NE(source_arr[i], 0); 157 } 158 159 CopySamples(destination, source); 160 for (size_t i = 0; i < kArraySize; ++i) { 161 ASSERT_EQ(dest_arr[i], source_arr[i]) << "i == " << i; 162 } 163 } 164 165 TEST(AudioViewTest, ClearSamples) { 166 std::array<int16_t, 100u> samples = {}; 167 FillBuffer(ArrayView<int16_t>(samples)); 168 ASSERT_NE(samples[0], 0); 169 ClearSamples(samples); 170 for (const auto s : samples) { 171 ASSERT_EQ(s, 0); 172 } 173 174 std::array<float, 100u> samples_f = {}; 175 FillBuffer(ArrayView<float>(samples_f)); 176 ASSERT_NE(samples_f[0], 0.0); 177 ClearSamples(samples_f); 178 for (const auto s : samples_f) { 179 ASSERT_EQ(s, 0.0); 180 } 181 182 // Clear only half of the buffer 183 FillBuffer(ArrayView<int16_t>(samples)); 184 const auto half_way = samples.size() / 2; 185 ClearSamples(samples, half_way); 186 for (size_t i = 0u; i < samples.size(); ++i) { 187 if (i < half_way) { 188 ASSERT_EQ(samples[i], 0); 189 } else { 190 ASSERT_NE(samples[i], 0); 191 } 192 } 193 } 194 195 TEST(AudioViewTest, DeinterleavedViewPointerArray) { 196 // Create vectors of varying sizes to guarantee that they don't end up 197 // aligned in memory. 198 std::vector<float> v1(100), v2(200), v3(300), v4(400); 199 std::vector<float*> channels = {&v1[0], &v2[0], &v3[0], &v4[0]}; 200 201 DeinterleavedView<float> di(channels, v1.size()); 202 EXPECT_EQ(NumChannels(di), channels.size()); 203 EXPECT_EQ(SamplesPerChannel(di), v1.size()); 204 EXPECT_EQ(di[0].data(), v1.data()); 205 EXPECT_EQ(di[1].data(), v2.data()); 206 EXPECT_EQ(di[2].data(), v3.data()); 207 EXPECT_EQ(di[3].data(), v4.data()); 208 209 // Test that the same thing works with T* const *. 210 float* channel_array[] = {&v1[0], &v2[0], &v3[0], &v4[0]}; 211 di = DeinterleavedView<float>(channel_array, v1.size(), 212 std::size(channel_array)); 213 EXPECT_EQ(NumChannels(di), channels.size()); 214 EXPECT_EQ(SamplesPerChannel(di), v1.size()); 215 EXPECT_EQ(di[0].data(), v1.data()); 216 EXPECT_EQ(di[1].data(), v2.data()); 217 EXPECT_EQ(di[2].data(), v3.data()); 218 EXPECT_EQ(di[3].data(), v4.data()); 219 } 220 221 } // namespace webrtc