1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <math.h>
18 #include <vector>
19
20 #include <gtest/gtest.h>
21
22 #include <audio_utils/channels.h>
23
24 // TODO: Make a common include file for helper functions.
25
26 template<typename T>
checkMonotone(const T * ary,size_t size)27 void checkMonotone(const T *ary, size_t size)
28 {
29 for (size_t i = 1; i < size; ++i) {
30 EXPECT_LT(ary[i-1], ary[i]);
31 }
32 }
33
34 template<typename T>
checkUnsignedMonotoneOrZero(const T * ary,size_t size)35 void checkUnsignedMonotoneOrZero(const T *ary, size_t size)
36 {
37 if (size == 0) return;
38
39 T least = ary[0];
40 for (size_t i = 1; i < size; ++i) {
41 if (ary[i]) {
42 EXPECT_LT(least, ary[i]);
43 least = ary[i];
44 }
45 }
46 }
47
48 template<typename T>
expectEq(const T & c1,const T & c2)49 void expectEq(const T &c1, const T &c2) {
50 EXPECT_EQ(c1.size(), c2.size());
51 EXPECT_EQ(0, memcmp(c1.data(), c2.data(), sizeof(c1[0]) * std::min(c1.size(), c2.size())));
52 }
53
TEST(audio_utils_channels,geometry_constexpr)54 TEST(audio_utils_channels, geometry_constexpr) {
55 using namespace android::audio_utils::channels;
56 // fails to compile if not const.
57 constexpr size_t RIGHT_IDX = 1; // bit position of AUDIO_CHANNEL_OUT_FRONT_RIGHT;
58 static constexpr AUDIO_GEOMETRY_SIDE checkConstexprSide = sideFromChannelIdx(RIGHT_IDX);
59 static constexpr AUDIO_GEOMETRY_HEIGHT checkConstexprHeight = heightFromChannelIdx(RIGHT_IDX);
60 static constexpr AUDIO_GEOMETRY_DEPTH checkConstexprDepth = depthFromChannelIdx(RIGHT_IDX);
61 (void) checkConstexprSide;
62 (void) checkConstexprHeight;
63 (void) checkConstexprDepth;
64
65 static constexpr ssize_t leftIdx = pairIdxFromChannelIdx(RIGHT_IDX);
66 ASSERT_EQ(0, leftIdx);
67 }
68
TEST(audio_utils_channels,geometry_range)69 TEST(audio_utils_channels, geometry_range) {
70 using namespace android::audio_utils::channels;
71 for (size_t i = 0; i < FCC_24 + 2 /* sic */; ++i) {
72 const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(i);
73 const AUDIO_GEOMETRY_HEIGHT height = heightFromChannelIdx(i);
74 const AUDIO_GEOMETRY_DEPTH depth = depthFromChannelIdx(i);
75 ASSERT_TRUE(side == AUDIO_GEOMETRY_SIDE_LEFT
76 || side == AUDIO_GEOMETRY_SIDE_RIGHT
77 || side == AUDIO_GEOMETRY_SIDE_CENTER);
78 ASSERT_TRUE(height == AUDIO_GEOMETRY_HEIGHT_BOTTOM
79 || height == AUDIO_GEOMETRY_HEIGHT_MIDDLE
80 || height == AUDIO_GEOMETRY_HEIGHT_TOP);
81 ASSERT_TRUE(depth == AUDIO_GEOMETRY_DEPTH_FRONT
82 || depth == AUDIO_GEOMETRY_DEPTH_MIDDLE
83 || depth == AUDIO_GEOMETRY_DEPTH_BACK);
84 }
85 }
86
TEST(audio_utils_channels,array_lr_pair_matching)87 TEST(audio_utils_channels, array_lr_pair_matching) {
88 using namespace android::audio_utils::channels;
89 for (size_t i = 0; i < FCC_24; ++i) {
90 const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(i);
91 const ssize_t pairIdx = pairIdxFromChannelIdx(i);
92 switch (side) {
93 case AUDIO_GEOMETRY_SIDE_LEFT:
94 case AUDIO_GEOMETRY_SIDE_RIGHT: {
95 ASSERT_GE(pairIdx, 0);
96 ASSERT_LT(pairIdx, FCC_24);
97 const AUDIO_GEOMETRY_SIDE pairSide = side == AUDIO_GEOMETRY_SIDE_LEFT
98 ? AUDIO_GEOMETRY_SIDE_RIGHT : AUDIO_GEOMETRY_SIDE_LEFT;
99 ASSERT_EQ(pairSide, sideFromChannelIdx(pairIdx));
100 } break;
101 case AUDIO_GEOMETRY_SIDE_CENTER:
102 ASSERT_EQ(-1, pairIdx);
103 break;
104 }
105 }
106 }
107
TEST(audio_utils_channels,adjust_channels)108 TEST(audio_utils_channels, adjust_channels) {
109 constexpr size_t size = 65536;
110 std::vector<uint16_t> u16ref(size);
111 std::vector<uint16_t> u16expand(size * 2);
112 std::vector<uint16_t> u16ary(size);
113
114 // reference buffer is monotonic.
115 for (size_t i = 0; i < u16ref.size(); ++i) {
116 u16ref[i] = i;
117 }
118
119 // expand channels from stereo to quad.
120 adjust_channels(
121 u16ref.data() /*in_buff*/,
122 2 /*in_channels*/,
123 u16expand.data() /*out_buff*/,
124 4 /*out_channels*/,
125 sizeof(u16ref[0]) /*sample_size_in_bytes*/,
126 sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
127
128 // expanded buffer must increase (or be zero).
129 checkUnsignedMonotoneOrZero(u16expand.data(), u16expand.size());
130
131 // contract channels back to stereo.
132 adjust_channels(
133 u16expand.data() /*in_buff*/,
134 4 /*in_channels*/,
135 u16ary.data() /*out_buff*/,
136 2 /*out_channels*/,
137 sizeof(u16expand[0]) /*sample_size_in_bytes*/,
138 sizeof(u16expand[0]) * u16expand.size() /*num_in_bytes*/);
139
140 // contracted array must be identical to original.
141 expectEq(u16ary, u16ref);
142 }
143
TEST(audio_utils_channels,adjust_selected_channels)144 TEST(audio_utils_channels, adjust_selected_channels) {
145 constexpr size_t size = 65536;
146 std::vector<uint16_t> u16ref(size);
147 std::vector<uint16_t> u16contract(size / 2);
148 std::vector<uint16_t> u16ary(size);
149
150 // reference buffer is monotonic.
151 for (size_t i = 0; i < u16ref.size(); ++i) {
152 u16ref[i] = i;
153 }
154
155 // contract from quad to stereo.
156 adjust_selected_channels(
157 u16ref.data() /*in_buff*/,
158 4 /*in_channels*/,
159 u16contract.data() /*out_buff*/,
160 2 /*out_channels*/,
161 sizeof(u16ref[0]) /*sample_size_in_bytes*/,
162 sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
163
164 // contracted buffer must increase.
165 checkMonotone(u16contract.data(), u16contract.size());
166
167 // initialize channels 3 and 4 of final comparison array.
168 for (size_t i = 0; i < u16ary.size() / 4; ++i) {
169 u16ary[i * 4 + 2] = u16ref[i * 4 + 2];
170 u16ary[i * 4 + 3] = u16ref[i * 4 + 3];
171 }
172
173 // expand stereo into channels 1 and 2 of quad comparison array.
174 adjust_selected_channels(
175 u16contract.data() /*in_buff*/,
176 2 /*in_channels*/,
177 u16ary.data() /*out_buff*/,
178 4 /*out_channels*/,
179 sizeof(u16contract[0]) /*sample_size_in_bytes*/,
180 sizeof(u16contract[0]) * u16contract.size() /*num_in_bytes*/);
181
182 // comparison array must be identical to original.
183 expectEq(u16ary, u16ref);
184 }
185
TEST(audio_utils_channels,adjust_channels_non_destructive)186 TEST(audio_utils_channels, adjust_channels_non_destructive) {
187 constexpr size_t size = 65536; /* arbitrary large multiple of 8 */
188 std::vector<uint16_t> u16ref(size);
189 std::vector<uint16_t> u16contracted(size);
190 std::vector<uint16_t> u16expanded(size);
191 std::vector<uint16_t> u16inout(size);
192
193 // Reference buffer increases monotonically.
194 // For second test, in/out buffer begins identical to ref.
195 for (size_t i = 0; i < u16ref.size(); ++i) {
196 u16ref[i] = i;
197 u16inout[i] = i;
198 }
199
200 // *** First test: different in/out buffers ***
201
202 // Contract from quad to stereo.
203 adjust_channels_non_destructive(
204 u16ref.data() /*in_buff*/,
205 4 /*in_channels*/,
206 u16contracted.data() /*out_buff*/,
207 2 /*out_channels*/,
208 sizeof(u16ref[0]) /*sample_size_in_bytes*/,
209 sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
210
211 // Each half of contracted buffer should increase monotonically.
212 checkMonotone(u16contracted.data(), u16contracted.size() / 2);
213 checkMonotone(&u16contracted[u16contracted.size() / 2], u16contracted.size() / 2);
214
215 // Expand stereo to quad
216 adjust_channels_non_destructive(
217 u16contracted.data() /*in_buff*/,
218 2 /*in_channels*/,
219 u16expanded.data() /*out_buff*/,
220 4 /*out_channels*/,
221 sizeof(u16contracted[0]) /*sample_size_in_bytes*/,
222 sizeof(u16contracted[0]) * (u16contracted.size() / 2) /*num_in_bytes*/);
223
224 // Comparison array must be identical to reference.
225 expectEq(u16expanded, u16ref);
226
227 // *** Second test: in_buff == out_buff ***
228
229 // Contract from eight channels to stereo.
230 adjust_channels_non_destructive(
231 u16inout.data() /*in_buff*/,
232 8 /*in_channels*/,
233 u16inout.data() /*out_buff*/,
234 2 /*out_channels*/,
235 sizeof(u16inout[0]) /*sample_size_in_bytes*/,
236 sizeof(u16inout[0]) * u16inout.size() /*num_in_bytes*/);
237
238 // Each section [1/4][3/4] of contracted buffer should increase monotonically.
239 checkMonotone(u16inout.data(), u16inout.size() / 4);
240 checkMonotone(&u16inout[u16inout.size() / 4], (u16inout.size() * 3) / 4);
241
242 // Expand stereo to eight channels.
243 adjust_channels_non_destructive(
244 u16inout.data() /*in_buff*/,
245 2 /*in_channels*/,
246 u16inout.data() /*out_buff*/,
247 8 /*out_channels*/,
248 sizeof(u16inout[0]) /*sample_size_in_bytes*/,
249 sizeof(u16inout[0]) * (u16inout.size() / 4) /*num_in_bytes*/);
250
251 // Comparison array must be identical to reference.
252 expectEq(u16inout, u16ref);
253 }
254