You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
254 lines
8.9 KiB
254 lines
8.9 KiB
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <vector>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <audio_utils/channels.h>
|
|
|
|
// TODO: Make a common include file for helper functions.
|
|
|
|
template<typename T>
|
|
void checkMonotone(const T *ary, size_t size)
|
|
{
|
|
for (size_t i = 1; i < size; ++i) {
|
|
EXPECT_LT(ary[i-1], ary[i]);
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void checkUnsignedMonotoneOrZero(const T *ary, size_t size)
|
|
{
|
|
if (size == 0) return;
|
|
|
|
T least = ary[0];
|
|
for (size_t i = 1; i < size; ++i) {
|
|
if (ary[i]) {
|
|
EXPECT_LT(least, ary[i]);
|
|
least = ary[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
template<typename T>
|
|
void expectEq(const T &c1, const T &c2) {
|
|
EXPECT_EQ(c1.size(), c2.size());
|
|
EXPECT_EQ(0, memcmp(c1.data(), c2.data(), sizeof(c1[0]) * std::min(c1.size(), c2.size())));
|
|
}
|
|
|
|
TEST(audio_utils_channels, geometry_constexpr) {
|
|
using namespace android::audio_utils::channels;
|
|
// fails to compile if not const.
|
|
constexpr size_t RIGHT_IDX = 1; // bit position of AUDIO_CHANNEL_OUT_FRONT_RIGHT;
|
|
static constexpr AUDIO_GEOMETRY_SIDE checkConstexprSide = sideFromChannelIdx(RIGHT_IDX);
|
|
static constexpr AUDIO_GEOMETRY_HEIGHT checkConstexprHeight = heightFromChannelIdx(RIGHT_IDX);
|
|
static constexpr AUDIO_GEOMETRY_DEPTH checkConstexprDepth = depthFromChannelIdx(RIGHT_IDX);
|
|
(void) checkConstexprSide;
|
|
(void) checkConstexprHeight;
|
|
(void) checkConstexprDepth;
|
|
|
|
static constexpr ssize_t leftIdx = pairIdxFromChannelIdx(RIGHT_IDX);
|
|
ASSERT_EQ(0, leftIdx);
|
|
}
|
|
|
|
TEST(audio_utils_channels, geometry_range) {
|
|
using namespace android::audio_utils::channels;
|
|
for (size_t i = 0; i < FCC_24 + 2 /* sic */; ++i) {
|
|
const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(i);
|
|
const AUDIO_GEOMETRY_HEIGHT height = heightFromChannelIdx(i);
|
|
const AUDIO_GEOMETRY_DEPTH depth = depthFromChannelIdx(i);
|
|
ASSERT_TRUE(side == AUDIO_GEOMETRY_SIDE_LEFT
|
|
|| side == AUDIO_GEOMETRY_SIDE_RIGHT
|
|
|| side == AUDIO_GEOMETRY_SIDE_CENTER);
|
|
ASSERT_TRUE(height == AUDIO_GEOMETRY_HEIGHT_BOTTOM
|
|
|| height == AUDIO_GEOMETRY_HEIGHT_MIDDLE
|
|
|| height == AUDIO_GEOMETRY_HEIGHT_TOP);
|
|
ASSERT_TRUE(depth == AUDIO_GEOMETRY_DEPTH_FRONT
|
|
|| depth == AUDIO_GEOMETRY_DEPTH_MIDDLE
|
|
|| depth == AUDIO_GEOMETRY_DEPTH_BACK);
|
|
}
|
|
}
|
|
|
|
TEST(audio_utils_channels, array_lr_pair_matching) {
|
|
using namespace android::audio_utils::channels;
|
|
for (size_t i = 0; i < FCC_24; ++i) {
|
|
const AUDIO_GEOMETRY_SIDE side = sideFromChannelIdx(i);
|
|
const ssize_t pairIdx = pairIdxFromChannelIdx(i);
|
|
switch (side) {
|
|
case AUDIO_GEOMETRY_SIDE_LEFT:
|
|
case AUDIO_GEOMETRY_SIDE_RIGHT: {
|
|
ASSERT_GE(pairIdx, 0);
|
|
ASSERT_LT(pairIdx, FCC_24);
|
|
const AUDIO_GEOMETRY_SIDE pairSide = side == AUDIO_GEOMETRY_SIDE_LEFT
|
|
? AUDIO_GEOMETRY_SIDE_RIGHT : AUDIO_GEOMETRY_SIDE_LEFT;
|
|
ASSERT_EQ(pairSide, sideFromChannelIdx(pairIdx));
|
|
} break;
|
|
case AUDIO_GEOMETRY_SIDE_CENTER:
|
|
ASSERT_EQ(-1, pairIdx);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
TEST(audio_utils_channels, adjust_channels) {
|
|
constexpr size_t size = 65536;
|
|
std::vector<uint16_t> u16ref(size);
|
|
std::vector<uint16_t> u16expand(size * 2);
|
|
std::vector<uint16_t> u16ary(size);
|
|
|
|
// reference buffer is monotonic.
|
|
for (size_t i = 0; i < u16ref.size(); ++i) {
|
|
u16ref[i] = i;
|
|
}
|
|
|
|
// expand channels from stereo to quad.
|
|
adjust_channels(
|
|
u16ref.data() /*in_buff*/,
|
|
2 /*in_channels*/,
|
|
u16expand.data() /*out_buff*/,
|
|
4 /*out_channels*/,
|
|
sizeof(u16ref[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
|
|
|
|
// expanded buffer must increase (or be zero).
|
|
checkUnsignedMonotoneOrZero(u16expand.data(), u16expand.size());
|
|
|
|
// contract channels back to stereo.
|
|
adjust_channels(
|
|
u16expand.data() /*in_buff*/,
|
|
4 /*in_channels*/,
|
|
u16ary.data() /*out_buff*/,
|
|
2 /*out_channels*/,
|
|
sizeof(u16expand[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16expand[0]) * u16expand.size() /*num_in_bytes*/);
|
|
|
|
// contracted array must be identical to original.
|
|
expectEq(u16ary, u16ref);
|
|
}
|
|
|
|
TEST(audio_utils_channels, adjust_selected_channels) {
|
|
constexpr size_t size = 65536;
|
|
std::vector<uint16_t> u16ref(size);
|
|
std::vector<uint16_t> u16contract(size / 2);
|
|
std::vector<uint16_t> u16ary(size);
|
|
|
|
// reference buffer is monotonic.
|
|
for (size_t i = 0; i < u16ref.size(); ++i) {
|
|
u16ref[i] = i;
|
|
}
|
|
|
|
// contract from quad to stereo.
|
|
adjust_selected_channels(
|
|
u16ref.data() /*in_buff*/,
|
|
4 /*in_channels*/,
|
|
u16contract.data() /*out_buff*/,
|
|
2 /*out_channels*/,
|
|
sizeof(u16ref[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
|
|
|
|
// contracted buffer must increase.
|
|
checkMonotone(u16contract.data(), u16contract.size());
|
|
|
|
// initialize channels 3 and 4 of final comparison array.
|
|
for (size_t i = 0; i < u16ary.size() / 4; ++i) {
|
|
u16ary[i * 4 + 2] = u16ref[i * 4 + 2];
|
|
u16ary[i * 4 + 3] = u16ref[i * 4 + 3];
|
|
}
|
|
|
|
// expand stereo into channels 1 and 2 of quad comparison array.
|
|
adjust_selected_channels(
|
|
u16contract.data() /*in_buff*/,
|
|
2 /*in_channels*/,
|
|
u16ary.data() /*out_buff*/,
|
|
4 /*out_channels*/,
|
|
sizeof(u16contract[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16contract[0]) * u16contract.size() /*num_in_bytes*/);
|
|
|
|
// comparison array must be identical to original.
|
|
expectEq(u16ary, u16ref);
|
|
}
|
|
|
|
TEST(audio_utils_channels, adjust_channels_non_destructive) {
|
|
constexpr size_t size = 65536; /* arbitrary large multiple of 8 */
|
|
std::vector<uint16_t> u16ref(size);
|
|
std::vector<uint16_t> u16contracted(size);
|
|
std::vector<uint16_t> u16expanded(size);
|
|
std::vector<uint16_t> u16inout(size);
|
|
|
|
// Reference buffer increases monotonically.
|
|
// For second test, in/out buffer begins identical to ref.
|
|
for (size_t i = 0; i < u16ref.size(); ++i) {
|
|
u16ref[i] = i;
|
|
u16inout[i] = i;
|
|
}
|
|
|
|
// *** First test: different in/out buffers ***
|
|
|
|
// Contract from quad to stereo.
|
|
adjust_channels_non_destructive(
|
|
u16ref.data() /*in_buff*/,
|
|
4 /*in_channels*/,
|
|
u16contracted.data() /*out_buff*/,
|
|
2 /*out_channels*/,
|
|
sizeof(u16ref[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16ref[0]) * u16ref.size() /*num_in_bytes*/);
|
|
|
|
// Each half of contracted buffer should increase monotonically.
|
|
checkMonotone(u16contracted.data(), u16contracted.size() / 2);
|
|
checkMonotone(&u16contracted[u16contracted.size() / 2], u16contracted.size() / 2);
|
|
|
|
// Expand stereo to quad
|
|
adjust_channels_non_destructive(
|
|
u16contracted.data() /*in_buff*/,
|
|
2 /*in_channels*/,
|
|
u16expanded.data() /*out_buff*/,
|
|
4 /*out_channels*/,
|
|
sizeof(u16contracted[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16contracted[0]) * (u16contracted.size() / 2) /*num_in_bytes*/);
|
|
|
|
// Comparison array must be identical to reference.
|
|
expectEq(u16expanded, u16ref);
|
|
|
|
// *** Second test: in_buff == out_buff ***
|
|
|
|
// Contract from eight channels to stereo.
|
|
adjust_channels_non_destructive(
|
|
u16inout.data() /*in_buff*/,
|
|
8 /*in_channels*/,
|
|
u16inout.data() /*out_buff*/,
|
|
2 /*out_channels*/,
|
|
sizeof(u16inout[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16inout[0]) * u16inout.size() /*num_in_bytes*/);
|
|
|
|
// Each section [1/4][3/4] of contracted buffer should increase monotonically.
|
|
checkMonotone(u16inout.data(), u16inout.size() / 4);
|
|
checkMonotone(&u16inout[u16inout.size() / 4], (u16inout.size() * 3) / 4);
|
|
|
|
// Expand stereo to eight channels.
|
|
adjust_channels_non_destructive(
|
|
u16inout.data() /*in_buff*/,
|
|
2 /*in_channels*/,
|
|
u16inout.data() /*out_buff*/,
|
|
8 /*out_channels*/,
|
|
sizeof(u16inout[0]) /*sample_size_in_bytes*/,
|
|
sizeof(u16inout[0]) * (u16inout.size() / 4) /*num_in_bytes*/);
|
|
|
|
// Comparison array must be identical to reference.
|
|
expectEq(u16inout, u16ref);
|
|
}
|