mirror of
https://github.com/Evolution-X/hardware_interfaces
synced 2026-02-01 21:37:44 +00:00
Merge changes from topic "aidl_audio_effect_5" am: bbefdc5d36 am: 243f9db0aa am: 5fe890c58c
Original change: https://android-review.googlesource.com/c/platform/hardware/interfaces/+/2254121 Change-Id: I102c162ba12c7d25cf16dffa5246b8cb39d396b3 Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -59,5 +59,9 @@ parcelable Descriptor {
|
||||
@VintfStability
|
||||
parcelable Common {
|
||||
android.hardware.audio.effect.Descriptor.Identity id;
|
||||
int cpuLoad;
|
||||
int memoryUsage;
|
||||
@utf8InCpp String name;
|
||||
@utf8InCpp String implementor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,12 +35,32 @@ package android.hardware.audio.effect;
|
||||
@VintfStability
|
||||
union Equalizer {
|
||||
android.hardware.audio.effect.Equalizer.VendorExtension vendor;
|
||||
@VintfStability
|
||||
parcelable Capability {
|
||||
ParcelableHolder extension;
|
||||
}
|
||||
android.hardware.audio.effect.Equalizer.BandLevel[] bandLevels;
|
||||
int preset;
|
||||
@VintfStability
|
||||
parcelable VendorExtension {
|
||||
ParcelableHolder extension;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable Capability {
|
||||
ParcelableHolder extension;
|
||||
android.hardware.audio.effect.Equalizer.BandFrequency[] bandFrequencies;
|
||||
android.hardware.audio.effect.Equalizer.Preset[] presets;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable BandLevel {
|
||||
int index;
|
||||
int level;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable BandFrequency {
|
||||
int index;
|
||||
int min;
|
||||
int max;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable Preset {
|
||||
int index;
|
||||
@utf8InCpp String name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,4 +34,41 @@
|
||||
package android.hardware.audio.effect;
|
||||
@VintfStability
|
||||
parcelable Flags {
|
||||
android.hardware.audio.effect.Flags.Type type = android.hardware.audio.effect.Flags.Type.INSERT;
|
||||
android.hardware.audio.effect.Flags.Insert insert = android.hardware.audio.effect.Flags.Insert.ANY;
|
||||
android.hardware.audio.effect.Flags.Volume volume = android.hardware.audio.effect.Flags.Volume.NONE;
|
||||
android.hardware.audio.effect.Flags.HardwareAccelerator hwAcceleratorMode = android.hardware.audio.effect.Flags.HardwareAccelerator.NONE;
|
||||
boolean offloadIndication;
|
||||
boolean deviceIndication;
|
||||
boolean audioModeIndication;
|
||||
boolean audioSourceIndication;
|
||||
boolean noProcessing;
|
||||
@Backing(type="byte") @VintfStability
|
||||
enum Type {
|
||||
INSERT = 0,
|
||||
AUXILIARY = 1,
|
||||
REPLACE = 2,
|
||||
PRE_PROC = 3,
|
||||
POST_PROC = 4,
|
||||
}
|
||||
@Backing(type="byte") @VintfStability
|
||||
enum Insert {
|
||||
ANY = 0,
|
||||
FIRST = 1,
|
||||
LAST = 2,
|
||||
EXCLUSIVE = 3,
|
||||
}
|
||||
@Backing(type="byte") @VintfStability
|
||||
enum Volume {
|
||||
NONE = 0,
|
||||
CTRL = 1,
|
||||
IND = 2,
|
||||
MONITOR = 3,
|
||||
}
|
||||
@Backing(type="byte") @VintfStability
|
||||
enum HardwareAccelerator {
|
||||
NONE = 0,
|
||||
SIMPLE = 1,
|
||||
TUNNEL = 2,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,28 +35,42 @@ package android.hardware.audio.effect;
|
||||
@VintfStability
|
||||
union Parameter {
|
||||
android.hardware.audio.effect.Parameter.Common common;
|
||||
android.media.audio.common.AudioDeviceType device;
|
||||
android.media.audio.common.AudioMode mode;
|
||||
android.media.audio.common.AudioSource source;
|
||||
android.hardware.audio.effect.Parameter.Volume volume;
|
||||
boolean offload;
|
||||
android.hardware.audio.effect.Parameter.VendorEffectParameter vendorEffect;
|
||||
android.hardware.audio.effect.Parameter.Specific specific;
|
||||
@VintfStability
|
||||
union Id {
|
||||
int commonTag;
|
||||
int vendorTag;
|
||||
android.hardware.audio.effect.Parameter.Specific.Tag specificTag;
|
||||
android.hardware.audio.effect.Parameter.Specific.Id specificId;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable Common {
|
||||
int session;
|
||||
int ioHandle;
|
||||
android.media.audio.common.AudioDeviceDescription device;
|
||||
android.media.audio.common.AudioConfig input;
|
||||
android.media.audio.common.AudioConfig output;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable Volume {
|
||||
float left;
|
||||
float right;
|
||||
}
|
||||
@VintfStability
|
||||
parcelable VendorEffectParameter {
|
||||
ParcelableHolder extension;
|
||||
}
|
||||
@VintfStability
|
||||
union Specific {
|
||||
android.hardware.audio.effect.Parameter.Specific.Id id;
|
||||
android.hardware.audio.effect.Equalizer equalizer;
|
||||
@VintfStability
|
||||
union Id {
|
||||
android.hardware.audio.effect.Equalizer.Tag equalizerTag = android.hardware.audio.effect.Equalizer.Tag.vendor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,9 @@ package android.hardware.audio.effect;
|
||||
@VintfStability
|
||||
@Backing(type="int")
|
||||
enum CommandId {
|
||||
/// MUST be supported by all effects
|
||||
/**
|
||||
* Commands MUST be supported by all effects.
|
||||
*/
|
||||
/**
|
||||
* Start effect engine processing.
|
||||
* An effect instance must start processing data and transfer to PROCESSING state if it is in
|
||||
@@ -53,10 +55,13 @@ enum CommandId {
|
||||
*/
|
||||
RESET = 2,
|
||||
|
||||
/// MUST be supported by a specific type of effect.
|
||||
// Commands must supported by Equalizer.
|
||||
/**
|
||||
* Commands MUST be supported by a specific type of effect.
|
||||
*/
|
||||
|
||||
/// Extension commands for vendor.
|
||||
/**
|
||||
* Extension commands for vendor.
|
||||
*/
|
||||
VENDOR_COMMAND_0 = 0x100,
|
||||
VENDOR_COMMAND_1,
|
||||
VENDOR_COMMAND_2,
|
||||
|
||||
@@ -36,31 +36,57 @@ parcelable Descriptor {
|
||||
/**
|
||||
* UUID for effect types, these definitions are in sync with SDK, see @c AudioEffect.java.
|
||||
*/
|
||||
// UUID for environmental reverberation effect type.
|
||||
/**
|
||||
* UUID for environmental reverberation effect type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_ENV_REVERB = "c2e5d5f0-94bd-4763-9cac-4e234d06839e";
|
||||
// UUID for preset reverberation effect type.
|
||||
/**
|
||||
* UUID for preset reverberation effect type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_PRESET_REVERB = "47382d60-ddd8-11db-bf3a-0002a5d5c51b";
|
||||
// UUID for equalizer effect type.
|
||||
/**
|
||||
* UUID for equalizer effect type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_EQUALIZER = "0bed4300-ddd6-11db-8f34-0002a5d5c51b";
|
||||
// UUID for bass boost effect type.
|
||||
/**
|
||||
* UUID for bass boost effect type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_BASS_BOOST = "0634f220-ddd4-11db-a0fc-0002a5d5c51b";
|
||||
// UUID for virtualizer effect type.
|
||||
/**
|
||||
* UUID for virtualizer effect type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_VIRTUALIZER = "37cc2c00-dddd-11db-8577-0002a5d5c51b";
|
||||
// UUID for Automatic Gain Control (AGC) type.
|
||||
/**
|
||||
* UUID for Automatic Gain Control (AGC) type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_AGC = "0a8abfe0-654c-11e0-ba26-0002a5d5c51b";
|
||||
// UUID for Acoustic Echo Canceler (AEC) type.
|
||||
/**
|
||||
* UUID for Acoustic Echo Canceler (AEC) type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_AEC = "7b491460-8d4d-11e0-bd61-0002a5d5c51b";
|
||||
// UUID for Noise Suppressor (NS) type.
|
||||
/**
|
||||
* UUID for Noise Suppressor (NS) type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_NS = "58b4b260-8e06-11e0-aa8e-0002a5d5c51b";
|
||||
// UUID for Loudness Enhancer type.
|
||||
/**
|
||||
* UUID for Loudness Enhancer type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_LOUDNESS_ENHANCER = "fe3199be-aed0-413f-87bb-11260eb63cf1";
|
||||
// UUID for Dynamics Processing type.
|
||||
/**
|
||||
* UUID for Dynamics Processing type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_DYNAMICS_PROCESSING = "7261676f-6d75-7369-6364-28e2fd3ac39e";
|
||||
// UUID for Haptic Generator type.
|
||||
/**
|
||||
* UUID for Haptic Generator type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_HAPTIC_GENERATOR = "1411e6d6-aecd-4021-a1cf-a6aceb0d71e5";
|
||||
// UUID for Spatializer type.
|
||||
/**
|
||||
* UUID for Spatializer type.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_SPATIALIZER = "ccd4cf09-a79d-46c2-9aae-06a1698d6c8f";
|
||||
// UUID for Volume type. The volume effect is used for automated tests only.
|
||||
/**
|
||||
* UUID for Volume type. The volume effect is used for automated tests only.
|
||||
*/
|
||||
const String EFFECT_TYPE_UUID_VOLUME = "09e8ede0-ddde-11db-b4f6-0002a5d5c51b";
|
||||
|
||||
/**
|
||||
@@ -87,13 +113,32 @@ parcelable Descriptor {
|
||||
Flags flags;
|
||||
}
|
||||
|
||||
// Common attributes of all effect implementation.
|
||||
/**
|
||||
* Common attributes of all effect implementation.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Common {
|
||||
/**
|
||||
* Identity of effect implementation.
|
||||
*/
|
||||
Identity id;
|
||||
/**
|
||||
* CPU load indication expressed in 0.1 MIPS units as estimated on an ARM9E core (ARMv5TE)
|
||||
* with 0 WS.
|
||||
*/
|
||||
int cpuLoad;
|
||||
/**
|
||||
* Data memory usage expressed in KB and includes only dynamically allocated memory.
|
||||
*/
|
||||
int memoryUsage;
|
||||
/**
|
||||
* Human readable effect name, no intended to display on UI directly.
|
||||
*/
|
||||
@utf8InCpp String name;
|
||||
/**
|
||||
* Human readable effect implementor name, no intended to display on UI directly.
|
||||
*/
|
||||
@utf8InCpp String implementor;
|
||||
}
|
||||
Common common;
|
||||
|
||||
|
||||
@@ -20,14 +20,23 @@ import android.media.audio.common.AudioProfile;
|
||||
|
||||
/**
|
||||
* Equalizer specific definitions.
|
||||
*
|
||||
* All parameters defined in union Equalizer must be gettable and settable. The capabilities defined
|
||||
* in Equalizer.Capability can only acquired with IEffect.getDescriptor() and not settable.
|
||||
*/
|
||||
@VintfStability
|
||||
union Equalizer {
|
||||
/**
|
||||
* Defines Equalizer implementation capabilities, it MUST be supported by all equalizer
|
||||
* implementations.
|
||||
*
|
||||
* Equalizer.Capability definition is used by android.hardware.audio.effect.Capability.
|
||||
* Vendor Equalizer implementation definition for additional parameters.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable VendorExtension {
|
||||
ParcelableHolder extension;
|
||||
}
|
||||
VendorExtension vendor;
|
||||
|
||||
/**
|
||||
* Capability MUST be supported by Equalizer implementation.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Capability {
|
||||
@@ -36,12 +45,55 @@ union Equalizer {
|
||||
* definition not enough.
|
||||
*/
|
||||
ParcelableHolder extension;
|
||||
|
||||
/**
|
||||
* Bands frequency ranges supported.
|
||||
*/
|
||||
BandFrequency[] bandFrequencies;
|
||||
|
||||
/**
|
||||
* Presets name and index.
|
||||
*/
|
||||
Preset[] presets;
|
||||
}
|
||||
|
||||
// Vendor Equalizer implementation definition for additional parameters.
|
||||
/**
|
||||
* Level setting for each band.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable VendorExtension {
|
||||
ParcelableHolder extension;
|
||||
parcelable BandLevel {
|
||||
int index;
|
||||
int level;
|
||||
}
|
||||
VendorExtension vendor;
|
||||
|
||||
/**
|
||||
* Supported minimal and maximal frequency for each band.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable BandFrequency {
|
||||
int index;
|
||||
int min;
|
||||
int max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory presets supported.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Preset {
|
||||
int index;
|
||||
/**
|
||||
* Preset name, used to identify presets but no intended to display on UI directly.
|
||||
*/
|
||||
@utf8InCpp String name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Level for each band.
|
||||
*/
|
||||
BandLevel[] bandLevels;
|
||||
/**
|
||||
* Index of current preset.
|
||||
*/
|
||||
int preset;
|
||||
}
|
||||
|
||||
@@ -17,10 +17,131 @@
|
||||
package android.hardware.audio.effect;
|
||||
|
||||
/**
|
||||
* The common part of available capability/configuration for effects. For effect type specific
|
||||
* capability, see @c android.hardware.audio.effect.Capability.
|
||||
* Some common capability for an effect instance.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Flags {
|
||||
// TODO: add Effect engine defined capabilities/requirements flags.
|
||||
/**
|
||||
* Type of connection.
|
||||
*/
|
||||
@VintfStability
|
||||
@Backing(type="byte")
|
||||
enum Type {
|
||||
/**
|
||||
* After track process.
|
||||
*/
|
||||
INSERT = 0,
|
||||
/**
|
||||
* Connect to track auxiliary output and use send level.
|
||||
*/
|
||||
AUXILIARY = 1,
|
||||
/**
|
||||
* Rreplaces track process function; must implement SRC, volume and mono to stereo.
|
||||
*/
|
||||
REPLACE = 2,
|
||||
/**
|
||||
* Applied below audio HAL on in.
|
||||
*/
|
||||
PRE_PROC = 3,
|
||||
/**
|
||||
* Applied below audio HAL on out.
|
||||
*/
|
||||
POST_PROC = 4,
|
||||
}
|
||||
Type type = Type.INSERT;
|
||||
|
||||
/**
|
||||
* Insertion preference.
|
||||
*/
|
||||
@VintfStability
|
||||
@Backing(type="byte")
|
||||
enum Insert {
|
||||
ANY = 0,
|
||||
/**
|
||||
* First of the chain.
|
||||
*/
|
||||
FIRST = 1,
|
||||
/**
|
||||
* Last of the chain.
|
||||
*/
|
||||
LAST = 2,
|
||||
/**
|
||||
* Exclusive (only effect in the insert chain.
|
||||
*/
|
||||
EXCLUSIVE = 3,
|
||||
}
|
||||
Insert insert = Insert.ANY;
|
||||
|
||||
@VintfStability
|
||||
@Backing(type="byte")
|
||||
enum Volume {
|
||||
NONE = 0,
|
||||
/**
|
||||
* Implements volume control.
|
||||
*/
|
||||
CTRL = 1,
|
||||
/**
|
||||
* Requires volume indication.
|
||||
*/
|
||||
IND = 2,
|
||||
/**
|
||||
* Monitors requested volume.
|
||||
*/
|
||||
MONITOR = 3,
|
||||
}
|
||||
Volume volume = Volume.NONE;
|
||||
|
||||
@VintfStability
|
||||
@Backing(type="byte")
|
||||
enum HardwareAccelerator {
|
||||
/**
|
||||
* No hardware acceleration
|
||||
*/
|
||||
NONE = 0,
|
||||
/**
|
||||
* Non tunneled hw acceleration: effect reads the samples, send them to HW accelerated
|
||||
* effect processor, reads back the processed samples and returns them to the output buffer.
|
||||
*/
|
||||
SIMPLE = 1,
|
||||
/**
|
||||
* The effect interface is only used to control the effect engine. This mode is relevant for
|
||||
* global effects actually applied by the audio hardware on the output stream.
|
||||
*/
|
||||
TUNNEL = 2,
|
||||
}
|
||||
HardwareAccelerator hwAcceleratorMode = HardwareAccelerator.NONE;
|
||||
|
||||
/**
|
||||
* Effect instance set this flag to true if it requires update on if the playback thread the
|
||||
* effect attached to is offloaded or not. In this case the framework must call
|
||||
* IEffect.setParameter(Parameter.offload) to notify effect instance when playback thread
|
||||
* offload changes.
|
||||
*/
|
||||
boolean offloadIndication;
|
||||
|
||||
/**
|
||||
* Effect instance set this flag to true if it requires device change update. In this case the
|
||||
* framework must call IEffect.setParameter(Parameter.device) to notify effect instance when the
|
||||
* device changes.
|
||||
*/
|
||||
boolean deviceIndication;
|
||||
|
||||
/**
|
||||
* Effect instance set this flag to true if it requires audio mode change update. In this case
|
||||
* the framework must call IEffect.setParameter(Parameter.mode) to notify effect instance when
|
||||
* the audio mode changes.
|
||||
*/
|
||||
boolean audioModeIndication;
|
||||
|
||||
/**
|
||||
* Effect instance set this flag to true if it requires audio source change update. In this case
|
||||
* the framework must call IEffect.setParameter(Parameter.source) to notify effect instance when
|
||||
* the audio source changes.
|
||||
*/
|
||||
boolean audioSourceIndication;
|
||||
|
||||
/**
|
||||
* Set to true if no processing done for this effect instance.
|
||||
*/
|
||||
boolean noProcessing;
|
||||
}
|
||||
|
||||
@@ -53,14 +53,22 @@ interface IEffect {
|
||||
int fmqByteProduced;
|
||||
}
|
||||
|
||||
// Return data structure of IEffect.open() interface.
|
||||
/**
|
||||
* Return data structure of IEffect.open() interface.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable OpenEffectReturn {
|
||||
// Message queue for effect processing status.
|
||||
/**
|
||||
* Message queue for effect processing status.
|
||||
*/
|
||||
MQDescriptor<Status, SynchronizedReadWrite> statusMQ;
|
||||
// Message queue for input data buffer.
|
||||
/**
|
||||
* Message queue for input data buffer.
|
||||
*/
|
||||
MQDescriptor<byte, SynchronizedReadWrite> inputDataMQ;
|
||||
// Message queue for output data buffer.
|
||||
/**
|
||||
* Message queue for output data buffer.
|
||||
*/
|
||||
MQDescriptor<byte, SynchronizedReadWrite> outputDataMQ;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ interface IFactory {
|
||||
* An effect can exist more than once in the returned list, which means this effect must be used
|
||||
* in more than one processing type.
|
||||
*
|
||||
* @param type Type of processing to query, can be AudioStreamType or AudioSource.
|
||||
* @param type Type of processing to query, can be AudioStreamType, AudioSource, or null.
|
||||
* @return list of processing defined with the optional filter by Processing.Type.
|
||||
*/
|
||||
Processing[] queryProcessing(in @nullable Processing.Type type);
|
||||
|
||||
@@ -18,7 +18,10 @@ package android.hardware.audio.effect;
|
||||
|
||||
import android.hardware.audio.effect.Equalizer;
|
||||
import android.media.audio.common.AudioConfig;
|
||||
import android.media.audio.common.AudioDeviceDescription;
|
||||
import android.media.audio.common.AudioDeviceType;
|
||||
import android.media.audio.common.AudioMode;
|
||||
import android.media.audio.common.AudioSource;
|
||||
|
||||
/**
|
||||
* Defines all parameters supported by the effect instance.
|
||||
*
|
||||
@@ -40,12 +43,18 @@ union Parameter {
|
||||
*/
|
||||
@VintfStability
|
||||
union Id {
|
||||
// Common parameter tag.
|
||||
/**
|
||||
* Common parameter tag.
|
||||
*/
|
||||
int commonTag;
|
||||
// Vendor defined parameter tag.
|
||||
/**
|
||||
* Vendor defined parameter tag.
|
||||
*/
|
||||
int vendorTag;
|
||||
// Specific effect parameter tag.
|
||||
Specific.Tag specificTag;
|
||||
/**
|
||||
* Specific effect parameter tag.
|
||||
*/
|
||||
Specific.Id specificId;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,19 +62,61 @@ union Parameter {
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Common {
|
||||
// Type of Audio device.
|
||||
/**
|
||||
* Type of Audio device.
|
||||
*/
|
||||
int session;
|
||||
// I/O Handle.
|
||||
/**
|
||||
* I/O Handle.
|
||||
*/
|
||||
int ioHandle;
|
||||
// Type of Audio device.
|
||||
AudioDeviceDescription device;
|
||||
// Input config.
|
||||
/**
|
||||
* Input config.
|
||||
*/
|
||||
AudioConfig input;
|
||||
// Output config.
|
||||
/**
|
||||
* Output config.
|
||||
*/
|
||||
AudioConfig output;
|
||||
}
|
||||
Common common;
|
||||
|
||||
/**
|
||||
* Used by audio framework to set the device type to effect engine.
|
||||
* Effect must implement setParameter(device) if Flags.deviceIndication set to true.
|
||||
*/
|
||||
AudioDeviceType device;
|
||||
/**
|
||||
* Used by audio framework to set the audio mode to effect engine.
|
||||
* Effect must implement setParameter(mode) if Flags.audioModeIndication set to true.
|
||||
*/
|
||||
AudioMode mode;
|
||||
/**
|
||||
* Used by audio framework to set the audio source to effect engine.
|
||||
* Effect must implement setParameter(source) if Flags.audioSourceIndication set to true.
|
||||
*/
|
||||
AudioSource source;
|
||||
|
||||
/**
|
||||
* The volume gain for left and right channel, left and right equals to same value if it's mono.
|
||||
*/
|
||||
@VintfStability
|
||||
parcelable Volume {
|
||||
float left;
|
||||
float right;
|
||||
}
|
||||
/**
|
||||
* Used by audio framework to delegate volume control to effect engine.
|
||||
* Effect must implement setParameter(volume) if Flags.volume set to Volume.IND.
|
||||
*/
|
||||
Volume volume;
|
||||
|
||||
/**
|
||||
* Used by audio framework to delegate offload information to effect engine.
|
||||
* Effect must implement setParameter(offload) if Flags.offloadSupported set to true.
|
||||
*/
|
||||
boolean offload;
|
||||
|
||||
/**
|
||||
* Parameters for vendor extension effect implementation usage.
|
||||
*/
|
||||
@@ -80,8 +131,16 @@ union Parameter {
|
||||
*/
|
||||
@VintfStability
|
||||
union Specific {
|
||||
@VintfStability
|
||||
union Id {
|
||||
/**
|
||||
* Equalizer.Tag to identify the parameters in Equalizer.
|
||||
*/
|
||||
Equalizer.Tag equalizerTag = Equalizer.Tag.vendor;
|
||||
}
|
||||
Id id;
|
||||
|
||||
Equalizer equalizer;
|
||||
// TODO: add other effect definitions here
|
||||
}
|
||||
Specific specific;
|
||||
}
|
||||
|
||||
@@ -116,6 +116,6 @@ cc_binary {
|
||||
cc_library_headers {
|
||||
name: "libaudioaidl_headers",
|
||||
export_include_dirs: ["include"],
|
||||
vendor: true,
|
||||
vendor_available: true,
|
||||
host_supported: true,
|
||||
}
|
||||
|
||||
@@ -28,11 +28,11 @@ EffectThread::EffectThread() {
|
||||
}
|
||||
|
||||
EffectThread::~EffectThread() {
|
||||
destroy();
|
||||
destroyThread();
|
||||
LOG(DEBUG) << __func__ << " done";
|
||||
};
|
||||
|
||||
RetCode EffectThread::create(const std::string& name, const int priority) {
|
||||
RetCode EffectThread::createThread(const std::string& name, const int priority) {
|
||||
if (mThread.joinable()) {
|
||||
LOG(WARNING) << __func__ << " thread already created, no-op";
|
||||
return RetCode::SUCCESS;
|
||||
@@ -44,7 +44,7 @@ RetCode EffectThread::create(const std::string& name, const int priority) {
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
RetCode EffectThread::destroy() {
|
||||
RetCode EffectThread::destroyThread() {
|
||||
{
|
||||
std::lock_guard lg(mMutex);
|
||||
mStop = mExit = true;
|
||||
@@ -58,10 +58,10 @@ RetCode EffectThread::destroy() {
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
RetCode EffectThread::start() {
|
||||
RetCode EffectThread::startThread() {
|
||||
if (!mThread.joinable()) {
|
||||
LOG(ERROR) << __func__ << " thread already destroyed";
|
||||
return RetCode::ERROR;
|
||||
return RetCode::ERROR_THREAD;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -78,10 +78,10 @@ RetCode EffectThread::start() {
|
||||
return RetCode::SUCCESS;
|
||||
}
|
||||
|
||||
RetCode EffectThread::stop() {
|
||||
RetCode EffectThread::stopThread() {
|
||||
if (!mThread.joinable()) {
|
||||
LOG(ERROR) << __func__ << " thread already destroyed";
|
||||
return RetCode::ERROR;
|
||||
return RetCode::ERROR_THREAD;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -117,15 +117,4 @@ void EffectThread::threadLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
std::string toString(RetCode& code) {
|
||||
switch (code) {
|
||||
case RetCode::SUCCESS:
|
||||
return "SUCCESS";
|
||||
case RetCode::ERROR:
|
||||
return "ERROR";
|
||||
default:
|
||||
return "EnumError";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -16,10 +16,12 @@
|
||||
|
||||
#define LOG_TAG "AHAL_EqualizerSw"
|
||||
#include <Utils.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "effect-impl/EffectUUID.h"
|
||||
#include <android-base/logging.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
#include "equalizer-impl/EqualizerSw.h"
|
||||
|
||||
using android::hardware::audio::common::getFrameSizeInBytes;
|
||||
@@ -68,20 +70,26 @@ ndk::ScopedAStatus EqualizerSw::open(const Parameter::Common& common,
|
||||
auto& output = common.output;
|
||||
size_t inputFrameSize = getFrameSizeInBytes(input.base.format, input.base.channelMask);
|
||||
size_t outputFrameSize = getFrameSizeInBytes(output.base.format, output.base.channelMask);
|
||||
if (!createFmq(1, input.frameCount * inputFrameSize, output.frameCount * outputFrameSize,
|
||||
_aidl_return)) {
|
||||
mContext = std::make_shared<EqualizerSwContext>(1, input.frameCount * inputFrameSize,
|
||||
output.frameCount * outputFrameSize);
|
||||
if (!mContext) {
|
||||
LOG(ERROR) << __func__ << " created EqualizerSwContext failed";
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
|
||||
"FailedToCreateFmq");
|
||||
}
|
||||
setContext(mContext);
|
||||
|
||||
// create the worker thread
|
||||
if (RetCode::SUCCESS != mWorker->create(LOG_TAG)) {
|
||||
if (RetCode::SUCCESS != createThread(LOG_TAG)) {
|
||||
LOG(ERROR) << __func__ << " created worker thread failed";
|
||||
destroyFmq();
|
||||
mContext.reset();
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_UNSUPPORTED_OPERATION,
|
||||
"FailedToCreateFmq");
|
||||
"FailedToCreateWorker");
|
||||
}
|
||||
|
||||
_aidl_return->statusMQ = mContext->getStatusFmq()->dupeDesc();
|
||||
_aidl_return->inputDataMQ = mContext->getInputDataFmq()->dupeDesc();
|
||||
_aidl_return->outputDataMQ = mContext->getOutputDataFmq()->dupeDesc();
|
||||
mState = State::IDLE;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
@@ -98,8 +106,9 @@ ndk::ScopedAStatus EqualizerSw::close() {
|
||||
|
||||
// stop the worker thread
|
||||
mState = State::INIT;
|
||||
mWorker->destroy();
|
||||
destroyFmq();
|
||||
destroyThread();
|
||||
mContext.reset();
|
||||
|
||||
LOG(DEBUG) << __func__;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
@@ -121,19 +130,19 @@ ndk::ScopedAStatus EqualizerSw::command(CommandId in_commandId) {
|
||||
case CommandId::START:
|
||||
// start processing.
|
||||
mState = State::PROCESSING;
|
||||
mWorker->start();
|
||||
startThread();
|
||||
LOG(DEBUG) << __func__ << " state: " << toString(mState);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
case CommandId::STOP:
|
||||
// stop processing.
|
||||
mState = State::IDLE;
|
||||
mWorker->stop();
|
||||
stopThread();
|
||||
LOG(DEBUG) << __func__ << " state: " << toString(mState);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
case CommandId::RESET:
|
||||
// TODO: reset buffer status.
|
||||
mState = State::IDLE;
|
||||
mWorker->stop();
|
||||
stopThread();
|
||||
LOG(DEBUG) << __func__ << " state: " << toString(mState);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
default:
|
||||
@@ -173,23 +182,27 @@ ndk::ScopedAStatus EqualizerSw::getParameter(const Parameter::Id& in_paramId,
|
||||
LOG(DEBUG) << __func__ << " get: " << _aidl_return->toString();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
case Parameter::Id::specificTag: {
|
||||
auto& id = in_paramId.get<Parameter::Id::specificTag>();
|
||||
if (id != Parameter::Specific::equalizer) {
|
||||
LOG(ERROR) << " unsupported parameter Id: " << in_paramId.toString();
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
|
||||
EX_ILLEGAL_ARGUMENT, "Parameter::IdNotSupported");
|
||||
}
|
||||
case Parameter::Id::specificId: {
|
||||
auto& id = in_paramId.get<Parameter::Id::specificId>();
|
||||
Parameter::Specific specific;
|
||||
specific.set<Parameter::Specific::equalizer>(mEqualizerParam);
|
||||
ndk::ScopedAStatus status = getSpecificParameter(id, &specific);
|
||||
if (!status.isOk()) {
|
||||
LOG(ERROR) << __func__
|
||||
<< " getSpecificParameter error: " << status.getDescription();
|
||||
return status;
|
||||
}
|
||||
_aidl_return->set<Parameter::specific>(specific);
|
||||
LOG(DEBUG) << __func__ << _aidl_return->toString();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
default:
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Parameter::IdNotSupported");
|
||||
case Parameter::Id::vendorTag: {
|
||||
LOG(DEBUG) << __func__ << " noop for vendor tag now";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << " unsupported tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"Parameter:IdNotSupported");
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
|
||||
@@ -198,35 +211,12 @@ ndk::ScopedAStatus EqualizerSw::getState(State* _aidl_return) {
|
||||
}
|
||||
|
||||
/// Private methods.
|
||||
bool EqualizerSw::createFmq(int statusDepth, int inBufferSize, int outBufferSize,
|
||||
OpenEffectReturn* ret) {
|
||||
mStatusMQ = std::make_unique<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
|
||||
mInputMQ = std::make_unique<DataMQ>(inBufferSize);
|
||||
mOutputMQ = std::make_unique<DataMQ>(outBufferSize);
|
||||
|
||||
if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
|
||||
LOG(ERROR) << __func__ << " created invalid FMQ";
|
||||
return false;
|
||||
}
|
||||
ret->statusMQ = mStatusMQ->dupeDesc();
|
||||
ret->inputDataMQ = mInputMQ->dupeDesc();
|
||||
ret->outputDataMQ = mOutputMQ->dupeDesc();
|
||||
return true;
|
||||
}
|
||||
|
||||
void EqualizerSw::destroyFmq() {
|
||||
mStatusMQ.reset(nullptr);
|
||||
mInputMQ.reset(nullptr);
|
||||
mOutputMQ.reset(nullptr);
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EqualizerSw::setCommonParameter(const Parameter::Common& common) {
|
||||
mCommonParam = common;
|
||||
LOG(DEBUG) << __func__ << " set: " << mCommonParam.toString();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
|
||||
// TODO: implementation need change to save all parameters.
|
||||
ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific& specific) {
|
||||
if (Parameter::Specific::equalizer != specific.getTag()) {
|
||||
LOG(ERROR) << " unsupported effect: " << specific.toString();
|
||||
@@ -234,9 +224,76 @@ ndk::ScopedAStatus EqualizerSw::setSpecificParameter(const Parameter::Specific&
|
||||
"EffectNotSupported");
|
||||
}
|
||||
|
||||
mEqualizerParam = specific.get<Parameter::Specific::equalizer>();
|
||||
LOG(DEBUG) << __func__ << mEqualizerParam.toString();
|
||||
return ndk::ScopedAStatus::ok();
|
||||
auto& eqParam = specific.get<Parameter::Specific::equalizer>();
|
||||
auto tag = eqParam.getTag();
|
||||
switch (tag) {
|
||||
case Equalizer::bandLevels: {
|
||||
auto& bandLevels = eqParam.get<Equalizer::bandLevels>();
|
||||
const auto& [minItem, maxItem] = std::minmax_element(
|
||||
bandLevels.begin(), bandLevels.end(),
|
||||
[](const auto& a, const auto& b) { return a.index < b.index; });
|
||||
if (bandLevels.size() >= NUM_OF_BANDS || minItem->index < 0 ||
|
||||
maxItem->index >= NUM_OF_BANDS) {
|
||||
LOG(ERROR) << " bandLevels " << bandLevels.size() << "minIndex " << minItem->index
|
||||
<< "maxIndex " << maxItem->index << " illegal ";
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"ExceedMaxBandNum");
|
||||
}
|
||||
mBandLevels = bandLevels;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
case Equalizer::preset: {
|
||||
int preset = eqParam.get<Equalizer::preset>();
|
||||
if (preset < 0 || preset >= NUM_OF_PRESETS) {
|
||||
LOG(ERROR) << " preset: " << preset << " invalid";
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"ExceedMaxBandNum");
|
||||
}
|
||||
mPreset = preset;
|
||||
LOG(DEBUG) << __func__ << " preset set to " << mPreset;
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
case Equalizer::vendor: {
|
||||
LOG(DEBUG) << __func__ << " noop for vendor tag now";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
}
|
||||
|
||||
LOG(ERROR) << __func__ << " unsupported eq param tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"ParamNotSupported");
|
||||
}
|
||||
|
||||
ndk::ScopedAStatus EqualizerSw::getSpecificParameter(Parameter::Specific::Id id,
|
||||
Parameter::Specific* specific) {
|
||||
Equalizer eqParam;
|
||||
auto tag = id.getTag();
|
||||
if (tag != Parameter::Specific::Id::equalizerTag) {
|
||||
LOG(ERROR) << " invalid tag: " << toString(tag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"UnsupportedTag");
|
||||
}
|
||||
auto eqTag = id.get<Parameter::Specific::Id::equalizerTag>();
|
||||
switch (eqTag) {
|
||||
case Equalizer::bandLevels: {
|
||||
eqParam.set<Equalizer::bandLevels>(mBandLevels);
|
||||
specific->set<Parameter::Specific::equalizer>(eqParam);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
case Equalizer::preset: {
|
||||
eqParam.set<Equalizer::preset>(mPreset);
|
||||
LOG(DEBUG) << __func__ << " preset " << mPreset;
|
||||
specific->set<Parameter::Specific::equalizer>(eqParam);
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
case Equalizer::vendor: {
|
||||
LOG(DEBUG) << __func__ << " noop for vendor tag now";
|
||||
return ndk::ScopedAStatus::ok();
|
||||
}
|
||||
}
|
||||
LOG(ERROR) << __func__ << " unsupported eq param: " << toString(eqTag);
|
||||
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
|
||||
"ParamNotSupported");
|
||||
}
|
||||
|
||||
void EqualizerSw::cleanUp() {
|
||||
@@ -248,9 +305,18 @@ void EqualizerSw::cleanUp() {
|
||||
}
|
||||
}
|
||||
|
||||
// Processing method running in worker thread.
|
||||
void EqualizerSwWorker::process() {
|
||||
// TODO: add EQ processing with FMQ, should wait until data available before data processing.
|
||||
IEffect::Status EqualizerSw::status(binder_status_t status, size_t consumed, size_t produced) {
|
||||
IEffect::Status ret;
|
||||
ret.status = status;
|
||||
ret.fmqByteConsumed = consumed;
|
||||
ret.fmqByteProduced = produced;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Processing method running in EffectWorker thread.
|
||||
IEffect::Status EqualizerSw::effectProcessImpl() {
|
||||
// TODO: get data buffer and process.
|
||||
return status(STATUS_OK, mContext->availableToRead(), mContext->availableToWrite());
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
65
audio/aidl/default/include/effect-impl/EffectContext.h
Normal file
65
audio/aidl/default/include/effect-impl/EffectContext.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <aidl/android/hardware/audio/effect/BnEffect.h>
|
||||
#include <fmq/AidlMessageQueue.h>
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EffectContext {
|
||||
public:
|
||||
typedef ::android::AidlMessageQueue<
|
||||
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
StatusMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
|
||||
EffectContext(size_t statusDepth, size_t inBufferSize, size_t outBufferSize) {
|
||||
mStatusMQ = std::make_shared<StatusMQ>(statusDepth, true /*configureEventFlagWord*/);
|
||||
mInputMQ = std::make_shared<DataMQ>(inBufferSize);
|
||||
mOutputMQ = std::make_shared<DataMQ>(outBufferSize);
|
||||
|
||||
if (!mStatusMQ->isValid() || !mInputMQ->isValid() || !mOutputMQ->isValid()) {
|
||||
LOG(ERROR) << __func__ << " created invalid FMQ";
|
||||
}
|
||||
mWorkBuffer.reserve(std::max(inBufferSize, outBufferSize));
|
||||
};
|
||||
|
||||
std::shared_ptr<StatusMQ> getStatusFmq() { return mStatusMQ; };
|
||||
std::shared_ptr<DataMQ> getInputDataFmq() { return mInputMQ; };
|
||||
std::shared_ptr<DataMQ> getOutputDataFmq() { return mOutputMQ; };
|
||||
|
||||
int8_t* getWorkBuffer() { return static_cast<int8_t*>(mWorkBuffer.data()); };
|
||||
// TODO: update with actual available size
|
||||
size_t availableToRead() { return mWorkBuffer.capacity(); };
|
||||
size_t availableToWrite() { return mWorkBuffer.capacity(); };
|
||||
|
||||
private:
|
||||
std::shared_ptr<StatusMQ> mStatusMQ;
|
||||
std::shared_ptr<DataMQ> mInputMQ;
|
||||
std::shared_ptr<DataMQ> mOutputMQ;
|
||||
// TODO handle effect process input and output
|
||||
// work buffer set by effect instances, the access and update are in same thread
|
||||
std::vector<int8_t> mWorkBuffer;
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
@@ -22,12 +22,10 @@
|
||||
#include <android-base/thread_annotations.h>
|
||||
#include <system/thread_defs.h>
|
||||
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
enum class RetCode { SUCCESS, ERROR };
|
||||
|
||||
std::string toString(RetCode& code);
|
||||
|
||||
class EffectThread {
|
||||
public:
|
||||
// default priority is same as HIDL: ANDROID_PRIORITY_URGENT_AUDIO
|
||||
@@ -35,10 +33,11 @@ class EffectThread {
|
||||
virtual ~EffectThread();
|
||||
|
||||
// called by effect implementation.
|
||||
RetCode create(const std::string& name, const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode destroy();
|
||||
RetCode start();
|
||||
RetCode stop();
|
||||
RetCode createThread(const std::string& name,
|
||||
const int priority = ANDROID_PRIORITY_URGENT_AUDIO);
|
||||
RetCode destroyThread();
|
||||
RetCode startThread();
|
||||
RetCode stopThread();
|
||||
|
||||
// Will call process() in a loop if the thread is running.
|
||||
void threadLoop();
|
||||
|
||||
51
audio/aidl/default/include/effect-impl/EffectTypes.h
Normal file
51
audio/aidl/default/include/effect-impl/EffectTypes.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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 <ostream>
|
||||
#include <string>
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
enum class RetCode {
|
||||
SUCCESS,
|
||||
ERROR_ILLEGAL_PARAMETER, /* Illegal parameter */
|
||||
ERROR_THREAD, /* Effect thread error */
|
||||
ERROR_NULL_POINTER, /* NULL pointer */
|
||||
ERROR_ALIGNMENT_ERROR, /* Memory alignment error */
|
||||
ERROR_BLOCK_SIZE_EXCEED /* Maximum block size exceeded */
|
||||
};
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& out, const RetCode& code) {
|
||||
switch (code) {
|
||||
case RetCode::SUCCESS:
|
||||
return out << "SUCCESS";
|
||||
case RetCode::ERROR_ILLEGAL_PARAMETER:
|
||||
return out << "ERROR_ILLEGAL_PARAMETER";
|
||||
case RetCode::ERROR_THREAD:
|
||||
return out << "ERROR_THREAD";
|
||||
case RetCode::ERROR_NULL_POINTER:
|
||||
return out << "ERROR_NULL_POINTER";
|
||||
case RetCode::ERROR_ALIGNMENT_ERROR:
|
||||
return out << "ERROR_ALIGNMENT_ERROR";
|
||||
case RetCode::ERROR_BLOCK_SIZE_EXCEED:
|
||||
return out << "ERROR_BLOCK_SIZE_EXCEED";
|
||||
}
|
||||
|
||||
return out << "EnumError: " << code;
|
||||
}
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
@@ -21,6 +21,17 @@ 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}};
|
||||
|
||||
// Zero UUID
|
||||
static const AudioUuid EffectZeroUuid = {
|
||||
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,
|
||||
|
||||
74
audio/aidl/default/include/effect-impl/EffectWorker.h
Normal file
74
audio/aidl/default/include/effect-impl/EffectWorker.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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 <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
|
||||
#include "EffectContext.h"
|
||||
#include "EffectThread.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
std::string toString(RetCode& code);
|
||||
|
||||
class EffectWorker : public EffectThread {
|
||||
public:
|
||||
// set effect context for worker, suppose to only happen once here
|
||||
void setContext(std::shared_ptr<EffectContext> context) {
|
||||
std::call_once(mOnceFlag, [&]() { mContext = context; });
|
||||
};
|
||||
|
||||
// handle FMQ and call effect implemented virtual function
|
||||
void process() override {
|
||||
if (!mContext) {
|
||||
LOG(ERROR) << __func__ << " invalid context!";
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<EffectContext::StatusMQ> statusMQ = mContext->getStatusFmq();
|
||||
std::shared_ptr<EffectContext::DataMQ> inputMQ = mContext->getInputDataFmq();
|
||||
std::shared_ptr<EffectContext::DataMQ> outputMQ = mContext->getOutputDataFmq();
|
||||
|
||||
// Only this worker will read from input data MQ and write to output data MQ.
|
||||
auto readSize = inputMQ->availableToRead(), writeSize = outputMQ->availableToWrite();
|
||||
if (readSize && writeSize) {
|
||||
LOG(DEBUG) << __func__ << " available to read " << readSize << " available to write "
|
||||
<< writeSize;
|
||||
auto buffer = mContext->getWorkBuffer();
|
||||
inputMQ->read(buffer, readSize);
|
||||
IEffect::Status status = effectProcessImpl();
|
||||
writeSize = std::min((int32_t)writeSize, status.fmqByteProduced);
|
||||
outputMQ->write(buffer, writeSize);
|
||||
statusMQ->writeBlocking(&status, 1);
|
||||
LOG(DEBUG) << __func__ << " done processing, effect consumed " << status.fmqByteConsumed
|
||||
<< " produced " << status.fmqByteProduced;
|
||||
} else {
|
||||
// TODO: maybe add some sleep here to avoid busy waiting
|
||||
}
|
||||
}
|
||||
|
||||
// must implement by each effect implementation
|
||||
virtual IEffect::Status effectProcessImpl() = 0;
|
||||
|
||||
private:
|
||||
// make sure the context only set once.
|
||||
std::once_flag mOnceFlag;
|
||||
std::shared_ptr<EffectContext> mContext;
|
||||
};
|
||||
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
@@ -21,20 +21,29 @@
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
|
||||
#include "effect-impl/EffectThread.h"
|
||||
#include "effect-impl/EffectContext.h"
|
||||
#include "effect-impl/EffectTypes.h"
|
||||
#include "effect-impl/EffectUUID.h"
|
||||
#include "effect-impl/EffectWorker.h"
|
||||
|
||||
namespace aidl::android::hardware::audio::effect {
|
||||
|
||||
class EqualizerSwWorker : public EffectThread {
|
||||
// EqualizerSwWorker(const std::string name){EffectThread(name)};
|
||||
void process() override;
|
||||
class EqualizerSwContext : public EffectContext {
|
||||
public:
|
||||
EqualizerSwContext(int statusDepth, int inBufferSize, int outBufferSize)
|
||||
: EffectContext(statusDepth, inBufferSize, outBufferSize) {
|
||||
LOG(DEBUG) << __func__;
|
||||
}
|
||||
|
||||
private:
|
||||
// Add equalizer specific context for processing here
|
||||
};
|
||||
|
||||
class EqualizerSw : public BnEffect {
|
||||
class EqualizerSw : public BnEffect, EffectWorker {
|
||||
public:
|
||||
EqualizerSw() {
|
||||
// create the worker
|
||||
mWorker = std::make_unique<EqualizerSwWorker>();
|
||||
Equalizer::Capability eqCap = {.bandFrequencies = mBandFrequency, .presets = mPresets};
|
||||
mDesc.capability.set<Capability::equalizer>(eqCap);
|
||||
LOG(DEBUG) << __func__;
|
||||
};
|
||||
~EqualizerSw() {
|
||||
@@ -52,12 +61,11 @@ class EqualizerSw : public BnEffect {
|
||||
ndk::ScopedAStatus getParameter(const Parameter::Id& in_paramId,
|
||||
Parameter* _aidl_return) override;
|
||||
|
||||
IEffect::Status effectProcessImpl() override;
|
||||
|
||||
private:
|
||||
// effect processing thread.
|
||||
std::unique_ptr<EqualizerSwWorker> mWorker;
|
||||
// Effect descriptor.
|
||||
const Descriptor mDesc = {
|
||||
.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
|
||||
Descriptor mDesc = {.common = {.id = {.type = EqualizerTypeUUID, .uuid = EqualizerSwImplUUID}}};
|
||||
|
||||
// Parameters.
|
||||
Parameter::Common mCommonParam;
|
||||
@@ -66,21 +74,32 @@ class EqualizerSw : public BnEffect {
|
||||
// Instance state INIT by default.
|
||||
State mState = State::INIT;
|
||||
|
||||
typedef ::android::AidlMessageQueue<
|
||||
Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
StatusMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
int mPreset = PRESET_CUSTOM; // the current preset
|
||||
const std::vector<Equalizer::BandFrequency> mBandFrequency = {{0, 30000, 120000},
|
||||
{1, 120001, 460000},
|
||||
{2, 460001, 1800000},
|
||||
{3, 1800001, 7000000},
|
||||
{4, 7000001, 20000000}};
|
||||
// preset band level
|
||||
std::vector<Equalizer::BandLevel> mBandLevels = {{0, 3}, {1, 0}, {2, 0}, {3, 0}, {4, 3}};
|
||||
// presets supported by the device
|
||||
const std::vector<Equalizer::Preset> mPresets = {
|
||||
{0, "Normal"}, {1, "Classical"}, {2, "Dance"}, {3, "Flat"}, {4, "Folk"},
|
||||
{5, "Heavy Metal"}, {6, "Hip Hop"}, {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
|
||||
static const int NUM_OF_BANDS = 5;
|
||||
static const int NUM_OF_PRESETS = 10;
|
||||
static const int PRESET_CUSTOM = -1;
|
||||
|
||||
std::unique_ptr<StatusMQ> mStatusMQ;
|
||||
std::unique_ptr<DataMQ> mInputMQ;
|
||||
std::unique_ptr<DataMQ> mOutputMQ;
|
||||
// Equalizer worker context
|
||||
std::shared_ptr<EqualizerSwContext> mContext;
|
||||
|
||||
ndk::ScopedAStatus setCommonParameter(const Parameter::Common& common_param);
|
||||
ndk::ScopedAStatus setSpecificParameter(const Parameter::Specific& specific);
|
||||
bool createFmq(int statusDepth, int inBufferSize, int outBufferSize, OpenEffectReturn* ret);
|
||||
void destroyFmq();
|
||||
ndk::ScopedAStatus getSpecificParameter(Parameter::Specific::Id id,
|
||||
Parameter::Specific* specific);
|
||||
|
||||
void cleanUp();
|
||||
|
||||
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
|
||||
};
|
||||
} // namespace aidl::android::hardware::audio::effect
|
||||
|
||||
@@ -60,6 +60,7 @@ cc_test {
|
||||
"android.hardware.common-V2-ndk",
|
||||
"android.hardware.common.fmq-V1-ndk",
|
||||
],
|
||||
header_libs: ["libaudioaidl_headers"],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
@@ -75,6 +76,7 @@ cc_test {
|
||||
cc_test {
|
||||
name: "VtsHalAudioEffectTargetTest",
|
||||
defaults: [
|
||||
"latest_android_hardware_audio_common_ndk_static",
|
||||
"latest_android_media_audio_common_types_ndk_static",
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
@@ -84,12 +86,49 @@ cc_test {
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libfmq",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.audio.effect-V1-ndk",
|
||||
"android.hardware.common-V2-ndk",
|
||||
"android.hardware.common.fmq-V1-ndk",
|
||||
"libaudioaidlcommon",
|
||||
],
|
||||
header_libs: ["libaudioaidl_headers"],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Werror",
|
||||
"-Wthread-safety",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
"vts",
|
||||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "VtsHalEqualizerTargetTest",
|
||||
defaults: [
|
||||
"latest_android_hardware_audio_common_ndk_static",
|
||||
"latest_android_media_audio_common_types_ndk_static",
|
||||
"VtsHalTargetTestDefaults",
|
||||
"use_libaidlvintf_gtest_helper_static",
|
||||
],
|
||||
srcs: [
|
||||
"VtsHalEqualizerTargetTest.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbinder_ndk",
|
||||
"libfmq",
|
||||
],
|
||||
static_libs: [
|
||||
"android.hardware.audio.effect-V1-ndk",
|
||||
"android.hardware.common-V2-ndk",
|
||||
"android.hardware.common.fmq-V1-ndk",
|
||||
"libaudioaidlcommon",
|
||||
],
|
||||
header_libs: ["libaudioaidl_headers"],
|
||||
cflags: [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
|
||||
@@ -24,13 +24,14 @@
|
||||
#include <android/binder_auto_utils.h>
|
||||
|
||||
#include "TestUtils.h"
|
||||
#include "effect-impl/EffectUUID.h"
|
||||
|
||||
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::Parameter;
|
||||
using aidl::android::hardware::audio::effect::Processing;
|
||||
using aidl::android::media::audio::common::AudioUuid;
|
||||
|
||||
@@ -69,7 +70,6 @@ class EffectFactoryHelper {
|
||||
}
|
||||
|
||||
void CreateEffects() {
|
||||
ASSERT_NE(mEffectFactory, nullptr);
|
||||
for (const auto& id : mIds) {
|
||||
std::shared_ptr<IEffect> effect;
|
||||
EXPECT_IS_OK(mEffectFactory->createEffect(id.uuid, &effect));
|
||||
@@ -80,6 +80,26 @@ class EffectFactoryHelper {
|
||||
}
|
||||
}
|
||||
|
||||
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, &ids));
|
||||
} else {
|
||||
EXPECT_IS_OK(mEffectFactory->queryEffects(type, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CreateEffectsAndExpect(
|
||||
const std::vector<std::pair<Descriptor::Identity, binder_exception_t>>& uuid_status) {
|
||||
ASSERT_NE(mEffectFactory, nullptr);
|
||||
@@ -126,8 +146,10 @@ class EffectFactoryHelper {
|
||||
|
||||
std::shared_ptr<IFactory> GetFactory() { return mEffectFactory; }
|
||||
const std::vector<Descriptor::Identity>& GetEffectIds() { return mIds; }
|
||||
const std::vector<Descriptor::Identity>& GetCompleteEffectIdList() { return mCompleteIds; }
|
||||
const std::map<std::shared_ptr<IEffect>, Descriptor::Identity>& GetEffectMap() {
|
||||
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(); }
|
||||
|
||||
310
audio/aidl/vts/EffectHelper.h
Normal file
310
audio/aidl/vts/EffectHelper.h
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* 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 <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#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>
|
||||
|
||||
#include "AudioHalBinderServiceUtil.h"
|
||||
#include "EffectFactoryHelper.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
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 = {
|
||||
.type = AudioFormatType::PCM, .pcm = PcmType::INT_16_BIT, .encoding = ""};
|
||||
|
||||
class EffectHelper {
|
||||
public:
|
||||
explicit EffectHelper(const std::string& name) : mFactoryHelper(EffectFactoryHelper(name)) {
|
||||
mFactoryHelper.ConnectToFactoryService();
|
||||
}
|
||||
|
||||
void OpenEffects(const AudioUuid& type = EffectNullUuid) {
|
||||
auto open = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
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));
|
||||
}
|
||||
|
||||
void CloseEffects(const binder_status_t status = EX_NONE) {
|
||||
auto close = [&](const std::shared_ptr<IEffect>& 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));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void GetEffectDescriptors() {
|
||||
auto get = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
Descriptor desc;
|
||||
EXPECT_IS_OK(effect->getDescriptor(&desc));
|
||||
mEffectDescriptors.push_back(std::move(desc));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
|
||||
}
|
||||
|
||||
void CommandEffects(CommandId command) {
|
||||
auto close = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
EXPECT_IS_OK(effect->command(command));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
|
||||
}
|
||||
|
||||
void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
|
||||
auto func = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
EXPECT_STATUS(status, effect->command(command));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
|
||||
}
|
||||
|
||||
void ExpectState(State expected) {
|
||||
auto get = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
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) {
|
||||
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) {
|
||||
Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
|
||||
Parameter::Id id;
|
||||
id.set<Parameter::Id::commonTag>(0);
|
||||
paramCommonExpect.set<Parameter::common>(mCommon);
|
||||
EXPECT_IS_OK(effect->getParameter(id, ¶mCommonGet));
|
||||
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,
|
||||
std::vector<Descriptor::Identity>* _aidl_return) {
|
||||
mFactoryHelper.QueryEffects(in_type, in_instance, _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);
|
||||
}
|
||||
}
|
||||
|
||||
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 mWriteMQSize = 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 = -1, 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;
|
||||
input.base.sampleRate = iSampleRate;
|
||||
input.base.channelMask = mInputChannelLayout;
|
||||
input.frameCount = iFrameCount;
|
||||
output.base.sampleRate = oSampleRate;
|
||||
output.base.channelMask = mOutputChannelLayout;
|
||||
output.frameCount = oFrameCount;
|
||||
inputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
|
||||
input.base.format, input.base.channelMask);
|
||||
outputFrameSize = android::hardware::audio::common::getFrameSizeInBytes(
|
||||
output.base.format, output.base.channelMask);
|
||||
}
|
||||
|
||||
void setSpecific(Parameter::Specific& specific) { mSpecific = specific; }
|
||||
|
||||
// usually this function only call once.
|
||||
void PrepareInputData(size_t s = mWriteMQSize) {
|
||||
size_t maxInputSize = s;
|
||||
for (auto& it : mEffectParams) {
|
||||
auto& mq = it.inputMQ;
|
||||
EXPECT_NE(nullptr, mq);
|
||||
EXPECT_TRUE(mq->isValid());
|
||||
const size_t bytesToWrite = mq->availableToWrite();
|
||||
EXPECT_EQ(inputFrameSize * mCommon.input.frameCount, bytesToWrite);
|
||||
EXPECT_NE(0UL, bytesToWrite);
|
||||
EXPECT_TRUE(s <= bytesToWrite);
|
||||
maxInputSize = std::max(maxInputSize, bytesToWrite);
|
||||
}
|
||||
mInputBuffer.resize(maxInputSize);
|
||||
std::fill(mInputBuffer.begin(), mInputBuffer.end(), 0x5a);
|
||||
}
|
||||
|
||||
void writeToFmq(size_t s = mWriteMQSize) {
|
||||
for (auto& it : mEffectParams) {
|
||||
auto& mq = it.inputMQ;
|
||||
EXPECT_NE(nullptr, mq);
|
||||
const size_t bytesToWrite = mq->availableToWrite();
|
||||
EXPECT_NE(0Ul, bytesToWrite);
|
||||
EXPECT_TRUE(s <= bytesToWrite);
|
||||
EXPECT_TRUE(mq->write(mInputBuffer.data(), s));
|
||||
}
|
||||
}
|
||||
|
||||
void readFromFmq(size_t expectSize = mWriteMQSize) {
|
||||
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(expectSize, (unsigned)status.fmqByteProduced);
|
||||
|
||||
auto& outputMq = it.outputMQ;
|
||||
EXPECT_NE(nullptr, outputMq);
|
||||
EXPECT_EQ(expectSize, outputMq->availableToRead());
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
Parameter::Specific mSpecific;
|
||||
|
||||
size_t inputFrameSize, outputFrameSize;
|
||||
std::vector<int8_t> mInputBuffer; // reuse same buffer for all effects testing
|
||||
|
||||
typedef ::android::AidlMessageQueue<
|
||||
IEffect::Status, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
StatusMQ;
|
||||
typedef ::android::AidlMessageQueue<
|
||||
int8_t, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>
|
||||
DataMQ;
|
||||
|
||||
class EffectParam {
|
||||
public:
|
||||
std::unique_ptr<StatusMQ> statusMQ;
|
||||
std::unique_ptr<DataMQ> inputMQ;
|
||||
std::unique_ptr<DataMQ> outputMQ;
|
||||
};
|
||||
std::vector<EffectParam> mEffectParams;
|
||||
std::vector<Descriptor> mEffectDescriptors;
|
||||
};
|
||||
@@ -37,6 +37,8 @@
|
||||
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::IFactory;
|
||||
using aidl::android::hardware::audio::effect::Processing;
|
||||
using aidl::android::media::audio::common::AudioUuid;
|
||||
@@ -50,17 +52,8 @@ class EffectFactoryTest : public testing::TestWithParam<std::string> {
|
||||
|
||||
EffectFactoryHelper mFactory = EffectFactoryHelper(GetParam());
|
||||
|
||||
// TODO: these UUID can get from config file
|
||||
// ec7178ec-e5e1-4432-a3f4-4657e6795210
|
||||
const AudioUuid nullUuid = {static_cast<int32_t>(0xec7178ec),
|
||||
0xe5e1,
|
||||
0x4432,
|
||||
0xa3f4,
|
||||
{0x46, 0x57, 0xe6, 0x79, 0x52, 0x10}};
|
||||
const AudioUuid zeroUuid = {
|
||||
static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
|
||||
const Descriptor::Identity nullDesc = {.uuid = nullUuid};
|
||||
const Descriptor::Identity zeroDesc = {.uuid = zeroUuid};
|
||||
const Descriptor::Identity nullDesc = {.uuid = EffectNullUuid};
|
||||
const Descriptor::Identity zeroDesc = {.uuid = EffectZeroUuid};
|
||||
};
|
||||
|
||||
TEST_P(EffectFactoryTest, SetupAndTearDown) {
|
||||
@@ -82,20 +75,20 @@ TEST_P(EffectFactoryTest, DescriptorUUIDNotNull) {
|
||||
mFactory.QueryEffects(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, zeroUuid);
|
||||
EXPECT_NE(desc.uuid, zeroUuid);
|
||||
EXPECT_NE(desc.type, EffectNullUuid);
|
||||
EXPECT_NE(desc.uuid, EffectNullUuid);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistType) {
|
||||
std::vector<Descriptor::Identity> descriptors;
|
||||
mFactory.QueryEffects(nullUuid, std::nullopt, &descriptors);
|
||||
mFactory.QueryEffects(EffectNullUuid, std::nullopt, &descriptors);
|
||||
EXPECT_EQ(descriptors.size(), 0UL);
|
||||
}
|
||||
|
||||
TEST_P(EffectFactoryTest, QueriedDescriptorNotExistInstance) {
|
||||
std::vector<Descriptor::Identity> descriptors;
|
||||
mFactory.QueryEffects(std::nullopt, nullUuid, &descriptors);
|
||||
mFactory.QueryEffects(std::nullopt, EffectNullUuid, &descriptors);
|
||||
EXPECT_EQ(descriptors.size(), 0UL);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,14 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#define LOG_TAG "VtsHalAudioEffectTargetTest"
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#define LOG_TAG "VtsHalAudioEffect"
|
||||
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.h>
|
||||
#include <android-base/logging.h>
|
||||
@@ -30,13 +30,13 @@
|
||||
#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/AudioChannelLayout.h>
|
||||
#include <aidl/android/media/audio/common/AudioDeviceType.h>
|
||||
|
||||
#include "AudioHalBinderServiceUtil.h"
|
||||
#include "EffectFactoryHelper.h"
|
||||
#include "EffectHelper.h"
|
||||
#include "TestUtils.h"
|
||||
|
||||
using namespace android;
|
||||
@@ -49,201 +49,72 @@ using aidl::android::hardware::audio::effect::IEffect;
|
||||
using aidl::android::hardware::audio::effect::IFactory;
|
||||
using aidl::android::hardware::audio::effect::Parameter;
|
||||
using aidl::android::hardware::audio::effect::State;
|
||||
using aidl::android::media::audio::common::AudioChannelLayout;
|
||||
using aidl::android::media::audio::common::AudioDeviceType;
|
||||
|
||||
class AudioEffect : public testing::TestWithParam<std::string> {
|
||||
class AudioEffectTest : public testing::TestWithParam<std::string>, public EffectHelper {
|
||||
public:
|
||||
AudioEffectTest() : EffectHelper(GetParam()) {}
|
||||
|
||||
void SetUp() override {
|
||||
ASSERT_NO_FATAL_FAILURE(mFactoryHelper.ConnectToFactoryService());
|
||||
CreateEffects();
|
||||
initParamCommonFormat();
|
||||
initParamCommon();
|
||||
initParamSpecific();
|
||||
// initParamSpecific();
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
CloseEffects();
|
||||
DestroyEffects();
|
||||
}
|
||||
|
||||
void OpenEffects() {
|
||||
auto open = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
IEffect::OpenEffectReturn ret;
|
||||
EXPECT_IS_OK(effect->open(mCommon, mSpecific, &ret));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(open));
|
||||
}
|
||||
|
||||
void CloseEffects(const binder_status_t status = EX_NONE) {
|
||||
auto close = [&](const std::shared_ptr<IEffect>& 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 DestroyEffects(const binder_status_t status = EX_NONE, const int remaining = 0) {
|
||||
ASSERT_NO_FATAL_FAILURE(mFactoryHelper.DestroyEffects(status, remaining));
|
||||
}
|
||||
|
||||
void GetEffectDescriptors() {
|
||||
auto get = [](const std::shared_ptr<IEffect>& effect) {
|
||||
Descriptor desc;
|
||||
EXPECT_IS_OK(effect->getDescriptor(&desc));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(get));
|
||||
}
|
||||
|
||||
void CommandEffects(CommandId command) {
|
||||
auto close = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
EXPECT_IS_OK(effect->command(command));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(close));
|
||||
}
|
||||
|
||||
void CommandEffectsExpectStatus(CommandId command, const binder_status_t status) {
|
||||
auto func = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
EXPECT_STATUS(status, effect->command(command));
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
|
||||
}
|
||||
|
||||
void ExpectState(State expected) {
|
||||
auto get = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
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) {
|
||||
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) {
|
||||
Parameter paramCommonGet = Parameter(), paramCommonExpect = Parameter();
|
||||
Parameter::Id id;
|
||||
id.set<Parameter::Id::commonTag>(0);
|
||||
paramCommonExpect.set<Parameter::common>(mCommon);
|
||||
EXPECT_IS_OK(effect->getParameter(id, ¶mCommonGet));
|
||||
EXPECT_EQ(paramCommonExpect, paramCommonGet)
|
||||
<< paramCommonExpect.toString() << " vs " << paramCommonGet.toString();
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(func));
|
||||
}
|
||||
|
||||
template <typename Functor>
|
||||
void ForEachEffect(Functor functor) {
|
||||
auto effectMap = mFactoryHelper.GetEffectMap();
|
||||
for (const auto& it : effectMap) {
|
||||
SCOPED_TRACE(it.second.toString());
|
||||
functor(it.first);
|
||||
}
|
||||
}
|
||||
|
||||
void initParamCommon(int session = -1, int ioHandle = -1,
|
||||
AudioDeviceType deviceType = AudioDeviceType::NONE,
|
||||
int iSampleRate = 48000, int oSampleRate = 48000, long iFrameCount = 0x100,
|
||||
long oFrameCount = 0x100) {
|
||||
mCommon.session = session;
|
||||
mCommon.ioHandle = ioHandle;
|
||||
mCommon.device.type = deviceType;
|
||||
mCommon.input.base.sampleRate = iSampleRate;
|
||||
mCommon.input.base.channelMask = mInputChannelLayout;
|
||||
mCommon.input.frameCount = iFrameCount;
|
||||
mCommon.output.base.sampleRate = oSampleRate;
|
||||
mCommon.output.base.channelMask = mOutputChannelLayout;
|
||||
mCommon.output.frameCount = oFrameCount;
|
||||
}
|
||||
|
||||
void initParamSpecific(Parameter::Specific::Tag tag = Parameter::Specific::equalizer) {
|
||||
switch (tag) {
|
||||
case Parameter::Specific::equalizer:
|
||||
mSpecific.set<Parameter::Specific::equalizer>();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void setInputChannelLayout(AudioChannelLayout input) { mInputChannelLayout = input; }
|
||||
void setOutputChannelLayout(AudioChannelLayout output) { mOutputChannelLayout = output; }
|
||||
|
||||
EffectFactoryHelper mFactoryHelper = EffectFactoryHelper(GetParam());
|
||||
|
||||
private:
|
||||
AudioChannelLayout mInputChannelLayout =
|
||||
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
|
||||
AudioChannelLayout::LAYOUT_STEREO);
|
||||
AudioChannelLayout mOutputChannelLayout =
|
||||
AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
|
||||
AudioChannelLayout::LAYOUT_STEREO);
|
||||
|
||||
Parameter::Common mCommon;
|
||||
Parameter::Specific mSpecific;
|
||||
static IEffect::OpenEffectReturn mOpenReturn;
|
||||
};
|
||||
|
||||
TEST_P(AudioEffect, OpenEffectTest) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
TEST_P(AudioEffectTest, OpenEffectTest) {
|
||||
OpenEffects();
|
||||
}
|
||||
|
||||
TEST_P(AudioEffect, OpenAndCloseEffect) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
TEST_P(AudioEffectTest, OpenAndCloseEffect) {
|
||||
OpenEffects();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
TEST_P(AudioEffect, CloseUnopenedEffectTest) {
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
TEST_P(AudioEffectTest, CloseUnopenedEffectTest) {
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
TEST_P(AudioEffect, DoubleOpenCloseEffects) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
TEST_P(AudioEffectTest, DoubleOpenCloseEffects) {
|
||||
OpenEffects();
|
||||
CloseEffects();
|
||||
OpenEffects();
|
||||
CloseEffects();
|
||||
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
OpenEffects();
|
||||
OpenEffects();
|
||||
CloseEffects();
|
||||
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
OpenEffects();
|
||||
CloseEffects();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
TEST_P(AudioEffect, GetDescriptors) {
|
||||
EXPECT_NO_FATAL_FAILURE(GetEffectDescriptors());
|
||||
TEST_P(AudioEffectTest, GetDescriptors) {
|
||||
GetEffectDescriptors();
|
||||
}
|
||||
|
||||
TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
|
||||
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));
|
||||
mFactoryHelper.QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
|
||||
QueryEffects(desc.common.id.type, desc.common.id.uuid, &idList);
|
||||
EXPECT_EQ(idList.size(), 1UL);
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(checker));
|
||||
ForEachEffect(checker);
|
||||
|
||||
// Check unique with a set
|
||||
auto stringHash = [](const Descriptor::Identity& id) {
|
||||
return std::hash<std::string>()(id.toString());
|
||||
};
|
||||
auto vec = mFactoryHelper.GetCompleteEffectIdList();
|
||||
auto vec = GetCompleteEffectIdList();
|
||||
std::unordered_set<Descriptor::Identity, decltype(stringHash)> idSet(0, stringHash);
|
||||
for (auto it : vec) {
|
||||
EXPECT_EQ(idSet.count(it), 0UL);
|
||||
@@ -253,218 +124,235 @@ TEST_P(AudioEffect, DescriptorIdExistAndUnique) {
|
||||
|
||||
/// State testing.
|
||||
// An effect instance is in INIT state by default after it was created.
|
||||
TEST_P(AudioEffect, InitStateAfterCreation) {
|
||||
TEST_P(AudioEffectTest, InitStateAfterCreation) {
|
||||
ExpectState(State::INIT);
|
||||
}
|
||||
|
||||
// An effect instance transfer to INIT state after it was open successfully with IEffect.open().
|
||||
TEST_P(AudioEffect, IdleStateAfterOpen) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
TEST_P(AudioEffectTest, IdleStateAfterOpen) {
|
||||
OpenEffects();
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// An effect instance is in PROCESSING state after it receive an START command.
|
||||
TEST_P(AudioEffect, ProcessingStateAfterStart) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, ProcessingStateAfterStart) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CommandEffects(CommandId::STOP);
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// An effect instance transfer to IDLE state after Command.Id.STOP in PROCESSING state.
|
||||
TEST_P(AudioEffect, IdleStateAfterStop) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, IdleStateAfterStop) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// An effect instance transfer to IDLE state after Command.Id.RESET in PROCESSING state.
|
||||
TEST_P(AudioEffect, IdleStateAfterReset) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, IdleStateAfterReset) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
|
||||
CommandEffects(CommandId::RESET);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// An effect instance transfer to INIT if instance receive a close() call.
|
||||
TEST_P(AudioEffect, InitStateAfterClose) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, InitStateAfterClose) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
ExpectState(State::INIT);
|
||||
}
|
||||
|
||||
// An effect instance shouldn't accept any command before open.
|
||||
TEST_P(AudioEffect, NoCommandAcceptedBeforeOpen) {
|
||||
TEST_P(AudioEffectTest, NoCommandAcceptedBeforeOpen) {
|
||||
ExpectState(State::INIT);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE));
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE));
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE));
|
||||
CommandEffectsExpectStatus(CommandId::START, EX_ILLEGAL_STATE);
|
||||
CommandEffectsExpectStatus(CommandId::STOP, EX_ILLEGAL_STATE);
|
||||
CommandEffectsExpectStatus(CommandId::RESET, EX_ILLEGAL_STATE);
|
||||
ExpectState(State::INIT);
|
||||
}
|
||||
|
||||
// No-op when receive STOP command in IDLE state.
|
||||
TEST_P(AudioEffect, StopCommandInIdleStateNoOp) {
|
||||
TEST_P(AudioEffectTest, StopCommandInIdleStateNoOp) {
|
||||
ExpectState(State::INIT);
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
OpenEffects();
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// No-op when receive STOP command in IDLE state.
|
||||
TEST_P(AudioEffect, ResetCommandInIdleStateNoOp) {
|
||||
TEST_P(AudioEffectTest, ResetCommandInIdleStateNoOp) {
|
||||
ExpectState(State::INIT);
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
OpenEffects();
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
|
||||
CommandEffects(CommandId::RESET);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Repeat START and STOP command.
|
||||
TEST_P(AudioEffect, RepeatStartAndStop) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, RepeatStartAndStop) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Repeat START and RESET command.
|
||||
TEST_P(AudioEffect, RepeatStartAndReset) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, RepeatStartAndReset) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
|
||||
CommandEffects(CommandId::RESET);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
|
||||
CommandEffects(CommandId::RESET);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Repeat START and STOP command, try to close at PROCESSING state.
|
||||
TEST_P(AudioEffect, CloseProcessingStateEffects) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, CloseProcessingStateEffects) {
|
||||
OpenEffects();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects(EX_ILLEGAL_STATE));
|
||||
CloseEffects(EX_ILLEGAL_STATE);
|
||||
// cleanup
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
}
|
||||
|
||||
// Expect EX_ILLEGAL_STATE if the effect instance is not in a proper state to be destroyed.
|
||||
TEST_P(AudioEffect, DestroyOpenEffects) {
|
||||
TEST_P(AudioEffectTest, DestroyOpenEffects) {
|
||||
// cleanup all effects.
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
ASSERT_NO_FATAL_FAILURE(DestroyEffects());
|
||||
CloseEffects();
|
||||
DestroyEffects();
|
||||
|
||||
// open effects, destroy without close, expect to get EX_ILLEGAL_STATE status.
|
||||
EXPECT_NO_FATAL_FAILURE(CreateEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(DestroyEffects(EX_ILLEGAL_STATE, 1));
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CreateEffects();
|
||||
OpenEffects();
|
||||
DestroyEffects(EX_ILLEGAL_STATE, 1);
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
/// Parameter testing.
|
||||
// Verify parameters pass in open can be successfully get.
|
||||
TEST_P(AudioEffect, VerifyParametersAfterOpen) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
TEST_P(AudioEffectTest, VerifyParametersAfterOpen) {
|
||||
OpenEffects();
|
||||
VerifyParameters();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Verify parameters pass in set can be successfully get.
|
||||
TEST_P(AudioEffect, SetAndGetParameter) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
|
||||
44100 /* iSampleRate */, 44100 /* oSampleRate */);
|
||||
EXPECT_NO_FATAL_FAILURE(SetParameter());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
TEST_P(AudioEffectTest, SetAndGetParameter) {
|
||||
OpenEffects();
|
||||
VerifyParameters();
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
|
||||
44100 /* oSampleRate */);
|
||||
SetParameter();
|
||||
VerifyParameters();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Verify parameters pass in set can be successfully get.
|
||||
TEST_P(AudioEffect, SetAndGetParameterInProcessing) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, SetAndGetParameterInProcessing) {
|
||||
OpenEffects();
|
||||
VerifyParameters();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
|
||||
44100 /* iSampleRate */, 44100 /* oSampleRate */);
|
||||
EXPECT_NO_FATAL_FAILURE(SetParameter());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
|
||||
44100 /* oSampleRate */);
|
||||
SetParameter();
|
||||
VerifyParameters();
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Parameters kept after reset.
|
||||
TEST_P(AudioEffect, ResetAndVerifyParameter) {
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
TEST_P(AudioEffectTest, ResetAndVerifyParameter) {
|
||||
OpenEffects();
|
||||
VerifyParameters();
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
|
||||
44100 /* iSampleRate */, 44100 /* oSampleRate */);
|
||||
EXPECT_NO_FATAL_FAILURE(SetParameter());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::RESET));
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
|
||||
44100 /* oSampleRate */);
|
||||
SetParameter();
|
||||
VerifyParameters();
|
||||
CommandEffects(CommandId::RESET);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
VerifyParameters();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
// Multiple instances of same implementation running.
|
||||
TEST_P(AudioEffect, MultipleInstancesRunning) {
|
||||
EXPECT_NO_FATAL_FAILURE(CreateEffects(3));
|
||||
TEST_P(AudioEffectTest, MultipleInstancesRunning) {
|
||||
CreateEffects(3);
|
||||
ExpectState(State::INIT);
|
||||
EXPECT_NO_FATAL_FAILURE(OpenEffects());
|
||||
OpenEffects();
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::START));
|
||||
CommandEffects(CommandId::START);
|
||||
ExpectState(State::PROCESSING);
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, AudioDeviceType::IN_DEFAULT /* deviceType */,
|
||||
44100 /* iSampleRate */, 44100 /* oSampleRate */);
|
||||
EXPECT_NO_FATAL_FAILURE(SetParameter());
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CommandEffects(CommandId::STOP));
|
||||
initParamCommon(1 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */,
|
||||
44100 /* oSampleRate */);
|
||||
SetParameter();
|
||||
VerifyParameters();
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
EXPECT_NO_FATAL_FAILURE(VerifyParameters());
|
||||
EXPECT_NO_FATAL_FAILURE(CloseEffects());
|
||||
VerifyParameters();
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AudioEffectTest, AudioEffect,
|
||||
// Send data to effects and expect it to consume by check statusMQ.
|
||||
TEST_P(AudioEffectTest, ExpectEffectsToConsumeDataInMQ) {
|
||||
OpenEffects();
|
||||
PrepareInputData(mWriteMQSize);
|
||||
|
||||
CommandEffects(CommandId::START);
|
||||
writeToFmq(mWriteMQSize);
|
||||
readFromFmq(mWriteMQSize);
|
||||
|
||||
ExpectState(State::PROCESSING);
|
||||
CommandEffects(CommandId::STOP);
|
||||
// cleanup
|
||||
CommandEffects(CommandId::STOP);
|
||||
ExpectState(State::IDLE);
|
||||
CloseEffects();
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AudioEffectTestTest, AudioEffectTest,
|
||||
testing::ValuesIn(android::getAidlHalInstanceNames(IFactory::descriptor)),
|
||||
android::PrintInstanceNameToString);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffect);
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AudioEffectTest);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(1);
|
||||
ABinderProcess_startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
||||
|
||||
233
audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
Normal file
233
audio/aidl/vts/VtsHalEqualizerTargetTest.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
* 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 <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define LOG_TAG "VtsHalEqualizerTest"
|
||||
|
||||
#include <aidl/Gtest.h>
|
||||
#include <aidl/Vintf.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 <gtest/gtest.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/AudioChannelLayout.h>
|
||||
#include <aidl/android/media/audio/common/AudioDeviceType.h>
|
||||
|
||||
#include "AudioHalBinderServiceUtil.h"
|
||||
#include "EffectHelper.h"
|
||||
#include "TestUtils.h"
|
||||
#include "effect-impl/EffectUUID.h"
|
||||
|
||||
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::Parameter;
|
||||
|
||||
/**
|
||||
* Here we focus on specific parameter checking, general IEffect interfaces testing performed in
|
||||
* VtsAudioEfectTargetTest.
|
||||
*/
|
||||
using EqualizerParamTestParam = std::tuple<int, int, int>;
|
||||
|
||||
class EqualizerParamTest : public ::testing::TestWithParam<EqualizerParamTestParam>,
|
||||
public EffectHelper {
|
||||
public:
|
||||
EqualizerParamTest()
|
||||
: EffectHelper(android::getAidlHalInstanceNames(IFactory::descriptor)[0]),
|
||||
mParamPresetIndex(std::get<0 /* kPresetIndexRange */>(GetParam())),
|
||||
mParamBandIndex(std::get<1 /* kBandIndexRange */>(GetParam())),
|
||||
mParamBandLevel(std::get<2 /* kBandLevelRange */>(GetParam())) {}
|
||||
|
||||
void SetUp() override {
|
||||
CreateEffectsWithUUID(EqualizerTypeUUID);
|
||||
initParamCommonFormat();
|
||||
initParamCommon();
|
||||
initParamSpecific();
|
||||
OpenEffects(EqualizerTypeUUID);
|
||||
SCOPED_TRACE(testing::Message() << "preset: " << mParamPresetIndex << " bandIdx "
|
||||
<< mParamBandIndex << " level " << mParamBandLevel);
|
||||
}
|
||||
|
||||
void TearDown() override {
|
||||
CloseEffects();
|
||||
DestroyEffects();
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
const int mParamPresetIndex;
|
||||
const int mParamBandIndex;
|
||||
const int mParamBandLevel;
|
||||
|
||||
void SetAndGetEqualizerParameters() {
|
||||
auto functor = [&](const std::shared_ptr<IEffect>& effect) {
|
||||
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;
|
||||
|
||||
// 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();
|
||||
|
||||
// get
|
||||
if (expected == EX_NONE) {
|
||||
Parameter getParam;
|
||||
Parameter::Specific::Id id;
|
||||
id.set<Parameter::Specific::Id::equalizerTag>(tag);
|
||||
// if set success, then get should match
|
||||
EXPECT_STATUS(expected, effect->getParameter(id, &getParam));
|
||||
EXPECT_EQ(expectParam, getParam) << "\n"
|
||||
<< expectParam.toString() << "\n"
|
||||
<< getParam.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
EXPECT_NO_FATAL_FAILURE(ForEachEffect(functor));
|
||||
}
|
||||
|
||||
void addPresetParam(int preset) {
|
||||
Equalizer eq;
|
||||
eq.set<Equalizer::preset>(preset);
|
||||
mTags.push_back({Equalizer::preset, std::make_unique<Equalizer>(std::move(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))});
|
||||
}
|
||||
|
||||
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>();
|
||||
switch (tag) {
|
||||
case Equalizer::preset: {
|
||||
int index = eq->get<Equalizer::preset>();
|
||||
return isPresetIndexInRange(eqCap, index);
|
||||
}
|
||||
case Equalizer::bandLevels: {
|
||||
auto& bandLevel = eq->get<Equalizer::bandLevels>();
|
||||
return isBandIndexInRange(eqCap, bandLevel);
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
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 {
|
||||
for (auto& it : bandLevel) {
|
||||
if (!isBandIndexInRange(cap, it.index)) 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;
|
||||
}
|
||||
|
||||
private:
|
||||
Equalizer::VendorExtension mVendorExtension;
|
||||
std::vector<std::pair<Equalizer::Tag, std::unique_ptr<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(EqualizerParamTest, SetAndGetSingleBand) {
|
||||
Equalizer::BandLevel bandLevel = {mParamBandIndex, mParamBandLevel};
|
||||
std::vector<Equalizer::BandLevel> bandLevels;
|
||||
bandLevels.push_back(bandLevel);
|
||||
EXPECT_NO_FATAL_FAILURE(addBandLevelsParam(bandLevels));
|
||||
SetAndGetEqualizerParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
Testing preset index range with [-10, 10], assuming the min/max preset index 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
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
EqualizerTest, EqualizerParamTest,
|
||||
::testing::Combine(testing::Range(kPresetIndexRange.first, kPresetIndexRange.second),
|
||||
testing::Range(kBandIndexRange.first, kBandIndexRange.second),
|
||||
testing::Range(kBandLevelRange.first, kBandLevelRange.second)));
|
||||
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EqualizerTest);
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
ABinderProcess_setThreadPoolMaxThreadCount(1);
|
||||
ABinderProcess_startThreadPool();
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
Reference in New Issue
Block a user