/* * Copyright 2022 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 #include #include #include #include #include #define LOG_TAG "EffectsFactoryHalInterfaceTest" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace android { using effect::utils::EffectParamReader; using effect::utils::EffectParamWriter; using ::aidl::android::media::audio::common::AudioUuid; // EffectsFactoryHalInterface TEST(libAudioHalTest, createEffectsFactoryHalInterface) { ASSERT_NE(nullptr, EffectsFactoryHalInterface::create()); } TEST(libAudioHalTest, queryNumberEffects) { auto factory = EffectsFactoryHalInterface::create(); ASSERT_NE(nullptr, factory); uint32_t numEffects = 0; EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects)); EXPECT_NE(0ul, numEffects); } TEST(libAudioHalTest, getDescriptorByNumber) { auto factory = EffectsFactoryHalInterface::create(); ASSERT_NE(nullptr, factory); uint32_t numEffects = 0; EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects)); EXPECT_NE(0ul, numEffects); effect_descriptor_t desc; for (uint32_t i = 0; i < numEffects; i++) { EXPECT_EQ(OK, factory->getDescriptor(i, &desc)); } } TEST(libAudioHalTest, createEffect) { auto factory = EffectsFactoryHalInterface::create(); ASSERT_NE(nullptr, factory); uint32_t numEffects = 0; EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects)); EXPECT_NE(0ul, numEffects); effect_descriptor_t desc; for (uint32_t i = 0; i < numEffects; i++) { sp interface; EXPECT_EQ(OK, factory->getDescriptor(i, &desc)); EXPECT_EQ(OK, factory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */, 1 /* deviceId */, &interface)); } } TEST(libAudioHalTest, getProcessings) { auto factory = EffectsFactoryHalInterface::create(); ASSERT_NE(nullptr, factory); const auto &processings = factory->getProcessings(); if (processings) { EXPECT_NE(0UL, processings->preprocess.size() + processings->postprocess.size() + processings->deviceprocess.size()); auto processingChecker = [](const auto& processings) { if (processings.size() != 0) { // any process need at least 1 effect inside std::for_each(processings.begin(), processings.end(), [](const auto& process) { EXPECT_NE(0ul, process.effects.size()); // any effect should have a valid name string, and not proxy for (const auto& effect : process.effects) { SCOPED_TRACE("Effect: {" + (effect == nullptr ? "NULL}" : ("{name: " + effect->name + ", isproxy: " + (effect->isProxy ? "true" : "false") + ", sw: " + (effect->libSw ? "non-null" : "null") + ", hw: " + (effect->libHw ? "non-null" : "null") + "}"))); EXPECT_NE(nullptr, effect); EXPECT_NE("", effect->name); EXPECT_EQ(false, effect->isProxy); EXPECT_EQ(nullptr, effect->libSw); EXPECT_EQ(nullptr, effect->libHw); } }); } }; processingChecker(processings->preprocess); processingChecker(processings->postprocess); processingChecker(processings->deviceprocess); } else { GTEST_SKIP() << "no processing found, skipping the test"; } } TEST(libAudioHalTest, getHalVersion) { auto factory = EffectsFactoryHalInterface::create(); ASSERT_NE(nullptr, factory); auto version = factory->getHalVersion(); EXPECT_NE(0, version.getMajorVersion()); } class EffectParamCombination { public: template void init(const P& p, const V& v, size_t len) { setBuffer.resize(sizeof(effect_param_t) + sizeof(p) + sizeof(v) + 4); getBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4); expectBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4); parameterSet = std::make_shared(createEffectParam(setBuffer.data(), p, v)); parameterGet = std::make_shared(createEffectParam(getBuffer.data(), p, v)); parameterExpect = std::make_shared(createEffectParam(expectBuffer.data(), p, v)); valueSize = len; } std::shared_ptr parameterSet; /* setParameter */ std::shared_ptr parameterGet; /* getParameter */ std::shared_ptr parameterExpect; /* expected from getParameter */ size_t valueSize; /* ValueSize expect to write in reply data buffer */ private: std::vector setBuffer; std::vector getBuffer; std::vector expectBuffer; template EffectParamReader createEffectParam(void* buf, const P& p, const V& v) { effect_param_t* paramRet = (effect_param_t*)buf; paramRet->psize = sizeof(P); paramRet->vsize = sizeof(V); EffectParamWriter writer(*paramRet); EXPECT_EQ(OK, writer.writeToParameter(&p)); EXPECT_EQ(OK, writer.writeToValue(&v)); writer.finishValueWrite(); return writer; } }; template std::shared_ptr createEffectParamCombination(const P& p, const V& v, size_t len) { auto comb = std::make_shared(); comb->init(p, v, len); return comb; } enum ParamName { TUPLE_UUID, TUPLE_PARAM_COMBINATION }; using EffectParamTestTuple = std::tuple>; static const effect_uuid_t EXTEND_EFFECT_TYPE_UUID = { 0xfa81dbde, 0x588b, 0x11ed, 0x9b6a, {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}}; std::vector testPairs = { std::make_tuple(FX_IID_AEC, createEffectParamCombination(AEC_PARAM_ECHO_DELAY, 0xff /* echoDelayMs */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple(FX_IID_AGC, createEffectParamCombination(AGC_PARAM_TARGET_LEVEL, 20 /* targetLevel */, sizeof(int16_t) /* returnValueSize */)), std::make_tuple(FX_IID_AGC2, createEffectParamCombination( AGC2_PARAM_FIXED_DIGITAL_GAIN, 15 /* digitalGainDb */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple(SL_IID_BASSBOOST, createEffectParamCombination(BASSBOOST_PARAM_STRENGTH, 20 /* strength */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple(EFFECT_UIID_DOWNMIX, createEffectParamCombination(DOWNMIX_PARAM_TYPE, DOWNMIX_TYPE_FOLD, sizeof(int16_t) /* returnValueSize */)), std::make_tuple(SL_IID_DYNAMICSPROCESSING, createEffectParamCombination( std::array({DP_PARAM_INPUT_GAIN, 0 /* channel */}), 30 /* gainDb */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple( FX_IID_HAPTICGENERATOR, createEffectParamCombination( HG_PARAM_HAPTIC_INTENSITY, std::array( {1, uint32_t(::android::os::HapticScale::HIGH) /* scale */}), 0 /* returnValueSize */)), std::make_tuple( FX_IID_LOUDNESS_ENHANCER, createEffectParamCombination(LOUDNESS_ENHANCER_PARAM_TARGET_GAIN_MB, 5 /* gain */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple(FX_IID_NS, createEffectParamCombination(NS_PARAM_LEVEL, 1 /* level */, sizeof(int32_t) /* returnValueSize */)), std::make_tuple(&EXTEND_EFFECT_TYPE_UUID, createEffectParamCombination(1, 0xbead, sizeof(int32_t)))}; class libAudioHalEffectParamTest : public ::testing::TestWithParam { public: libAudioHalEffectParamTest() : mParamTuple(GetParam()), mFactory(EffectsFactoryHalInterface::create()), mTypeUuid(std::get(mParamTuple)), mCombination(std::get(mParamTuple)), mExpectedValue([&]() { std::vector expectData(mCombination->valueSize); mCombination->parameterExpect->readFromValue(expectData.data(), mCombination->valueSize); return expectData; }()), mDescs([&]() { std::vector descs; if (mFactory && mTypeUuid && OK == mFactory->getDescriptors(mTypeUuid, &descs)) { return descs; } return descs; }()) {} void SetUp() override { ASSERT_NE(0ul, mDescs.size()); for (const auto& desc : mDescs) { sp interface = createEffectHal(desc); ASSERT_NE(nullptr, interface); mHalInterfaces.push_back(interface); } } void initEffect(const sp& interface) { uint32_t initReply = 0; uint32_t initReplySize = sizeof(initReply); ASSERT_EQ(OK, interface->command(EFFECT_CMD_INIT, 0, nullptr, &initReplySize, &initReply)); } void TearDown() override { for (auto& interface : mHalInterfaces) { interface->close(); } } sp createEffectHal(const effect_descriptor_t& desc) { sp interface = nullptr; if (0 == std::memcmp(&desc.type, mTypeUuid, sizeof(effect_uuid_t)) && OK == mFactory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */, 1 /* deviceId */, &interface)) { return interface; } return nullptr; } void setAndGetParameter(const sp& interface) { uint32_t replySize = sizeof(uint32_t); uint8_t reply[replySize]; auto parameterSet = mCombination->parameterSet; ASSERT_EQ(OK, interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)parameterSet->getTotalSize(), const_cast(¶meterSet->getEffectParam()), &replySize, &reply)) << parameterSet->toString(); ASSERT_EQ(replySize, sizeof(uint32_t)); effect_param_t* getParam = const_cast(&mCombination->parameterGet->getEffectParam()); size_t maxReplySize = mCombination->valueSize + sizeof(effect_param_t) + sizeof(parameterSet->getPaddedParameterSize()); replySize = maxReplySize; EXPECT_EQ(OK, interface->command(EFFECT_CMD_GET_PARAM, (uint32_t)parameterSet->getTotalSize(), const_cast(¶meterSet->getEffectParam()), &replySize, getParam)); EffectParamReader parameterGet(*getParam); EXPECT_EQ(replySize, parameterGet.getTotalSize()) << parameterGet.toString(); if (mCombination->valueSize) { std::vector response(mCombination->valueSize); EXPECT_EQ(OK, parameterGet.readFromValue(response.data(), mCombination->valueSize)) << " try get valueSize " << mCombination->valueSize << " from " << parameterGet.toString(); EXPECT_EQ(response, mExpectedValue); } } const EffectParamTestTuple mParamTuple; const sp mFactory; const effect_uuid_t* mTypeUuid; std::shared_ptr mCombination; const std::vector mExpectedValue; const std::vector mDescs; std::vector> mHalInterfaces; }; TEST_P(libAudioHalEffectParamTest, setAndGetParam) { for (auto& interface : mHalInterfaces) { EXPECT_NO_FATAL_FAILURE(initEffect(interface)); EXPECT_NO_FATAL_FAILURE(setAndGetParameter(interface)); } } INSTANTIATE_TEST_SUITE_P( libAudioHalEffectParamTest, libAudioHalEffectParamTest, ::testing::ValuesIn(testPairs), [](const testing::TestParamInfo& info) { AudioUuid uuid = ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid( *std::get(info.param)) .value(); std::string name = "UUID_" + uuid.toString(); std::replace_if( name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_'); return name; }); GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(libAudioHalEffectParamTest); int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } // TODO: b/263986405 Add multi-thread testing } // namespace android