1 /*
2  * Copyright (C) 2021 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 <audio_utils/ChannelMix.h>
18 #include <audio_utils/Statistics.h>
19 #include <gtest/gtest.h>
20 #include <log/log.h>
21 
22 static constexpr audio_channel_mask_t kOutputChannelMasks[] = {
23     AUDIO_CHANNEL_OUT_STEREO,
24     AUDIO_CHANNEL_OUT_5POINT1, // AUDIO_CHANNEL_OUT_5POINT1_BACK
25     AUDIO_CHANNEL_OUT_7POINT1,
26     AUDIO_CHANNEL_OUT_7POINT1POINT4,
27     AUDIO_CHANNEL_OUT_9POINT1POINT6,
28 };
29 
30 static constexpr audio_channel_mask_t kInputChannelMasks[] = {
31     AUDIO_CHANNEL_OUT_FRONT_LEFT, // Legacy: the ChannelMix effect treats MONO as FRONT_LEFT only.
32                                   // The AudioMixer interprets MONO as a special case requiring
33                                   // channel replication, bypassing the ChannelMix effect.
34     AUDIO_CHANNEL_OUT_FRONT_CENTER,
35     AUDIO_CHANNEL_OUT_STEREO,
36     AUDIO_CHANNEL_OUT_2POINT1,
37     AUDIO_CHANNEL_OUT_2POINT0POINT2,
38     AUDIO_CHANNEL_OUT_QUAD, // AUDIO_CHANNEL_OUT_QUAD_BACK
39     AUDIO_CHANNEL_OUT_QUAD_SIDE,
40     AUDIO_CHANNEL_OUT_SURROUND,
41     AUDIO_CHANNEL_OUT_2POINT1POINT2,
42     AUDIO_CHANNEL_OUT_3POINT0POINT2,
43     AUDIO_CHANNEL_OUT_PENTA,
44     AUDIO_CHANNEL_OUT_3POINT1POINT2,
45     AUDIO_CHANNEL_OUT_5POINT1, // AUDIO_CHANNEL_OUT_5POINT1_BACK
46     AUDIO_CHANNEL_OUT_5POINT1_SIDE,
47     AUDIO_CHANNEL_OUT_6POINT1,
48     AUDIO_CHANNEL_OUT_5POINT1POINT2,
49     AUDIO_CHANNEL_OUT_7POINT1,
50     AUDIO_CHANNEL_OUT_5POINT1POINT4,
51     AUDIO_CHANNEL_OUT_7POINT1POINT2,
52     AUDIO_CHANNEL_OUT_7POINT1POINT4,
53     AUDIO_CHANNEL_OUT_9POINT1POINT6,
54     AUDIO_CHANNEL_OUT_13POINT_360RA,
55     AUDIO_CHANNEL_OUT_22POINT2,
56     audio_channel_mask_t(AUDIO_CHANNEL_OUT_22POINT2
57             | AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT | AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT),
58 };
59 
60 constexpr float COEF_25 = 0.2508909536f;
61 constexpr float COEF_35 = 0.3543928915f;
62 constexpr float COEF_36 = 0.3552343859f;
63 constexpr float COEF_61 = 0.6057043428f;
64 
65 constexpr inline float kScaleFromChannelIdxLeft[] = {
66     1.f,       // AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1u,
67     0.f,       // AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2u,
68     M_SQRT1_2, // AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x4u,
69     0.5f,      // AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x8u,
70     M_SQRT1_2, // AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x10u,
71     0.f,       // AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x20u,
72     COEF_61,   // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40u,
73     COEF_25,   // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
74     0.5f,      // AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x100u,
75     M_SQRT1_2, // AUDIO_CHANNEL_OUT_SIDE_LEFT             = 0x200u,
76     0.f,       // AUDIO_CHANNEL_OUT_SIDE_RIGHT            = 0x400u,
77     COEF_36,   // AUDIO_CHANNEL_OUT_TOP_CENTER            = 0x800u,
78     1.f,       // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000u,
79     M_SQRT1_2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000u,
80     0.f,       // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000u,
81     M_SQRT1_2, // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000u,
82     COEF_35,   // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000u,
83     0.f,       // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000u,
84     COEF_61,   // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT         = 0x40000u,
85     0.f,       // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT        = 0x80000u,
86     1.f,       // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT     = 0x100000u,
87     M_SQRT1_2, // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER   = 0x200000u,
88     0.f,       // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT    = 0x400000u,
89     0.f,       // AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2       = 0x800000u,
90     M_SQRT1_2, // AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT       = 0x1000000u,
91     0.f,       // AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT      = 0x2000000u,
92 };
93 
94 constexpr inline float kScaleFromChannelIdxRight[] = {
95     0.f,       // AUDIO_CHANNEL_OUT_FRONT_LEFT            = 0x1u,
96     1.f,       // AUDIO_CHANNEL_OUT_FRONT_RIGHT           = 0x2u,
97     M_SQRT1_2, // AUDIO_CHANNEL_OUT_FRONT_CENTER          = 0x4u,
98     0.5f,      // AUDIO_CHANNEL_OUT_LOW_FREQUENCY         = 0x8u,
99     0.f,       // AUDIO_CHANNEL_OUT_BACK_LEFT             = 0x10u,
100     M_SQRT1_2, // AUDIO_CHANNEL_OUT_BACK_RIGHT            = 0x20u,
101     COEF_25,   // AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER  = 0x40u,
102     COEF_61,   // AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER = 0x80u,
103     0.5f,      // AUDIO_CHANNEL_OUT_BACK_CENTER           = 0x100u,
104     0.f,       // AUDIO_CHANNEL_OUT_SIDE_LEFT             = 0x200u,
105     M_SQRT1_2, // AUDIO_CHANNEL_OUT_SIDE_RIGHT            = 0x400u,
106     COEF_36,   // AUDIO_CHANNEL_OUT_TOP_CENTER            = 0x800u,
107     0.f,       // AUDIO_CHANNEL_OUT_TOP_FRONT_LEFT        = 0x1000u,
108     M_SQRT1_2, // AUDIO_CHANNEL_OUT_TOP_FRONT_CENTER      = 0x2000u,
109     1.f,       // AUDIO_CHANNEL_OUT_TOP_FRONT_RIGHT       = 0x4000u,
110     0.f,       // AUDIO_CHANNEL_OUT_TOP_BACK_LEFT         = 0x8000u,
111     COEF_35,   // AUDIO_CHANNEL_OUT_TOP_BACK_CENTER       = 0x10000u,
112     M_SQRT1_2, // AUDIO_CHANNEL_OUT_TOP_BACK_RIGHT        = 0x20000u,
113     0.f,       // AUDIO_CHANNEL_OUT_TOP_SIDE_LEFT         = 0x40000u,
114     COEF_61,   // AUDIO_CHANNEL_OUT_TOP_SIDE_RIGHT        = 0x80000u,
115     0.f,       // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_LEFT     = 0x100000u,
116     M_SQRT1_2, // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_CENTER   = 0x200000u,
117     1.f,       // AUDIO_CHANNEL_OUT_BOTTOM_FRONT_RIGHT    = 0x400000u,
118     M_SQRT1_2, // AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2       = 0x800000u,
119     0.f,       // AUDIO_CHANNEL_OUT_FRONT_WIDE_LEFT       = 0x1000000u,
120     M_SQRT1_2, // AUDIO_CHANNEL_OUT_FRONT_WIDE_RIGHT      = 0x2000000u,
121 };
122 
123 // Our near expectation is 16x the bit that doesn't fit the mantissa.
124 // this works so long as we add values close in exponent with each other
125 // realizing that errors accumulate as the sqrt of N (random walk, lln, etc).
126 #define EXPECT_NEAR_EPSILON(e, v) EXPECT_NEAR((e), (v), \
127         abs((e) * std::numeric_limits<std::decay_t<decltype(e)>>::epsilon() * 8))
128 
129 template<typename T>
channelStatistics(const std::vector<T> & input,size_t channels)130 static auto channelStatistics(const std::vector<T>& input, size_t channels) {
131     std::vector<android::audio_utils::Statistics<T>> result(channels);
132     const size_t frames = input.size() / channels;
133     if (frames > 0) {
134         const float *fptr = input.data();
135         for (size_t i = 0; i < frames; ++i) {
136             for (size_t j = 0; j < channels; ++j) {
137                 result[j].add(*fptr++);
138             }
139         }
140     }
141     return result;
142 }
143 
144 using ChannelMixParam = std::tuple<int /* output channel mask */,
145         int /* input channel mask */,
146         bool /* accumulate */>;
147 
148 // For ChannelMixParam tuple get.
149 constexpr size_t OUTPUT_CHANNEL_MASK_POSITION = 0;
150 constexpr size_t INPUT_CHANNEL_MASK_POSITION = 1;
151 constexpr size_t ACCUMULATE_POSITION = 2;
152 
153 class ChannelMixTest : public ::testing::TestWithParam<ChannelMixParam> {
154 public:
155 
testBalance(audio_channel_mask_t outputChannelMask,audio_channel_mask_t inputChannelMask,bool accumulate)156     void testBalance(audio_channel_mask_t outputChannelMask,
157             audio_channel_mask_t inputChannelMask, bool accumulate) {
158         using namespace ::android::audio_utils::channels;
159 
160         size_t frames = 100; // set to an even number (2, 4, 6 ... ) stream alternates +1, -1.
161         const unsigned outChannels = audio_channel_count_from_out_mask(outputChannelMask);
162         const unsigned inChannels = audio_channel_count_from_out_mask(inputChannelMask);
163         std::vector<float> input(frames * inChannels);
164         std::vector<float> output(frames * outChannels);
165 
166         double savedPower[32 /* inChannels */][32 /* outChannels */]{};
167 
168         // Precompute output channel geometry.
169         AUDIO_GEOMETRY_SIDE outSide[outChannels];  // what side that channel index is on
170         int outIndexToOffset[32] = {[0 ... 31] = -1};
171         int outPair[outChannels];  // is there a matching pair channel?
172         for (unsigned i = 0, channel = outputChannelMask; channel != 0; ++i) {
173             const int index = __builtin_ctz(channel);
174             outIndexToOffset[index] = i;
175             outSide[i] = sideFromChannelIdx(index);
176             outPair[i] = pairIdxFromChannelIdx(index);
177 
178             const int channelBit = 1 << index;
179             channel &= ~channelBit;
180         }
181         for (unsigned i = 0; i < outChannels; ++i) {
182             if (outPair[i] >= 0 && outPair[i] < (signed)std::size(outIndexToOffset)) {
183                 outPair[i] = outIndexToOffset[outPair[i]];
184             }
185         }
186 
187         auto remix = IChannelMix::create(outputChannelMask);
188 
189         for (unsigned i = 0, channel = inputChannelMask; channel != 0; ++i) {
190             const int index = __builtin_ctz(channel);
191             const int pairIndex = pairIdxFromChannelIdx(index);
192             const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(index);
193             const int channelBit = 1 << index;
194             channel &= ~channelBit;
195 
196             // Generate a +0.5, -0.5 alternating stream in one channel, which has variance 0.25f
197             auto indata = input.data();
198             for (unsigned j = 0; j < frames; ++j) {
199                 for (unsigned k = 0; k < inChannels; ++k) {
200                     *indata++ = (k == i) ? (j & 1 ? -0.5f : 0.5f) : 0;
201                 }
202             }
203 
204             // Add an offset to the output data - this is ignored if replace instead of accumulate.
205             // This must not cause the output to exceed [-1.f, 1.f] otherwise clamping will occur.
206             auto outdata = output.data();
207             for (unsigned j = 0; j < frames; ++j) {
208                 for (unsigned k = 0; k < outChannels; ++k) {
209                     *outdata++ = 0.5f;
210                 }
211             }
212 
213             // Do the channel mix
214             remix->process(input.data(), output.data(), frames, accumulate, inputChannelMask);
215 
216             // if we accumulate, we need to subtract the initial data offset.
217             if (accumulate) {
218                 outdata = output.data();
219                 for (unsigned j = 0; j < frames; ++j) {
220                     for (unsigned k = 0; k < outChannels; ++k) {
221                         *outdata++ -= 0.5f;
222                     }
223                 }
224             }
225 
226             // renormalize the stream to unit amplitude (and unity variance).
227             outdata = output.data();
228             for (unsigned j = 0; j < frames; ++j) {
229                 for (unsigned k = 0; k < outChannels; ++k) {
230                     *outdata++ *= 2.f;
231                 }
232             }
233 
234             auto stats = channelStatistics(output, outChannels);
235             // printf("power: %s %s\n", stats[0].toString().c_str(), stats[1].toString().c_str());
236             double power[outChannels];
237             for (size_t j = 0; j < outChannels; ++j) {
238                 power[j] = stats[j].getPopVariance();
239             }
240 
241             // Check symmetric power for pair channels on exchange of front left/right position.
242             // to do this, we save previous power measurements.
243             if (pairIndex >= 0 && pairIndex < index) {
244 
245                 for (unsigned j = 0; j < outChannels; ++j) {
246                     if (outPair[j] >= 0) {
247                         EXPECT_NEAR_EPSILON(power[j], savedPower[pairIndex][outPair[j]]);
248                         EXPECT_NEAR_EPSILON(power[outPair[j]], savedPower[pairIndex][j]);
249                     }
250                 }
251             }
252             for (unsigned j = 0; j < outChannels; ++j) {
253                 savedPower[index][j] = power[j];
254             }
255 
256             // For downmix to stereo, we compare exact values to a predefined matrix.
257             const bool checkExpectedPower = outputChannelMask == AUDIO_CHANNEL_OUT_STEREO;
258             constexpr size_t FL = 0;
259             constexpr size_t FR = 1;
260 
261             // Confirm exactly the mix amount prescribed by the existing ChannelMix effect.
262             // For future changes to the ChannelMix effect, the nearness needs to be relaxed
263             // to compare behavior S or earlier.
264 
265             constexpr float POWER_TOLERANCE = 0.001;
266             const float expectedPower = checkExpectedPower ?
267                     kScaleFromChannelIdxLeft[index] * kScaleFromChannelIdxLeft[index]
268                     + kScaleFromChannelIdxRight[index] * kScaleFromChannelIdxRight[index] : 0;
269 
270             if (checkExpectedPower) {
271                 EXPECT_NEAR(expectedPower, power[FL] + power[FR], POWER_TOLERANCE);
272             }
273             switch (side) {
274             case AUDIO_GEOMETRY_SIDE_LEFT:
275                 if (channelBit == AUDIO_CHANNEL_OUT_FRONT_LEFT_OF_CENTER) {
276                     break;
277                 }
278                 for (unsigned j = 0; j < outChannels; ++j) {
279                     if (outSide[j] == AUDIO_GEOMETRY_SIDE_RIGHT) {
280                         EXPECT_EQ(0.f, power[j]);
281                     }
282                 }
283                 break;
284             case AUDIO_GEOMETRY_SIDE_RIGHT:
285                 if (channelBit == AUDIO_CHANNEL_OUT_FRONT_RIGHT_OF_CENTER) {
286                     break;
287                 }
288                 for (unsigned j = 0; j < outChannels; ++j) {
289                     if (outSide[j] == AUDIO_GEOMETRY_SIDE_LEFT) {
290                         EXPECT_EQ(0.f, power[j]);
291                     }
292                 }
293                 break;
294             case AUDIO_GEOMETRY_SIDE_CENTER:
295                 if (channelBit == AUDIO_CHANNEL_OUT_LOW_FREQUENCY) {
296                     if (inputChannelMask & AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2) {
297                         EXPECT_EQ(0.f, power[FR]);
298                         break;
299                     } else {
300                         for (unsigned j = 0; j < outChannels; ++j) {
301                             if (outPair[j] >= 0) {
302                                 EXPECT_NEAR_EPSILON(power[j], power[outPair[j]]);
303                             }
304                         }
305                         if (checkExpectedPower) {
306                             EXPECT_NEAR(expectedPower, power[FL] + power[FR], POWER_TOLERANCE);
307                         }
308                         break;
309                     }
310                 } else if (channelBit == AUDIO_CHANNEL_OUT_LOW_FREQUENCY_2) {
311                     EXPECT_EQ(0.f, power[FL]);
312                     if (checkExpectedPower) {
313                         EXPECT_NEAR(expectedPower, power[FR], POWER_TOLERANCE);
314                     }
315                     break;
316                 }
317                 for (unsigned j = 0; j < outChannels; ++j) {
318                     if (outPair[j] >= 0) {
319                         EXPECT_NEAR_EPSILON(power[j], power[outPair[j]]);
320                     }
321                 }
322                 break;
323             }
324         }
325     }
326 };
327 
328 static constexpr const char *kName1[] = {"_replace_", "_accumulate_"};
329 
330 // The Balance test checks that the power output is symmetric with left / right channel swap.
331 
TEST_P(ChannelMixTest,balance)332 TEST_P(ChannelMixTest, balance) {
333     testBalance(kOutputChannelMasks[std::get<OUTPUT_CHANNEL_MASK_POSITION>(GetParam())],
334             kInputChannelMasks[std::get<INPUT_CHANNEL_MASK_POSITION>(GetParam())],
335             std::get<ACCUMULATE_POSITION>(GetParam()));
336 }
337 
338 INSTANTIATE_TEST_SUITE_P(
339         ChannelMixTestAll, ChannelMixTest,
340         ::testing::Combine(
341                 ::testing::Range(0, (int)std::size(kOutputChannelMasks)),
342                 ::testing::Range(0, (int)std::size(kInputChannelMasks)),
343                 ::testing::Bool() // accumulate off, on
344                 ),
__anon26f1fbff0102(const testing::TestParamInfo<ChannelMixTest::ParamType>& info) 345         [](const testing::TestParamInfo<ChannelMixTest::ParamType>& info) {
346             const int out_index = std::get<OUTPUT_CHANNEL_MASK_POSITION>(info.param);
347             const audio_channel_mask_t outputChannelMask = kOutputChannelMasks[out_index];
348             const int in_index = std::get<INPUT_CHANNEL_MASK_POSITION>(info.param);
349             const audio_channel_mask_t inputChannelMask = kInputChannelMasks[in_index];
350             const std::string name =
351                     std::string(audio_channel_out_mask_to_string(outputChannelMask)) +
352                     "_" + std::string(audio_channel_out_mask_to_string(inputChannelMask)) +
353                     kName1[std::get<ACCUMULATE_POSITION>(info.param)] + std::to_string(in_index);
354             return name;
355         });
356 
357 // --------------------------------------------------------------------------------------
358 
359 using ChannelMixIdentityParam = std::tuple<int /* channel mask */, bool /* accumulate */>;
360 
361 enum {
362     IDENTITY_CHANNEL_MASK_POSITION = 0,
363     IDENTITY_ACCUMULATE_POSITION = 1,
364 };
365 
366 class ChannelMixIdentityTest : public ::testing::TestWithParam<ChannelMixIdentityParam> {
367 public:
368 
testIdentity(audio_channel_mask_t channelMask,bool accumulate)369     void testIdentity(audio_channel_mask_t channelMask, bool accumulate) {
370         const size_t frames = 100;
371         const unsigned channels = audio_channel_count_from_out_mask(channelMask);
372         std::vector<float> input(frames * channels);
373         std::vector<float> output(frames * channels);
374 
375         auto remix = ::android::audio_utils::channels::IChannelMix::create(channelMask);
376 
377         constexpr float kInvalid = -0.7f;
378         constexpr float kImpulse = 0.3f;
379 
380         for (size_t i = 0; i < channels; ++i) {
381             // A remix with one of the channels specified should equal itself.
382 
383             std::fill(input.begin(), input.end(), 0.f);
384             if (!accumulate) std::fill(output.begin(), output.end(), kInvalid);
385             for (size_t j = 0; j < frames; ++j) {
386                 input[j * channels + i] = kImpulse;
387             }
388 
389             // Do the channel mix
390             remix->process(input.data(), output.data(), frames, false /* accumulate */,
391                            channelMask);
392 
393             EXPECT_EQ(0, memcmp(input.data(), output.data(), frames * channels * sizeof(float)));
394         }
395     }
396 };
397 
398 // The Identity test checks that putting audio data on an input channel included in the
399 // destination channel mask must be preserved on the same channel on the output.
400 
401 // For simplicity, we use the same channel mask for input and output.
402 // This is not optimized out here because it doesn't happen in practice: we only set
403 // up the ChannelMix object when the channel mask differs.
404 
TEST_P(ChannelMixIdentityTest,identity)405 TEST_P(ChannelMixIdentityTest, identity) {
406     testIdentity(kOutputChannelMasks[std::get<IDENTITY_CHANNEL_MASK_POSITION>(GetParam())],
407             std::get<IDENTITY_ACCUMULATE_POSITION>(GetParam()));
408 }
409 
410 INSTANTIATE_TEST_SUITE_P(
411         ChannelMixIdentityTestAll, ChannelMixIdentityTest,
412         ::testing::Combine(
413             ::testing::Range(0, (int)std::size(kOutputChannelMasks)),
414             ::testing::Bool() // accumulate off, on
415         ),
__anon26f1fbff0302(const testing::TestParamInfo<ChannelMixIdentityTest::ParamType>& info) 416         [](const testing::TestParamInfo<ChannelMixIdentityTest::ParamType>& info) {
417             const int index = std::get<IDENTITY_CHANNEL_MASK_POSITION>(info.param);
418             const audio_channel_mask_t channelMask = kOutputChannelMasks[index];
419             const std::string name =
420                     std::string(audio_channel_out_mask_to_string(channelMask)) +
421                     kName1[std::get<IDENTITY_ACCUMULATE_POSITION>(info.param)] +
422                     std::to_string(index);
423             return name;
424         });
425 
426 // --------------------------------------------------------------------------------------
427 
428 using StereoDownMix = android::audio_utils::channels::ChannelMix<AUDIO_CHANNEL_OUT_STEREO>;
TEST(channelmix,input_channel_mask)429 TEST(channelmix, input_channel_mask) {
430     using namespace ::android::audio_utils::channels;
431     StereoDownMix channelMix(AUDIO_CHANNEL_NONE);
432 
433     ASSERT_EQ(AUDIO_CHANNEL_NONE, channelMix.getInputChannelMask());
434     ASSERT_TRUE(channelMix.setInputChannelMask(AUDIO_CHANNEL_OUT_STEREO));
435     ASSERT_EQ(AUDIO_CHANNEL_OUT_STEREO, channelMix.getInputChannelMask());
436 }
437