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.
293 lines
11 KiB
293 lines
11 KiB
/*
|
|
* Copyright 2023 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.
|
|
*/
|
|
|
|
//#define LOG_NDEBUG 0
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <memory>
|
|
#include <utility>
|
|
#define LOG_TAG "EffectProxyTest"
|
|
|
|
#include <aidl/android/media/audio/common/AudioUuid.h>
|
|
#include <aidl/Vintf.h>
|
|
#include <android/binder_manager.h>
|
|
#include <gtest/gtest.h>
|
|
#include <utils/RefBase.h>
|
|
|
|
#include "EffectProxy.h"
|
|
|
|
/**
|
|
* This test suite is depending on audio effect AIDL service.
|
|
*/
|
|
namespace android {
|
|
|
|
using ::aidl::android::hardware::audio::effect::CommandId;
|
|
using ::aidl::android::hardware::audio::effect::Descriptor;
|
|
using ::aidl::android::hardware::audio::effect::Flags;
|
|
using ::aidl::android::hardware::audio::effect::IEffect;
|
|
using ::aidl::android::hardware::audio::effect::IFactory;
|
|
using ::aidl::android::hardware::audio::effect::Parameter;
|
|
using ::aidl::android::hardware::audio::effect::State;
|
|
using ::aidl::android::media::audio::common::AudioChannelLayout;
|
|
using ::aidl::android::media::audio::common::AudioFormatDescription;
|
|
using ::aidl::android::media::audio::common::AudioFormatType;
|
|
using ::aidl::android::media::audio::common::AudioUuid;
|
|
using ::aidl::android::media::audio::common::PcmType;
|
|
using ::android::effect::EffectProxy;
|
|
|
|
class EffectProxyTest : public testing::Test {
|
|
public:
|
|
void SetUp() override {
|
|
auto serviceName = android::getAidlHalInstanceNames(IFactory::descriptor);
|
|
// only unit test with the first one in case more than one EffectFactory service exist
|
|
if (0ul == serviceName.size()) {
|
|
GTEST_SKIP() << "EffectFactory not available on device, skipping";
|
|
}
|
|
mFactory = IFactory::fromBinder(
|
|
ndk::SpAIBinder(AServiceManager_waitForService(serviceName[0].c_str())));
|
|
ASSERT_NE(nullptr, mFactory);
|
|
mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &mDescs);
|
|
for (const auto& desc : mDescs) {
|
|
if (desc.common.id.proxy.has_value()) {
|
|
mProxyDescs[desc.common.id.proxy.value()].emplace_back(desc);
|
|
}
|
|
}
|
|
}
|
|
|
|
void TearDown() override {}
|
|
|
|
const AudioFormatDescription kDefaultFormatDescription = {
|
|
.type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
|
|
|
|
Parameter::Common createParamCommon(
|
|
int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
|
|
long iFrameCount = 0x100, long oFrameCount = 0x100,
|
|
AudioChannelLayout inputChannelLayout =
|
|
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
|
|
AudioChannelLayout::LAYOUT_STEREO),
|
|
AudioChannelLayout outputChannelLayout =
|
|
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
|
|
AudioChannelLayout::LAYOUT_STEREO)) {
|
|
Parameter::Common common;
|
|
common.session = session;
|
|
common.ioHandle = ioHandle;
|
|
|
|
auto& input = common.input;
|
|
auto& output = common.output;
|
|
input.base.sampleRate = iSampleRate;
|
|
input.base.channelMask = inputChannelLayout;
|
|
input.base.format = kDefaultFormatDescription;
|
|
input.frameCount = iFrameCount;
|
|
output.base.sampleRate = oSampleRate;
|
|
output.base.channelMask = outputChannelLayout;
|
|
output.base.format = kDefaultFormatDescription;
|
|
output.frameCount = oFrameCount;
|
|
return common;
|
|
}
|
|
|
|
enum TupleIndex { HANDLE, DESCRIPTOR };
|
|
using EffectProxyTuple = std::tuple<std::shared_ptr<EffectProxy>, std::vector<Descriptor>>;
|
|
|
|
std::map<AudioUuid, EffectProxyTuple> createAllProxies() {
|
|
std::map<AudioUuid, EffectProxyTuple> proxyMap;
|
|
for (const auto& itor : mProxyDescs) {
|
|
const auto& uuid = itor.first;
|
|
if (proxyMap.end() == proxyMap.find(uuid)) {
|
|
std::get<TupleIndex::HANDLE>(proxyMap[uuid]) =
|
|
ndk::SharedRefBase::make<EffectProxy>(itor.first, itor.second, mFactory);
|
|
}
|
|
}
|
|
return proxyMap;
|
|
}
|
|
|
|
std::shared_ptr<IFactory> mFactory;
|
|
std::vector<Descriptor> mDescs;
|
|
std::map<const AudioUuid, std::vector<Descriptor>> mProxyDescs;
|
|
};
|
|
|
|
TEST_F(EffectProxyTest, createProxy) {
|
|
auto proxyMap = createAllProxies();
|
|
// if there are some descriptor defined with proxy, then proxyMap can not be empty
|
|
EXPECT_EQ(mProxyDescs.size() == 0, proxyMap.size() == 0);
|
|
}
|
|
|
|
TEST_F(EffectProxyTest, addSubEffectsCreateAndDestroy) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
for (const auto& itor : proxyMap) {
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
TEST_F(EffectProxyTest, addSubEffectsCreateOpenCloseDestroy) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
Parameter::Common common = createParamCommon();
|
|
IEffect::OpenEffectReturn ret;
|
|
for (const auto& itor : proxyMap) {
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
// Add sub-effects, set active sub-effect with different checkers
|
|
TEST_F(EffectProxyTest, setOffloadParam) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
// Any flag exist should be able to set successfully
|
|
Parameter::Common common = createParamCommon();
|
|
IEffect::OpenEffectReturn ret;
|
|
for (const auto& itor : proxyMap) {
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
|
|
effect_offload_param_t offloadParam{false, 0};
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
offloadParam.isOffload = true;
|
|
offloadParam.ioHandle++;
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
TEST_F(EffectProxyTest, destroyWithoutCreate) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
for (const auto& itor : proxyMap) {
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
TEST_F(EffectProxyTest, closeWithoutOpen) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
for (const auto& itor : proxyMap) {
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
// Add sub-effects, set active sub-effect, create, open, and send command, expect success handling
|
|
TEST_F(EffectProxyTest, normalSequency) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
Parameter::Common common = createParamCommon();
|
|
IEffect::OpenEffectReturn ret;
|
|
Parameter::VolumeStereo volumeStereo({.left = .1f, .right = -0.8f});
|
|
Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
|
|
const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
|
|
State state;
|
|
for (const auto& itor : proxyMap) {
|
|
Parameter getParam = Parameter::make<Parameter::offload>(true);
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
effect_offload_param_t offloadParam{true, 0};
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
|
|
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
|
|
|
|
EXPECT_TRUE(proxy->setParameter(expect).isOk());
|
|
EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
|
|
EXPECT_EQ(expect, getParam)
|
|
<< " EXPECTED: " << expect.toString() << "\nACTUAL: " << getParam.toString();
|
|
|
|
EXPECT_TRUE(proxy->command(CommandId::START).isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::PROCESSING, state);
|
|
|
|
EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::IDLE, state);
|
|
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
// setParameter, change active sub-effect, verify with getParameter
|
|
TEST_F(EffectProxyTest, changeActiveSubAndVerifyParameter) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
Parameter::Common common = createParamCommon();
|
|
IEffect::OpenEffectReturn ret;
|
|
Parameter::VolumeStereo volumeStereo({.left = .5f, .right = .8f});
|
|
Parameter expect = Parameter::make<Parameter::volumeStereo>(volumeStereo);
|
|
const Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
|
|
for (const auto& itor : proxyMap) {
|
|
Parameter getParam = Parameter::make<Parameter::offload>(true);
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
|
|
EXPECT_TRUE(proxy->setParameter(expect).isOk());
|
|
EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
|
|
EXPECT_EQ(expect, getParam);
|
|
|
|
effect_offload_param_t offloadParam{false, 0};
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
|
|
EXPECT_EQ(expect, getParam);
|
|
|
|
offloadParam.isOffload = true;
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
EXPECT_TRUE(proxy->getParameter(id, &getParam).isOk());
|
|
EXPECT_EQ(expect, getParam);
|
|
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
// send command, change active sub-effect, then verify the state with getState
|
|
TEST_F(EffectProxyTest, changeActiveSubAndVerifyState) {
|
|
auto proxyMap = createAllProxies();
|
|
|
|
Parameter::Common common = createParamCommon();
|
|
IEffect::OpenEffectReturn ret;
|
|
State state;
|
|
for (const auto& itor : proxyMap) {
|
|
Parameter expect;
|
|
auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::INIT, state);
|
|
EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::IDLE, state);
|
|
EXPECT_TRUE(proxy->command(CommandId::START).isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::PROCESSING, state);
|
|
|
|
effect_offload_param_t offloadParam{false, 0};
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
|
|
offloadParam.isOffload = true;
|
|
EXPECT_TRUE(proxy->setOffloadParam(&offloadParam).isOk());
|
|
|
|
EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::IDLE, state);
|
|
|
|
EXPECT_TRUE(proxy->close().isOk());
|
|
EXPECT_TRUE(proxy->getState(&state).isOk());
|
|
EXPECT_EQ(State::INIT, state);
|
|
EXPECT_TRUE(proxy->destroy().isOk());
|
|
}
|
|
}
|
|
|
|
} // namespace android
|