Merge "AIDL effect vts test cases refinement"

This commit is contained in:
Shunkai Yao
2022-11-18 23:17:59 +00:00
committed by Gerrit Code Review
32 changed files with 1679 additions and 1104 deletions

View File

@@ -66,6 +66,7 @@ cc_defaults {
name: "aidlaudioeffectservice_defaults",
defaults: [
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
vendor: true,
shared_libs: [
@@ -78,7 +79,6 @@ cc_defaults {
"libutils",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.audio.effect-V1-ndk",
],
header_libs: [
"libaudioaidl_headers",
@@ -111,10 +111,11 @@ cc_binary {
"libbassboostsw",
"libbundleaidl",
"libdynamicsprocessingsw",
"libenvreverbsw",
"libequalizersw",
"libhapticgeneratorsw",
"libloudnessenhancersw",
"libreverbsw",
"libpresetreverbsw",
"libtinyxml2",
"libvirtualizersw",
"libvisualizersw",

View File

@@ -34,7 +34,8 @@
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
<library name="loudness_enhancersw" path="libloudnessenhancersw.so"/>
<library name="reverbsw" path="libreverbsw.so"/>
<library name="env_reverbsw" path="libenvreverbsw.so"/>
<library name="preset_reverbsw" path="libpresetreverbsw.so"/>
<library name="virtualizersw" path="libvirtualizersw.so"/>
<library name="visualizersw" path="libvisualizersw.so"/>
<library name="volumesw" path="libvolumesw.so"/>
@@ -64,11 +65,12 @@
<effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
<effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
<effect name="loudness_enhancer" library="loudness_enhancersw" uuid="fa819610-588b-11ed-9b6a-0242ac120002"/>
<effect name="reverb" library="reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
<effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
<effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
<effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
<effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
<effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
<effectProxy name="equalizer" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
<effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
<libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
<libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
</effectProxy>

View File

@@ -26,14 +26,14 @@
#include "BassBoostSw.h"
using aidl::android::hardware::audio::effect::BassBoostSw;
using aidl::android::hardware::audio::effect::BassBoostSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kBassBoostSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != BassBoostSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kBassBoostSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class BassBoostSw final : public EffectImpl {
public:
BassBoostSw() { LOG(DEBUG) << __func__; }
~BassBoostSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class BassBoostSw final : public EffectImpl {
const BassBoost::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = BassBoostTypeUUID,
.uuid = BassBoostSwImplUUID,
.common = {.id = {.type = kBassBoostTypeUUID,
.uuid = kBassBoostSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "BassBoostSw"},
.name = "BassBoostSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::bassBoost>(kCapability)};
/* parameters */

View File

@@ -26,14 +26,14 @@
#include "DynamicsProcessingSw.h"
using aidl::android::hardware::audio::effect::DynamicsProcessingSw;
using aidl::android::hardware::audio::effect::DynamicsProcessingSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kDynamicsProcessingSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != DynamicsProcessingSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class DynamicsProcessingSw final : public EffectImpl {
public:
DynamicsProcessingSw() { LOG(DEBUG) << __func__; }
~DynamicsProcessingSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class DynamicsProcessingSw final : public EffectImpl {
const DynamicsProcessing::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = DynamicsProcessingTypeUUID,
.uuid = DynamicsProcessingSwImplUUID,
.common = {.id = {.type = kDynamicsProcessingTypeUUID,
.uuid = kDynamicsProcessingSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "DynamicsProcessingSw"},
.name = "DynamicsProcessingSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::dynamicsProcessing>(kCapability)};
/* parameters */

View File

@@ -24,14 +24,14 @@ package {
}
cc_library_shared {
name: "libreverbsw",
name: "libenvreverbsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"ReverbSw.cpp",
"EnvReverbSw.cpp",
":effectCommonFile",
],
visibility: [

View File

@@ -15,7 +15,7 @@
*/
#include <cstddef>
#define LOG_TAG "AHAL_ReverbSw"
#define LOG_TAG "AHAL_EnvReverbSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
@@ -23,22 +23,22 @@
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "ReverbSw.h"
#include "EnvReverbSw.h"
using aidl::android::hardware::audio::effect::EnvReverbSw;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::ReverbSw;
using aidl::android::hardware::audio::effect::ReverbSwImplUUID;
using aidl::android::hardware::audio::effect::kEnvReverbSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != ReverbSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kEnvReverbSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<ReverbSw>();
*instanceSpp = ndk::SharedRefBase::make<EnvReverbSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
@@ -64,13 +64,13 @@ extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& inst
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus ReverbSw::getDescriptor(Descriptor* _aidl_return) {
ndk::ScopedAStatus EnvReverbSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
ndk::ScopedAStatus EnvReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
@@ -81,24 +81,24 @@ ndk::ScopedAStatus ReverbSw::setParameterSpecific(const Parameter::Specific& spe
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus ReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::reverb>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> ReverbSw::createContext(const Parameter::Common& common) {
std::shared_ptr<EffectContext> EnvReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<ReverbSwContext>(1 /* statusFmqDepth */, common);
mContext = std::make_shared<EnvReverbSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode ReverbSw::releaseContext() {
RetCode EnvReverbSw::releaseContext() {
if (mContext) {
mContext.reset();
}
@@ -106,7 +106,7 @@ RetCode ReverbSw::releaseContext() {
}
// Processing method running in EffectWorker thread.
IEffect::Status ReverbSw::effectProcessImpl(float* in, float* out, int process) {
IEffect::Status EnvReverbSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {

View File

@@ -26,21 +26,21 @@
namespace aidl::android::hardware::audio::effect {
class ReverbSwContext final : public EffectContext {
class EnvReverbSwContext final : public EffectContext {
public:
ReverbSwContext(int statusDepth, const Parameter::Common& common)
EnvReverbSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class ReverbSw final : public EffectImpl {
class EnvReverbSw final : public EffectImpl {
public:
ReverbSw() { LOG(DEBUG) << __func__; }
~ReverbSw() {
EnvReverbSw() { LOG(DEBUG) << __func__; }
~EnvReverbSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -52,18 +52,19 @@ class ReverbSw final : public EffectImpl {
RetCode releaseContext() override;
private:
std::shared_ptr<ReverbSwContext> mContext;
std::shared_ptr<EnvReverbSwContext> mContext;
/* capabilities */
const Reverb::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = ReverbTypeUUID,
.uuid = ReverbSwImplUUID,
.common = {.id = {.type = kEnvReverbTypeUUID,
.uuid = kEnvReverbSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "ReverbSw"},
.name = "EnvReverbSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::reverb>(kCapability)};
/* parameters */

View File

@@ -26,14 +26,14 @@
#include "EqualizerSw.h"
using aidl::android::hardware::audio::effect::EqualizerSw;
using aidl::android::hardware::audio::effect::EqualizerSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kEqualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != EqualizerSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kEqualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -82,8 +82,8 @@ class EqualizerSw final : public EffectImpl {
public:
EqualizerSw() { LOG(DEBUG) << __func__; }
~EqualizerSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -109,13 +109,14 @@ class EqualizerSw final : public EffectImpl {
const Equalizer::Capability kEqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
// Effect descriptor.
const Descriptor kDesc = {.common = {.id = {.type = EqualizerTypeUUID,
.uuid = EqualizerSwImplUUID,
.proxy = std::nullopt},
const Descriptor kDesc = {.common = {.id = {.type = kEqualizerTypeUUID,
.uuid = kEqualizerSwImplUUID,
.proxy = kEqualizerProxyUUID},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "EqualizerSw"},
.name = "EqualizerSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::equalizer>(kEqCap)};
ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Tag& tag,

View File

@@ -26,14 +26,14 @@
#include "HapticGeneratorSw.h"
using aidl::android::hardware::audio::effect::HapticGeneratorSw;
using aidl::android::hardware::audio::effect::HapticGeneratorSwImplUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kHapticGeneratorSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != HapticGeneratorSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kHapticGeneratorSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class HapticGeneratorSw final : public EffectImpl {
public:
HapticGeneratorSw() { LOG(DEBUG) << __func__; }
~HapticGeneratorSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class HapticGeneratorSw final : public EffectImpl {
const HapticGenerator::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = HapticGeneratorTypeUUID,
.uuid = HapticGeneratorSwImplUUID,
.common = {.id = {.type = kHapticGeneratorTypeUUID,
.uuid = kHapticGeneratorSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "HapticGeneratorSw"},
.name = "HapticGeneratorSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::hapticGenerator>(kCapability)};
/* parameters */

View File

@@ -30,11 +30,8 @@ namespace aidl::android::hardware::audio::effect {
class EffectImpl : public BnEffect, public EffectWorker {
public:
EffectImpl() { LOG(DEBUG) << __func__; }
~EffectImpl() {
cleanUp();
LOG(DEBUG) << __func__;
}
EffectImpl() = default;
virtual ~EffectImpl() = default;
/**
* Each effect implementation CAN override these methods if necessary
@@ -78,9 +75,9 @@ class EffectImpl : public BnEffect, public EffectWorker {
State mState GUARDED_BY(mMutex) = State::INIT;
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
void cleanUp();
private:
void cleanUp();
std::shared_ptr<EffectContext> mContext GUARDED_BY(mMutex);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -23,150 +23,160 @@ namespace aidl::android::hardware::audio::effect {
using ::aidl::android::media::audio::common::AudioUuid;
// Null UUID
static const AudioUuid EffectNullUuid = {static_cast<int32_t>(0xec7178ec),
0xe5e1,
0x4432,
0xa3f4,
{0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
// ec7178ec-e5e1-4432-a3f4-4657e6795210
static const AudioUuid kEffectNullUuid = {static_cast<int32_t>(0xec7178ec),
0xe5e1,
0x4432,
0xa3f4,
{0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
// Zero UUID
static const AudioUuid EffectZeroUuid = {
static const AudioUuid kEffectZeroUuid = {
static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// Equalizer type UUID.
static const AudioUuid EqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
0xddd6,
0x11db,
0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// 0bed4300-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// ce772f20-847d-11df-bb17-0002a5d5c51b
static const AudioUuid EqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa8184a4-588b-11ed-9b6a-0242ac120002
static const AudioUuid BassBoostTypeUUID = {static_cast<int32_t>(0xfa8184a4),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
0xddd4,
0x11db,
0xa0fc,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa8181f2-588b-11ed-9b6a-0242ac120002
static const AudioUuid BassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81862a-588b-11ed-9b6a-0242ac120002
static const AudioUuid DownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8187ba-588b-11ed-9b6a-0242ac120002
static const AudioUuid DownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818954-588b-11ed-9b6a-0242ac120002
static const AudioUuid DynamicsProcessingTypeUUID = {static_cast<int32_t>(0xfa818954),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818d78-588b-11ed-9b6a-0242ac120002
static const AudioUuid DynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa818f62-588b-11ed-9b6a-0242ac120002
static const AudioUuid HapticGeneratorTypeUUID = {static_cast<int32_t>(0xfa818f62),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819110-588b-11ed-9b6a-0242ac120002
static const AudioUuid HapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8194a8-588b-11ed-9b6a-0242ac120002
static const AudioUuid LoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfa8194a8),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819610-588b-11ed-9b6a-0242ac120002
static const AudioUuid LoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819886-588b-11ed-9b6a-0242ac120002
static const AudioUuid ReverbTypeUUID = {static_cast<int32_t>(0xfa819886),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8199c6-588b-11ed-9b6a-0242ac120002
static const AudioUuid ReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819af2-588b-11ed-9b6a-0242ac120002
static const AudioUuid VirtualizerTypeUUID = {static_cast<int32_t>(0xfa819af2),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819d86-588b-11ed-9b6a-0242ac120002
static const AudioUuid VirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819f3e-588b-11ed-9b6a-0242ac120002
static const AudioUuid VisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a0f6-588b-11ed-9b6a-0242ac120002
static const AudioUuid VisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
static const AudioUuid kBassBoostSwImplUUID = {static_cast<int32_t>(0xfa8181f2),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a2b8-588b-11ed-9b6a-0242ac120002
static const AudioUuid VolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a718-588b-11ed-9b6a-0242ac120002
static const AudioUuid VolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
// fa81862a-588b-11ed-9b6a-0242ac120002
static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa8187ba-588b-11ed-9b6a-0242ac120002
static const AudioUuid kDownmixSwImplUUID = {static_cast<int32_t>(0xfa8187ba),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
0xddd6,
0x11db,
0x8f34,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// 0bed4300-847d-11df-bb17-0002a5d5c51b
static const AudioUuid kEqualizerSwImplUUID = {static_cast<int32_t>(0x0bed4300),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// ce772f20-847d-11df-bb17-0002a5d5c51b
static const AudioUuid kEqualizerBundleImplUUID = {static_cast<int32_t>(0xce772f20),
0x847d,
0x11df,
0xbb17,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// c8e70ecd-48ca-456e-8a4f-0002a5d5c51b
static const AudioUuid kEqualizerProxyUUID = {static_cast<int32_t>(0xc8e70ecd),
0x48ca,
0x456e,
0x8a4f,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// 7261676f-6d75-7369-6364-28e2fd3ac39e
static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast<int32_t>(0x7261676f),
0x6d75,
0x7369,
0x6364,
{0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}};
// fa818d78-588b-11ed-9b6a-0242ac120002
static const AudioUuid kDynamicsProcessingSwImplUUID = {static_cast<int32_t>(0xfa818d78),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
0xaecd,
0x4021,
0xa1cf,
{0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}};
// fa819110-588b-11ed-9b6a-0242ac120002
static const AudioUuid kHapticGeneratorSwImplUUID = {static_cast<int32_t>(0xfa819110),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fe3199be-aed0-413f-87bb-11260eb63cf1
static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
0xaed0,
0x413f,
0x87bb,
{0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
// fa819610-588b-11ed-9b6a-0242ac120002
static const AudioUuid kLoudnessEnhancerSwImplUUID = {static_cast<int32_t>(0xfa819610),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// c2e5d5f0-94bd-4763-9cac-4e234d06839e
static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
0x94bd,
0x4763,
0x9cac,
{0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}};
// fa819886-588b-11ed-9b6a-0242ac120002
static const AudioUuid kEnvReverbSwImplUUID = {static_cast<int32_t>(0xfa819886),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
0xddd8,
0x11db,
0xbf3a,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa8199c6-588b-11ed-9b6a-0242ac120002
static const AudioUuid kPresetReverbSwImplUUID = {static_cast<int32_t>(0xfa8199c6),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 37cc2c00-dddd-11db-8577-0002a5d5c51b
static const AudioUuid kVirtualizerTypeUUID = {static_cast<int32_t>(0x37cc2c00),
0xdddd,
0x11db,
0x8577,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa819d86-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVirtualizerSwImplUUID = {static_cast<int32_t>(0xfa819d86),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa819f3e-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a0f6-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVisualizerSwImplUUID = {static_cast<int32_t>(0xfa81a0f6),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a2b8-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// fa81a718-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
0x588b,
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
/**
* @brief A map between effect name and effect type UUID.
@@ -174,20 +184,21 @@ static const AudioUuid VolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
* We need this map is because existing audio_effects.xml don't have a type UUID defined.
*/
static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
{"bassboost", BassBoostTypeUUID},
{"downmix", DownmixTypeUUID},
{"dynamics_processing", DynamicsProcessingTypeUUID},
{"equalizer", EqualizerTypeUUID},
{"haptic_generator", HapticGeneratorTypeUUID},
{"loudness_enhancer", LoudnessEnhancerTypeUUID},
{"reverb", ReverbTypeUUID},
{"reverb_env_aux", ReverbTypeUUID},
{"reverb_env_ins", ReverbTypeUUID},
{"reverb_pre_aux", ReverbTypeUUID},
{"reverb_pre_ins", ReverbTypeUUID},
{"virtualizer", VirtualizerTypeUUID},
{"visualizer", VisualizerTypeUUID},
{"volume", VolumeTypeUUID},
{"bassboost", kBassBoostTypeUUID},
{"downmix", kDownmixTypeUUID},
{"dynamics_processing", kDynamicsProcessingTypeUUID},
{"equalizer", kEqualizerTypeUUID},
{"haptic_generator", kHapticGeneratorTypeUUID},
{"loudness_enhancer", kLoudnessEnhancerTypeUUID},
{"env_reverb", kEnvReverbTypeUUID},
{"preset_reverb", kPresetReverbTypeUUID},
{"reverb_env_aux", kEnvReverbTypeUUID},
{"reverb_env_ins", kEnvReverbTypeUUID},
{"reverb_pre_aux", kPresetReverbTypeUUID},
{"reverb_pre_ins", kPresetReverbTypeUUID},
{"virtualizer", kVirtualizerTypeUUID},
{"visualizer", kVisualizerTypeUUID},
{"volume", kVolumeTypeUUID},
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -26,14 +26,14 @@
#include "LoudnessEnhancerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kLoudnessEnhancerSwImplUUID;
using aidl::android::hardware::audio::effect::LoudnessEnhancerSw;
using aidl::android::hardware::audio::effect::LoudnessEnhancerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != LoudnessEnhancerSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kLoudnessEnhancerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -48,8 +48,8 @@ class LoudnessEnhancerSw final : public EffectImpl {
public:
LoudnessEnhancerSw() { LOG(DEBUG) << __func__; }
~LoudnessEnhancerSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -66,13 +66,14 @@ class LoudnessEnhancerSw final : public EffectImpl {
const LoudnessEnhancer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = LoudnessEnhancerTypeUUID,
.uuid = LoudnessEnhancerSwImplUUID,
.common = {.id = {.type = kLoudnessEnhancerTypeUUID,
.uuid = kLoudnessEnhancerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "LoudnessEnhancerSw"},
.name = "LoudnessEnhancerSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::loudnessEnhancer>(kCapability)};
ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 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.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libpresetreverbsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"PresetReverbSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,118 @@
/*
* Copyright (C) 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.
*/
#include <cstddef>
#define LOG_TAG "AHAL_PresetReverbSw"
#include <Utils.h>
#include <algorithm>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "PresetReverbSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kPresetReverbSwImplUUID;
using aidl::android::hardware::audio::effect::PresetReverbSw;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != kPresetReverbSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<PresetReverbSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
if (!instanceSp) {
return EX_NONE;
}
State state;
ndk::ScopedAStatus status = instanceSp->getState(&state);
if (!status.isOk() || State::INIT != state) {
LOG(ERROR) << __func__ << " instance " << instanceSp.get()
<< " in state: " << toString(state) << ", status: " << status.getDescription();
return EX_ILLEGAL_STATE;
}
LOG(DEBUG) << __func__ << " instance " << instanceSp.get() << " destroyed";
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
ndk::ScopedAStatus PresetReverbSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus PresetReverbSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::reverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
std::lock_guard lg(mMutex);
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
mSpecificParam = specific.get<Parameter::Specific::reverb>();
LOG(DEBUG) << __func__ << " success with: " << specific.toString();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::reverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
specific->set<Parameter::Specific::reverb>(mSpecificParam);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> PresetReverbSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
return mContext;
}
mContext = std::make_shared<PresetReverbSwContext>(1 /* statusFmqDepth */, common);
return mContext;
}
RetCode PresetReverbSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status PresetReverbSw::effectProcessImpl(float* in, float* out, int process) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " process " << process;
for (int i = 0; i < process; i++) {
*out++ = *in++;
}
return {STATUS_OK, process, process};
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,73 @@
/*
* Copyright (C) 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.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class PresetReverbSwContext final : public EffectContext {
public:
PresetReverbSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
// TODO: add specific context here
};
class PresetReverbSw final : public EffectImpl {
public:
PresetReverbSw() { LOG(DEBUG) << __func__; }
~PresetReverbSw() {
cleanUp();
LOG(DEBUG) << __func__;
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
RetCode releaseContext() override;
private:
std::shared_ptr<PresetReverbSwContext> mContext;
/* capabilities */
const Reverb::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = kPresetReverbTypeUUID,
.uuid = kPresetReverbSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "PresetReverbSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::reverb>(kCapability)};
/* parameters */
Reverb mSpecificParam;
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -26,14 +26,14 @@
#include "VirtualizerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVirtualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VirtualizerSw;
using aidl::android::hardware::audio::effect::VirtualizerSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VirtualizerSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kVirtualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class VirtualizerSw final : public EffectImpl {
public:
VirtualizerSw() { LOG(DEBUG) << __func__; }
~VirtualizerSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class VirtualizerSw final : public EffectImpl {
const Virtualizer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VirtualizerTypeUUID,
.uuid = VirtualizerSwImplUUID,
.common = {.id = {.type = kVirtualizerTypeUUID,
.uuid = kVirtualizerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VirtualizerSw"},
.name = "VirtualizerSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::virtualizer>(kCapability)};
/* parameters */

View File

@@ -26,14 +26,14 @@
#include "VisualizerSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVisualizerSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VisualizerSw;
using aidl::android::hardware::audio::effect::VisualizerSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VisualizerSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kVisualizerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class VisualizerSw final : public EffectImpl {
public:
VisualizerSw() { LOG(DEBUG) << __func__; }
~VisualizerSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class VisualizerSw final : public EffectImpl {
const Visualizer::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VisualizerTypeUUID,
.uuid = VisualizerSwImplUUID,
.common = {.id = {.type = kVisualizerTypeUUID,
.uuid = kVisualizerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VisualizerSw"},
.name = "VisualizerSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::visualizer>(kCapability)};
/* parameters */

View File

@@ -26,14 +26,14 @@
#include "VolumeSw.h"
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kVolumeSwImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::audio::effect::VolumeSw;
using aidl::android::hardware::audio::effect::VolumeSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != VolumeSwImplUUID) {
if (!in_impl_uuid || *in_impl_uuid != kVolumeSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}

View File

@@ -39,8 +39,8 @@ class VolumeSw final : public EffectImpl {
public:
VolumeSw() { LOG(DEBUG) << __func__; }
~VolumeSw() {
cleanUp();
LOG(DEBUG) << __func__;
releaseContext();
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
@@ -57,13 +57,14 @@ class VolumeSw final : public EffectImpl {
const Volume::Capability kCapability;
/* Effect descriptor */
const Descriptor kDescriptor = {
.common = {.id = {.type = VolumeTypeUUID,
.uuid = VolumeSwImplUUID,
.common = {.id = {.type = kVolumeTypeUUID,
.uuid = kVolumeSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = "VolumeSw"},
.name = "VolumeSw",
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::volume>(kCapability)};
/* parameters */

View File

@@ -29,10 +29,7 @@
using namespace android;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EffectNullUuid;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::Processing;
using aidl::android::media::audio::common::AudioUuid;
class EffectFactoryHelper {
@@ -48,122 +45,36 @@ class EffectFactoryHelper {
ASSERT_NE(mEffectFactory, nullptr);
mEffectFactory = IFactory::fromBinder(binderUtil.restartService());
ASSERT_NE(mEffectFactory, nullptr);
ClearEffectMap();
}
void QueryEffects(const std::optional<AudioUuid>& in_type,
const std::optional<AudioUuid>& in_instance,
const std::optional<AudioUuid>& in_proxy,
std::vector<Descriptor::Identity>* _aidl_return) {
ASSERT_NE(mEffectFactory, nullptr);
EXPECT_IS_OK(mEffectFactory->queryEffects(in_type, in_instance, in_proxy, _aidl_return));
mIds = *_aidl_return;
}
std::shared_ptr<IFactory> GetFactory() const { return mEffectFactory; }
void QueryProcessing(const std::optional<Processing::Type>& in_type,
std::vector<Processing>* _aidl_return) {
ASSERT_NE(mEffectFactory, nullptr);
EXPECT_IS_OK(mEffectFactory->queryProcessing(in_type, _aidl_return));
// only update the whole list if no filter applied
if (!in_type.has_value()) {
mProcesses = *_aidl_return;
}
}
static std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>
getAllEffectDescriptors(std::string serviceName, std::optional<AudioUuid> type = std::nullopt) {
AudioHalBinderServiceUtil util;
auto names = android::getAidlHalInstanceNames(serviceName);
std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>> result;
void CreateEffects() {
for (const auto& id : mIds) {
std::shared_ptr<IEffect> effect;
EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
EXPECT_NE(effect, nullptr) << id.toString();
if (effect) {
mEffectIdMap[effect] = id;
for (const auto& name : names) {
auto factory = IFactory::fromBinder(util.connectToService(name));
if (factory) {
if (std::vector<Descriptor::Identity> ids;
factory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids).isOk()) {
for (const auto& id : ids) {
if (type.has_value() && id.type != type.value()) {
continue;
}
result.emplace_back(factory, id);
}
}
}
}
}
void QueryAndCreateEffects(const AudioUuid& type = EffectNullUuid) {
std::vector<Descriptor::Identity> ids;
ASSERT_NE(mEffectFactory, nullptr);
if (type == EffectNullUuid) {
EXPECT_IS_OK(
mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
} else {
EXPECT_IS_OK(mEffectFactory->queryEffects(type, std::nullopt, std::nullopt, &ids));
}
for (const auto& id : ids) {
ASSERT_EQ(id.type, type);
std::shared_ptr<IEffect> effect;
EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
EXPECT_NE(effect, nullptr) << id.toString();
if (effect) {
mEffectIdMap[effect] = id;
}
}
return result;
}
void CreateEffectsAndExpect(
const std::vector<std::pair<Descriptor::Identity, binder_exception_t>>& uuid_status) {
ASSERT_NE(mEffectFactory, nullptr);
for (const auto& it : uuid_status) {
std::shared_ptr<IEffect> effect;
auto status = mEffectFactory->createEffect(it.first.uuid, &effect);
EXPECT_STATUS(it.second, status);
if (effect) {
mEffectIdMap[effect] = it.first;
}
}
}
void DestroyEffectAndExpect(std::shared_ptr<IEffect>& instance, binder_exception_t exception) {
ASSERT_NE(mEffectFactory, nullptr);
auto status = mEffectFactory->destroyEffect(instance);
EXPECT_STATUS(exception, status);
}
void QueryAndCreateAllEffects() {
ASSERT_NE(mEffectFactory, nullptr);
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt,
&mCompleteIds));
for (const auto& id : mCompleteIds) {
std::shared_ptr<IEffect> effect;
EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
EXPECT_NE(effect, nullptr) << id.toString();
mEffectIdMap[effect] = id;
}
}
void DestroyEffects(const binder_exception_t expected = EX_NONE, const int remaining = 0) {
ASSERT_NE(mEffectFactory, nullptr);
for (auto it = mEffectIdMap.begin(); it != mEffectIdMap.end();) {
auto erased = it++;
auto status = mEffectFactory->destroyEffect(erased->first);
EXPECT_STATUS(expected, status);
if (status.isOk()) {
mEffectIdMap.erase(erased);
}
}
EXPECT_EQ((unsigned int)remaining, mEffectIdMap.size());
}
std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
return mCompleteIds;
}
const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() const {
return mEffectIdMap;
}
void ClearEffectMap() { mEffectIdMap.clear(); }
private:
std::shared_ptr<IFactory> mEffectFactory;
std::string mServiceName;
AudioHalBinderServiceUtil binderUtil;
std::vector<Descriptor::Identity> mIds;
std::vector<Descriptor::Identity> mCompleteIds;
std::vector<Processing> mProcesses;
std::map<std::shared_ptr<IEffect>, Descriptor::Identity> mEffectIdMap;
};

View File

@@ -16,6 +16,7 @@
#pragma once
#include <algorithm>
#include <memory>
#include <string>
#include <unordered_map>
@@ -24,7 +25,6 @@
#include <aidl/android/hardware/audio/effect/IEffect.h>
#include <aidl/android/hardware/audio/effect/IFactory.h>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <android/binder_auto_utils.h>
#include <fmq/AidlMessageQueue.h>
@@ -35,275 +35,139 @@
using namespace android;
using aidl::android::hardware::audio::effect::CommandId;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EffectNullUuid;
using aidl::android::hardware::audio::effect::EffectZeroUuid;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::Parameter;
using aidl::android::hardware::audio::effect::State;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioDeviceType;
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;
const AudioFormatDescription DefaultFormat = {
const AudioFormatDescription kDefaultFormatDescription = {
.type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
typedef ::android::AidlMessageQueue<IEffect::Status,
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
StatusMQ;
typedef ::android::AidlMessageQueue<float,
::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
DataMQ;
class EffectHelper {
public:
explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
mFactoryHelper.ConnectToFactoryService();
static void create(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect>& effect,
Descriptor::Identity id, binder_status_t status = EX_NONE) {
ASSERT_NE(factory, nullptr);
EXPECT_STATUS(status, factory->createEffect(id.uuid, &effect));
if (status == EX_NONE) {
ASSERT_NE(effect, nullptr) << id.uuid.toString();
}
}
void OpenEffects(const AudioUuid& type = EffectNullUuid) {
auto open = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
IEffect::OpenEffectReturn ret;
EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
EffectParam params;
params.statusMQ = std::make_unique<StatusMQ>(ret.statusMQ);
params.inputMQ = std::make_unique<DataMQ>(ret.inputDataMQ);
params.outputMQ = std::make_unique<DataMQ>(ret.outputDataMQ);
mEffectParams.push_back(std::move(params));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(open, type));
static void destroy(std::shared_ptr<IFactory> factory, std::shared_ptr<IEffect> effect,
binder_status_t status = EX_NONE) {
ASSERT_NE(factory, nullptr);
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, factory->destroyEffect(effect));
}
void CloseEffects(const binder_status_t status = EX_NONE) {
auto close = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
static void open(std::shared_ptr<IEffect> effect, const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
IEffect::OpenEffectReturn* ret, binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->open(common, specific, ret));
}
static void open(std::shared_ptr<IEffect> effect, int session = 0,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
Parameter::Common common = EffectHelper::createParamCommon(session);
IEffect::OpenEffectReturn ret;
open(effect, common, std::nullopt /* specific */, &ret, status);
}
static void close(std::shared_ptr<IEffect> effect, binder_status_t status = EX_NONE) {
if (effect) {
EXPECT_STATUS(status, effect->close());
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
}
void CreateEffects(const int n = 1) {
for (int i = 0; i < n; i++) {
ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects());
}
}
void CreateEffectsWithUUID(const AudioUuid& type = EffectNullUuid) {
ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateEffects(type));
static void getDescriptor(std::shared_ptr<IEffect> effect, Descriptor& desc,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->getDescriptor(&desc));
}
void QueryEffects() { ASSERT_NO_FATAL_FAILURE(mFactoryHelper.QueryAndCreateAllEffects()); }
void DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
mEffectDescriptors.clear();
static void expectState(std::shared_ptr<IEffect> effect, State expectState,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
State state;
EXPECT_STATUS(status, effect->getState(&state));
EXPECT_EQ(expectState, state);
}
void GetEffectDescriptors() {
auto get = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Descriptor desc;
EXPECT_IS_OK(effect->getDescriptor(&desc));
mEffectDescriptors.push_back(std::move(desc));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
static void command(std::shared_ptr<IEffect> effect, CommandId command,
binder_status_t status = EX_NONE) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->command(command));
}
void CommandEffects(CommandId command) {
auto close = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
EXPECT_IS_OK(effect->command(command));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
static void allocateInputData(const Parameter::Common common, std::unique_ptr<DataMQ>& mq,
std::vector<float>& buffer) {
ASSERT_NE(mq, nullptr);
auto frameSize = android::hardware::audio::common::getFrameSizeInBytes(
common.input.base.format, common.input.base.channelMask);
const size_t floatsToWrite = mq->availableToWrite();
EXPECT_NE(0UL, floatsToWrite);
EXPECT_EQ(frameSize * common.input.frameCount, floatsToWrite * sizeof(float));
buffer.resize(floatsToWrite);
std::fill(buffer.begin(), buffer.end(), 0x5a);
}
void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
EXPECT_STATUS(status, effect->command(command));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
static void writeToFmq(std::unique_ptr<DataMQ>& mq, const std::vector<float>& buffer) {
const size_t available = mq->availableToWrite();
EXPECT_NE(0Ul, available);
auto bufferFloats = buffer.size();
auto floatsToWrite = std::min(available, bufferFloats);
EXPECT_TRUE(mq->write(buffer.data(), floatsToWrite));
}
void ExpectState(State expected) {
auto get = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
State state = State::INIT;
EXPECT_IS_OK(effect->getState(&state));
EXPECT_EQ(expected, state);
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
}
void SetParameter() {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Parameter param;
param.set<Parameter::common>(mCommon);
EXPECT_IS_OK(effect->setParameter(param));
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
}
void VerifyParameters() {
auto func = [&](const std::shared_ptr<IEffect>& effect) {
ASSERT_NE(effect, nullptr);
Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
paramCommonExpect.set<Parameter::common>(mCommon);
EXPECT_IS_OK(effect->getParameter(id, &paramCommonGet));
EXPECT_EQ(paramCommonExpect, paramCommonGet)
<< paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
}
void QueryEffects(const std::optional<AudioUuid>& in_type,
const std::optional<AudioUuid>& in_instance,
const std::optional<AudioUuid>& in_proxy,
std::vector<Descriptor::Identity>* _aidl_return) {
mFactoryHelper.QueryEffects(in_type, in_instance, in_proxy, _aidl_return);
}
template <typename Functor>
void ForEachEffect(Functor functor, const std::optional<AudioUuid>& type = EffectNullUuid) {
auto effectMap = mFactoryHelper.GetEffectMap();
for (const auto& it : effectMap) {
SCOPED_TRACE(it.second.toString());
if (type != EffectNullUuid && it.second.type != type) continue;
functor(it.first);
static void readFromFmq(std::unique_ptr<StatusMQ>& statusMq, size_t statusNum,
std::unique_ptr<DataMQ>& dataMq, size_t expectFloats,
std::vector<float>& buffer) {
IEffect::Status status{};
EXPECT_TRUE(statusMq->readBlocking(&status, statusNum));
EXPECT_EQ(STATUS_OK, status.status);
if (statusNum != 0) {
EXPECT_EQ(expectFloats, (unsigned)status.fmqProduced);
EXPECT_EQ(expectFloats, dataMq->availableToRead());
if (expectFloats != 0) {
EXPECT_TRUE(dataMq->read(buffer.data(), expectFloats));
}
}
}
static 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;
template <typename Functor>
void ForEachDescriptor(Functor functor) {
for (size_t i = 0; i < mEffectDescriptors.size(); i++) {
SCOPED_TRACE(mEffectDescriptors[i].toString());
functor(i, mEffectDescriptors[i]);
}
}
static const size_t mWriteMQBytes = 0x400;
enum class IO : char { INPUT = 0, OUTPUT = 1, INOUT = 2 };
void initParamCommonFormat(IO io = IO::INOUT,
const AudioFormatDescription& format = DefaultFormat) {
if (io == IO::INPUT || io == IO::INOUT) {
mCommon.input.base.format = format;
}
if (io == IO::OUTPUT || io == IO::INOUT) {
mCommon.output.base.format = format;
}
}
void initParamCommonSampleRate(IO io = IO::INOUT, const int& sampleRate = 48000) {
if (io == IO::INPUT || io == IO::INOUT) {
mCommon.input.base.sampleRate = sampleRate;
}
if (io == IO::OUTPUT || io == IO::INOUT) {
mCommon.output.base.sampleRate = sampleRate;
}
}
void initParamCommonFrameCount(IO io = IO::INOUT, const long& frameCount = 48000) {
if (io == IO::INPUT || io == IO::INOUT) {
mCommon.input.frameCount = frameCount;
}
if (io == IO::OUTPUT || io == IO::INOUT) {
mCommon.output.frameCount = frameCount;
}
}
void initParamCommon(int session = 0, int ioHandle = -1, int iSampleRate = 48000,
int oSampleRate = 48000, long iFrameCount = 0x100,
long oFrameCount = 0x100) {
mCommon.session = session;
mCommon.ioHandle = ioHandle;
auto& input = mCommon.input;
auto& output = mCommon.output;
auto& input = common.input;
auto& output = common.output;
input.base.sampleRate = iSampleRate;
input.base.channelMask = mInputChannelLayout;
input.base.channelMask = inputChannelLayout;
input.base.format = kDefaultFormatDescription;
input.frameCount = iFrameCount;
input.base.format = DefaultFormat;
output.base.sampleRate = oSampleRate;
output.base.channelMask = mOutputChannelLayout;
output.base.format = DefaultFormat;
output.base.channelMask = outputChannelLayout;
output.base.format = kDefaultFormatDescription;
output.frameCount = oFrameCount;
output.base.format = DefaultFormat;
inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
input.base.format, input.base.channelMask);
outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
output.base.format, output.base.channelMask);
return common;
}
void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
// usually this function only call once.
void PrepareInputData(size_t bytes = mWriteMQBytes) {
size_t maxInputBytes = mWriteMQBytes;
for (auto& it : mEffectParams) {
auto& mq = it.inputMQ;
EXPECT_NE(nullptr, mq);
EXPECT_TRUE(mq->isValid());
const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
EXPECT_NE(0UL, bytesToWrite);
EXPECT_TRUE(bytes <= bytesToWrite);
maxInputBytes = std::max(maxInputBytes, bytesToWrite);
}
mInputBuffer.resize(maxInputBytes / sizeof(float));
std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
}
void writeToFmq(size_t bytes = mWriteMQBytes) {
for (auto& it : mEffectParams) {
auto& mq = it.inputMQ;
EXPECT_NE(nullptr, mq);
const size_t bytesToWrite = mq->availableToWrite() * sizeof(float);
EXPECT_NE(0Ul, bytesToWrite);
EXPECT_TRUE(bytes <= bytesToWrite);
EXPECT_TRUE(mq->write(mInputBuffer.data(), bytes / sizeof(float)));
}
}
void readFromFmq(size_t expectBytes = mWriteMQBytes) {
for (auto& it : mEffectParams) {
IEffect::Status status{};
auto& statusMq = it.statusMQ;
EXPECT_NE(nullptr, statusMq);
EXPECT_TRUE(statusMq->readBlocking(&status, 1));
EXPECT_EQ(STATUS_OK, status.status);
EXPECT_EQ(expectBytes, (unsigned)status.fmqProduced * sizeof(float));
auto& outputMq = it.outputMQ;
EXPECT_NE(nullptr, outputMq);
EXPECT_EQ(expectBytes, outputMq->availableToRead() * sizeof(float));
}
}
void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() const {
return mFactoryHelper.GetCompleteEffectIdList();
}
const std::vector<Descriptor>& getDescriptorVec() const { return mEffectDescriptors; }
private:
EffectFactoryHelper mFactoryHelper;
AudioChannelLayout mInputChannelLayout =
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
AudioChannelLayout::LAYOUT_STEREO);
AudioChannelLayout mOutputChannelLayout =
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
AudioChannelLayout::LAYOUT_STEREO);
Parameter::Common mCommon;
std::optional<Parameter::Specific> mSpecific = std::nullopt;
size_t inputFrameSize, outputFrameSize;
std::vector<float> mInputBuffer; // reuse same buffer for all effects testing
typedef ::android::AidlMessageQueue<
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
StatusMQ;
@@ -317,6 +181,4 @@ class EffectHelper {
std::unique_ptr<DataMQ> inputMQ;
std::unique_ptr<DataMQ> outputMQ;
};
std::vector<EffectParam> mEffectParams;
std::vector<Descriptor> mEffectDescriptors;
};

View File

@@ -15,6 +15,7 @@
*/
#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -37,23 +38,81 @@
using namespace android;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EffectNullUuid;
using aidl::android::hardware::audio::effect::EffectZeroUuid;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kEffectNullUuid;
using aidl::android::hardware::audio::effect::kEffectZeroUuid;
using aidl::android::hardware::audio::effect::Processing;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioStreamType;
using aidl::android::media::audio::common::AudioUuid;
/// Effect factory testing.
class EffectFactoryTest : public testing::TestWithParam<std::string> {
public:
void SetUp() override { ASSERT_NO_FATAL_FAILURE(mFactory.ConnectToFactoryService()); }
void SetUp() override {
mFactoryHelper = std::make_unique<EffectFactoryHelper>(GetParam());
connectAndGetFactory();
}
void TearDown() override { mFactory.DestroyEffects(); }
void TearDown() override {
for (auto& effect : mEffects) {
const auto status = mEffectFactory->destroyEffect(effect);
EXPECT_STATUS(EX_NONE, status);
}
}
EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
std::unique_ptr<EffectFactoryHelper> mFactoryHelper;
std::shared_ptr<IFactory> mEffectFactory;
std::vector<std::shared_ptr<IEffect>> mEffects;
const Descriptor::Identity kNullDesc = {.uuid = kEffectNullUuid};
const Descriptor::Identity kZeroDesc = {.uuid = kEffectZeroUuid};
const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid};
const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid};
template <typename Functor>
void ForEachId(const std::vector<Descriptor::Identity> ids, Functor functor) {
for (const auto& id : ids) {
SCOPED_TRACE(id.toString());
functor(id);
}
}
template <typename Functor>
void ForEachEffect(std::vector<std::shared_ptr<IEffect>> effects, Functor functor) {
for (auto& effect : effects) {
functor(effect);
}
}
std::vector<std::shared_ptr<IEffect>> createWithIds(
const std::vector<Descriptor::Identity> ids,
const binder_status_t expectStatus = EX_NONE) {
std::vector<std::shared_ptr<IEffect>> effects;
for (const auto& id : ids) {
std::shared_ptr<IEffect> effect;
EXPECT_STATUS(expectStatus, mEffectFactory->createEffect(id.uuid, &effect));
if (expectStatus == EX_NONE) {
EXPECT_NE(effect, nullptr) << " null effect with uuid: " << id.uuid.toString();
effects.push_back(std::move(effect));
}
}
return effects;
}
void destroyEffects(std::vector<std::shared_ptr<IEffect>> effects,
const binder_status_t expectStatus = EX_NONE) {
for (const auto& effect : effects) {
EXPECT_STATUS(expectStatus, mEffectFactory->destroyEffect(effect));
}
}
void creatAndDestroyIds(const std::vector<Descriptor::Identity> ids) {
for (const auto& id : ids) {
auto effects = createWithIds({id});
ASSERT_NO_FATAL_FAILURE(destroyEffects(effects));
}
}
void connectAndGetFactory() {
ASSERT_NO_FATAL_FAILURE(mFactoryHelper->ConnectToFactoryService());
mEffectFactory = mFactoryHelper->GetFactory();
ASSERT_NE(mEffectFactory, nullptr);
}
};
TEST_P(EffectFactoryTest, SetupAndTearDown) {
@@ -61,165 +120,160 @@ TEST_P(EffectFactoryTest, SetupAndTearDown) {
}
TEST_P(EffectFactoryTest, CanBeRestarted) {
ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
}
TEST_P(EffectFactoryTest, QueriedDescriptorList) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
EXPECT_NE(descriptors.size(), 0UL);
}
/**
* @brief Check at least support list of effect must be supported by aosp:
* https://developer.android.com/reference/android/media/audiofx/AudioEffect
*/
TEST_P(EffectFactoryTest, ExpectAllAospEffectTypes) {
std::vector<Descriptor::Identity> ids;
std::set<AudioUuid> typeUuidSet(
{aidl::android::hardware::audio::effect::kBassBoostTypeUUID,
aidl::android::hardware::audio::effect::kEqualizerTypeUUID,
aidl::android::hardware::audio::effect::kEnvReverbTypeUUID,
aidl::android::hardware::audio::effect::kPresetReverbTypeUUID,
aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID,
aidl::android::hardware::audio::effect::kHapticGeneratorTypeUUID,
aidl::android::hardware::audio::effect::kVirtualizerTypeUUID});
TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
// TODO: Factory eventually need to return the full list of MUST supported AOSP effects.
for (auto& desc : descriptors) {
EXPECT_NE(desc.type, EffectNullUuid);
EXPECT_NE(desc.uuid, EffectNullUuid);
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_TRUE(ids.size() >= typeUuidSet.size());
for (const auto& id : ids) {
typeUuidSet.erase(id.type);
}
std::string msg = " missing type UUID:\n";
for (const auto& uuid : typeUuidSet) {
msg += (uuid.toString() + "\n");
}
SCOPED_TRACE(msg);
EXPECT_EQ(0UL, typeUuidSet.size());
}
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(EffectNullUuid, std::nullopt, std::nullopt, &descriptors);
EXPECT_EQ(descriptors.size(), 0UL);
TEST_P(EffectFactoryTest, QueryNullTypeUuid) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(kEffectNullUuid, std::nullopt, std::nullopt, &ids));
EXPECT_EQ(ids.size(), 0UL);
}
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, EffectNullUuid, std::nullopt, &descriptors);
EXPECT_EQ(descriptors.size(), 0UL);
TEST_P(EffectFactoryTest, QueriedNullImplUuid) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, kEffectNullUuid, std::nullopt, &ids));
EXPECT_EQ(ids.size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateAndDestroyOnce) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
auto& effectMap = mFactory.GetEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
TEST_P(EffectFactoryTest, QueriedNullProxyUuid) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, kEffectNullUuid, &ids));
EXPECT_EQ(ids.size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
// create all effects, and then destroy them all together
TEST_P(EffectFactoryTest, CreateAndDestroyEffects) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
auto& effectMap = mFactory.GetEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
// Create and destroy again
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
std::vector<std::shared_ptr<IEffect>> effects;
effects = createWithIds(ids);
EXPECT_EQ(ids.size(), effects.size());
destroyEffects(effects);
}
TEST_P(EffectFactoryTest, CreateMultipleInstanceOfSameEffect) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
auto& effectMap = mFactory.GetEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
// Create effect instances of same implementation
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), 2 * numIds);
std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
EXPECT_EQ(ids.size(), effects.size());
std::vector<std::shared_ptr<IEffect>> effects2 = createWithIds(ids);
EXPECT_EQ(ids.size(), effects2.size());
std::vector<std::shared_ptr<IEffect>> effects3 = createWithIds(ids);
EXPECT_EQ(ids.size(), effects3.size());
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), 3 * numIds);
destroyEffects(effects);
destroyEffects(effects2);
destroyEffects(effects3);
}
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
// create and destroy each effect one by one
TEST_P(EffectFactoryTest, CreateAndDestroyEffectsOneByOne) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
creatAndDestroyIds(ids);
}
// for each effect: repeat 3 times create and destroy
TEST_P(EffectFactoryTest, CreateAndDestroyRepeat) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
creatAndDestroyIds(ids);
creatAndDestroyIds(ids);
creatAndDestroyIds(ids);
}
// Expect EX_ILLEGAL_ARGUMENT when create with invalid UUID.
TEST_P(EffectFactoryTest, CreateWithInvalidUuid) {
std::vector<std::pair<Descriptor::Identity, binder_status_t>> descriptors;
descriptors.push_back(std::make_pair(nullDesc, EX_ILLEGAL_ARGUMENT));
descriptors.push_back(std::make_pair(zeroDesc, EX_ILLEGAL_ARGUMENT));
auto& effectMap = mFactory.GetEffectMap();
mFactory.CreateEffectsAndExpect(descriptors);
EXPECT_EQ(effectMap.size(), 0UL);
std::vector<Descriptor::Identity> ids = {kNullDesc, kZeroDesc};
auto effects = createWithIds(ids, EX_ILLEGAL_ARGUMENT);
EXPECT_EQ(effects.size(), 0UL);
}
// Expect EX_ILLEGAL_ARGUMENT when destroy null interface.
TEST_P(EffectFactoryTest, DestroyWithInvalidInterface) {
std::shared_ptr<IEffect> spDummyEffect(nullptr);
mFactory.DestroyEffectAndExpect(spDummyEffect, EX_ILLEGAL_ARGUMENT);
destroyEffects({spDummyEffect}, EX_ILLEGAL_ARGUMENT);
}
TEST_P(EffectFactoryTest, CreateAndRemoveReference) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
// Same descriptor ID should work after service restart.
TEST_P(EffectFactoryTest, CreateDestroyWithRestart) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
creatAndDestroyIds(ids);
auto& effectMap = mFactory.GetEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
// remove all reference
mFactory.ClearEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactoryHelper->RestartFactoryService();
connectAndGetFactory();
creatAndDestroyIds(ids);
}
TEST_P(EffectFactoryTest, CreateRemoveReferenceAndCreateDestroy) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
EXPECT_NE(numIds, 0UL);
// Effect handle invalid after restart.
TEST_P(EffectFactoryTest, EffectInvalidAfterRestart) {
std::vector<Descriptor::Identity> ids;
EXPECT_IS_OK(mEffectFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &ids));
EXPECT_NE(ids.size(), 0UL);
std::vector<std::shared_ptr<IEffect>> effects = createWithIds(ids);
auto& effectMap = mFactory.GetEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
// remove all reference
mFactory.ClearEffectMap();
EXPECT_EQ(effectMap.size(), 0UL);
ASSERT_NO_FATAL_FAILURE(mFactoryHelper->RestartFactoryService());
// Create and destroy again
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
}
TEST_P(EffectFactoryTest, CreateRestartAndCreateDestroy) {
std::vector<Descriptor::Identity> descriptors;
mFactory.QueryEffects(std::nullopt, std::nullopt, std::nullopt, &descriptors);
auto numIds = mFactory.GetEffectIds().size();
auto& effectMap = mFactory.GetEffectMap();
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
ASSERT_NO_FATAL_FAILURE(mFactory.RestartFactoryService());
mFactory.CreateEffects();
EXPECT_EQ(effectMap.size(), numIds);
mFactory.DestroyEffects();
EXPECT_EQ(effectMap.size(), 0UL);
connectAndGetFactory();
destroyEffects(effects, EX_ILLEGAL_ARGUMENT);
}
// expect no error with the queryProcessing interface, but don't check number of processing
TEST_P(EffectFactoryTest, QueryProcess) {
std::vector<Processing> processing;
mFactory.QueryProcessing(std::nullopt, &processing);
// TODO: verify the number of process in example implementation after audio_effects.xml migrated
EXPECT_IS_OK(mEffectFactory->queryProcessing(std::nullopt, &processing));
Processing::Type streamType =
Processing::Type::make<Processing::Type::streamType>(AudioStreamType::SYSTEM);
std::vector<Processing> processingFilteredByStream;
EXPECT_IS_OK(mEffectFactory->queryProcessing(streamType, &processingFilteredByStream));
Processing::Type source =
Processing::Type::make<Processing::Type::source>(AudioSource::DEFAULT);
std::vector<Processing> processingFilteredBySource;
EXPECT_IS_OK(mEffectFactory->queryProcessing(source, &processingFilteredBySource));
EXPECT_TRUE(processing.size() >= processingFilteredByStream.size());
EXPECT_TRUE(processing.size() >= processingFilteredBySource.size());
}
INSTANTIATE_TEST_SUITE_P(EffectFactoryTest, EffectFactoryTest,

View File

@@ -16,26 +16,24 @@
#define LOG_TAG "VtsHalAudioEffectTargetTest"
#include <chrono>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <Utils.h>
#include <aidl/Gtest.h>
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/effect/IEffect.h>
#include <aidl/android/hardware/audio/effect/IFactory.h>
#include <android-base/logging.h>
#include <android-base/properties.h>
#include <android/binder_interface_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
#include <Utils.h>
#include <aidl/android/hardware/audio/effect/IEffect.h>
#include <aidl/android/hardware/audio/effect/IFactory.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include <fmq/AidlMessageQueue.h>
#include "AudioHalBinderServiceUtil.h"
#include "EffectFactoryHelper.h"
#include "EffectHelper.h"
#include "TestUtils.h"
@@ -49,309 +47,725 @@ 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::AudioDeviceType;
class AudioEffectTest : public testing::TestWithParam<std::string>, public EffectHelper {
enum ParamName { PARAM_INSTANCE_NAME };
using EffectTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>>;
class AudioEffectTest : public testing::TestWithParam<EffectTestParam>, public EffectHelper {
public:
AudioEffectTest() : EffectHelper(GetParam()) {}
AudioEffectTest() { std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam()); }
void SetUp() override {
CreateEffects();
initParamCommonFormat();
initParamCommon();
}
void SetUp() override {}
void TearDown() override {}
void TearDown() override {
CloseEffects();
DestroyEffects();
}
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
Descriptor::Identity mIdentity;
};
TEST_P(AudioEffectTest, OpenEffectTest) {
OpenEffects();
TEST_P(AudioEffectTest, SetupAndTearDown) {
// Intentionally empty test body.
}
TEST_P(AudioEffectTest, OpenAndCloseEffect) {
OpenEffects();
CloseEffects();
TEST_P(AudioEffectTest, CreateAndDestroy) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
TEST_P(AudioEffectTest, CloseUnopenedEffectTest) {
CloseEffects();
TEST_P(AudioEffectTest, OpenAndClose) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
TEST_P(AudioEffectTest, DoubleOpenCloseEffects) {
OpenEffects();
CloseEffects();
OpenEffects();
CloseEffects();
OpenEffects();
OpenEffects();
CloseEffects();
OpenEffects();
CloseEffects();
CloseEffects();
TEST_P(AudioEffectTest, CloseUnopenedEffect) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
TEST_P(AudioEffectTest, GetDescriptors) {
GetEffectDescriptors();
TEST_P(AudioEffectTest, DoubleOpenAndClose) {
std::shared_ptr<IEffect> effect1, effect2;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect1));
ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
ASSERT_NO_FATAL_FAILURE(close(effect1));
ASSERT_NO_FATAL_FAILURE(close(effect2));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
}
TEST_P(AudioEffectTest, DescriptorIdExistAndUnique) {
auto checker = [&](const std::shared_ptr<IEffect>& effect) {
Descriptor desc;
std::vector<Descriptor::Identity> idList;
EXPECT_IS_OK(effect->getDescriptor(&desc));
QueryEffects(desc.common.id.type, desc.common.id.uuid, desc.common.id.proxy, &idList);
// Must have at least one instance.
EXPECT_NE(idList.size(), 0UL);
};
ForEachEffect(checker);
TEST_P(AudioEffectTest, TripleOpenAndClose) {
std::shared_ptr<IEffect> effect1, effect2, effect3;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect3, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect1));
ASSERT_NO_FATAL_FAILURE(open(effect2, 1 /* session */));
ASSERT_NO_FATAL_FAILURE(open(effect3, 2 /* session */));
ASSERT_NO_FATAL_FAILURE(close(effect1));
ASSERT_NO_FATAL_FAILURE(close(effect2));
ASSERT_NO_FATAL_FAILURE(close(effect3));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect3));
}
// Check unique with a set
auto stringHash = [](const Descriptor::Identity& id) {
return std::hash<std::string>()(id.toString());
};
auto vec = GetCompleteEffectIdList();
std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
for (auto it : vec) {
EXPECT_EQ(idSet.count(it), 0UL) << it.toString();
idSet.insert(it);
TEST_P(AudioEffectTest, GetDescritorBeforeOpen) {
std::shared_ptr<IEffect> effect;
Descriptor desc;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
EXPECT_EQ(mIdentity.toString(), desc.common.id.toString());
EXPECT_NE("", desc.common.name);
EXPECT_NE("", desc.common.implementor);
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
TEST_P(AudioEffectTest, GetDescritorAfterOpen) {
std::shared_ptr<IEffect> effect;
Descriptor beforeOpen, afterOpen, afterClose;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, beforeOpen));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterOpen));
EXPECT_EQ(beforeOpen.toString(), afterOpen.toString()) << "\n"
<< beforeOpen.toString() << "\n"
<< afterOpen.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, afterClose));
EXPECT_EQ(beforeOpen.toString(), afterClose.toString()) << "\n"
<< beforeOpen.toString() << "\n"
<< afterClose.toString();
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
TEST_P(AudioEffectTest, DescriptorExistAndUnique) {
std::shared_ptr<IEffect> effect;
Descriptor desc;
auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor);
std::set<Descriptor::Identity> idSet;
for (const auto& it : descList) {
auto& id = it.second;
EXPECT_EQ(0ul, idSet.count(id));
idSet.insert(id);
}
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(getDescriptor(effect, desc));
EXPECT_EQ(1ul, idSet.count(desc.common.id));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
/// State testing.
// An effect instance is in INIT state by default after it was created.
TEST_P(AudioEffectTest, InitStateAfterCreation) {
ExpectState(State::INIT);
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance transfer to INIT state after it was open successfully with IEffect.open().
// An effect instance transfer to IDLE state after IEffect.ASSERT_NO_FATAL_FAILURE(open().
TEST_P(AudioEffectTest, IdleStateAfterOpen) {
OpenEffects();
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance is in PROCESSING state after it receive an START command.
TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
TEST_P(AudioEffectTest, IdleStateAfterStop) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
TEST_P(AudioEffectTest, IdleStateAfterReset) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::RESET);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance transfer to INIT if instance receive a close() call.
// An effect instance transfer to INIT after IEffect.ASSERT_NO_FATAL_FAILURE(close().
TEST_P(AudioEffectTest, InitStateAfterClose) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
ExpectState(State::INIT);
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// An effect instance shouldn't accept any command before open.
TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
ExpectState(State::INIT);
CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE);
CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE);
CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE);
ExpectState(State::INIT);
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START, EX_ILLEGAL_STATE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP, EX_ILLEGAL_STATE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET, EX_ILLEGAL_STATE));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// No-op when receive STOP command in IDLE state.
TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
ExpectState(State::INIT);
OpenEffects();
ExpectState(State::IDLE);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// No-op when receive STOP command in IDLE state.
// No-op when receive RESET command in IDLE state.
TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
ExpectState(State::INIT);
OpenEffects();
ExpectState(State::IDLE);
CommandEffects(CommandId::RESET);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Repeat START and STOP command.
TEST_P(AudioEffectTest, RepeatStartAndStop) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Repeat START and RESET command.
TEST_P(AudioEffectTest, RepeatStartAndReset) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::RESET);
ExpectState(State::IDLE);
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::RESET);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Repeat START and STOP command, try to close at PROCESSING state.
// Try to close an effect instance at PROCESSING state.
TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
OpenEffects();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
CloseEffects(EX_ILLEGAL_STATE);
// cleanup
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(close(effect, EX_ILLEGAL_STATE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
TEST_P(AudioEffectTest, DestroyOpenEffects) {
// cleanup all effects.
CloseEffects();
DestroyEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
// open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
CreateEffects();
OpenEffects();
auto vec = GetCompleteEffectIdList();
DestroyEffects(EX_ILLEGAL_STATE, vec.size());
CloseEffects();
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
}
// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
TEST_P(AudioEffectTest, DestroyProcessingEffects) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect, EX_ILLEGAL_STATE));
}
TEST_P(AudioEffectTest, NormalSequenceStates) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::INIT));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
/// Parameter testing.
// Verify parameters pass in open can be successfully get.
TEST_P(AudioEffectTest, VerifyParametersAfterOpen) {
OpenEffects();
VerifyParameters();
CloseEffects();
TEST_P(AudioEffectTest, VerifyCommonParametersAfterOpen) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon();
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
Parameter get = Parameter(), expect = Parameter();
expect.set<Parameter::common>(common);
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(expect, get) << expect.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Verify parameters pass in set can be successfully get.
TEST_P(AudioEffectTest, SetAndGetParameter) {
OpenEffects();
VerifyParameters();
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
44100 /* oSampleRate */);
SetParameter();
VerifyParameters();
CloseEffects();
TEST_P(AudioEffectTest, SetAndGetCommonParameter) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
EXPECT_IS_OK(effect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Verify parameters pass in set can be successfully get.
// Verify parameters set and get in PROCESSING state.
TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
OpenEffects();
VerifyParameters();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
44100 /* oSampleRate */);
SetParameter();
VerifyParameters();
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
EXPECT_IS_OK(effect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Parameters kept after reset.
TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
OpenEffects();
VerifyParameters();
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
44100 /* oSampleRate */);
SetParameter();
VerifyParameters();
CommandEffects(CommandId::RESET);
ExpectState(State::IDLE);
VerifyParameters();
CloseEffects();
// Verify parameters set and get in IDLE state.
TEST_P(AudioEffectTest, SetAndGetParameterInIdle) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
EXPECT_IS_OK(effect->setParameter(set));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// TODO: need a way to support setting different sessionId to different effect instances
#if 0
// Multiple instances of same implementation running.
TEST_P(AudioEffectTest, MultipleInstancesRunningWithDiffSessionId) {
CreateEffects();
ExpectState(State::INIT);
OpenEffects();
ExpectState(State::IDLE);
CommandEffects(CommandId::START);
ExpectState(State::PROCESSING);
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
44100 /* oSampleRate */);
SetParameter();
VerifyParameters();
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
VerifyParameters();
CloseEffects();
}
#endif
// Verify Parameters kept after stop.
TEST_P(AudioEffectTest, SetAndGetParameterAfterStop) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
// Send data to effects and expect it to consume by check statusMQ.
TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
OpenEffects();
PrepareInputData(mWriteMQBytes);
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
EXPECT_IS_OK(effect->setParameter(set));
CommandEffects(CommandId::START);
writeToFmq(mWriteMQBytes);
readFromFmq(mWriteMQBytes);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ExpectState(State::PROCESSING);
CommandEffects(CommandId::STOP);
// cleanup
CommandEffects(CommandId::STOP);
ExpectState(State::IDLE);
CloseEffects();
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest,
testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
android::PrintInstanceNameToString);
// Verify Parameters kept after reset.
TEST_P(AudioEffectTest, SetAndGetParameterAfterReset) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
ASSERT_NO_FATAL_FAILURE(open(effect));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */);
Parameter get = Parameter(), set = Parameter();
set.set<Parameter::common>(common);
EXPECT_IS_OK(effect->setParameter(set));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::RESET));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
Parameter::Id id;
id.set<Parameter::Id::commonTag>(Parameter::common);
EXPECT_IS_OK(effect->getParameter(id, &get));
EXPECT_EQ(set, get) << set.toString() << " vs " << get.toString();
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
/// Data processing test
// Send data to effects and expect it to be consumed by checking statusMQ.
TEST_P(AudioEffectTest, ConsumeDataInProcessingState) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data to effects and expect it to be consumed after effect restart.
TEST_P(AudioEffectTest, ConsumeDataAfterRestart) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data to IDLE effects and expect it to be consumed after effect start.
TEST_P(AudioEffectTest, SendDataAtIdleAndConsumeDataInProcessing) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data multiple times.
TEST_P(AudioEffectTest, ProcessDataMultipleTimes) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
// expect no status and data after consume
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
// expect no status and data after consume
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data to IDLE state effects and expect it not be consumed.
TEST_P(AudioEffectTest, NotConsumeDataInIdleState) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::PROCESSING));
EffectHelper::readFromFmq(statusMQ, 1, outputMQ, buffer.size(), buffer);
ASSERT_NO_FATAL_FAILURE(command(effect, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data to closed effects and expect it not be consumed.
TEST_P(AudioEffectTest, NotConsumeDataByClosedEffect) {
std::shared_ptr<IEffect> effect;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect, mIdentity));
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(effect, common, std::nullopt /* specific */, &ret, EX_NONE));
ASSERT_NO_FATAL_FAILURE(close(effect));
auto statusMQ = std::make_unique<EffectHelper::StatusMQ>(ret.statusMQ);
auto inputMQ = std::make_unique<EffectHelper::DataMQ>(ret.inputDataMQ);
auto outputMQ = std::make_unique<EffectHelper::DataMQ>(ret.outputDataMQ);
std::vector<float> buffer;
EffectHelper::allocateInputData(common, inputMQ, buffer);
EffectHelper::writeToFmq(inputMQ, buffer);
EffectHelper::readFromFmq(statusMQ, 0, outputMQ, 0, buffer);
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect));
}
// Send data to multiple effects.
TEST_P(AudioEffectTest, ConsumeDataMultipleEffects) {
std::shared_ptr<IEffect> effect1, effect2;
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect1, mIdentity));
ASSERT_NO_FATAL_FAILURE(create(mFactory, effect2, mIdentity));
Parameter::Common common1 = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
Parameter::Common common2 = EffectHelper::createParamCommon(
1 /* session */, 1 /* ioHandle */, 48000 /* iSampleRate */, 48000 /* oSampleRate */,
2 * kInputFrameCount /* iFrameCount */, 2 * kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret1, ret2;
ASSERT_NO_FATAL_FAILURE(open(effect1, common1, std::nullopt /* specific */, &ret1, EX_NONE));
ASSERT_NO_FATAL_FAILURE(open(effect2, common2, std::nullopt /* specific */, &ret2, EX_NONE));
ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::PROCESSING));
ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::START));
ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::PROCESSING));
auto statusMQ1 = std::make_unique<EffectHelper::StatusMQ>(ret1.statusMQ);
auto inputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.inputDataMQ);
auto outputMQ1 = std::make_unique<EffectHelper::DataMQ>(ret1.outputDataMQ);
std::vector<float> buffer1, buffer2;
EffectHelper::allocateInputData(common1, inputMQ1, buffer1);
EffectHelper::writeToFmq(inputMQ1, buffer1);
EffectHelper::readFromFmq(statusMQ1, 1, outputMQ1, buffer1.size(), buffer1);
auto statusMQ2 = std::make_unique<EffectHelper::StatusMQ>(ret2.statusMQ);
auto inputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.inputDataMQ);
auto outputMQ2 = std::make_unique<EffectHelper::DataMQ>(ret2.outputDataMQ);
EffectHelper::allocateInputData(common2, inputMQ2, buffer2);
EffectHelper::writeToFmq(inputMQ2, buffer2);
EffectHelper::readFromFmq(statusMQ2, 1, outputMQ2, buffer2.size(), buffer2);
ASSERT_NO_FATAL_FAILURE(command(effect1, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect1, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect1));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect1));
ASSERT_NO_FATAL_FAILURE(command(effect2, CommandId::STOP));
ASSERT_NO_FATAL_FAILURE(expectState(effect2, State::IDLE));
ASSERT_NO_FATAL_FAILURE(close(effect2));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, effect2));
}
INSTANTIATE_TEST_SUITE_P(
SingleEffectInstanceTest, AudioEffectTest,
::testing::Combine(testing::ValuesIn(
EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor))),
[](const testing::TestParamInfo<AudioEffectTest::ParamType>& info) {
auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::ostringstream address;
address << msSinceEpoch << "_factory_" << instance.first.get();
std::string name = address.str() + "_UUID_timeLow_" +
::android::internal::ToString(instance.second.uuid.timeLow) +
"_timeMid_" +
::android::internal::ToString(instance.second.uuid.timeMid);
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
int main(int argc, char** argv) {

View File

@@ -35,8 +35,6 @@
#include <Utils.h>
#include <aidl/android/hardware/audio/effect/IEffect.h>
#include <aidl/android/hardware/audio/effect/IFactory.h>
#include <aidl/android/media/audio/common/AudioChannelLayout.h>
#include <aidl/android/media/audio/common/AudioDeviceType.h>
#include "AudioHalBinderServiceUtil.h"
#include "EffectHelper.h"
@@ -47,103 +45,126 @@ using namespace android;
using aidl::android::hardware::audio::effect::Capability;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EffectNullUuid;
using aidl::android::hardware::audio::effect::Equalizer;
using aidl::android::hardware::audio::effect::EqualizerTypeUUID;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kEqualizerTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;
/**
* Here we focus on specific parameter checking, general IEffect interfaces testing performed in
* VtsAudioEfectTargetTest.
* Here we focus on specific effect (equalizer) parameter checking, general IEffect interfaces
* testing performed in VtsAudioEfectTargetTest.
*/
enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESET_INDEX, PARAM_BAND_INDEX, PARAM_BAND_LEVEL };
using EqualizerParamTestParam = std::tuple<std::string, int, int, int>;
enum ParamName { PARAM_INSTANCE_NAME, PARAM_BAND_LEVEL };
using EqualizerParamTestParam =
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
/*
Testing parameter range, assuming the parameter supported by effect is in this range.
This range is verified with IEffect.getDescriptor(), for any index supported vts expect EX_NONE
from IEffect.setParameter(), otherwise expect EX_ILLEGAL_ARGUMENT.
*/
constexpr std::pair<int, int> kPresetIndexRange = {-1, 10}; // valid range [0, 9]
constexpr std::pair<int, int> kBandIndexRange = {-1, 5}; // valid range [0, 4]
constexpr std::pair<int, int> kBandLevelRange = {-5, 5}; // needs update with implementation
const std::vector<int> kBandLevels = {0, -10, 10}; // needs update with implementation
class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
public EffectHelper {
class EqualizerTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
public EffectHelper {
public:
EqualizerParamTest()
: EffectHelper(std::get<PARAM_INSTANCE_NAME>(GetParam())),
mParamPresetIndex(std::get<PARAM_PRESET_INDEX>(GetParam())),
mParamBandIndex(std::get<PARAM_BAND_INDEX>(GetParam())),
mParamBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {}
EqualizerTest() : mBandLevel(std::get<PARAM_BAND_LEVEL>(GetParam())) {
std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
}
void SetUp() override {
CreateEffectsWithUUID(EqualizerTypeUUID);
initParamCommonFormat();
initParamCommon();
initParamSpecific();
OpenEffects(EqualizerTypeUUID);
SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx "
<< mParamBandIndex << " level " << mParamBandLevel);
}
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
ASSERT_NE(nullptr, mEffect);
ASSERT_NO_FATAL_FAILURE(setTagRange());
}
void TearDown() override {
CloseEffects();
DestroyEffects();
CleanUp();
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
int mParamPresetIndex = 0;
int mParamBandIndex = 0;
int mParamBandLevel = 0;
std::pair<int, int> setPresetIndexRange(const Equalizer::Capability& cap) const {
const auto [min, max] =
std::minmax_element(cap.presets.begin(), cap.presets.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
return {min->index, max->index};
}
std::pair<int, int> setBandIndexRange(const Equalizer::Capability& cap) const {
const auto [min, max] =
std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
return {min->index, max->index};
}
void setTagRange() {
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
mPresetIndex = setPresetIndexRange(eqCap);
mBandIndex = setBandIndexRange(eqCap);
}
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor::Identity mIdentity;
std::pair<int, int> mPresetIndex;
std::pair<int, int> mBandIndex;
const int mBandLevel;
Descriptor mDesc;
void SetAndGetEqualizerParameters() {
auto functor = [&](const std::shared_ptr<IEffect>& effect) {
for (auto& it : mTags) {
auto& tag = it.first;
auto& eq = it.second;
ASSERT_NE(nullptr, mEffect);
for (auto& it : mTags) {
auto& tag = it.first;
auto& eq = it.second;
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, effect->getDescriptor(&desc));
const bool valid = isTagInRange(it.first, it.second, desc);
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// validate parameter
const bool valid = isTagInRange(it.first, it.second);
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::equalizer>(*eq.get());
expectParam.set<Parameter::specific>(specific);
EXPECT_STATUS(expected, effect->setParameter(expectParam))
<< expectParam.toString();
// set
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::equalizer>(eq);
expectParam.set<Parameter::specific>(specific);
EXPECT_STATUS(expected, mEffect->setParameter(expectParam))
<< expectParam.toString() << "\n"
<< mDesc.toString();
// only get if parameter in range and set success
if (expected == EX_NONE) {
Parameter getParam;
Parameter::Id id;
Equalizer::Id eqId;
eqId.set<Equalizer::Id::commonTag>(tag);
id.set<Parameter::Id::equalizerTag>(eqId);
// if set success, then get should match
EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
EXPECT_TRUE(isEqParameterExpected(expectParam, getParam));
}
// only get if parameter in range and set success
if (expected == EX_NONE) {
Parameter getParam;
Parameter::Id id;
Equalizer::Id eqId;
eqId.set<Equalizer::Id::commonTag>(tag);
id.set<Parameter::Id::equalizerTag>(eqId);
// if set success, then get should match
EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
EXPECT_TRUE(isEqParameterExpected(expectParam, getParam))
<< "\nexpect:" << expectParam.toString()
<< "\ngetParam:" << getParam.toString();
}
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
}
}
bool isEqParameterExpected(const Parameter& expect, const Parameter& target) {
// if parameter same, then for sure matched
// if parameter same, then for sure they are matched
if (expect == target) return true;
// if not, see if target include the expect parameter, and others all default (0).
/*
This is verify the case of client setParameter to a single bandLevel ({3, -1} for
example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
*/
* This is to verify the case of client setParameter to a single bandLevel ({3, -1} for
* example), and return of getParameter must be [{0, 0}, {1, 0}, {2, 0}, {3, -1}, {4, 0}]
*/
EXPECT_EQ(expect.getTag(), Parameter::specific);
EXPECT_EQ(target.getTag(), Parameter::specific);
@@ -160,10 +181,16 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
switch (eqTag) {
case Equalizer::bandLevels: {
auto expectBl = expectEq.get<Equalizer::bandLevels>();
std::sort(expectBl.begin(), expectBl.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
expectBl.erase(std::unique(expectBl.begin(), expectBl.end()), expectBl.end());
auto targetBl = targetEq.get<Equalizer::bandLevels>();
return std::includes(targetBl.begin(), targetBl.end(), expectBl.begin(),
expectBl.end());
}
case Equalizer::preset: {
return expectEq.get<Equalizer::preset>() == targetEq.get<Equalizer::preset>();
}
default:
return false;
}
@@ -173,27 +200,24 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
void addPresetParam(int preset) {
Equalizer eq;
eq.set<Equalizer::preset>(preset);
mTags.push_back({Equalizer::preset, std::make_unique<Equalizer>(std::move(eq))});
mTags.push_back({Equalizer::preset, eq});
}
void addBandLevelsParam(std::vector<Equalizer::BandLevel>& bandLevels) {
Equalizer eq;
eq.set<Equalizer::bandLevels>(bandLevels);
mTags.push_back({Equalizer::bandLevels, std::make_unique<Equalizer>(std::move(eq))});
mTags.push_back({Equalizer::bandLevels, eq});
}
bool isTagInRange(const Equalizer::Tag& tag, const std::unique_ptr<Equalizer>& eq,
const Descriptor& desc) const {
std::cout << "xxx" << toString(tag) << " " << desc.toString();
const Equalizer::Capability& eqCap = desc.capability.get<Capability::equalizer>();
bool isTagInRange(const Equalizer::Tag& tag, const Equalizer& eq) const {
switch (tag) {
case Equalizer::preset: {
int index = eq->get<Equalizer::preset>();
return isPresetIndexInRange(eqCap, index);
int index = eq.get<Equalizer::preset>();
return index >= mPresetIndex.first && index <= mPresetIndex.second;
}
case Equalizer::bandLevels: {
auto& bandLevel = eq->get<Equalizer::bandLevels>();
return isBandIndexInRange(eqCap, bandLevel);
auto& bandLevel = eq.get<Equalizer::bandLevels>();
return isBandInRange(bandLevel);
}
default:
return false;
@@ -201,78 +225,125 @@ class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestPar
return false;
}
bool isPresetIndexInRange(const Equalizer::Capability& cap, int idx) const {
const auto [min, max] =
std::minmax_element(cap.presets.begin(), cap.presets.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
return idx >= min->index && idx <= max->index;
}
bool isBandIndexInRange(const Equalizer::Capability& cap,
const std::vector<Equalizer::BandLevel>& bandLevel) const {
bool isBandInRange(const std::vector<Equalizer::BandLevel>& bandLevel) const {
for (auto& it : bandLevel) {
if (!isBandIndexInRange(cap, it.index)) return false;
if (it.index < mBandIndex.first || it.index > mBandIndex.second) return false;
}
return true;
}
bool isBandIndexInRange(const Equalizer::Capability& cap, int idx) const {
const auto [min, max] =
std::minmax_element(cap.bandFrequencies.begin(), cap.bandFrequencies.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
return idx >= min->index && idx <= max->index;
Parameter::Specific getDefaultParamSpecific() {
Equalizer eq = Equalizer::make<Equalizer::preset>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::equalizer>(eq);
return specific;
}
private:
std::vector<std::pair<Equalizer::Tag, std::unique_ptr<Equalizer>>> mTags;
std::vector<std::pair<Equalizer::Tag, Equalizer>> mTags;
bool validCapabilityTag(Capability& cap) { return cap.getTag() == Capability::equalizer; }
void initParamSpecific() {
Equalizer eq;
eq.set<Equalizer::preset>(0);
Parameter::Specific specific;
specific.set<Parameter::Specific::equalizer>(eq);
setSpecific(specific);
}
void CleanUp() { mTags.clear(); }
};
TEST_P(EqualizerParamTest, SetAndGetPreset) {
EXPECT_NO_FATAL_FAILURE(addPresetParam(mParamPresetIndex));
SetAndGetEqualizerParameters();
TEST_P(EqualizerTest, SetAndGetPresetOutOfLowerBound) {
addPresetParam(mPresetIndex.second - 1);
ASSERT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerParamTest, SetAndGetSingleBand) {
std::vector<Equalizer::BandLevel> bandLevels;
Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
bandLevels.push_back(bandLevel);
EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
SetAndGetEqualizerParameters();
TEST_P(EqualizerTest, SetAndGetPresetOutOfUpperBound) {
addPresetParam(mPresetIndex.second + 1);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetPresetAtLowerBound) {
addPresetParam(mPresetIndex.first);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetPresetAtHigherBound) {
addPresetParam(mPresetIndex.second);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetPresetInBound) {
addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetBandOutOfLowerBound) {
std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first - 1, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetBandOutOfUpperBound) {
std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second + 1, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetBandAtLowerBound) {
std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.first, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetBandAtHigherBound) {
std::vector<Equalizer::BandLevel> bandLevels{{mBandIndex.second, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetBandInBound) {
std::vector<Equalizer::BandLevel> bandLevels{
{(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetMultiBands) {
addPresetParam(mPresetIndex.first);
std::vector<Equalizer::BandLevel> bandLevels{
{mBandIndex.first, mBandLevel},
{mBandIndex.second, mBandLevel},
{(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
addBandLevelsParam(bandLevels);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
TEST_P(EqualizerTest, SetAndGetMultipleParams) {
std::vector<Equalizer::BandLevel> bandLevels{
{(mBandIndex.first + mBandIndex.second) >> 1, mBandLevel}};
addBandLevelsParam(bandLevels);
addPresetParam((mPresetIndex.first + mPresetIndex.second) >> 1);
EXPECT_NO_FATAL_FAILURE(SetAndGetEqualizerParameters());
}
INSTANTIATE_TEST_SUITE_P(
EqualizerTest, EqualizerParamTest,
::testing::Combine(
testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
testing::Range(kPresetIndexRange.first, kPresetIndexRange.second),
testing::Range(kBandIndexRange.first, kBandIndexRange.second),
testing::Range(kBandLevelRange.first, kBandLevelRange.second)),
[](const testing::TestParamInfo<EqualizerParamTest::ParamType>& info) {
std::string instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string presetIdx = std::to_string(std::get<PARAM_PRESET_INDEX>(info.param));
std::string bandIdx = std::to_string(std::get<PARAM_BAND_INDEX>(info.param));
EqualizerTest, EqualizerTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEqualizerTypeUUID)),
testing::ValuesIn(kBandLevels)),
[](const testing::TestParamInfo<EqualizerTest::ParamType>& info) {
auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string bandLevel = std::to_string(std::get<PARAM_BAND_LEVEL>(info.param));
std::string name = instance + "_presetIndex" + presetIdx + "_bandIndex" + bandIdx +
"_bandLevel" + bandLevel;
std::ostringstream address;
address << msSinceEpoch << "_factory_" << instance.first.get();
std::string name = address.str() + "_UUID_timeLow_" +
::android::internal::ToString(instance.second.uuid.timeLow) +
"_timeMid_" +
::android::internal::ToString(instance.second.uuid.timeMid) +
"_bandLevel_" + bandLevel;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerParamTest);
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);

View File

@@ -27,8 +27,8 @@ using aidl::android::hardware::audio::effect::Capability;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kLoudnessEnhancerTypeUUID;
using aidl::android::hardware::audio::effect::LoudnessEnhancer;
using aidl::android::hardware::audio::effect::LoudnessEnhancerTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;
/**
@@ -36,7 +36,8 @@ using aidl::android::hardware::audio::effect::Parameter;
* VtsAudioEffectTargetTest.
*/
enum ParamName { PARAM_INSTANCE_NAME, PARAM_GAIN_MB };
using LoudnessEnhancerParamTestParam = std::tuple<std::string, int>;
using LoudnessEnhancerParamTestParam =
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor::Identity>, int>;
// Every int 32 bit value is a valid gain, so testing the corner cases and one regular value.
// TODO : Update the test values once range/capability is updated by implementation.
@@ -46,53 +47,64 @@ const std::vector<int> kGainMbValues = {std::numeric_limits<int>::min(), 100,
class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhancerParamTestParam>,
public EffectHelper {
public:
LoudnessEnhancerParamTest()
: EffectHelper(std::get<PARAM_INSTANCE_NAME>(GetParam())),
mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {}
LoudnessEnhancerParamTest() : mParamGainMb(std::get<PARAM_GAIN_MB>(GetParam())) {
std::tie(mFactory, mIdentity) = std::get<PARAM_INSTANCE_NAME>(GetParam());
}
void SetUp() override {
CreateEffectsWithUUID(LoudnessEnhancerTypeUUID);
initParamCommonFormat();
initParamCommon();
initParamSpecific();
OpenEffects(LoudnessEnhancerTypeUUID);
SCOPED_TRACE(testing::Message() << "gainMb: " << mParamGainMb);
}
ASSERT_NE(nullptr, mFactory);
ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mIdentity));
Parameter::Specific specific = getDefaultParamSpecific();
Parameter::Common common = EffectHelper::createParamCommon(
0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
IEffect::OpenEffectReturn ret;
ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
ASSERT_NE(nullptr, mEffect);
}
void TearDown() override {
CloseEffects();
DestroyEffects();
CleanUp();
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
Parameter::Specific getDefaultParamSpecific() {
LoudnessEnhancer le = LoudnessEnhancer::make<LoudnessEnhancer::gainMb>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::loudnessEnhancer>(le);
return specific;
}
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor::Identity mIdentity;
int mParamGainMb = 0;
void SetAndGetLoudnessEnhancerParameters() {
auto functor = [&](const std::shared_ptr<IEffect>& effect) {
for (auto& it : mTags) {
auto& tag = it.first;
auto& le = it.second;
void SetAndGetParameters() {
for (auto& it : mTags) {
auto& tag = it.first;
auto& le = it.second;
// set parameter
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::loudnessEnhancer>(le);
expectParam.set<Parameter::specific>(specific);
// All values are valid, set parameter should succeed
EXPECT_STATUS(EX_NONE, effect->setParameter(expectParam)) << expectParam.toString();
// set parameter
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::loudnessEnhancer>(le);
expectParam.set<Parameter::specific>(specific);
// All values are valid, set parameter should succeed
EXPECT_STATUS(EX_NONE, mEffect->setParameter(expectParam)) << expectParam.toString();
// get parameter
Parameter getParam;
Parameter::Id id;
LoudnessEnhancer::Id leId;
leId.set<LoudnessEnhancer::Id::commonTag>(tag);
id.set<Parameter::Id::loudnessEnhancerTag>(leId);
EXPECT_STATUS(EX_NONE, effect->getParameter(id, &getParam));
// get parameter
Parameter getParam;
Parameter::Id id;
LoudnessEnhancer::Id leId;
leId.set<LoudnessEnhancer::Id::commonTag>(tag);
id.set<Parameter::Id::loudnessEnhancerTag>(leId);
EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
EXPECT_EQ(expectParam, getParam);
}
};
EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
<< "\ngetParam:" << getParam.toString();
}
}
void addGainMbParam(int gainMb) {
@@ -103,33 +115,33 @@ class LoudnessEnhancerParamTest : public ::testing::TestWithParam<LoudnessEnhanc
private:
std::vector<std::pair<LoudnessEnhancer::Tag, LoudnessEnhancer>> mTags;
void initParamSpecific() {
LoudnessEnhancer le;
le.set<LoudnessEnhancer::gainMb>(0);
Parameter::Specific specific;
specific.set<Parameter::Specific::loudnessEnhancer>(le);
setSpecific(specific);
}
void CleanUp() { mTags.clear(); }
};
TEST_P(LoudnessEnhancerParamTest, SetAndGetGainMb) {
EXPECT_NO_FATAL_FAILURE(addGainMbParam(mParamGainMb));
SetAndGetLoudnessEnhancerParameters();
SetAndGetParameters();
}
INSTANTIATE_TEST_SUITE_P(
LoudnessEnhancerTest, LoudnessEnhancerParamTest,
::testing::Combine(
testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
testing::ValuesIn(kGainMbValues)),
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kLoudnessEnhancerTypeUUID)),
testing::ValuesIn(kGainMbValues)),
[](const testing::TestParamInfo<LoudnessEnhancerParamTest::ParamType>& info) {
std::string instance = std::get<PARAM_INSTANCE_NAME>(info.param);
auto msSinceEpoch = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now().time_since_epoch())
.count();
auto instance = std::get<PARAM_INSTANCE_NAME>(info.param);
std::string gainMb = std::to_string(std::get<PARAM_GAIN_MB>(info.param));
std::string name = instance + "_gainMb" + gainMb;
std::ostringstream address;
address << msSinceEpoch << "_factory_" << instance.first.get();
std::string name = address.str() + "_UUID_timeLow_" +
::android::internal::ToString(instance.second.uuid.timeLow) +
"_timeMid_" +
::android::internal::ToString(instance.second.uuid.timeMid) +
"_gainMb" + gainMb;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;