Merge "Remove radio ISAP HIDL entry in compat matrix."
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index a166e61..6a545c1 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -13,6 +13,9 @@
"name": "VtsHalDownmixTargetTest"
},
{
+ "name": "VtsHalDynamicsProcessingTargetTest"
+ },
+ {
"name": "VtsHalEnvironmentalReverbTargetTest"
},
{
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
index 79299ee..86b69fa 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/CommandId.aidl
@@ -37,14 +37,14 @@
START = 0,
STOP = 1,
RESET = 2,
- VENDOR_COMMAND_0 = 256,
- VENDOR_COMMAND_1 = 257,
- VENDOR_COMMAND_2 = 258,
- VENDOR_COMMAND_3 = 259,
- VENDOR_COMMAND_4 = 260,
- VENDOR_COMMAND_5 = 261,
- VENDOR_COMMAND_6 = 262,
- VENDOR_COMMAND_7 = 263,
- VENDOR_COMMAND_8 = 264,
- VENDOR_COMMAND_9 = 265,
+ VENDOR_COMMAND_0 = 0x100,
+ VENDOR_COMMAND_1,
+ VENDOR_COMMAND_2,
+ VENDOR_COMMAND_3,
+ VENDOR_COMMAND_4,
+ VENDOR_COMMAND_5,
+ VENDOR_COMMAND_6,
+ VENDOR_COMMAND_7,
+ VENDOR_COMMAND_8,
+ VENDOR_COMMAND_9,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
index 76f8ce5..402441d 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Downmix.aidl
@@ -47,7 +47,7 @@
}
@VintfStability
enum Type {
- STRIP = 0,
- FOLD = 1,
+ STRIP,
+ FOLD,
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
index ed4dc80..8e5b719 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -36,14 +36,14 @@
union DynamicsProcessing {
android.hardware.audio.effect.VendorExtension vendorExtension;
android.hardware.audio.effect.DynamicsProcessing.EngineArchitecture engineArchitecture;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig preEq;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig postEq;
- android.hardware.audio.effect.DynamicsProcessing.EqBandConfig preEqBand;
- android.hardware.audio.effect.DynamicsProcessing.EqBandConfig postEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandChannelConfig mbc;
- android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig mbcBand;
- android.hardware.audio.effect.DynamicsProcessing.LimiterConfig limiter;
- float inputGainDb;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] preEq;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] postEq;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] preEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.EqBandConfig[] postEqBand;
+ android.hardware.audio.effect.DynamicsProcessing.ChannelConfig[] mbc;
+ android.hardware.audio.effect.DynamicsProcessing.MbcBandConfig[] mbcBand;
+ android.hardware.audio.effect.DynamicsProcessing.LimiterConfig[] limiter;
+ android.hardware.audio.effect.DynamicsProcessing.InputGain[] inputGain;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -52,37 +52,39 @@
@VintfStability
parcelable Capability {
ParcelableHolder extension;
+ float minCutOffFreq;
+ float maxCutOffFreq;
}
enum ResolutionPreference {
- FAVOR_FREQUENCY_RESOLUTION = 0,
- FAVOR_TIME_RESOLUTION = 1,
+ FAVOR_FREQUENCY_RESOLUTION,
+ FAVOR_TIME_RESOLUTION,
}
@VintfStability
- parcelable BandEnablement {
+ parcelable StageEnablement {
boolean inUse;
int bandCount;
}
@VintfStability
parcelable EngineArchitecture {
android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference resolutionPreference = android.hardware.audio.effect.DynamicsProcessing.ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
- float preferredFrameDurationMs;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement preEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement postEqBand;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement mbcBand;
+ float preferredProcessingDurationMs;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement preEqStage;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement postEqStage;
+ android.hardware.audio.effect.DynamicsProcessing.StageEnablement mbcStage;
boolean limiterInUse;
}
@VintfStability
- parcelable BandChannelConfig {
+ parcelable ChannelConfig {
int channel;
- android.hardware.audio.effect.DynamicsProcessing.BandEnablement enablement;
+ boolean enable;
}
@VintfStability
parcelable EqBandConfig {
int channel;
int band;
boolean enable;
- float cutoffFrequency;
- float gain;
+ float cutoffFrequencyHz;
+ float gainDb;
}
@VintfStability
parcelable MbcBandConfig {
@@ -90,7 +92,6 @@
int band;
boolean enable;
float cutoffFrequencyHz;
- float gainDb;
float attackTimeMs;
float releaseTimeMs;
float ratio;
@@ -105,7 +106,6 @@
parcelable LimiterConfig {
int channel;
boolean enable;
- boolean inUse;
int linkGroup;
float attackTimeMs;
float releaseTimeMs;
@@ -113,4 +113,9 @@
float thresholdDb;
float postGainDb;
}
+ @VintfStability
+ parcelable InputGain {
+ int channel;
+ float gainDb;
+ }
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 0e61932..9edad09 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -44,22 +44,6 @@
int diffusionPm;
int densityPm;
boolean bypass;
- const int MIN_ROOM_LEVEL_MB = -6000;
- const int MAX_ROOM_LEVEL_MB = 0;
- const int MIN_ROOM_HF_LEVEL_MB = -4000;
- const int MAX_ROOM_HF_LEVEL_MB = 0;
- const int MIN_DECAY_TIME_MS = 100;
- const int MAX_DECAY_TIME_MS = 20000;
- const int MIN_DECAY_HF_RATIO_PM = 100;
- const int MAX_DECAY_HF_RATIO_PM = 1000;
- const int MIN_LEVEL_MB = -6000;
- const int MAX_LEVEL_MB = 0;
- const int MIN_DELAY_MS = 0;
- const int MAX_DELAY_MS = 65;
- const int MIN_DIFFUSION_PM = 0;
- const int MAX_DIFFUSION_PM = 1000;
- const int MIN_DENSITY_PM = 0;
- const int MAX_DENSITY_PM = 1000;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -68,6 +52,17 @@
@VintfStability
parcelable Capability {
android.hardware.audio.effect.VendorExtension extension;
+ int minRoomLevelMb;
+ int maxRoomLevelMb;
+ int minRoomHfLevelMb;
+ int maxRoomHfLevelMb;
int maxDecayTimeMs;
+ int minDecayHfRatioPm;
+ int maxDecayHfRatioPm;
+ int minLevelMb;
+ int maxLevelMb;
+ int maxDelayMs;
+ int maxDiffusionPm;
+ int maxDensityPm;
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
index 959594b..20f7e02 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/HapticGenerator.aidl
@@ -48,9 +48,9 @@
}
@Backing(type="int") @VintfStability
enum VibratorScale {
- MUTE = -100,
- VERY_LOW = -2,
- LOW = -1,
+ MUTE = (-100),
+ VERY_LOW = (-2),
+ LOW = (-1),
NONE = 0,
HIGH = 1,
VERY_HIGH = 2,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
index 223d95a..397f897 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/NoiseSuppression.aidl
@@ -47,8 +47,8 @@
}
@Backing(type="int") @VintfStability
enum Level {
- LOW = 0,
- MEDIUM = 1,
- HIGH = 2,
+ LOW,
+ MEDIUM,
+ HIGH,
}
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
index 24a9ce1..4651742 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/PresetReverb.aidl
@@ -38,13 +38,13 @@
android.hardware.audio.effect.PresetReverb.Presets preset;
@Backing(type="int") @VintfStability
enum Presets {
- NONE = 0,
- SMALLROOM = 1,
- MEDIUMROOM = 2,
- LARGEROOM = 3,
- MEDIUMHALL = 4,
- LARGEHALL = 5,
- PLATE = 6,
+ NONE,
+ SMALLROOM,
+ MEDIUMROOM,
+ LARGEROOM,
+ MEDIUMHALL,
+ LARGEHALL,
+ PLATE,
}
@VintfStability
union Id {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
index 3176b01..17f9814 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/State.aidl
@@ -34,7 +34,7 @@
package android.hardware.audio.effect;
@Backing(type="byte") @VintfStability
enum State {
- INIT = 0,
- IDLE = 1,
- PROCESSING = 2,
+ INIT,
+ IDLE,
+ PROCESSING,
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
index 25f0b73..c8cb551 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Visualizer.aidl
@@ -62,12 +62,12 @@
@VintfStability
enum ScalingMode {
NORMALIZED = 0,
- AS_PLAYED = 1,
+ AS_PLAYED,
}
@VintfStability
enum MeasurementMode {
NONE = 0,
- PEAK_RMS = 1,
+ PEAK_RMS,
}
@VintfStability
union GetOnlyParameters {
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
index e25b15a..501dc01 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-async-sm.gv
@@ -30,6 +30,7 @@
STANDBY -> PAUSED [label="burst"]; // producer -> active
IDLE -> STANDBY [label="standby"]; // consumer -> passive
IDLE -> TRANSFERRING [label="burst"]; // producer -> active
+ IDLE -> ACTIVE [label="burst"]; // full write
ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
ACTIVE -> DRAINING [label="drain"]; // producer -> passive
ACTIVE -> TRANSFERRING [label="burst"]; // early unblocking
@@ -45,6 +46,7 @@
PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
DRAINING -> IDLE [label="←IStreamCallback.onDrainReady"];
DRAINING -> TRANSFERRING [label="burst"]; // producer -> active
+ DRAINING -> ACTIVE [label="burst"]; // full write
DRAINING -> DRAIN_PAUSED [label="pause"]; // consumer -> passive (not consuming)
DRAIN_PAUSED -> DRAINING [label="start"]; // consumer -> active
DRAIN_PAUSED -> TRANSFER_PAUSED [label="burst"]; // producer -> active
diff --git a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
index 6aa5c61..47e7fda 100644
--- a/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
+++ b/audio/aidl/android/hardware/audio/core/stream-out-sm.gv
@@ -31,6 +31,7 @@
ACTIVE -> ACTIVE [label="burst"];
ACTIVE -> PAUSED [label="pause"]; // consumer -> passive (not consuming)
ACTIVE -> DRAINING [label="drain"]; // producer -> passive
+ ACTIVE -> IDLE [label="drain"]; // synchronous drain
PAUSED -> PAUSED [label="burst"];
PAUSED -> ACTIVE [label="start"]; // consumer -> active
PAUSED -> IDLE [label="flush"]; // producer -> passive, buffer is cleared
diff --git a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
index ee5dcad..6db3338 100644
--- a/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
+++ b/audio/aidl/android/hardware/audio/effect/DynamicsProcessing.aidl
@@ -51,6 +51,14 @@
* capability definition not enough.
*/
ParcelableHolder extension;
+ /**
+ * Min Cut off frequency (in Hz) for all Bands.
+ */
+ float minCutOffFreq;
+ /**
+ * Max Cut off frequency (in Hz) for all Bands.
+ */
+ float maxCutOffFreq;
}
/**
@@ -68,16 +76,16 @@
}
/**
- * Band enablement configuration.
+ * Stage enablement configuration.
*/
@VintfStability
- parcelable BandEnablement {
+ parcelable StageEnablement {
/**
- * True if multi-band stage is in use.
+ * True if stage is in use.
*/
boolean inUse;
/**
- * Number of bands configured for this stage.
+ * Number of bands configured for this stage. Must be positive when inUse is true.
*/
int bandCount;
}
@@ -92,21 +100,22 @@
*/
ResolutionPreference resolutionPreference = ResolutionPreference.FAVOR_FREQUENCY_RESOLUTION;
/**
- * Preferred frame duration in milliseconds (ms).
+ * Preferred processing duration in milliseconds (ms). Must not be negative, 0 means no
+ * preference.
*/
- float preferredFrameDurationMs;
+ float preferredProcessingDurationMs;
/**
* PreEq stage (Multi-band Equalizer) configuration.
*/
- BandEnablement preEqBand;
+ StageEnablement preEqStage;
/**
* PostEq stage (Multi-band Equalizer) configuration.
*/
- BandEnablement postEqBand;
+ StageEnablement postEqStage;
/**
* MBC stage (Multi-band Compressor) configuration.
*/
- BandEnablement mbcBand;
+ StageEnablement mbcStage;
/**
* True if Limiter stage is in use.
*/
@@ -114,18 +123,19 @@
}
/**
- * Band enablement configuration for a specific channel.
+ * Enablement configuration for a specific channel.
*/
@VintfStability
- parcelable BandChannelConfig {
+ parcelable ChannelConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * Channel index.
+ * Channel enablement configuration. Can not be true if corresponding stage is not in use.
*/
- BandEnablement enablement;
+ boolean enable;
}
/**
@@ -134,7 +144,8 @@
@VintfStability
parcelable EqBandConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
@@ -142,17 +153,20 @@
*/
int band;
/**
- * True if EQ stage is enabled.
+ * True if EQ band is enabled.
+ * If EngineArchitecture EQ stage inUse was set to false, then enable can not be set to
+ * true.
*/
boolean enable;
/**
- * Topmost frequency number (in Hz) this band will process.
+ * Topmost frequency number (in Hz) this band will process. Must be in the range of
+ * [minCutOffFreq, maxCutOffFreq] defined in Capability.
*/
- float cutoffFrequency;
+ float cutoffFrequencyHz;
/**
* Gain factor in decibels (dB).
*/
- float gain;
+ float gainDb;
}
/**
@@ -161,51 +175,53 @@
@VintfStability
parcelable MbcBandConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * Band index, must in the range of [0, bandCount-1].
+ * Band index. Must be in the range of [0, bandCount-1].
*/
int band;
/**
- * True if MBC stage is enabled.
+ * True if MBC band is enabled.
+ * If EngineArchitecture MBC inUse was set to false, then enable here can not be set to
+ * true.
*/
boolean enable;
/**
- * Topmost frequency number (in Hz) this band will process.
+ * Topmost frequency number (in Hz) this band will process. Must be in the range of
+ * [minCutOffFreq, maxCutOffFreq] defined in Capability.
*/
float cutoffFrequencyHz;
/**
- * Gain factor in decibels (dB).
- */
- float gainDb;
- /**
- * Attack Time for compressor in milliseconds (ms).
+ * Attack Time for compressor in milliseconds (ms). Must not be negative.
*/
float attackTimeMs;
/**
- * Release Time for compressor in milliseconds (ms).
+ * Release Time for compressor in milliseconds (ms). Must not be negative.
*/
float releaseTimeMs;
/**
- * Compressor ratio (N:1) (input:output).
+ * Compressor ratio (N:1) (input:output). Must not be negative.
*/
float ratio;
/**
- * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). Must not be
+ * positive.
*/
float thresholdDb;
/**
- * Width in decibels (dB) around compressor threshold point.
+ * Width in decibels (dB) around compressor threshold point. Must not be negative.
*/
float kneeWidthDb;
/**
- * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS). Must not be positive.
*/
float noiseGateThresholdDb;
/**
- * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold.
+ * Expander ratio (1:N) (input:output) for signals below the Noise Gate Threshold. Must not
+ * be negative.
*/
float expanderRatio;
/**
@@ -224,36 +240,35 @@
@VintfStability
parcelable LimiterConfig {
/**
- * Channel index.
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
*/
int channel;
/**
- * True if Limiter stage is enabled.
+ * True if Limiter band is enabled.
+ * If EngineArchitecture limiterInUse was set to false, then enable can not be set to true.
*/
boolean enable;
/**
- * True if Limiter stage is in use.
- */
- boolean inUse;
- /**
* Index of group assigned to this Limiter. Only limiters that share the same linkGroup
* index will react together.
*/
int linkGroup;
/**
- * Attack Time for compressor in milliseconds (ms).
+ * Attack Time for compressor in milliseconds (ms). Must not be negative.
*/
float attackTimeMs;
/**
- * Release Time for compressor in milliseconds (ms).
+ * Release Time for compressor in milliseconds (ms). Must not be negative.
*/
float releaseTimeMs;
/**
- * Compressor ratio (N:1) (input:output).
+ * Compressor ratio (N:1) (input:output). Must not be negative.
*/
float ratio;
/**
- * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS).
+ * Compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). Must not be
+ * positive.
*/
float thresholdDb;
/**
@@ -263,39 +278,55 @@
}
/**
+ * Input gain for a channel (specified by the channel index).
+ */
+ @VintfStability
+ parcelable InputGain {
+ /**
+ * Channel index. Must not be negative, and not exceed the channel count calculated from
+ * Parameter.common.input.base.channelMask.
+ */
+ int channel;
+ /**
+ * Gain applied to the input signal in decibels (dB). 0 dB means no change in level.
+ */
+ float gainDb;
+ }
+
+ /**
* Effect engine architecture.
*/
EngineArchitecture engineArchitecture;
/**
- * PreEq stage per channel configuration.
+ * PreEq stage per channel configuration. Only valid when pre EQ stage inUse is true.
*/
- BandChannelConfig preEq;
+ ChannelConfig[] preEq;
/**
- * PostEq stage per channel configuration.
+ * PostEq stage per channel configuration. Only valid when post EQ stage inUse is true.
*/
- BandChannelConfig postEq;
+ ChannelConfig[] postEq;
/**
- * PreEq stage per band configuration.
+ * PreEq stage per band configuration. Only valid when pre EQ stage inUse is true.
*/
- EqBandConfig preEqBand;
+ EqBandConfig[] preEqBand;
/**
- * PostEq stage per band configuration.
+ * PostEq stage per band configuration. Only valid when post EQ stage inUse is true.
*/
- EqBandConfig postEqBand;
+ EqBandConfig[] postEqBand;
/**
- * MBC stage per channel configuration.
+ * MBC stage per channel configuration. Only valid when MBC stage inUse is true.
*/
- BandChannelConfig mbc;
+ ChannelConfig[] mbc;
/**
- * PostEq stage per band configuration.
+ * PostEq stage per band configuration. Only valid when MBC stage inUse is true.
*/
- MbcBandConfig mbcBand;
+ MbcBandConfig[] mbcBand;
/**
- * Limiter stage configuration.
+ * Limiter stage configuration. Only valid when limiter stage inUse is true.
*/
- LimiterConfig limiter;
+ LimiterConfig[] limiter;
/**
- * Input gain factor in decibels (dB). 0 dB means no change in level.
+ * Input gain factor.
*/
- float inputGainDb;
+ InputGain[] inputGain;
}
diff --git a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 81c0dde..fc98fe6 100644
--- a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -50,112 +50,96 @@
VendorExtension extension;
/**
+ * Minimal possible room level in millibels.
+ */
+ int minRoomLevelMb;
+ /**
+ * Maximum possible room level in millibels.
+ */
+ int maxRoomLevelMb;
+ /**
+ * Minimal possible room hf level in millibels.
+ */
+ int minRoomHfLevelMb;
+ /**
+ * Maximum possible room hf level in millibels.
+ */
+ int maxRoomHfLevelMb;
+ /**
* Max decay time supported in millisecond.
*/
int maxDecayTimeMs;
+ /**
+ * Minimal possible per mille decay hf ratio.
+ */
+ int minDecayHfRatioPm;
+ /**
+ * Maximum possible per mille decay hf ratio.
+ */
+ int maxDecayHfRatioPm;
+ /**
+ * Minimal possible room level in millibels.
+ */
+ int minLevelMb;
+ /**
+ * Maximum possible room level in millibels.
+ */
+ int maxLevelMb;
+ /**
+ * Maximum possible delay time in milliseconds.
+ */
+ int maxDelayMs;
+ /**
+ * Maximum possible per mille diffusion.
+ */
+ int maxDiffusionPm;
+ /**
+ * Maximum possible per mille density.
+ */
+ int maxDensityPm;
}
/**
- * Minimal possible room level in millibels.
- */
- const int MIN_ROOM_LEVEL_MB = -6000;
- /**
- * Maximum possible room level in millibels.
- */
- const int MAX_ROOM_LEVEL_MB = 0;
- /**
- * Room level apply to the reverb effect in millibels.
+ * Room level apply to the reverb effect in millibels. The value of the roomLevelMb must be in
+ * range of the value specified by the 'minRoomLevelMb' capability and the 'maxRoomLevelMb'
+ * capability.
*/
int roomLevelMb;
-
/**
- * Minimal possible room hf level in millibels.
- */
- const int MIN_ROOM_HF_LEVEL_MB = -4000;
- /**
- * Maximum possible room hf level in millibels.
- */
- const int MAX_ROOM_HF_LEVEL_MB = 0;
- /**
- * Room HF level apply to the reverb effect in millibels.
+ * Room HF level apply to the reverb effect in millibels. The value of the roomHfLevelMb must be
+ * in range of the value specified by the 'minRoomHfLevelMb' capability and the
+ * 'maxRoomHfLevelMb' capability.
*/
int roomHfLevelMb;
-
/**
- * Minimal possible decay time in milliseconds.
- */
- const int MIN_DECAY_TIME_MS = 100;
- /**
- * Maximum possible decay time in milliseconds.
- */
- const int MAX_DECAY_TIME_MS = 20000;
- /**
- * Delay time apply to the reverb effect in milliseconds.
+ * Delay time apply to the reverb effect in milliseconds.The value of the decayTimeMs must
+ * be non-negative and not exceed the value specified by the 'maxDecayTimeMs' capability.
*/
int decayTimeMs;
-
/**
- * Minimal possible per mille decay hf ratio.
- */
- const int MIN_DECAY_HF_RATIO_PM = 100;
- /**
- * Maximum possible per mille decay hf ratio.
- */
- const int MAX_DECAY_HF_RATIO_PM = 1000;
- /**
- * HF decay ratio in permilles.
+ * HF decay ratio in permilles. The value of the decayHfRatioPm must be in range
+ * of the value specified by the 'minDecayHfRatioPm' capability and the 'maxDecayHfRatioPm'
+ * capability.
*/
int decayHfRatioPm;
-
/**
- * Minimal possible room level in millibels.
- */
- const int MIN_LEVEL_MB = -6000;
- /**
- * Maximum possible room level in millibels.
- */
- const int MAX_LEVEL_MB = 0;
- /**
- * Reverb level in millibels.
+ * Reverb level in millibels. The value of the levelMb must be in range
+ * of the value specified by the 'minLevelMb' capability and the 'maxLevelMb' capability.
*/
int levelMb;
-
/**
- * Minimal possible delay time in milliseconds.
- */
- const int MIN_DELAY_MS = 0;
- /**
- * Maximum possible delay time in milliseconds.
- */
- const int MAX_DELAY_MS = 65;
- /**
- * Reverb delay in milliseconds.
+ * Reverb delay in milliseconds. The value of the delayMs must be non-negative and not
+ * exceed the value specified by the 'maxDelayMs' capability.
*/
int delayMs;
-
/**
- * Minimal possible per mille diffusion.
- */
- const int MIN_DIFFUSION_PM = 0;
- /**
- * Maximum possible per mille diffusion.
- */
- const int MAX_DIFFUSION_PM = 1000;
- /**
- * Diffusion in permilles.
+ * Diffusion in permilles. The value of the diffusionPm must be non-negative and not
+ * exceed the value specified by the 'maxDiffusionPm' capability.
*/
int diffusionPm;
-
/**
- * Minimal possible per mille density.
- */
- const int MIN_DENSITY_PM = 0;
- /**
- * Maximum possible per mille density.
- */
- const int MAX_DENSITY_PM = 1000;
- /**
- * Density in permilles.
+ * Density in permilles. The value of the densityPm must be non-negative and not
+ * exceed the value specified by the 'maxDensityPm' capability.
*/
int densityPm;
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index 6f23636..1e6785f 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -156,7 +156,7 @@
"libbassboostsw",
"libbundleaidl",
"libdownmixaidl",
- "libdynamicsprocessingsw",
+ "libdynamicsprocessingaidl",
"libenvreverbsw",
"libequalizersw",
"libhapticgeneratoraidl",
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index e8b5bfc..13b04cd 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -46,6 +46,7 @@
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioProfile;
+using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::PcmType;
using android::hardware::audio::common::getFrameSizeInBytes;
@@ -138,12 +139,15 @@
(flags.getTag() == AudioIoFlags::Tag::output &&
!isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::output>(),
AudioOutputFlags::MMAP_NOIRQ))) {
+ StreamContext::DebugParameters params{mDebug.streamTransientStateDelayMs,
+ mVendorDebug.forceTransientBurst,
+ mVendorDebug.forceSynchronousDrain};
StreamContext temp(
std::make_unique<StreamContext::CommandMQ>(1, true /*configureEventFlagWord*/),
std::make_unique<StreamContext::ReplyMQ>(1, true /*configureEventFlagWord*/),
portConfigIt->format.value(), portConfigIt->channelMask.value(),
std::make_unique<StreamContext::DataMQ>(frameSize * in_bufferSizeFrames),
- asyncCallback, mDebug.streamTransientStateDelayMs);
+ asyncCallback, params);
if (temp.isValid()) {
*out_context = std::move(temp);
} else {
@@ -976,18 +980,69 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+const std::string Module::VendorDebug::kForceTransientBurstName = "aosp.forceTransientBurst";
+const std::string Module::VendorDebug::kForceSynchronousDrainName = "aosp.forceSynchronousDrain";
+
ndk::ScopedAStatus Module::getVendorParameters(const std::vector<std::string>& in_ids,
std::vector<VendorParameter>* _aidl_return) {
LOG(DEBUG) << __func__ << ": id count: " << in_ids.size();
- (void)_aidl_return;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ bool allParametersKnown = true;
+ for (const auto& id : in_ids) {
+ if (id == VendorDebug::kForceTransientBurstName) {
+ VendorParameter forceTransientBurst{.id = id};
+ forceTransientBurst.ext.setParcelable(Boolean{mVendorDebug.forceTransientBurst});
+ _aidl_return->push_back(std::move(forceTransientBurst));
+ } else if (id == VendorDebug::kForceSynchronousDrainName) {
+ VendorParameter forceSynchronousDrain{.id = id};
+ forceSynchronousDrain.ext.setParcelable(Boolean{mVendorDebug.forceSynchronousDrain});
+ _aidl_return->push_back(std::move(forceSynchronousDrain));
+ } else {
+ allParametersKnown = false;
+ LOG(ERROR) << __func__ << ": unrecognized parameter \"" << id << "\"";
+ }
+ }
+ if (allParametersKnown) return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
+namespace {
+
+template <typename W>
+bool extractParameter(const VendorParameter& p, decltype(W::value)* v) {
+ std::optional<W> value;
+ binder_status_t result = p.ext.getParcelable(&value);
+ if (result == STATUS_OK && value.has_value()) {
+ *v = value.value().value;
+ return true;
+ }
+ LOG(ERROR) << __func__ << ": failed to read the value of the parameter \"" << p.id
+ << "\": " << result;
+ return false;
+}
+
+} // namespace
+
ndk::ScopedAStatus Module::setVendorParameters(const std::vector<VendorParameter>& in_parameters,
bool in_async) {
LOG(DEBUG) << __func__ << ": parameter count " << in_parameters.size()
<< ", async: " << in_async;
- return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+ bool allParametersKnown = true;
+ for (const auto& p : in_parameters) {
+ if (p.id == VendorDebug::kForceTransientBurstName) {
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceTransientBurst)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ } else if (p.id == VendorDebug::kForceSynchronousDrainName) {
+ if (!extractParameter<Boolean>(p, &mVendorDebug.forceSynchronousDrain)) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ } else {
+ allParametersKnown = false;
+ LOG(ERROR) << __func__ << ": unrecognized parameter \"" << p.id << "\"";
+ }
+ }
+ if (allParametersKnown) return ndk::ScopedAStatus::ok();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
ndk::ScopedAStatus Module::addDeviceEffect(
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index a490a2a..0520cba 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -402,7 +402,11 @@
usleep(1000); // Simulate a blocking call into the driver.
populateReply(&reply, mIsConnected);
// Can switch the state to ERROR if a driver error occurs.
- switchToTransientState(StreamDescriptor::State::DRAINING);
+ if (mState == StreamDescriptor::State::ACTIVE && mForceSynchronousDrain) {
+ mState = StreamDescriptor::State::IDLE;
+ } else {
+ switchToTransientState(StreamDescriptor::State::DRAINING);
+ }
} else if (mState == StreamDescriptor::State::TRANSFER_PAUSED) {
mState = StreamDescriptor::State::DRAIN_PAUSED;
populateReply(&reply, mIsConnected);
@@ -467,14 +471,19 @@
bool StreamOutWorkerLogic::write(size_t clientSize, StreamDescriptor::Reply* reply) {
const size_t readByteCount = mDataMQ->availableToRead();
- // Amount of data that the HAL module is going to actually use.
- const size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
bool fatal = false;
if (bool success = readByteCount > 0 ? mDataMQ->read(&mDataBuffer[0], readByteCount) : true) {
const bool isConnected = mIsConnected;
LOG(DEBUG) << __func__ << ": reading of " << readByteCount << " bytes from data MQ"
<< " succeeded; connected? " << isConnected;
- // Frames are consumed and counted regardless of connection status.
+ // Amount of data that the HAL module is going to actually use.
+ size_t byteCount = std::min({clientSize, readByteCount, mDataBufferSize});
+ if (byteCount >= mFrameSize && mForceTransientBurst) {
+ // In order to prevent the state machine from going to ACTIVE state,
+ // simulate partial write.
+ byteCount -= mFrameSize;
+ }
+ // Frames are consumed and counted regardless of the connection status.
reply->fmqByteCount += byteCount;
mFrameCount += byteCount / mFrameSize;
populateReply(reply, isConnected);
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
index 7f06013..40b46e0 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.cpp
@@ -54,7 +54,6 @@
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = AcousticEchoCancelerSw::kDescriptor;
- LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
return EX_NONE;
}
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index 9670e9c..e460f89 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -33,7 +33,7 @@
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
<library name="downmix" path="libdownmixaidl.so"/>
- <library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
+ <library name="dynamics_processing" path="libdynamicsprocessingaidl.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
<library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
@@ -72,7 +72,7 @@
<libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
</effectProxy>
<effect name="downmix" library="downmix" uuid="93f04452-e4fe-41cc-91f9-e475b6d1d69f"/>
- <effect name="dynamics_processing" library="dynamics_processingsw" uuid="fa818d78-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="dynamics_processing" library="dynamics_processing" uuid="e0e6539b-1781-7261-676f-6d7573696340"/>
<effect name="haptic_generator" library="haptic_generator" uuid="97c4acd1-8b82-4f2f-832e-c2fe5d7a9931"/>
<effect name="loudness_enhancer" library="loudness_enhancer" uuid="fa415329-2034-4bea-b5dc-5b381c8d1e2c"/>
<effect name="env_reverb" library="env_reverbsw" uuid="fa819886-588b-11ed-9b6a-0242ac120002"/>
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
index 39345a9..0ffbaa1 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "AHAL_DynamicsProcessingSw"
#include <Utils.h>
#include <algorithm>
+#include <set>
#include <unordered_set>
#include <android-base/logging.h>
@@ -60,7 +61,8 @@
namespace aidl::android::hardware::audio::effect {
const std::string DynamicsProcessingSw::kEffectName = "DynamicsProcessingSw";
-const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability;
+const DynamicsProcessing::Capability DynamicsProcessingSw::kCapability = {.minCutOffFreq = 220,
+ .maxCutOffFreq = 20000};
const Descriptor DynamicsProcessingSw::kDescriptor = {
.common = {.id = {.type = kDynamicsProcessingTypeUUID,
.uuid = kDynamicsProcessingSwImplUUID,
@@ -83,16 +85,143 @@
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::dynamicsProcessing>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LOG(INFO) << __func__ << specific.toString();
+ auto& dpParam = specific.get<Parameter::Specific::dynamicsProcessing>();
+ auto tag = dpParam.getTag();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ RETURN_IF(mContext->setEngineArchitecture(
+ dpParam.get<DynamicsProcessing::engineArchitecture>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEq: {
+ RETURN_IF(mContext->setPreEqChannelCfgs(dpParam.get<DynamicsProcessing::preEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEq: {
+ RETURN_IF(mContext->setPostEqChannelCfgs(dpParam.get<DynamicsProcessing::postEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbc: {
+ RETURN_IF(mContext->setMbcChannelCfgs(dpParam.get<DynamicsProcessing::mbc>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcChannelCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEqBand: {
+ RETURN_IF(mContext->setPreEqBandCfgs(dpParam.get<DynamicsProcessing::preEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEqBand: {
+ RETURN_IF(mContext->setPostEqBandCfgs(dpParam.get<DynamicsProcessing::postEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbcBand: {
+ RETURN_IF(mContext->setMbcBandCfgs(dpParam.get<DynamicsProcessing::mbcBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcBandCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::limiter: {
+ RETURN_IF(mContext->setLimiterCfgs(dpParam.get<DynamicsProcessing::limiter>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "limiterCfgsFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::inputGain: {
+ RETURN_IF(mContext->setInputGainCfgs(dpParam.get<DynamicsProcessing::inputGain>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "inputGainCfgFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus DynamicsProcessingSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::dynamicsProcessing>(mSpecificParam);
+ auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+ auto dpIdTag = dpId.getTag();
+ switch (dpIdTag) {
+ case DynamicsProcessing::Id::commonTag:
+ return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+ specific);
+ case DynamicsProcessing::Id::vendorExtensionTag:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(dpIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingSw::getParameterDynamicsProcessing(
+ const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ DynamicsProcessing dpParam;
+ switch (tag) {
+ case DynamicsProcessing::Tag::engineArchitecture: {
+ dpParam.set<DynamicsProcessing::engineArchitecture>(mContext->getEngineArchitecture());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEq: {
+ dpParam.set<DynamicsProcessing::preEq>(mContext->getPreEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEq: {
+ dpParam.set<DynamicsProcessing::postEq>(mContext->getPostEqChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbc: {
+ dpParam.set<DynamicsProcessing::mbc>(mContext->getMbcChannelCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::preEqBand: {
+ dpParam.set<DynamicsProcessing::preEqBand>(mContext->getPreEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::postEqBand: {
+ dpParam.set<DynamicsProcessing::postEqBand>(mContext->getPostEqBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::mbcBand: {
+ dpParam.set<DynamicsProcessing::mbcBand>(mContext->getMbcBandCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::limiter: {
+ dpParam.set<DynamicsProcessing::limiter>(mContext->getLimiterCfgs());
+ break;
+ }
+ case DynamicsProcessing::Tag::inputGain: {
+ dpParam.set<DynamicsProcessing::inputGain>(mContext->getInputGainCfgs());
+ break;
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DynamicsProcessingTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::dynamicsProcessing>(dpParam);
+ LOG(INFO) << __func__ << specific->toString();
return ndk::ScopedAStatus::ok();
}
@@ -127,4 +256,252 @@
return {STATUS_OK, samples, samples};
}
+RetCode DynamicsProcessingSwContext::setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ mChannelCount =
+ ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask);
+ resizeChannels();
+ resizeBands();
+ LOG(INFO) << __func__ << mCommon.toString();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setEngineArchitecture(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ RETURN_VALUE_IF(!validateEngineConfig(cfg), RetCode::ERROR_ILLEGAL_PARAMETER,
+ "illegalEngineConfig");
+
+ if (mEngineSettings == cfg) {
+ LOG(INFO) << __func__ << " not change in engine, do nothing";
+ return RetCode::SUCCESS;
+ }
+ mEngineSettings = cfg;
+ resizeBands();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingSwContext::setChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+ for (auto& cfg : cfgs) {
+ if (cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount) {
+ LOG(ERROR) << __func__ << " skip illegal channel config " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ if (0 != channelSet.count(cfg.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << cfg.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(cfg.channel);
+ }
+ targetCfgs[cfg.channel] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPreEqChCfgs, mEngineSettings.preEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mPostEqChCfgs, mEngineSettings.postEqStage);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcChannelCfgs(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ return setChannelCfgs(cfgs, mMbcChCfgs, mEngineSettings.mbcStage);
+}
+
+RetCode DynamicsProcessingSwContext::setEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ RETURN_VALUE_IF(!stage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER, "eqStageNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ for (auto& cfg : cfgs) {
+ if (0 != bandSet.count({cfg.channel, cfg.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ if (!validateEqBandConfig(cfg, mChannelCount, stage.bandCount, channelConfig)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << cfg.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ targetCfgs[cfg.channel * stage.bandCount + cfg.band] = cfg;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setPreEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPreEqChBands, mEngineSettings.preEqStage, mPreEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setPostEqBandCfgs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ return setEqBandCfgs(cfgs, mPostEqChBands, mEngineSettings.postEqStage, mPostEqChCfgs);
+}
+
+RetCode DynamicsProcessingSwContext::setMbcBandCfgs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "mbcNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ int bandCount = mEngineSettings.mbcStage.bandCount;
+ std::vector<bool> filled(mChannelCount * bandCount, false);
+ for (auto& it : cfgs) {
+ if (0 != bandSet.count({it.channel, it.band})) {
+ LOG(WARNING) << __func__ << " duplicated band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ bandSet.insert({it.channel, it.band});
+ }
+ if (!validateMbcBandConfig(it, mChannelCount, mEngineSettings.mbcStage.bandCount,
+ mMbcChCfgs)) {
+ LOG(WARNING) << __func__ << " skip invalid band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ ;
+ }
+ mMbcChBands[it.channel * bandCount + it.band] = it;
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingSwContext::setLimiterCfgs(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ RETURN_VALUE_IF(!mEngineSettings.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "limiterNotInUse");
+
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+
+ for (auto& it : cfgs) {
+ if (0 != channelSet.count(it.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(it.channel);
+ }
+ if (!validateLimiterConfig(it, mChannelCount)) {
+ LOG(WARNING) << __func__ << " skip invalid limiter " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ mLimiterCfgs[it.channel] = it;
+ }
+ return ret;
+}
+
+void DynamicsProcessingSwContext::resizeChannels() {
+ if (mPreEqChCfgs.size() != mChannelCount) {
+ mPreEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChCfgs.size() != mChannelCount) {
+ mPostEqChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mMbcChCfgs.size() != mChannelCount) {
+ mMbcChCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mLimiterCfgs.size() != mChannelCount) {
+ mLimiterCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+ if (mInputGainCfgs.size() != mChannelCount) {
+ mInputGainCfgs.resize(mChannelCount, {.channel = kInvalidChannelId});
+ }
+}
+
+void DynamicsProcessingSwContext::resizeBands() {
+ if (mPreEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.preEqStage.bandCount)) {
+ mPreEqChBands.resize(mChannelCount * mEngineSettings.preEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mPostEqChBands.size() != (size_t)(mChannelCount * mEngineSettings.postEqStage.bandCount)) {
+ mPostEqChBands.resize(mChannelCount * mEngineSettings.postEqStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+ if (mMbcChBands.size() != (size_t)(mChannelCount * mEngineSettings.mbcStage.bandCount)) {
+ mMbcChBands.resize(mChannelCount * mEngineSettings.mbcStage.bandCount,
+ {.channel = kInvalidChannelId});
+ }
+}
+
+RetCode DynamicsProcessingSwContext::setInputGainCfgs(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ for (const auto& cfg : cfgs) {
+ RETURN_VALUE_IF(cfg.channel < 0 || (size_t)cfg.channel >= mChannelCount,
+ RetCode::ERROR_ILLEGAL_PARAMETER, "invalidChannel");
+ mInputGainCfgs[cfg.channel] = cfg;
+ }
+ return RetCode::SUCCESS;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingSwContext::getInputGainCfgs() {
+ std::vector<DynamicsProcessing::InputGain> ret;
+ std::copy_if(mInputGainCfgs.begin(), mInputGainCfgs.end(), std::back_inserter(ret),
+ [&](const auto& gain) { return gain.channel != kInvalidChannelId; });
+ return ret;
+}
+
+bool DynamicsProcessingSwContext::validateCutoffFrequency(float freq) {
+ return freq >= DynamicsProcessingSw::kCapability.minCutOffFreq &&
+ freq <= DynamicsProcessingSw::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingSwContext::validateStageEnablement(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingSwContext::validateEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& engine) {
+ return engine.preferredProcessingDurationMs >= 0 &&
+ validateStageEnablement(engine.preEqStage) &&
+ validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+bool DynamicsProcessingSwContext::validateEqBandConfig(
+ const DynamicsProcessing::EqBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand && validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingSwContext::validateMbcBandConfig(
+ const DynamicsProcessing::MbcBandConfig& band, int maxChannel, int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig) {
+ return band.channel >= 0 && band.channel < maxChannel &&
+ (size_t)band.channel < channelConfig.size() && channelConfig[band.channel].enable &&
+ band.band >= 0 && band.band < maxBand &&
+ validateCutoffFrequency(band.cutoffFrequencyHz) && band.attackTimeMs >= 0 &&
+ band.releaseTimeMs >= 0 && band.ratio >= 0 && band.thresholdDb <= 0 &&
+ band.kneeWidthDb <= 0 && band.noiseGateThresholdDb <= 0 && band.expanderRatio >= 0;
+}
+
+bool DynamicsProcessingSwContext::validateLimiterConfig(
+ const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+ return limiter.channel >= 0 && limiter.channel < maxChannel && limiter.attackTimeMs >= 0 &&
+ limiter.releaseTimeMs >= 0 && limiter.ratio >= 0 && limiter.thresholdDb <= 0;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
index 2ae46c5..e336df7 100644
--- a/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
+++ b/audio/aidl/default/dynamicProcessing/DynamicsProcessingSw.h
@@ -29,11 +29,77 @@
class DynamicsProcessingSwContext final : public EffectContext {
public:
DynamicsProcessingSwContext(int statusDepth, const Parameter::Common& common)
- : EffectContext(statusDepth, common) {
+ : EffectContext(statusDepth, common),
+ mChannelCount(::android::hardware::audio::common::getChannelCount(
+ common.input.base.channelMask)),
+ mPreEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mPostEqChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mMbcChCfgs(mChannelCount, {.channel = kInvalidChannelId}),
+ mLimiterCfgs(mChannelCount, {.channel = kInvalidChannelId}) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
-};
+
+ // utils
+ RetCode setChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ std::vector<DynamicsProcessing::ChannelConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& engineSetting);
+
+ RetCode setEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ std::vector<DynamicsProcessing::EqBandConfig>& targetCfgs,
+ const DynamicsProcessing::StageEnablement& stage,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+
+ // set params
+ RetCode setCommon(const Parameter::Common& common) override;
+ RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& cfg);
+ RetCode setPreEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPostEqChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setMbcChannelCfgs(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs);
+ RetCode setPreEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setPostEqBandCfgs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ RetCode setMbcBandCfgs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ RetCode setLimiterCfgs(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs);
+ RetCode setInputGainCfgs(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ // get params
+ DynamicsProcessing::EngineArchitecture getEngineArchitecture() { return mEngineSettings; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPreEqChannelCfgs() { return mPreEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getPostEqChannelCfgs() { return mPostEqChCfgs; }
+ std::vector<DynamicsProcessing::ChannelConfig> getMbcChannelCfgs() { return mMbcChCfgs; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPreEqBandCfgs() { return mPreEqChBands; }
+ std::vector<DynamicsProcessing::EqBandConfig> getPostEqBandCfgs() { return mPostEqChBands; }
+ std::vector<DynamicsProcessing::MbcBandConfig> getMbcBandCfgs() { return mMbcChBands; }
+ std::vector<DynamicsProcessing::LimiterConfig> getLimiterCfgs() { return mLimiterCfgs; }
+ std::vector<DynamicsProcessing::InputGain> getInputGainCfgs();
+
+ private:
+ static constexpr int32_t kInvalidChannelId = -1;
+ size_t mChannelCount = 0;
+ DynamicsProcessing::EngineArchitecture mEngineSettings;
+ // Channel config vector with size of mChannelCount
+ std::vector<DynamicsProcessing::ChannelConfig> mPreEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mPostEqChCfgs;
+ std::vector<DynamicsProcessing::ChannelConfig> mMbcChCfgs;
+ std::vector<DynamicsProcessing::LimiterConfig> mLimiterCfgs;
+ std::vector<DynamicsProcessing::InputGain> mInputGainCfgs;
+ // Band config vector with size of mChannelCount * bandCount
+ std::vector<DynamicsProcessing::EqBandConfig> mPreEqChBands;
+ std::vector<DynamicsProcessing::EqBandConfig> mPostEqChBands;
+ std::vector<DynamicsProcessing::MbcBandConfig> mMbcChBands;
+
+ bool validateCutoffFrequency(float freq);
+ bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+ bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+ bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+ int maxBand,
+ const std::vector<DynamicsProcessing::ChannelConfig>& channelConfig);
+ bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+ void resizeChannels();
+ void resizeBands();
+}; // DynamicsProcessingSwContext
class DynamicsProcessingSw final : public EffectImpl {
public:
@@ -60,7 +126,9 @@
private:
std::shared_ptr<DynamicsProcessingSwContext> mContext;
- /* parameters */
- DynamicsProcessing mSpecificParam;
-};
+ ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+ Parameter::Specific* specific);
+
+}; // DynamicsProcessingSw
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index 9d7159a..905dba4 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -60,8 +60,18 @@
namespace aidl::android::hardware::audio::effect {
const std::string EnvReverbSw::kEffectName = "EnvReverbSw";
-const EnvironmentalReverb::Capability EnvReverbSw::kCapability = {
- .maxDecayTimeMs = EnvironmentalReverb::MAX_DECAY_TIME_MS};
+const EnvironmentalReverb::Capability EnvReverbSw::kCapability = {.minRoomLevelMb = -6000,
+ .maxRoomLevelMb = 0,
+ .minRoomHfLevelMb = -4000,
+ .maxRoomHfLevelMb = 0,
+ .maxDecayTimeMs = 7000,
+ .minDecayHfRatioPm = 100,
+ .maxDecayHfRatioPm = 2000,
+ .minLevelMb = -6000,
+ .maxLevelMb = 0,
+ .maxDelayMs = 65,
+ .maxDiffusionPm = 1000,
+ .maxDensityPm = 1000};
const Descriptor EnvReverbSw::kDescriptor = {
.common = {.id = {.type = kEnvReverbTypeUUID,
.uuid = kEnvReverbSwImplUUID,
@@ -251,4 +261,88 @@
return {STATUS_OK, samples, samples};
}
+RetCode EnvReverbSwContext::setErRoomLevel(int roomLevel) {
+ if (roomLevel < EnvReverbSw::kCapability.minRoomLevelMb ||
+ roomLevel > EnvReverbSw::kCapability.maxRoomLevelMb) {
+ LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new room level
+ mRoomLevel = roomLevel;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErRoomHfLevel(int roomHfLevel) {
+ if (roomHfLevel < EnvReverbSw::kCapability.minRoomHfLevelMb ||
+ roomHfLevel > EnvReverbSw::kCapability.maxRoomHfLevelMb) {
+ LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new room HF level
+ mRoomHfLevel = roomHfLevel;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErDecayTime(int decayTime) {
+ if (decayTime < 0 || decayTime > EnvReverbSw::kCapability.maxDecayTimeMs) {
+ LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new decay time
+ mDecayTime = decayTime;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErDecayHfRatio(int decayHfRatio) {
+ if (decayHfRatio < EnvReverbSw::kCapability.minDecayHfRatioPm ||
+ decayHfRatio > EnvReverbSw::kCapability.maxDecayHfRatioPm) {
+ LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new decay HF ratio
+ mDecayHfRatio = decayHfRatio;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErLevel(int level) {
+ if (level < EnvReverbSw::kCapability.minLevelMb ||
+ level > EnvReverbSw::kCapability.maxLevelMb) {
+ LOG(ERROR) << __func__ << " invalid level: " << level;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new level
+ mLevel = level;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErDelay(int delay) {
+ if (delay < 0 || delay > EnvReverbSw::kCapability.maxDelayMs) {
+ LOG(ERROR) << __func__ << " invalid delay: " << delay;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new delay
+ mDelay = delay;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErDiffusion(int diffusion) {
+ if (diffusion < 0 || diffusion > EnvReverbSw::kCapability.maxDiffusionPm) {
+ LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new diffusion
+ mDiffusion = diffusion;
+ return RetCode::SUCCESS;
+}
+
+RetCode EnvReverbSwContext::setErDensity(int density) {
+ if (density < 0 || density > EnvReverbSw::kCapability.maxDensityPm) {
+ LOG(ERROR) << __func__ << " invalid density: " << density;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new density
+ mDensity = density;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index f521215..77f384e 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -33,100 +33,28 @@
LOG(DEBUG) << __func__;
}
- RetCode setErRoomLevel(int roomLevel) {
- if (roomLevel < EnvironmentalReverb::MIN_ROOM_LEVEL_MB ||
- roomLevel > EnvironmentalReverb::MAX_ROOM_LEVEL_MB) {
- LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new room level
- mRoomLevel = roomLevel;
- return RetCode::SUCCESS;
- }
+ RetCode setErRoomLevel(int roomLevel);
int getErRoomLevel() const { return mRoomLevel; }
- RetCode setErRoomHfLevel(int roomHfLevel) {
- if (roomHfLevel < EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB ||
- roomHfLevel > EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB) {
- LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new room HF level
- mRoomHfLevel = roomHfLevel;
- return RetCode::SUCCESS;
- }
+ RetCode setErRoomHfLevel(int roomHfLevel);
int getErRoomHfLevel() const { return mRoomHfLevel; }
- RetCode setErDecayTime(int decayTime) {
- if (decayTime < EnvironmentalReverb::MIN_DECAY_TIME_MS ||
- decayTime > EnvironmentalReverb::MAX_DECAY_TIME_MS) {
- LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new decay time
- mDecayTime = decayTime;
- return RetCode::SUCCESS;
- }
+ RetCode setErDecayTime(int decayTime);
int getErDecayTime() const { return mDecayTime; }
- RetCode setErDecayHfRatio(int decayHfRatio) {
- if (decayHfRatio < EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM ||
- decayHfRatio > EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM) {
- LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new decay HF ratio
- mDecayHfRatio = decayHfRatio;
- return RetCode::SUCCESS;
- }
+ RetCode setErDecayHfRatio(int decayHfRatio);
int getErDecayHfRatio() const { return mDecayHfRatio; }
- RetCode setErLevel(int level) {
- if (level < EnvironmentalReverb::MIN_LEVEL_MB ||
- level > EnvironmentalReverb::MAX_LEVEL_MB) {
- LOG(ERROR) << __func__ << " invalid level: " << level;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new level
- mLevel = level;
- return RetCode::SUCCESS;
- }
+ RetCode setErLevel(int level);
int getErLevel() const { return mLevel; }
- RetCode setErDelay(int delay) {
- if (delay < EnvironmentalReverb::MIN_DELAY_MS ||
- delay > EnvironmentalReverb::MAX_DELAY_MS) {
- LOG(ERROR) << __func__ << " invalid delay: " << delay;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new delay
- mDelay = delay;
- return RetCode::SUCCESS;
- }
+ RetCode setErDelay(int delay);
int getErDelay() const { return mDelay; }
- RetCode setErDiffusion(int diffusion) {
- if (diffusion < EnvironmentalReverb::MIN_DIFFUSION_PM ||
- diffusion > EnvironmentalReverb::MAX_DIFFUSION_PM) {
- LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new diffusion
- mDiffusion = diffusion;
- return RetCode::SUCCESS;
- }
+ RetCode setErDiffusion(int diffusion);
int getErDiffusion() const { return mDiffusion; }
- RetCode setErDensity(int density) {
- if (density < EnvironmentalReverb::MIN_DENSITY_PM ||
- density > EnvironmentalReverb::MAX_DENSITY_PM) {
- LOG(ERROR) << __func__ << " invalid density: " << density;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new density
- mDensity = density;
- return RetCode::SUCCESS;
- }
+ RetCode setErDensity(int density);
int getErDensity() const { return mDensity; }
RetCode setErBypass(bool bypass) {
@@ -137,14 +65,14 @@
bool getErBypass() const { return mBypass; }
private:
- int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB; // Default room level
- int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB; // Default room hf level
+ int mRoomLevel = -6000; // Default room level
+ int mRoomHfLevel = 0; // Default room hf level
int mDecayTime = 1000; // Default decay time
int mDecayHfRatio = 500; // Default decay hf ratio
- int mLevel = EnvironmentalReverb::MIN_LEVEL_MB; // Default level
+ int mLevel = -6000; // Default level
int mDelay = 40; // Default delay
- int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM; // Default diffusion
- int mDensity = EnvironmentalReverb::MAX_DENSITY_PM; // Default density
+ int mDiffusion = 1000; // Default diffusion
+ int mDensity = 1000; // Default density
bool mBypass = false; // Default bypass
};
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index e9f43d8..000a704 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -36,6 +36,13 @@
explicit Module(Type type) : mType(type) {}
private:
+ struct VendorDebug {
+ static const std::string kForceTransientBurstName;
+ static const std::string kForceSynchronousDrainName;
+ bool forceTransientBurst = false;
+ bool forceSynchronousDrain = false;
+ };
+
ndk::ScopedAStatus setModuleDebug(
const ::aidl::android::hardware::audio::core::ModuleDebug& in_debug) override;
ndk::ScopedAStatus getTelephony(std::shared_ptr<ITelephony>* _aidl_return) override;
@@ -128,6 +135,7 @@
const Type mType;
std::unique_ptr<internal::Configuration> mConfig;
ModuleDebug mDebug;
+ VendorDebug mVendorDebug;
// For the interfaces requiring to return the same instance, we need to hold them
// via a strong pointer. The binder token is retained for a call to 'setMinSchedulerPolicy'.
std::shared_ptr<ITelephony> mTelephony;
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index 5abd4de..2cf5951 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -62,12 +62,21 @@
// Ensure that this value is not used by any of StreamDescriptor.State enums
static constexpr int32_t STATE_CLOSED = -1;
+ struct DebugParameters {
+ // An extra delay for transient states, in ms.
+ int transientStateDelayMs = 0;
+ // Force the "burst" command to move the SM to the TRANSFERRING state.
+ bool forceTransientBurst = false;
+ // Force the "drain" command to be synchronous, going directly to the IDLE state.
+ bool forceSynchronousDrain = false;
+ };
+
StreamContext() = default;
StreamContext(std::unique_ptr<CommandMQ> commandMQ, std::unique_ptr<ReplyMQ> replyMQ,
const ::aidl::android::media::audio::common::AudioFormatDescription& format,
const ::aidl::android::media::audio::common::AudioChannelLayout& channelLayout,
std::unique_ptr<DataMQ> dataMQ, std::shared_ptr<IStreamCallback> asyncCallback,
- int transientStateDelayMs)
+ DebugParameters debugParameters)
: mCommandMQ(std::move(commandMQ)),
mInternalCommandCookie(std::rand()),
mReplyMQ(std::move(replyMQ)),
@@ -75,7 +84,7 @@
mChannelLayout(channelLayout),
mDataMQ(std::move(dataMQ)),
mAsyncCallback(asyncCallback),
- mTransientStateDelayMs(transientStateDelayMs) {}
+ mDebugParameters(debugParameters) {}
StreamContext(StreamContext&& other)
: mCommandMQ(std::move(other.mCommandMQ)),
mInternalCommandCookie(other.mInternalCommandCookie),
@@ -83,8 +92,8 @@
mFormat(other.mFormat),
mChannelLayout(other.mChannelLayout),
mDataMQ(std::move(other.mDataMQ)),
- mAsyncCallback(other.mAsyncCallback),
- mTransientStateDelayMs(other.mTransientStateDelayMs) {}
+ mAsyncCallback(std::move(other.mAsyncCallback)),
+ mDebugParameters(std::move(other.mDebugParameters)) {}
StreamContext& operator=(StreamContext&& other) {
mCommandMQ = std::move(other.mCommandMQ);
mInternalCommandCookie = other.mInternalCommandCookie;
@@ -92,8 +101,8 @@
mFormat = std::move(other.mFormat);
mChannelLayout = std::move(other.mChannelLayout);
mDataMQ = std::move(other.mDataMQ);
- mAsyncCallback = other.mAsyncCallback;
- mTransientStateDelayMs = other.mTransientStateDelayMs;
+ mAsyncCallback = std::move(other.mAsyncCallback);
+ mDebugParameters = std::move(other.mDebugParameters);
return *this;
}
@@ -107,10 +116,12 @@
::aidl::android::media::audio::common::AudioFormatDescription getFormat() const {
return mFormat;
}
+ bool getForceTransientBurst() const { return mDebugParameters.forceTransientBurst; }
+ bool getForceSynchronousDrain() const { return mDebugParameters.forceSynchronousDrain; }
size_t getFrameSize() const;
int getInternalCommandCookie() const { return mInternalCommandCookie; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
- int getTransientStateDelayMs() const { return mTransientStateDelayMs; }
+ int getTransientStateDelayMs() const { return mDebugParameters.transientStateDelayMs; }
bool isValid() const;
void reset();
@@ -122,7 +133,7 @@
::aidl::android::media::audio::common::AudioChannelLayout mChannelLayout;
std::unique_ptr<DataMQ> mDataMQ;
std::shared_ptr<IStreamCallback> mAsyncCallback;
- int mTransientStateDelayMs;
+ DebugParameters mDebugParameters;
};
class StreamWorkerCommonLogic : public ::android::hardware::audio::common::StreamLogic {
@@ -141,7 +152,9 @@
mReplyMQ(context.getReplyMQ()),
mDataMQ(context.getDataMQ()),
mAsyncCallback(context.getAsyncCallback()),
- mTransientStateDelayMs(context.getTransientStateDelayMs()) {}
+ mTransientStateDelayMs(context.getTransientStateDelayMs()),
+ mForceTransientBurst(context.getForceTransientBurst()),
+ mForceSynchronousDrain(context.getForceSynchronousDrain()) {}
std::string init() override;
void populateReply(StreamDescriptor::Reply* reply, bool isConnected) const;
void populateReplyWrongState(StreamDescriptor::Reply* reply,
@@ -164,6 +177,8 @@
std::shared_ptr<IStreamCallback> mAsyncCallback;
const std::chrono::duration<int, std::milli> mTransientStateDelayMs;
std::chrono::time_point<std::chrono::steady_clock> mTransientStateStart;
+ const bool mForceTransientBurst;
+ const bool mForceSynchronousDrain;
// We use an array and the "size" field instead of a vector to be able to detect
// memory allocation issues.
std::unique_ptr<int8_t[]> mDataBuffer;
diff --git a/audio/aidl/default/include/effect-impl/EffectContext.h b/audio/aidl/default/include/effect-impl/EffectContext.h
index 1f39db0..a3e7ff2 100644
--- a/audio/aidl/default/include/effect-impl/EffectContext.h
+++ b/audio/aidl/default/include/effect-impl/EffectContext.h
@@ -119,11 +119,11 @@
virtual RetCode setCommon(const Parameter::Common& common) {
mCommon = common;
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return RetCode::SUCCESS;
}
virtual Parameter::Common getCommon() {
- LOG(ERROR) << __func__ << mCommon.toString();
+ LOG(INFO) << __func__ << mCommon.toString();
return mCommon;
}
diff --git a/audio/aidl/default/include/effect-impl/EffectTypes.h b/audio/aidl/default/include/effect-impl/EffectTypes.h
index 58c8672..b100a2e 100644
--- a/audio/aidl/default/include/effect-impl/EffectTypes.h
+++ b/audio/aidl/default/include/effect-impl/EffectTypes.h
@@ -98,12 +98,13 @@
} \
} while (0)
-#define RETURN_VALUE_IF(expr, ret, log) \
- do { \
- if (expr) { \
- LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr " << #expr << (log); \
- return ret; \
- } \
+#define RETURN_VALUE_IF(expr, ret, log) \
+ do { \
+ if (expr) { \
+ LOG(ERROR) << __func__ << ":" << __LINE__ << " return with expr \"" << #expr \
+ << "\":" << (log); \
+ return ret; \
+ } \
} while (0)
#define RETURN_IF_BINDER_EXCEPTION(functor) \
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 6eec29e..1a60829 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -135,6 +135,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// e0e6539b-1781-7261-676f-6d7573696340
+static const AudioUuid kDynamicsProcessingImplUUID = {static_cast<int32_t>(0xe0e6539b),
+ 0x1781,
+ 0x7261,
+ 0x676f,
+ {0x6d, 0x75, 0x73, 0x69, 0x63, 0x40}};
// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
0xaecd,
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index becdf1b..f9d12dd 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -81,6 +81,12 @@
}
cc_test {
+ name: "VtsHalDynamicsProcessingTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalDynamicsProcessingTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEnvironmentalReverbTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 8da475e..d4f2811 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -18,6 +18,7 @@
#include <chrono>
#include <cmath>
#include <condition_variable>
+#include <forward_list>
#include <limits>
#include <memory>
#include <mutex>
@@ -85,6 +86,7 @@
using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioSource;
using aidl::android::media::audio::common::AudioUsage;
+using aidl::android::media::audio::common::Boolean;
using aidl::android::media::audio::common::Float;
using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::Void;
@@ -126,7 +128,7 @@
return WithDebugFlags(parent.mFlags);
}
- WithDebugFlags() {}
+ WithDebugFlags() = default;
explicit WithDebugFlags(const ModuleDebug& initial) : mInitial(initial), mFlags(initial) {}
WithDebugFlags(const WithDebugFlags&) = delete;
WithDebugFlags& operator=(const WithDebugFlags&) = delete;
@@ -135,7 +137,10 @@
EXPECT_IS_OK(mModule->setModuleDebug(mInitial));
}
}
- void SetUp(IModule* module) { ASSERT_IS_OK(module->setModuleDebug(mFlags)); }
+ void SetUp(IModule* module) {
+ ASSERT_IS_OK(module->setModuleDebug(mFlags));
+ mModule = module;
+ }
ModuleDebug& flags() { return mFlags; }
private:
@@ -144,13 +149,65 @@
IModule* mModule = nullptr;
};
+template <typename T>
+class WithModuleParameter {
+ public:
+ WithModuleParameter(const std::string parameterId, const T& value)
+ : mParameterId(parameterId), mValue(value) {}
+ WithModuleParameter(const WithModuleParameter&) = delete;
+ WithModuleParameter& operator=(const WithModuleParameter&) = delete;
+ ~WithModuleParameter() {
+ if (mModule != nullptr) {
+ VendorParameter parameter{.id = mParameterId};
+ parameter.ext.setParcelable(mInitial);
+ EXPECT_IS_OK(mModule->setVendorParameters({parameter}, false));
+ }
+ }
+ ScopedAStatus SetUpNoChecks(IModule* module, bool failureExpected) {
+ std::vector<VendorParameter> parameters;
+ ScopedAStatus result = module->getVendorParameters({mParameterId}, ¶meters);
+ if (result.isOk() && parameters.size() == 1) {
+ std::optional<T> maybeInitial;
+ binder_status_t status = parameters[0].ext.getParcelable(&maybeInitial);
+ if (status == STATUS_OK && maybeInitial.has_value()) {
+ mInitial = maybeInitial.value();
+ VendorParameter parameter{.id = mParameterId};
+ parameter.ext.setParcelable(mValue);
+ result = module->setVendorParameters({parameter}, false);
+ if (result.isOk()) {
+ LOG(INFO) << __func__ << ": overriding parameter \"" << mParameterId
+ << "\" with " << mValue.toString()
+ << ", old value: " << mInitial.toString();
+ mModule = module;
+ }
+ } else {
+ LOG(ERROR) << __func__ << ": error while retrieving the value of \"" << mParameterId
+ << "\"";
+ return ScopedAStatus::fromStatus(status);
+ }
+ }
+ if (!result.isOk()) {
+ LOG(failureExpected ? INFO : ERROR)
+ << __func__ << ": can not override vendor parameter \"" << mParameterId << "\""
+ << result;
+ }
+ return result;
+ }
+
+ private:
+ const std::string mParameterId;
+ const T mValue;
+ IModule* mModule = nullptr;
+ T mInitial;
+};
+
// For consistency, WithAudioPortConfig can start both with a non-existent
// port config, and with an existing one. Existence is determined by the
// id of the provided config. If it's not 0, then WithAudioPortConfig is
// essentially a no-op wrapper.
class WithAudioPortConfig {
public:
- WithAudioPortConfig() {}
+ WithAudioPortConfig() = default;
explicit WithAudioPortConfig(const AudioPortConfig& config) : mInitialConfig(config) {}
WithAudioPortConfig(const WithAudioPortConfig&) = delete;
WithAudioPortConfig& operator=(const WithAudioPortConfig&) = delete;
@@ -302,26 +359,31 @@
void SetUpImpl(const std::string& moduleName) {
ASSERT_NO_FATAL_FAILURE(ConnectToService(moduleName));
- debug.flags().simulateDeviceConnections = true;
- ASSERT_NO_FATAL_FAILURE(debug.SetUp(module.get()));
}
- void TearDownImpl() {
- if (module != nullptr) {
- EXPECT_IS_OK(module->setModuleDebug(ModuleDebug{}));
- }
- }
+ void TearDownImpl() { debug.reset(); }
void ConnectToService(const std::string& moduleName) {
+ ASSERT_EQ(module, nullptr);
+ ASSERT_EQ(debug, nullptr);
module = IModule::fromBinder(binderUtil.connectToService(moduleName));
ASSERT_NE(module, nullptr);
+ ASSERT_NO_FATAL_FAILURE(SetUpDebug());
}
void RestartService() {
ASSERT_NE(module, nullptr);
moduleConfig.reset();
+ debug.reset();
module = IModule::fromBinder(binderUtil.restartService());
ASSERT_NE(module, nullptr);
+ ASSERT_NO_FATAL_FAILURE(SetUpDebug());
+ }
+
+ void SetUpDebug() {
+ debug.reset(new WithDebugFlags());
+ debug->flags().simulateDeviceConnections = true;
+ ASSERT_NO_FATAL_FAILURE(debug->SetUp(module.get()));
}
void ApplyEveryConfig(const std::vector<AudioPortConfig>& configs) {
@@ -390,7 +452,7 @@
std::shared_ptr<IModule> module;
std::unique_ptr<ModuleConfig> moduleConfig;
AudioHalBinderServiceUtil binderUtil;
- WithDebugFlags debug;
+ std::unique_ptr<WithDebugFlags> debug;
};
class AudioCoreModule : public AudioCoreModuleBase, public testing::TestWithParam<std::string> {
@@ -465,6 +527,7 @@
size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
private:
@@ -504,10 +567,48 @@
return std::to_string(static_cast<int32_t>(event));
}
+// Note: we use a reference wrapper, not a pointer, because methods of std::*list
+// return references to inserted elements. This way, we can put a returned reference
+// into the children vector without any type conversions, and this makes DAG creation
+// code more clear.
+template <typename T>
+struct DagNode : public std::pair<T, std::vector<std::reference_wrapper<DagNode<T>>>> {
+ using Children = std::vector<std::reference_wrapper<DagNode>>;
+ DagNode(const T& t, const Children& c) : std::pair<T, Children>(t, c) {}
+ DagNode(T&& t, Children&& c) : std::pair<T, Children>(std::move(t), std::move(c)) {}
+ const T& datum() const { return this->first; }
+ Children& children() { return this->second; }
+ const Children& children() const { return this->second; }
+};
+// Since DagNodes do contain references to next nodes, node links provided
+// by the list are not used. Thus, the order of the nodes in the list is not
+// important, except that the starting node must be at the front of the list,
+// which means, it must always be added last.
+template <typename T>
+struct Dag : public std::forward_list<DagNode<T>> {
+ Dag() = default;
+ // We prohibit copying and moving Dag instances because implementing that
+ // is not trivial due to references between nodes.
+ Dag(const Dag&) = delete;
+ Dag(Dag&&) = delete;
+ Dag& operator=(const Dag&) = delete;
+ Dag& operator=(Dag&&) = delete;
+};
+
// Transition to the next state happens either due to a command from the client,
// or after an event received from the server.
using TransitionTrigger = std::variant<StreamDescriptor::Command, StreamEventReceiver::Event>;
-using StateTransition = std::pair<TransitionTrigger, StreamDescriptor::State>;
+std::string toString(const TransitionTrigger& trigger) {
+ if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
+ return std::string("'")
+ .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
+ .append("' command");
+ }
+ return std::string("'")
+ .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
+ .append("' event");
+}
+
struct StateSequence {
virtual ~StateSequence() = default;
virtual void rewind() = 0;
@@ -517,6 +618,10 @@
virtual void advance(StreamDescriptor::State state) = 0;
};
+// Defines the current state and the trigger to transfer to the next one,
+// thus "state" is the "from" state.
+using StateTransitionFrom = std::pair<StreamDescriptor::State, TransitionTrigger>;
+
static const StreamDescriptor::Command kGetStatusCommand =
StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::getStatus>(Void{});
static const StreamDescriptor::Command kStartCommand =
@@ -542,66 +647,65 @@
StreamEventReceiver::Event::TransferReady;
static const StreamEventReceiver::Event kDrainReadyEvent = StreamEventReceiver::Event::DrainReady;
-// Handle possible bifurcations:
-// - on burst and on start: 'TRANSFERRING' -> {'ACTIVE', 'TRANSFERRING'}
-// - on pause: 'TRANSFER_PAUSED' -> {'PAUSED', 'TRANSFER_PAUSED'}
-// It is assumed that the 'steps' provided on the construction contain the sequence
-// for the async case, which gets corrected in the case when the HAL decided to do
-// a synchronous transfer.
-class SmartStateSequence : public StateSequence {
+struct StateDag : public Dag<StateTransitionFrom> {
+ using Node = StateDag::reference;
+ using NextStates = StateDag::value_type::Children;
+
+ template <typename... Next>
+ Node makeNode(StreamDescriptor::State s, TransitionTrigger t, Next&&... next) {
+ return emplace_front(std::make_pair(s, t), NextStates{std::forward<Next>(next)...});
+ }
+ Node makeNodes(const std::vector<StateTransitionFrom>& v, Node last) {
+ auto helper = [&](auto i, auto&& h) -> Node {
+ if (i == v.end()) return last;
+ return makeNode(i->first, i->second, h(++i, h));
+ };
+ return helper(v.begin(), helper);
+ }
+ Node makeNodes(const std::vector<StateTransitionFrom>& v, StreamDescriptor::State f) {
+ return makeNodes(v, makeFinalNode(f));
+ }
+ Node makeFinalNode(StreamDescriptor::State s) {
+ // The actual command used here is irrelevant. Since it's the final node
+ // in the test sequence, no commands sent after reaching it.
+ return emplace_front(std::make_pair(s, kGetStatusCommand), NextStates{});
+ }
+};
+
+class StateSequenceFollower : public StateSequence {
public:
- explicit SmartStateSequence(const std::vector<StateTransition>& steps) : mSteps(steps) {}
- explicit SmartStateSequence(std::vector<StateTransition>&& steps) : mSteps(std::move(steps)) {}
- void rewind() override { mCurrentStep = 0; }
- bool done() const override { return mCurrentStep >= mSteps.size(); }
- TransitionTrigger getTrigger() override { return mSteps[mCurrentStep].first; }
+ explicit StateSequenceFollower(std::unique_ptr<StateDag> steps)
+ : mSteps(std::move(steps)), mCurrent(mSteps->front()) {}
+ void rewind() override { mCurrent = mSteps->front(); }
+ bool done() const override { return current().children().empty(); }
+ TransitionTrigger getTrigger() override { return current().datum().second; }
std::set<StreamDescriptor::State> getExpectedStates() override {
- std::set<StreamDescriptor::State> result = {getState()};
- if (isBurstBifurcation() || isStartBifurcation()) {
- result.insert(StreamDescriptor::State::ACTIVE);
- } else if (isPauseBifurcation()) {
- result.insert(StreamDescriptor::State::PAUSED);
- }
+ std::set<StreamDescriptor::State> result;
+ std::transform(current().children().cbegin(), current().children().cend(),
+ std::inserter(result, result.begin()),
+ [](const auto& node) { return node.get().datum().first; });
+ LOG(DEBUG) << __func__ << ": " << ::android::internal::ToString(result);
return result;
}
void advance(StreamDescriptor::State state) override {
- if (isBurstBifurcation() && state == StreamDescriptor::State::ACTIVE &&
- mCurrentStep + 1 < mSteps.size() &&
- mSteps[mCurrentStep + 1].first == TransitionTrigger{kTransferReadyEvent}) {
- mCurrentStep++;
+ if (auto it = std::find_if(
+ current().children().cbegin(), current().children().cend(),
+ [&](const auto& node) { return node.get().datum().first == state; });
+ it != current().children().cend()) {
+ LOG(DEBUG) << __func__ << ": " << toString(mCurrent.get().datum().first) << " -> "
+ << toString(it->get().datum().first);
+ mCurrent = *it;
+ } else {
+ LOG(FATAL) << __func__ << ": state " << toString(state) << " is unexpected";
}
- mCurrentStep++;
}
private:
- StreamDescriptor::State getState() const { return mSteps[mCurrentStep].second; }
- bool isBurstBifurcation() {
- return getTrigger() == TransitionTrigger{kBurstCommand} &&
- getState() == StreamDescriptor::State::TRANSFERRING;
- }
- bool isPauseBifurcation() {
- return getTrigger() == TransitionTrigger{kPauseCommand} &&
- getState() == StreamDescriptor::State::TRANSFER_PAUSED;
- }
- bool isStartBifurcation() {
- return getTrigger() == TransitionTrigger{kStartCommand} &&
- getState() == StreamDescriptor::State::TRANSFERRING;
- }
- const std::vector<StateTransition> mSteps;
- size_t mCurrentStep = 0;
+ StateDag::const_reference current() const { return mCurrent.get(); }
+ std::unique_ptr<StateDag> mSteps;
+ std::reference_wrapper<StateDag::value_type> mCurrent;
};
-std::string toString(const TransitionTrigger& trigger) {
- if (std::holds_alternative<StreamDescriptor::Command>(trigger)) {
- return std::string("'")
- .append(toString(std::get<StreamDescriptor::Command>(trigger).getTag()))
- .append("' command");
- }
- return std::string("'")
- .append(toString(std::get<StreamEventReceiver::Event>(trigger)))
- .append("' event");
-}
-
struct StreamLogicDriver {
virtual ~StreamLogicDriver() = default;
// Return 'true' to stop the worker.
@@ -927,7 +1031,7 @@
return common->close();
}
- WithStream() {}
+ WithStream() = default;
explicit WithStream(const AudioPortConfig& portConfig) : mPortConfig(portConfig) {}
WithStream(const WithStream&) = delete;
WithStream& operator=(const WithStream&) = delete;
@@ -1032,7 +1136,7 @@
class WithAudioPatch {
public:
- WithAudioPatch() {}
+ WithAudioPatch() = default;
WithAudioPatch(const AudioPortConfig& srcPortConfig, const AudioPortConfig& sinkPortConfig)
: mSrcPortConfig(srcPortConfig), mSinkPortConfig(sinkPortConfig) {}
WithAudioPatch(bool sinkIsCfg1, const AudioPortConfig& portConfig1,
@@ -1473,7 +1577,7 @@
GTEST_SKIP() << "No external devices in the module.";
}
AudioPort ignored;
- WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(debug);
+ WithDebugFlags doNotSimulateConnections = WithDebugFlags::createNested(*debug);
doNotSimulateConnections.flags().simulateDeviceConnections = false;
ASSERT_NO_FATAL_FAILURE(doNotSimulateConnections.SetUp(module.get()));
for (const auto& port : ports) {
@@ -1493,7 +1597,7 @@
}
WithDevicePortConnectedState portConnected(*ports.begin(), GenerateUniqueDeviceAddress());
ASSERT_NO_FATAL_FAILURE(portConnected.SetUp(module.get()));
- ModuleDebug midwayDebugChange = debug.flags();
+ ModuleDebug midwayDebugChange = debug->flags();
midwayDebugChange.simulateDeviceConnections = false;
EXPECT_STATUS(EX_ILLEGAL_STATE, module->setModuleDebug(midwayDebugChange))
<< "when trying to disable connections simulation while having a connected device";
@@ -2716,8 +2820,8 @@
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
- explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
- : mCommands(commands) {
+ StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands, size_t frameSizeBytes)
+ : mCommands(commands), mFrameSizeBytes(frameSizeBytes) {
mCommands->rewind();
}
@@ -2736,7 +2840,10 @@
if (actualSize != nullptr) {
// In the output scenario, reduce slightly the fmqByteCount to verify
// that the HAL module always consumes all data from the MQ.
- if (maxDataSize > 1) maxDataSize--;
+ if (maxDataSize > static_cast<int>(mFrameSizeBytes)) {
+ LOG(DEBUG) << __func__ << ": reducing data size by " << mFrameSizeBytes;
+ maxDataSize -= mFrameSizeBytes;
+ }
*actualSize = maxDataSize;
}
command->set<StreamDescriptor::Command::Tag::burst>(maxDataSize);
@@ -2782,6 +2889,7 @@
protected:
std::shared_ptr<StateSequence> mCommands;
+ const size_t mFrameSizeBytes;
std::optional<StreamDescriptor::State> mPreviousState;
std::optional<int64_t> mPreviousFrames;
bool mObservablePositionIncrease = false;
@@ -2830,7 +2938,7 @@
(!isNonBlocking && streamType == StreamTypeFilter::ASYNC)) {
continue;
}
- WithDebugFlags delayTransientStates = WithDebugFlags::createNested(debug);
+ WithDebugFlags delayTransientStates = WithDebugFlags::createNested(*debug);
delayTransientStates.flags().streamTransientStateDelayMs =
std::get<NAMED_CMD_DELAY_MS>(std::get<PARAM_CMD_SEQ>(GetParam()));
ASSERT_NO_FATAL_FAILURE(delayTransientStates.SetUp(module.get()));
@@ -2841,6 +2949,40 @@
} else {
ASSERT_NO_FATAL_FAILURE(RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
}
+ if (isNonBlocking) {
+ // Also try running the same sequence with "aosp.forceTransientBurst" set.
+ // This will only work with the default implementation. When it works, the stream
+ // tries always to move to the 'TRANSFERRING' state after a burst.
+ // This helps to check more paths for our test scenarios.
+ WithModuleParameter forceTransientBurst("aosp.forceTransientBurst", Boolean{true});
+ if (forceTransientBurst.SetUpNoChecks(module.get(), true /*failureExpected*/)
+ .isOk()) {
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ } else if (!IOTraits<Stream>::is_input) {
+ // Also try running the same sequence with "aosp.forceSynchronousDrain" set.
+ // This will only work with the default implementation. When it works, the stream
+ // tries always to move to the 'IDLE' state after a drain.
+ // This helps to check more paths for our test scenarios.
+ WithModuleParameter forceSynchronousDrain("aosp.forceSynchronousDrain",
+ Boolean{true});
+ if (forceSynchronousDrain.SetUpNoChecks(module.get(), true /*failureExpected*/)
+ .isOk()) {
+ if (!std::get<PARAM_SETUP_SEQ>(GetParam())) {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq1(portConfig, commandsAndStates));
+ } else {
+ ASSERT_NO_FATAL_FAILURE(
+ RunStreamIoCommandsImplSeq2(portConfig, commandsAndStates));
+ }
+ }
+ }
}
}
@@ -2861,7 +3003,8 @@
WithStream<Stream> stream(patch.getPortConfig(IOTraits<Stream>::is_input));
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
+ StreamLogicDefaultDriver driver(commandsAndStates,
+ stream.getContext()->getFrameSizeBytes());
typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
stream.getEventReceiver());
@@ -2882,7 +3025,8 @@
std::shared_ptr<StateSequence> commandsAndStates) {
WithStream<Stream> stream(portConfig);
ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
- StreamLogicDefaultDriver driver(commandsAndStates);
+ StreamLogicDefaultDriver driver(commandsAndStates,
+ stream.getContext()->getFrameSizeBytes());
typename IOTraits<Stream>::Worker worker(*stream.getContext(), &driver,
stream.getEventReceiver());
@@ -3219,38 +3363,52 @@
// TODO: Add async test cases for input once it is implemented.
-std::shared_ptr<StateSequence> makeBurstCommands(bool isSync, size_t burstCount) {
- const auto burst =
- isSync ? std::vector<StateTransition>{std::make_pair(kBurstCommand,
- StreamDescriptor::State::ACTIVE)}
- : std::vector<StateTransition>{
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kTransferReadyEvent, StreamDescriptor::State::ACTIVE)};
- std::vector<StateTransition> result{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE)};
- for (size_t i = 0; i < burstCount; ++i) {
- result.insert(result.end(), burst.begin(), burst.end());
+std::shared_ptr<StateSequence> makeBurstCommands(bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node last = d->makeFinalNode(State::ACTIVE);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kBurstCommand, last);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ // Allow optional routing via the TRANSFERRING state on bursts.
+ active.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, last));
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
}
- return std::make_shared<SmartStateSequence>(result);
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kReadSeq =
- std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteSyncSeq = std::make_tuple(
- std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true, 3));
-static const NamedCommandSequence kWriteAsyncSeq = std::make_tuple(
- std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false, 3));
+ std::make_tuple(std::string("Read"), 0, StreamTypeFilter::ANY, makeBurstCommands(true));
+static const NamedCommandSequence kWriteSyncSeq =
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::SYNC, makeBurstCommands(true));
+static const NamedCommandSequence kWriteAsyncSeq =
+ std::make_tuple(std::string("Write"), 0, StreamTypeFilter::ASYNC, makeBurstCommands(false));
std::shared_ptr<StateSequence> makeAsyncDrainCommands(bool isInput) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
- StreamDescriptor::State::DRAINING),
- isInput ? std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE)
- : std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(isInput ? kDrainInCommand : kDrainOutAllCommand,
- StreamDescriptor::State::DRAINING)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kDrainInCommand),
+ std::make_pair(State::DRAINING, kStartCommand),
+ std::make_pair(State::ACTIVE, kDrainInCommand)},
+ State::DRAINING);
+ } else {
+ StateDag::Node draining =
+ d->makeNodes({std::make_pair(State::DRAINING, kBurstCommand),
+ std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+ State::DRAINING);
+ StateDag::Node idle =
+ d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::TRANSFERRING, kDrainOutAllCommand)},
+ draining);
+ // If we get straight into ACTIVE on burst, no further testing is possible.
+ draining.children().push_back(d->makeFinalNode(State::ACTIVE));
+ idle.children().push_back(d->makeFinalNode(State::ACTIVE));
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kWriteDrainAsyncSeq =
std::make_tuple(std::string("WriteDrain"), kStreamTransientStateTransitionDelayMs,
@@ -3259,58 +3417,92 @@
std::string("Drain"), 0, StreamTypeFilter::ANY, makeAsyncDrainCommands(true));
std::shared_ptr<StateSequence> makeDrainOutCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(isSync ? TransitionTrigger(kGetStatusCommand)
- : TransitionTrigger(kDrainReadyEvent),
- StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node last = d->makeFinalNode(State::IDLE);
+ StateDag::Node active = d->makeNodes(
+ {std::make_pair(State::ACTIVE, kDrainOutAllCommand),
+ std::make_pair(State::DRAINING, isSync ? TransitionTrigger(kGetStatusCommand)
+ : TransitionTrigger(kDrainReadyEvent))},
+ last);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kTransferReadyEvent, active));
+ } else {
+ active.children().push_back(last);
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainOutSyncSeq = std::make_tuple(
std::string("Drain"), 0, StreamTypeFilter::SYNC, makeDrainOutCommands(true));
static const NamedCommandSequence kDrainOutAsyncSeq = std::make_tuple(
std::string("Drain"), 0, StreamTypeFilter::ASYNC, makeDrainOutCommands(false));
-std::shared_ptr<StateSequence> makeDrainOutPauseCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED)});
+std::shared_ptr<StateSequence> makeDrainPauseOutCommands(bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kStartCommand),
+ std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+ isSync ? State::PAUSED : State::TRANSFER_PAUSED);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+ } else {
+ // If we get straight into IDLE on drain, no further testing is possible.
+ active.children().push_back(d->makeFinalNode(State::IDLE));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainPauseOutSyncSeq =
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::SYNC, makeDrainOutPauseCommands(true));
+ StreamTypeFilter::SYNC, makeDrainPauseOutCommands(true));
static const NamedCommandSequence kDrainPauseOutAsyncSeq =
std::make_tuple(std::string("DrainPause"), kStreamTransientStateTransitionDelayMs,
- StreamTypeFilter::ASYNC, makeDrainOutPauseCommands(false));
+ StreamTypeFilter::ASYNC, makeDrainPauseOutCommands(false));
// This sequence also verifies that the capture / presentation position is not reset on standby.
std::shared_ptr<StateSequence> makeStandbyCommands(bool isInput, bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kStandbyCommand, StreamDescriptor::State::STANDBY),
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, isInput || isSync
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
- : StreamDescriptor::State::IDLE),
- std::make_pair(isInput ? kGetStatusCommand : kStandbyCommand, // no-op for input
- StreamDescriptor::State::STANDBY),
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand),
+ std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand)},
+ State::ACTIVE);
+ } else {
+ StateDag::Node idle3 =
+ d->makeNode(State::IDLE, kBurstCommand, d->makeFinalNode(State::ACTIVE));
+ StateDag::Node idle2 = d->makeNodes({std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand)},
+ idle3);
+ StateDag::Node active = d->makeNodes({std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ idle2);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle3.children().push_back(d->makeFinalNode(State::TRANSFERRING));
+ StateDag::Node transferring =
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+ idle2);
+ idle.children().push_back(transferring);
+ }
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kStandbyCommand),
+ std::make_pair(State::STANDBY, kStartCommand)},
+ idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kStandbyInSeq = std::make_tuple(
std::string("Standby"), 0, StreamTypeFilter::ANY, makeStandbyCommands(true, false));
@@ -3320,50 +3512,71 @@
std::make_tuple(std::string("Standby"), kStreamTransientStateTransitionDelayMs,
StreamTypeFilter::ASYNC, makeStandbyCommands(false, false));
-static const NamedCommandSequence kPauseInSeq =
- std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::ANY,
- std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::STANDBY)}));
-static const NamedCommandSequence kPauseOutSyncSeq =
- std::make_tuple(std::string("Pause"), 0, StreamTypeFilter::SYNC,
- std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::ACTIVE),
- std::make_pair(kPauseCommand, StreamDescriptor::State::PAUSED)}));
-/* TODO: Figure out a better way for testing sync/async bursts
-static const NamedCommandSequence kPauseOutAsyncSeq = std::make_tuple(
- std::string("Pause"), kStreamTransientStateTransitionDelayMs, StreamTypeFilter::ASYNC,
- std::make_shared<StaticStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kStartCommand, StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kBurstCommand, StreamDescriptor::State::TRANSFER_PAUSED)}));
-*/
+std::shared_ptr<StateSequence> makePauseCommands(bool isInput, bool isSync) {
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ State::STANDBY);
+ } else {
+ StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kStartCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kBurstCommand),
+ std::make_pair(State::PAUSED, kStartCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand)},
+ State::PAUSED);
+ if (!isSync) {
+ idle.children().push_back(
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kStartCommand),
+ std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kDrainOutAllCommand),
+ std::make_pair(State::DRAIN_PAUSED, kBurstCommand)},
+ State::TRANSFER_PAUSED));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
+}
+static const NamedCommandSequence kPauseInSeq = std::make_tuple(
+ std::string("Pause"), 0, StreamTypeFilter::ANY, makePauseCommands(true, false));
+static const NamedCommandSequence kPauseOutSyncSeq = std::make_tuple(
+ std::string("Pause"), 0, StreamTypeFilter::SYNC, makePauseCommands(false, true));
+static const NamedCommandSequence kPauseOutAsyncSeq =
+ std::make_tuple(std::string("Pause"), kStreamTransientStateTransitionDelayMs,
+ StreamTypeFilter::ASYNC, makePauseCommands(false, false));
std::shared_ptr<StateSequence> makeFlushCommands(bool isInput, bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isInput || isSync
- ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kPauseCommand, isInput || isSync
- ? StreamDescriptor::State::PAUSED
- : StreamDescriptor::State::TRANSFER_PAUSED),
- std::make_pair(kFlushCommand, isInput ? StreamDescriptor::State::STANDBY
- : StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ if (isInput) {
+ d->makeNodes({std::make_pair(State::STANDBY, kStartCommand),
+ std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ State::STANDBY);
+ } else {
+ StateDag::Node last = d->makeFinalNode(State::IDLE);
+ StateDag::Node idle = d->makeNodes({std::make_pair(State::IDLE, kBurstCommand),
+ std::make_pair(State::ACTIVE, kPauseCommand),
+ std::make_pair(State::PAUSED, kFlushCommand)},
+ last);
+ if (!isSync) {
+ idle.children().push_back(
+ d->makeNodes({std::make_pair(State::TRANSFERRING, kPauseCommand),
+ std::make_pair(State::TRANSFER_PAUSED, kFlushCommand)},
+ last));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ }
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kFlushInSeq = std::make_tuple(
std::string("Flush"), 0, StreamTypeFilter::ANY, makeFlushCommands(true, false));
@@ -3374,13 +3587,21 @@
StreamTypeFilter::ASYNC, makeFlushCommands(false, false));
std::shared_ptr<StateSequence> makeDrainPauseFlushOutCommands(bool isSync) {
- return std::make_shared<SmartStateSequence>(std::vector<StateTransition>{
- std::make_pair(kStartCommand, StreamDescriptor::State::IDLE),
- std::make_pair(kBurstCommand, isSync ? StreamDescriptor::State::ACTIVE
- : StreamDescriptor::State::TRANSFERRING),
- std::make_pair(kDrainOutAllCommand, StreamDescriptor::State::DRAINING),
- std::make_pair(kPauseCommand, StreamDescriptor::State::DRAIN_PAUSED),
- std::make_pair(kFlushCommand, StreamDescriptor::State::IDLE)});
+ using State = StreamDescriptor::State;
+ auto d = std::make_unique<StateDag>();
+ StateDag::Node draining = d->makeNodes({std::make_pair(State::DRAINING, kPauseCommand),
+ std::make_pair(State::DRAIN_PAUSED, kFlushCommand)},
+ State::IDLE);
+ StateDag::Node active = d->makeNode(State::ACTIVE, kDrainOutAllCommand, draining);
+ StateDag::Node idle = d->makeNode(State::IDLE, kBurstCommand, active);
+ if (!isSync) {
+ idle.children().push_back(d->makeNode(State::TRANSFERRING, kDrainOutAllCommand, draining));
+ } else {
+ // If we get straight into IDLE on drain, no further testing is possible.
+ active.children().push_back(d->makeFinalNode(State::IDLE));
+ }
+ d->makeNode(State::STANDBY, kStartCommand, idle);
+ return std::make_shared<StateSequenceFollower>(std::move(d));
}
static const NamedCommandSequence kDrainPauseFlushOutSyncSeq =
std::make_tuple(std::string("DrainPauseFlush"), kStreamTransientStateTransitionDelayMs,
diff --git a/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
new file mode 100644
index 0000000..9feff91
--- /dev/null
+++ b/audio/aidl/vts/VtsHalDynamicsProcessingTest.cpp
@@ -0,0 +1,1115 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <aidl/Vintf.h>
+
+#define LOG_TAG "VtsHalDynamicsProcessingTest"
+
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include <Utils.h>
+#include "EffectHelper.h"
+
+using namespace android;
+
+using aidl::android::hardware::audio::effect::Capability;
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DynamicsProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+class DynamicsProcessingTestHelper : public EffectHelper {
+ public:
+ DynamicsProcessingTestHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair,
+ int32_t channelLayOut = AudioChannelLayout::LAYOUT_STEREO) {
+ std::tie(mFactory, mDescriptor) = pair;
+ mChannelLayout = channelLayOut;
+ mChannelCount = ::android::hardware::audio::common::getChannelCount(
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ }
+
+ // setup
+ void SetUpDynamicsProcessingEffect() {
+ ASSERT_NE(nullptr, mFactory);
+ ASSERT_NO_FATAL_FAILURE(create(mFactory, mEffect, mDescriptor));
+
+ Parameter::Specific specific = getDefaultParamSpecific();
+ Parameter::Common common = EffectHelper::createParamCommon(
+ 0 /* session */, 1 /* ioHandle */, 44100 /* iSampleRate */, 44100 /* oSampleRate */,
+ 0x100 /* iFrameCount */, 0x100 /* oFrameCount */,
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout),
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(mChannelLayout));
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ mEngineConfigApplied = mEngineConfigPreset;
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ DynamicsProcessing dp = DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+ mEngineConfigPreset);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(dp);
+ return specific;
+ }
+
+ // teardown
+ void TearDownDynamicsProcessingEffect() {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ // utils functions for parameter checking
+ bool isParamValid(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dp,
+ const Descriptor& desc);
+ bool isParamEqual(const DynamicsProcessing::Tag& tag, const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest);
+
+ bool isEnablementValid(const DynamicsProcessing::StageEnablement& enablement);
+ bool isEngineConfigValid(const DynamicsProcessing::EngineArchitecture& cfg);
+
+ bool isCutoffFrequencyValid(float freq, const DynamicsProcessing::Capability& cap);
+ bool isChannelConfigValid(const std::vector<DynamicsProcessing::ChannelConfig>& cfgs,
+ bool stageInUse);
+
+ bool isPreEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isPostEqBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isMbcBandConfigValid(const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ bool stageInUse, int bandCount);
+ bool isLimiterConfigValid(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs,
+ bool stageInUse);
+ bool isInputGainValid(const std::vector<DynamicsProcessing::InputGain>& cfgs);
+
+ bool isEngineConfigEqual(const DynamicsProcessing::EngineArchitecture& refCfg,
+ const DynamicsProcessing::EngineArchitecture& testCfg);
+
+ template <typename T>
+ std::vector<T> filterEnabledVector(const std::vector<T>& vec);
+
+ template <typename T>
+ bool isAidlVectorEqualAfterFilter(const std::vector<T>& source, const std::vector<T>& target);
+
+ template <typename T>
+ bool isAidlVectorEqual(const std::vector<T>& source, const std::vector<T>& target);
+
+ // get set params and validate
+ void SetAndGetDynamicsProcessingParameters();
+
+ // enqueue test parameters
+ void addEngineConfig(const DynamicsProcessing::EngineArchitecture& cfg);
+ void addPreEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPostEqChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addMbcChannelConfig(const std::vector<DynamicsProcessing::ChannelConfig>& cfg);
+ void addPreEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addPostEqBandConfigs(const std::vector<DynamicsProcessing::EqBandConfig>& cfgs);
+ void addMbcBandConfigs(const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs);
+ void addLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfg);
+ void addInputGain(const std::vector<DynamicsProcessing::InputGain>& inputGain);
+
+ static constexpr float kPreferredProcessingDurationMs = 10.0f;
+ static constexpr int kBandCount = 5;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ DynamicsProcessing::EngineArchitecture mEngineConfigApplied;
+ DynamicsProcessing::EngineArchitecture mEngineConfigPreset{
+ .resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+ .preEqStage = {.inUse = true, .bandCount = kBandCount},
+ .postEqStage = {.inUse = true, .bandCount = kBandCount},
+ .mbcStage = {.inUse = true, .bandCount = kBandCount},
+ .limiterInUse = true,
+ };
+
+ std::unordered_set<int /* channelId */> mPreEqChannelEnable;
+ std::unordered_set<int /* channelId */> mPostEqChannelEnable;
+ std::unordered_set<int /* channelId */> mMbcChannelEnable;
+ std::unordered_set<int /* channelId */> mLimiterChannelEnable;
+ static const std::set<std::vector<DynamicsProcessing::ChannelConfig>> kChannelConfigTestSet;
+ static const std::set<DynamicsProcessing::StageEnablement> kStageEnablementTestSet;
+ static const std::set<std::vector<DynamicsProcessing::InputGain>> kInputGainTestSet;
+
+ private:
+ int32_t mChannelLayout;
+ int mChannelCount;
+ std::vector<std::pair<DynamicsProcessing::Tag, DynamicsProcessing>> mTags;
+ void CleanUp() {
+ mTags.clear();
+ mPreEqChannelEnable.clear();
+ mPostEqChannelEnable.clear();
+ mMbcChannelEnable.clear();
+ mLimiterChannelEnable.clear();
+ }
+};
+
+// test value set for DynamicsProcessing::StageEnablement
+const std::set<DynamicsProcessing::StageEnablement>
+ DynamicsProcessingTestHelper::kStageEnablementTestSet = {
+ {.inUse = true, .bandCount = DynamicsProcessingTestHelper::kBandCount},
+ {.inUse = true, .bandCount = 0},
+ {.inUse = true, .bandCount = -1},
+ {.inUse = false, .bandCount = DynamicsProcessingTestHelper::kBandCount}};
+
+// test value set for DynamicsProcessing::ChannelConfig
+const std::set<std::vector<DynamicsProcessing::ChannelConfig>>
+ DynamicsProcessingTestHelper::kChannelConfigTestSet = {
+ {{.channel = -1, .enable = false},
+ {.channel = 0, .enable = true},
+ {.channel = 1, .enable = false},
+ {.channel = 2, .enable = true}},
+
+ {{.channel = -1, .enable = false}, {.channel = 2, .enable = true}},
+
+ {{.channel = 0, .enable = true}, {.channel = 1, .enable = true}}};
+
+// test value set for DynamicsProcessing::InputGain
+const std::set<std::vector<DynamicsProcessing::InputGain>>
+ DynamicsProcessingTestHelper::kInputGainTestSet = {
+ {{.channel = 0, .gainDb = 10.f},
+ {.channel = 1, .gainDb = 0.f},
+ {.channel = 2, .gainDb = -10.f}},
+
+ {{.channel = -1, .gainDb = -10.f}, {.channel = -2, .gainDb = 10.f}},
+
+ {{.channel = -1, .gainDb = 10.f}, {.channel = 0, .gainDb = -10.f}}};
+
+bool DynamicsProcessingTestHelper::isParamValid(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dp,
+ const Descriptor& desc) {
+ const DynamicsProcessing::Capability& dpCap =
+ desc.capability.get<Capability::dynamicsProcessing>();
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigValid(dp.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::preEq>(),
+ mEngineConfigApplied.preEqStage.inUse);
+ }
+ case DynamicsProcessing::postEq: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::postEq>(),
+ mEngineConfigApplied.postEqStage.inUse);
+ }
+ case DynamicsProcessing::mbc: {
+ return isChannelConfigValid(dp.get<DynamicsProcessing::mbc>(),
+ mEngineConfigApplied.mbcStage.inUse);
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isPreEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::preEqBand>(),
+ mEngineConfigApplied.preEqStage.inUse,
+ mEngineConfigApplied.preEqStage.bandCount);
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isPostEqBandConfigValid(dpCap, dp.get<DynamicsProcessing::postEqBand>(),
+ mEngineConfigApplied.postEqStage.inUse,
+ mEngineConfigApplied.postEqStage.bandCount);
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isMbcBandConfigValid(dpCap, dp.get<DynamicsProcessing::mbcBand>(),
+ mEngineConfigApplied.mbcStage.inUse,
+ mEngineConfigApplied.mbcStage.bandCount);
+ }
+ case DynamicsProcessing::limiter: {
+ return isLimiterConfigValid(dp.get<DynamicsProcessing::limiter>(),
+ mEngineConfigApplied.limiterInUse);
+ }
+ case DynamicsProcessing::inputGain: {
+ return isInputGainValid(dp.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return true;
+ }
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isParamEqual(const DynamicsProcessing::Tag& tag,
+ const DynamicsProcessing& dpRef,
+ const DynamicsProcessing& dpTest) {
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ return isEngineConfigEqual(dpRef.get<DynamicsProcessing::engineArchitecture>(),
+ dpTest.get<DynamicsProcessing::engineArchitecture>());
+ }
+ case DynamicsProcessing::preEq: {
+ const auto& source = dpRef.get<DynamicsProcessing::preEq>();
+ const auto& target = dpTest.get<DynamicsProcessing::preEq>();
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(source, target);
+ }
+ case DynamicsProcessing::postEq: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::postEq>(),
+ dpTest.get<DynamicsProcessing::postEq>());
+ }
+ case DynamicsProcessing::mbc: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::ChannelConfig>(
+ dpRef.get<DynamicsProcessing::mbc>(), dpTest.get<DynamicsProcessing::mbc>());
+ }
+ case DynamicsProcessing::preEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::preEqBand>(),
+ dpTest.get<DynamicsProcessing::preEqBand>());
+ }
+ case DynamicsProcessing::postEqBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::EqBandConfig>(
+ dpRef.get<DynamicsProcessing::postEqBand>(),
+ dpTest.get<DynamicsProcessing::postEqBand>());
+ }
+ case DynamicsProcessing::mbcBand: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::MbcBandConfig>(
+ dpRef.get<DynamicsProcessing::mbcBand>(),
+ dpTest.get<DynamicsProcessing::mbcBand>());
+ }
+ case DynamicsProcessing::limiter: {
+ return isAidlVectorEqualAfterFilter<DynamicsProcessing::LimiterConfig>(
+ dpRef.get<DynamicsProcessing::limiter>(),
+ dpTest.get<DynamicsProcessing::limiter>());
+ }
+ case DynamicsProcessing::inputGain: {
+ return isAidlVectorEqual<DynamicsProcessing::InputGain>(
+ dpRef.get<DynamicsProcessing::inputGain>(),
+ dpTest.get<DynamicsProcessing::inputGain>());
+ }
+ case DynamicsProcessing::vendorExtension: {
+ return false;
+ }
+ }
+}
+
+bool DynamicsProcessingTestHelper::isEnablementValid(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigValid(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ return cfg.preferredProcessingDurationMs >= 0 && isEnablementValid(cfg.preEqStage) &&
+ isEnablementValid(cfg.postEqStage) && isEnablementValid(cfg.mbcStage);
+}
+
+bool DynamicsProcessingTestHelper::isChannelConfigValid(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs, bool stageInUse) {
+ std::unordered_set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isCutoffFrequencyValid(
+ float freq, const DynamicsProcessing::Capability& cap) {
+ return freq >= cap.minCutOffFreq && freq <= cap.maxCutOffFreq;
+}
+
+bool DynamicsProcessingTestHelper::isPreEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPreEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isPostEqBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs, bool stageInUse, int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ // not able to set/get parameter when stage not in use.
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mPostEqChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isMbcBandConfigValid(
+ const DynamicsProcessing::Capability& cap,
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs, bool stageInUse,
+ int bandCount) {
+ std::set<std::pair<int /* channelID */, int /* bandID */>> bandSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mMbcChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.band < 0 || cfg.band >= bandCount ||
+ (cfg.attackTimeMs < 0) || cfg.releaseTimeMs < 0 || cfg.ratio < 0 ||
+ cfg.thresholdDb > 0 || cfg.kneeWidthDb < 0 || cfg.noiseGateThresholdDb > 0 ||
+ cfg.expanderRatio < 0 || !isCutoffFrequencyValid(cfg.cutoffFrequencyHz, cap) ||
+ 0 != bandSet.count({cfg.channel, cfg.band})) {
+ return false;
+ }
+ bandSet.insert({cfg.channel, cfg.band});
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isLimiterConfigValid(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, bool stageInUse) {
+ std::set<int> channelSet;
+ if (!stageInUse) return false;
+ for (auto cfg : cfgs) {
+ if (0 == mLimiterChannelEnable.count(cfg.channel) || cfg.channel < 0 ||
+ cfg.channel >= mChannelCount || cfg.attackTimeMs < 0 || cfg.releaseTimeMs < 0 ||
+ cfg.ratio < 0 || cfg.thresholdDb > 0 || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isInputGainValid(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs) {
+ std::set<int> channelSet;
+ for (auto cfg : cfgs) {
+ if (cfg.channel < 0 || cfg.channel >= mChannelCount || 0 != channelSet.count(cfg.channel)) {
+ return false;
+ }
+ channelSet.insert(cfg.channel);
+ }
+ return true;
+}
+
+bool DynamicsProcessingTestHelper::isEngineConfigEqual(
+ const DynamicsProcessing::EngineArchitecture& ref,
+ const DynamicsProcessing::EngineArchitecture& test) {
+ return ref == test;
+}
+
+template <typename T>
+std::vector<T> DynamicsProcessingTestHelper::filterEnabledVector(const std::vector<T>& vec) {
+ std::vector<T> ret;
+ std::copy_if(vec.begin(), vec.end(), std::back_inserter(ret),
+ [](const auto& v) { return v.enable; });
+ return ret;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqual(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ if (source.size() != target.size()) return false;
+
+ auto tempS = source;
+ auto tempT = target;
+ std::sort(tempS.begin(), tempS.end());
+ std::sort(tempT.begin(), tempT.end());
+ return tempS == tempT;
+}
+
+template <typename T>
+bool DynamicsProcessingTestHelper::isAidlVectorEqualAfterFilter(const std::vector<T>& source,
+ const std::vector<T>& target) {
+ return isAidlVectorEqual<T>(filterEnabledVector<T>(source), filterEnabledVector<T>(target));
+}
+
+void DynamicsProcessingTestHelper::SetAndGetDynamicsProcessingParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& dp = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isParamValid(tag, dp, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::dynamicsProcessing>(dp);
+ expectParam.set<Parameter::specific>(specific);
+ ASSERT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ DynamicsProcessing::Id dpId;
+ dpId.set<DynamicsProcessing::Id::commonTag>(tag);
+ id.set<Parameter::Id::dynamicsProcessingTag>(dpId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ Parameter::Specific specificTest = getParam.get<Parameter::specific>();
+ const auto& target = specificTest.get<Parameter::Specific::dynamicsProcessing>();
+ EXPECT_TRUE(isParamEqual(tag, dp, target)) << dp.toString() << "\n"
+ << target.toString();
+ // update mEngineConfigApplied after setting successfully
+ if (tag == DynamicsProcessing::engineArchitecture) {
+ mEngineConfigApplied = target.get<DynamicsProcessing::engineArchitecture>();
+ }
+ }
+ }
+}
+
+void DynamicsProcessingTestHelper::addEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& cfg) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::engineArchitecture>(cfg);
+ mTags.push_back({DynamicsProcessing::engineArchitecture, dp});
+}
+
+void DynamicsProcessingTestHelper::addPreEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPreEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPostEqChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEq>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEq, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mPostEqChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addMbcChannelConfig(
+ const std::vector<DynamicsProcessing::ChannelConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbc>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbc, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mMbcChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addPreEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::preEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::preEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addPostEqBandConfigs(
+ const std::vector<DynamicsProcessing::EqBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::postEqBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::postEqBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addMbcBandConfigs(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::mbcBand>(cfgs);
+ mTags.push_back({DynamicsProcessing::mbcBand, dp});
+}
+
+void DynamicsProcessingTestHelper::addLimiterConfig(
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::limiter>(cfgs);
+ mTags.push_back({DynamicsProcessing::limiter, dp});
+ for (auto& cfg : cfgs) {
+ if (cfg.enable) mLimiterChannelEnable.insert(cfg.channel);
+ }
+}
+
+void DynamicsProcessingTestHelper::addInputGain(
+ const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+ DynamicsProcessing dp;
+ dp.set<DynamicsProcessing::inputGain>(inputGains);
+ mTags.push_back({DynamicsProcessing::inputGain, dp});
+}
+
+/**
+ * Test DynamicsProcessing Engine Configuration
+ */
+enum EngineArchitectureTestParamName {
+ ENGINE_TEST_INSTANCE_NAME,
+ ENGINE_TEST_RESOLUTION_PREFERENCE,
+ ENGINE_TEST_PREFERRED_DURATION,
+ ENGINE_TEST_STAGE_ENABLEMENT,
+ ENGINE_TEST_LIMITER_IN_USE
+};
+using EngineArchitectureTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ DynamicsProcessing::ResolutionPreference, float,
+ DynamicsProcessing::StageEnablement, bool>;
+
+void fillEngineArchConfig(DynamicsProcessing::EngineArchitecture& cfg,
+ const EngineArchitectureTestParams& params) {
+ cfg.resolutionPreference = std::get<ENGINE_TEST_RESOLUTION_PREFERENCE>(params);
+ cfg.preferredProcessingDurationMs = std::get<ENGINE_TEST_PREFERRED_DURATION>(params);
+ cfg.preEqStage = cfg.postEqStage = cfg.mbcStage =
+ std::get<ENGINE_TEST_STAGE_ENABLEMENT>(params);
+ cfg.limiterInUse = std::get<ENGINE_TEST_LIMITER_IN_USE>(params);
+}
+
+class DynamicsProcessingTestEngineArchitecture
+ : public ::testing::TestWithParam<EngineArchitectureTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEngineArchitecture()
+ : DynamicsProcessingTestHelper(std::get<ENGINE_TEST_INSTANCE_NAME>(GetParam())) {
+ fillEngineArchConfig(mCfg, GetParam());
+ };
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::EngineArchitecture mCfg;
+};
+
+TEST_P(DynamicsProcessingTestEngineArchitecture, SetAndGetEngineArch) {
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEngineArchitecture,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION,
+ DynamicsProcessing::ResolutionPreference::
+ FAVOR_FREQUENCY_RESOLUTION), // variant
+ testing::Values(-10.f, 0.f, 10.f), // processing duration
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kStageEnablementTestSet), // preEQ/postEQ/mbc
+ testing::Bool()), // limiter enable
+ [](const auto& info) {
+ auto descriptor = std::get<ENGINE_TEST_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::EngineArchitecture cfg;
+ fillEngineArchConfig(cfg, info.param);
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_Cfg_" + cfg.toString();
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEngineArchitecture);
+
+/**
+ * Test DynamicsProcessing Input Gain
+ */
+enum InputGainTestParamName {
+ INPUT_GAIN_INSTANCE_NAME,
+ INPUT_GAIN_PARAM,
+};
+class DynamicsProcessingTestInputGain
+ : public ::testing::TestWithParam<std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::InputGain>>>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestInputGain()
+ : DynamicsProcessingTestHelper(std::get<INPUT_GAIN_INSTANCE_NAME>(GetParam())),
+ mInputGain(std::get<INPUT_GAIN_PARAM>(GetParam())){};
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ const std::vector<DynamicsProcessing::InputGain> mInputGain;
+};
+
+TEST_P(DynamicsProcessingTestInputGain, SetAndGetInputGain) {
+ EXPECT_NO_FATAL_FAILURE(addInputGain(mInputGain));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestInputGain,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(DynamicsProcessingTestInputGain::kInputGainTestSet)),
+ [](const auto& info) {
+ auto descriptor = std::get<INPUT_GAIN_INSTANCE_NAME>(info.param).second;
+ std::string gains =
+ ::android::internal::ToString(std::get<INPUT_GAIN_PARAM>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_inputGains_" + gains;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestInputGain);
+
+/**
+ * Test DynamicsProcessing Limiter Config
+ */
+enum LimiterConfigTestParamName {
+ LIMITER_INSTANCE_NAME,
+ LIMITER_CHANNEL,
+ LIMITER_ENABLE,
+ LIMITER_LINK_GROUP,
+ LIMITER_ENGINE_IN_USE,
+ LIMITER_ADDITIONAL,
+};
+enum LimiterConfigTestAdditionalParam {
+ LIMITER_ATTACK_TIME,
+ LIMITER_RELEASE_TIME,
+ LIMITER_RATIO,
+ LIMITER_THRESHOLD,
+ LIMITER_POST_GAIN,
+ LIMITER_MAX_NUM,
+};
+using LimiterConfigTestAdditional = std::array<float, LIMITER_MAX_NUM>;
+// attachTime, releaseTime, ratio, thresh, postGain
+static constexpr std::array<LimiterConfigTestAdditional, 4> kLimiterConfigTestAdditionalParam = {
+ {{-1, -60, -2.5, -2, -3.14},
+ {-1, 60, -2.5, 2, -3.14},
+ {1, -60, 2.5, -2, 3.14},
+ {1, 60, 2.5, 2, 3.14}}};
+
+using LimiterConfigTestParams =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t, bool, int32_t, bool,
+ LimiterConfigTestAdditional>;
+
+void fillLimiterConfig(DynamicsProcessing::LimiterConfig& cfg,
+ const LimiterConfigTestParams& params) {
+ const std::array<float, LIMITER_MAX_NUM> additional = std::get<LIMITER_ADDITIONAL>(params);
+ cfg.channel = std::get<LIMITER_CHANNEL>(params);
+ cfg.enable = std::get<LIMITER_ENABLE>(params);
+ cfg.linkGroup = std::get<LIMITER_LINK_GROUP>(params);
+ cfg.attackTimeMs = additional[LIMITER_ATTACK_TIME];
+ cfg.releaseTimeMs = additional[LIMITER_RELEASE_TIME];
+ cfg.ratio = additional[LIMITER_RATIO];
+ cfg.thresholdDb = additional[LIMITER_THRESHOLD];
+ cfg.postGainDb = additional[LIMITER_POST_GAIN];
+}
+
+class DynamicsProcessingTestLimiterConfig
+ : public ::testing::TestWithParam<LimiterConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestLimiterConfig()
+ : DynamicsProcessingTestHelper(std::get<LIMITER_INSTANCE_NAME>(GetParam())),
+ mLimiterInUseEngine(std::get<LIMITER_ENGINE_IN_USE>(GetParam())) {
+ fillLimiterConfig(mCfg, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ DynamicsProcessing::LimiterConfig mCfg;
+ bool mLimiterInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestLimiterConfig, SetAndGetLimiterConfig) {
+ mEngineConfigPreset.limiterInUse = mLimiterInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addLimiterConfig({mCfg}));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestLimiterConfig,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 1, 2), // channel count
+ testing::Bool(), // enable
+ testing::Values(3), // link group
+ testing::Bool(), // engine limiter enable
+ testing::ValuesIn(kLimiterConfigTestAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<LIMITER_INSTANCE_NAME>(info.param).second;
+ DynamicsProcessing::LimiterConfig cfg;
+ fillLimiterConfig(cfg, info.param);
+ std::string engineLimiterInUse =
+ std::to_string(std::get<LIMITER_ENGINE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_limiterConfig_" +
+ cfg.toString() + "_engineSetting_" + engineLimiterInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestLimiterConfig);
+
+/**
+ * Test DynamicsProcessing ChannelConfig
+ */
+enum ChannelConfigTestParamName {
+ BAND_CHANNEL_TEST_INSTANCE_NAME,
+ BAND_CHANNEL_TEST_CHANNEL_CONFIG,
+ BAND_CHANNEL_TEST_ENGINE_IN_USE
+};
+using ChannelConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool>;
+
+class DynamicsProcessingTestChannelConfig
+ : public ::testing::TestWithParam<ChannelConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestChannelConfig()
+ : DynamicsProcessingTestHelper(std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(GetParam())),
+ mCfg(std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(GetParam())),
+ mInUseEngine(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(GetParam())) {}
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::ChannelConfig> mCfg;
+ const bool mInUseEngine;
+};
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPreEqChannelConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetPostEqChannelConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestChannelConfig, SetAndGetMbcChannelConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mInUseEngine;
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mCfg));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestChannelConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool()), // Engine inUse
+ [](const auto& info) {
+ auto descriptor = std::get<BAND_CHANNEL_TEST_INSTANCE_NAME>(info.param).second;
+ std::string engineInUse =
+ std::to_string(std::get<BAND_CHANNEL_TEST_ENGINE_IN_USE>(info.param));
+ std::string channelConfig = ::android::internal::ToString(
+ std::get<BAND_CHANNEL_TEST_CHANNEL_CONFIG>(info.param));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + channelConfig +
+ "_engineInUse_" + engineInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestChannelConfig);
+
+/**
+ * Test DynamicsProcessing EqBandConfig
+ */
+enum EqBandConfigTestParamName {
+ EQ_BAND_INSTANCE_NAME,
+ EQ_BAND_CHANNEL,
+ EQ_BAND_CHANNEL_ENABLE,
+ EQ_BAND_ENABLE,
+ EQ_BAND_CUT_OFF_FREQ,
+ EQ_BAND_GAIN,
+ EQ_BAND_STAGE_IN_USE
+};
+using EqBandConfigTestParams = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, float, bool>;
+
+void fillEqBandConfig(std::vector<DynamicsProcessing::EqBandConfig>& cfgs,
+ const EqBandConfigTestParams& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<EQ_BAND_CUT_OFF_FREQ>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i].channel = std::get<EQ_BAND_CHANNEL>(params);
+ cfgs[i].band = cutOffFreqs[i].first;
+ cfgs[i].enable = std::get<EQ_BAND_ENABLE>(params);
+ cfgs[i].cutoffFrequencyHz = cutOffFreqs[i].second;
+ cfgs[i].gainDb = std::get<EQ_BAND_GAIN>(params);
+ }
+}
+
+class DynamicsProcessingTestEqBandConfig : public ::testing::TestWithParam<EqBandConfigTestParams>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestEqBandConfig()
+ : DynamicsProcessingTestHelper(std::get<EQ_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<EQ_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<EQ_BAND_CHANNEL_ENABLE>(GetParam())) {
+ fillEqBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::EqBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPreEqBandConfig) {
+ mEngineConfigPreset.preEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.preEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPreEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPreEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+TEST_P(DynamicsProcessingTestEqBandConfig, SetAndGetPostEqBandConfig) {
+ mEngineConfigPreset.postEqStage.inUse = mStageInUse;
+ mEngineConfigPreset.postEqStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addPostEqChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addPostEqBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+std::vector<std::vector<std::pair<int, float>>> kBands{
+ {
+ {0, 600},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // 5 bands
+ {
+ {0, 800},
+ {3, 15000},
+ {2, 6000},
+ {1, 2000},
+ }, // 4 bands, unsorted
+ {
+ {0, 650},
+ {1, 2000},
+ {2, 6000},
+ {3, 10000},
+ {3, 16000},
+ }, // 5 bands, missing band
+ {
+ {0, 900},
+ {1, 8000},
+ {2, 4000},
+ {3, 12000},
+ }, // 4 bands, cutoff freq not increasing
+ {
+ {0, 450},
+ {1, 2000},
+ {7, 6000},
+ {3, 10000},
+ {4, 16000},
+ }, // bad band index
+ {
+ {0, 1},
+ {1, 8000},
+ }, // too low cutoff freq
+ {
+ {0, 1200},
+ {1, 80000},
+ }, // too high cutoff freq
+};
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestEqBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel ID
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel enable
+ testing::Bool(), // band enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Values(-3.14f, 3.14f), // gain
+ testing::Bool()), // stage in use
+ [](const auto& info) {
+ auto descriptor = std::get<EQ_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::EqBandConfig> cfgs;
+ fillEqBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<EQ_BAND_CHANNEL_ENABLE>(info.param));
+ std::string bands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<EQ_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_" + enable + "_bands_" +
+ bands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestEqBandConfig);
+
+/**
+ * Test DynamicsProcessing MbcBandConfig
+ */
+
+enum MbcBandConfigParamName {
+ MBC_BAND_INSTANCE_NAME,
+ MBC_BAND_CHANNEL,
+ MBC_BAND_CHANNEL_CONFIG,
+ MBC_BAND_ENABLE,
+ MBC_BAND_CUTOFF_FREQ,
+ MBC_BAND_STAGE_IN_USE,
+ MBC_BAND_ADDITIONAL
+};
+enum MbcBandConfigAdditional {
+ MBC_ADD_ATTACK_TIME,
+ MBC_ADD_RELEASE_TIME,
+ MBC_ADD_RATIO,
+ MBC_ADD_THRESHOLD,
+ MBC_ADD_KNEE_WIDTH,
+ MBC_ADD_NOISE_GATE_THRESHOLD,
+ MBC_ADD_EXPENDER_RATIO,
+ MBC_ADD_PRE_GAIN,
+ MBC_ADD_POST_GAIN,
+ MBC_ADD_MAX_NUM
+};
+using TestParamsMbcBandConfigAdditional = std::array<float, MBC_ADD_MAX_NUM>;
+
+// attachTime, releaseTime, ratio, thresh, kneeWidth, noise, expander, preGain, postGain
+static constexpr std::array<TestParamsMbcBandConfigAdditional, 4> kMbcBandConfigAdditionalParam = {
+ {{-3, -10, -2, -2, -5, -90, -2.5, -2, -2},
+ {0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {-3, 10, -2, 2, -5, 90, -2.5, 2, -2},
+ {3, 10, 2, 2, 5, 90, 2.5, 2, 2}}};
+
+using TestParamsMbcBandConfig =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int32_t,
+ std::vector<DynamicsProcessing::ChannelConfig>, bool,
+ std::vector<std::pair<int, float>>, bool, TestParamsMbcBandConfigAdditional>;
+
+void fillMbcBandConfig(std::vector<DynamicsProcessing::MbcBandConfig>& cfgs,
+ const TestParamsMbcBandConfig& params) {
+ const std::vector<std::pair<int, float>> cutOffFreqs = std::get<MBC_BAND_CUTOFF_FREQ>(params);
+ const std::array<float, MBC_ADD_MAX_NUM> additional = std::get<MBC_BAND_ADDITIONAL>(params);
+ int bandCount = cutOffFreqs.size();
+ cfgs.resize(bandCount);
+ for (int i = 0; i < bandCount; i++) {
+ cfgs[i] = DynamicsProcessing::MbcBandConfig{
+ .channel = std::get<MBC_BAND_CHANNEL>(params),
+ .band = cutOffFreqs[i].first,
+ .enable = std::get<MBC_BAND_ENABLE>(params),
+ .cutoffFrequencyHz = cutOffFreqs[i].second,
+ .attackTimeMs = additional[MBC_ADD_ATTACK_TIME],
+ .releaseTimeMs = additional[MBC_ADD_RELEASE_TIME],
+ .ratio = additional[MBC_ADD_RATIO],
+ .thresholdDb = additional[MBC_ADD_THRESHOLD],
+ .kneeWidthDb = additional[MBC_ADD_KNEE_WIDTH],
+ .noiseGateThresholdDb = additional[MBC_ADD_NOISE_GATE_THRESHOLD],
+ .expanderRatio = additional[MBC_ADD_EXPENDER_RATIO],
+ .preGainDb = additional[MBC_ADD_PRE_GAIN],
+ .postGainDb = additional[MBC_ADD_POST_GAIN]};
+ }
+}
+
+class DynamicsProcessingTestMbcBandConfig
+ : public ::testing::TestWithParam<TestParamsMbcBandConfig>,
+ public DynamicsProcessingTestHelper {
+ public:
+ DynamicsProcessingTestMbcBandConfig()
+ : DynamicsProcessingTestHelper(std::get<MBC_BAND_INSTANCE_NAME>(GetParam())),
+ mStageInUse(std::get<MBC_BAND_STAGE_IN_USE>(GetParam())),
+ mChannelConfig(std::get<MBC_BAND_CHANNEL_CONFIG>(GetParam())) {
+ fillMbcBandConfig(mCfgs, GetParam());
+ }
+
+ void SetUp() override { SetUpDynamicsProcessingEffect(); }
+
+ void TearDown() override { TearDownDynamicsProcessingEffect(); }
+
+ std::vector<DynamicsProcessing::MbcBandConfig> mCfgs;
+ const bool mStageInUse;
+ const std::vector<DynamicsProcessing::ChannelConfig> mChannelConfig;
+};
+
+TEST_P(DynamicsProcessingTestMbcBandConfig, SetAndGetMbcBandConfig) {
+ mEngineConfigPreset.mbcStage.inUse = mStageInUse;
+ mEngineConfigPreset.mbcStage.bandCount = mCfgs.size();
+ EXPECT_NO_FATAL_FAILURE(addEngineConfig(mEngineConfigPreset));
+ EXPECT_NO_FATAL_FAILURE(addMbcChannelConfig(mChannelConfig));
+ EXPECT_NO_FATAL_FAILURE(addMbcBandConfigs(mCfgs));
+ SetAndGetDynamicsProcessingParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ DynamicsProcessingTest, DynamicsProcessingTestMbcBandConfig,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kDynamicsProcessingTypeUUID)),
+ testing::Values(-1, 0, 10), // channel count
+ testing::ValuesIn(
+ DynamicsProcessingTestHelper::kChannelConfigTestSet), // channel config
+ testing::Bool(), // enable
+ testing::ValuesIn(kBands), // cut off frequencies
+ testing::Bool(), // stage in use
+ testing::ValuesIn(kMbcBandConfigAdditionalParam)), // Additional
+ [](const auto& info) {
+ auto descriptor = std::get<MBC_BAND_INSTANCE_NAME>(info.param).second;
+ std::vector<DynamicsProcessing::MbcBandConfig> cfgs;
+ fillMbcBandConfig(cfgs, info.param);
+ std::string enable =
+ ::android::internal::ToString(std::get<MBC_BAND_CHANNEL_CONFIG>(info.param));
+ std::string mbcBands = ::android::internal::ToString(cfgs);
+ std::string stageInUse = std::to_string(std::get<MBC_BAND_STAGE_IN_USE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_enable_" + enable +
+ "_bands_" + mbcBands + "_stageInUse_" + stageInUse;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(DynamicsProcessingTestMbcBandConfig);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
index e99c4a4..82c8757 100644
--- a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -18,6 +18,7 @@
#include <Utils.h>
#include <aidl/Vintf.h>
+#include <unordered_set>
#include "EffectHelper.h"
using namespace android;
@@ -38,30 +39,6 @@
* any index supported value test expects EX_NONE from IEffect.setParameter(), otherwise expects
* EX_ILLEGAL_ARGUMENT.
*/
-const std::vector<int> kRoomLevelValues = {
- EnvironmentalReverb::MIN_ROOM_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_LEVEL_MB,
- EnvironmentalReverb::MAX_ROOM_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_LEVEL_MB + 1};
-const std::vector<int> kRoomHfLevelValues = {
- EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB - 1, EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB,
- EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB, EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB + 1};
-const std::vector<int> kDecayTimeValues = {
- EnvironmentalReverb::MIN_DECAY_TIME_MS - 1, EnvironmentalReverb::MIN_DECAY_TIME_MS,
- EnvironmentalReverb::MAX_DECAY_TIME_MS, EnvironmentalReverb::MAX_DECAY_TIME_MS + 1};
-const std::vector<int> kDecayHfRatioValues = {
- EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM - 1, EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM,
- EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM, EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM + 1};
-const std::vector<int> kLevelValues = {
- EnvironmentalReverb::MIN_LEVEL_MB - 1, EnvironmentalReverb::MIN_LEVEL_MB,
- EnvironmentalReverb::MAX_LEVEL_MB, EnvironmentalReverb::MAX_LEVEL_MB + 1};
-const std::vector<int> kDelayValues = {
- EnvironmentalReverb::MIN_DELAY_MS - 1, EnvironmentalReverb::MIN_DELAY_MS,
- EnvironmentalReverb::MAX_DELAY_MS, EnvironmentalReverb::MAX_DELAY_MS + 1};
-const std::vector<int> kDiffusionValues = {
- EnvironmentalReverb::MIN_DIFFUSION_PM - 1, EnvironmentalReverb::MIN_DIFFUSION_PM,
- EnvironmentalReverb::MAX_DIFFUSION_PM, EnvironmentalReverb::MAX_DIFFUSION_PM + 1};
-const std::vector<int> kDensityValues = {
- EnvironmentalReverb::MIN_DENSITY_PM - 1, EnvironmentalReverb::MIN_DENSITY_PM,
- EnvironmentalReverb::MAX_DENSITY_PM, EnvironmentalReverb::MAX_DENSITY_PM + 1};
class EnvironmentalReverbHelper : public EffectHelper {
public:
@@ -88,8 +65,7 @@
}
Parameter::Specific getDefaultParamSpecific() {
- EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(
- EnvironmentalReverb::MIN_ROOM_LEVEL_MB);
+ EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(-6000);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
return specific;
@@ -99,14 +75,14 @@
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
- int mRoomLevel = EnvironmentalReverb::MIN_ROOM_LEVEL_MB;
- int mRoomHfLevel = EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+ int mRoomLevel = -6000;
+ int mRoomHfLevel = 0;
int mDecayTime = 1000;
int mDecayHfRatio = 500;
- int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;
+ int mLevel = -6000;
int mDelay = 40;
- int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;
- int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;
+ int mDiffusion = 1000;
+ int mDensity = 1000;
bool mBypass = false;
void SetAndGetReverbParameters() {
@@ -202,11 +178,11 @@
switch (tag) {
case EnvironmentalReverb::roomLevelMb: {
int roomLevel = er.get<EnvironmentalReverb::roomLevelMb>();
- return isRoomLevelInRange(roomLevel);
+ return isRoomLevelInRange(erCap, roomLevel);
}
case EnvironmentalReverb::roomHfLevelMb: {
int roomHfLevel = er.get<EnvironmentalReverb::roomHfLevelMb>();
- return isRoomHfLevelInRange(roomHfLevel);
+ return isRoomHfLevelInRange(erCap, roomHfLevel);
}
case EnvironmentalReverb::decayTimeMs: {
int decayTime = er.get<EnvironmentalReverb::decayTimeMs>();
@@ -214,23 +190,23 @@
}
case EnvironmentalReverb::decayHfRatioPm: {
int decayHfRatio = er.get<EnvironmentalReverb::decayHfRatioPm>();
- return isDecayHfRatioInRange(decayHfRatio);
+ return isDecayHfRatioInRange(erCap, decayHfRatio);
}
case EnvironmentalReverb::levelMb: {
int level = er.get<EnvironmentalReverb::levelMb>();
- return isLevelInRange(level);
+ return isLevelInRange(erCap, level);
}
case EnvironmentalReverb::delayMs: {
int delay = er.get<EnvironmentalReverb::delayMs>();
- return isDelayInRange(delay);
+ return isDelayInRange(erCap, delay);
}
case EnvironmentalReverb::diffusionPm: {
int diffusion = er.get<EnvironmentalReverb::diffusionPm>();
- return isDiffusionInRange(diffusion);
+ return isDiffusionInRange(erCap, diffusion);
}
case EnvironmentalReverb::densityPm: {
int density = er.get<EnvironmentalReverb::densityPm>();
- return isDensityInRange(density);
+ return isDensityInRange(erCap, density);
}
case EnvironmentalReverb::bypass: {
return true;
@@ -241,45 +217,191 @@
return false;
}
- bool isRoomLevelInRange(int roomLevel) const {
- return roomLevel >= EnvironmentalReverb::MIN_ROOM_LEVEL_MB &&
- roomLevel <= EnvironmentalReverb::MAX_ROOM_LEVEL_MB;
+ bool isRoomLevelInRange(const EnvironmentalReverb::Capability& cap, int roomLevel) const {
+ return roomLevel >= cap.minRoomLevelMb && roomLevel <= cap.maxRoomLevelMb;
}
- bool isRoomHfLevelInRange(int roomHfLevel) const {
- return roomHfLevel >= EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB &&
- roomHfLevel <= EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+ bool isRoomHfLevelInRange(const EnvironmentalReverb::Capability& cap, int roomHfLevel) const {
+ return roomHfLevel >= cap.minRoomHfLevelMb && roomHfLevel <= cap.maxRoomHfLevelMb;
}
bool isDecayTimeInRange(const EnvironmentalReverb::Capability& cap, int decayTime) const {
- return decayTime >= EnvironmentalReverb::MIN_DECAY_TIME_MS &&
- decayTime <= EnvironmentalReverb::MAX_DECAY_TIME_MS &&
- decayTime <= cap.maxDecayTimeMs;
+ return decayTime >= 0 && decayTime <= cap.maxDecayTimeMs;
}
- bool isDecayHfRatioInRange(int decayHfRatio) const {
- return decayHfRatio >= EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM &&
- decayHfRatio <= EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM;
+ bool isDecayHfRatioInRange(const EnvironmentalReverb::Capability& cap, int decayHfRatio) const {
+ return decayHfRatio >= cap.minDecayHfRatioPm && decayHfRatio <= cap.maxDecayHfRatioPm;
}
- bool isLevelInRange(int level) const {
- return level >= EnvironmentalReverb::MIN_LEVEL_MB &&
- level <= EnvironmentalReverb::MAX_LEVEL_MB;
+ bool isLevelInRange(const EnvironmentalReverb::Capability& cap, int level) const {
+ return level >= cap.minLevelMb && level <= cap.maxLevelMb;
}
- bool isDelayInRange(int delay) const {
- return delay >= EnvironmentalReverb::MIN_DELAY_MS &&
- delay <= EnvironmentalReverb::MAX_DELAY_MS;
+ bool isDelayInRange(const EnvironmentalReverb::Capability& cap, int delay) const {
+ return delay >= 0 && delay <= cap.maxDelayMs;
}
- bool isDiffusionInRange(int diffusion) const {
- return diffusion >= EnvironmentalReverb::MIN_DIFFUSION_PM &&
- diffusion <= EnvironmentalReverb::MAX_DIFFUSION_PM;
+ bool isDiffusionInRange(const EnvironmentalReverb::Capability& cap, int diffusion) const {
+ return diffusion >= 0 && diffusion <= cap.maxDiffusionPm;
}
- bool isDensityInRange(int density) const {
- return density >= EnvironmentalReverb::MIN_DENSITY_PM &&
- density <= EnvironmentalReverb::MAX_DENSITY_PM;
+ bool isDensityInRange(const EnvironmentalReverb::Capability& cap, int density) const {
+ return density >= 0 && density <= cap.maxDensityPm;
+ }
+
+ static std::unordered_set<int> getRoomLevelValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ int minRoomLevelMb = std::numeric_limits<int>::max();
+ int maxRoomLevelMb = std::numeric_limits<int>::min();
+ for (const auto& it : descList) {
+ maxRoomLevelMb = std::max(
+ it.second.capability.get<Capability::environmentalReverb>().maxRoomLevelMb,
+ maxRoomLevelMb);
+ minRoomLevelMb = std::min(
+ it.second.capability.get<Capability::environmentalReverb>().minRoomLevelMb,
+ minRoomLevelMb);
+ }
+ return {std::numeric_limits<int>::min(), minRoomLevelMb - 1, minRoomLevelMb,
+ (minRoomLevelMb + maxRoomLevelMb) >> 1, maxRoomLevelMb, maxRoomLevelMb + 1,
+ std::numeric_limits<int>::max()};
+ }
+
+ static std::unordered_set<int> getRoomHfLevelValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ int minRoomHfLevelMb = std::numeric_limits<int>::max();
+ int maxRoomHfLevelMb = std::numeric_limits<int>::min();
+ for (const auto& it : descList) {
+ maxRoomHfLevelMb = std::max(
+ it.second.capability.get<Capability::environmentalReverb>().maxRoomHfLevelMb,
+ maxRoomHfLevelMb);
+ minRoomHfLevelMb = std::min(
+ it.second.capability.get<Capability::environmentalReverb>().minRoomHfLevelMb,
+ minRoomHfLevelMb);
+ }
+ return {std::numeric_limits<int>::min(),
+ minRoomHfLevelMb - 1,
+ minRoomHfLevelMb,
+ (minRoomHfLevelMb + maxRoomHfLevelMb) >> 1,
+ maxRoomHfLevelMb,
+ maxRoomHfLevelMb + 1,
+ std::numeric_limits<int>::max()};
+ }
+
+ static std::unordered_set<int> getDecayTimeValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ const auto max = std::max_element(
+ descList.begin(), descList.end(),
+ [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+ const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+ return a.second.capability.get<Capability::environmentalReverb>()
+ .maxDecayTimeMs <
+ b.second.capability.get<Capability::environmentalReverb>()
+ .maxDecayTimeMs;
+ });
+ if (max == descList.end()) {
+ return {0};
+ }
+ int maxDecayTimeMs =
+ max->second.capability.get<Capability::environmentalReverb>().maxDecayTimeMs;
+ return {-1, 0, maxDecayTimeMs >> 1, maxDecayTimeMs - 1, maxDecayTimeMs, maxDecayTimeMs + 1};
+ }
+
+ static std::unordered_set<int> getDecayHfRatioValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ int minDecayHfRatioPm = std::numeric_limits<int>::max();
+ int maxDecayHfRatioPm = std::numeric_limits<int>::min();
+ for (const auto& it : descList) {
+ maxDecayHfRatioPm = std::max(
+ it.second.capability.get<Capability::environmentalReverb>().maxDecayHfRatioPm,
+ maxDecayHfRatioPm);
+ minDecayHfRatioPm = std::min(
+ it.second.capability.get<Capability::environmentalReverb>().minDecayHfRatioPm,
+ minDecayHfRatioPm);
+ }
+ return {std::numeric_limits<int>::min(),
+ minDecayHfRatioPm - 1,
+ minDecayHfRatioPm,
+ (minDecayHfRatioPm + maxDecayHfRatioPm) >> 1,
+ maxDecayHfRatioPm,
+ maxDecayHfRatioPm + 1,
+ std::numeric_limits<int>::max()};
+ }
+
+ static std::unordered_set<int> getLevelValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ int minLevelMb = std::numeric_limits<int>::max();
+ int maxLevelMb = std::numeric_limits<int>::min();
+ for (const auto& it : descList) {
+ maxLevelMb =
+ std::max(it.second.capability.get<Capability::environmentalReverb>().maxLevelMb,
+ maxLevelMb);
+ minLevelMb =
+ std::min(it.second.capability.get<Capability::environmentalReverb>().minLevelMb,
+ minLevelMb);
+ }
+ return {std::numeric_limits<int>::min(), minLevelMb - 1, minLevelMb,
+ (minLevelMb + maxLevelMb) >> 1, maxLevelMb, maxLevelMb + 1,
+ std::numeric_limits<int>::max()};
+ }
+
+ static std::unordered_set<int> getDelayValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ const auto max = std::max_element(
+ descList.begin(), descList.end(),
+ [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+ const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+ return a.second.capability.get<Capability::environmentalReverb>().maxDelayMs <
+ b.second.capability.get<Capability::environmentalReverb>().maxDelayMs;
+ });
+ if (max == descList.end()) {
+ return {0};
+ }
+ int maxDelayMs = max->second.capability.get<Capability::environmentalReverb>().maxDelayMs;
+ return {-1, 0, maxDelayMs >> 1, maxDelayMs - 1, maxDelayMs, maxDelayMs + 1};
+ }
+
+ static std::unordered_set<int> getDiffusionValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ const auto max = std::max_element(
+ descList.begin(), descList.end(),
+ [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+ const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+ return a.second.capability.get<Capability::environmentalReverb>()
+ .maxDiffusionPm <
+ b.second.capability.get<Capability::environmentalReverb>()
+ .maxDiffusionPm;
+ });
+ if (max == descList.end()) {
+ return {0};
+ }
+ int maxDiffusionPm =
+ max->second.capability.get<Capability::environmentalReverb>().maxDiffusionPm;
+ return {-1, 0, maxDiffusionPm >> 1, maxDiffusionPm - 1, maxDiffusionPm, maxDiffusionPm + 1};
+ }
+
+ static std::unordered_set<int> getDensityValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kEnvReverbTypeUUID);
+ const auto max = std::max_element(
+ descList.begin(), descList.end(),
+ [](const std::pair<std::shared_ptr<IFactory>, Descriptor>& a,
+ const std::pair<std::shared_ptr<IFactory>, Descriptor>& b) {
+ return a.second.capability.get<Capability::environmentalReverb>().maxDensityPm <
+ b.second.capability.get<Capability::environmentalReverb>().maxDensityPm;
+ });
+ if (max == descList.end()) {
+ return {0};
+ }
+ int maxDensityPm =
+ max->second.capability.get<Capability::environmentalReverb>().maxDensityPm;
+ return {-1, 0, maxDensityPm >> 1, maxDensityPm - 1, maxDensityPm, maxDensityPm + 1};
}
private:
@@ -310,7 +432,7 @@
EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kRoomLevelValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getRoomLevelValues())),
[](const testing::TestParamInfo<EnvironmentalReverbRoomLevelTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string roomLevel = std::to_string(std::get<1>(info.param));
@@ -347,7 +469,7 @@
EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kRoomHfLevelValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getRoomHfLevelValues())),
[](const testing::TestParamInfo<EnvironmentalReverbRoomHfLevelTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string roomHfLevel = std::to_string(std::get<1>(info.param));
@@ -384,7 +506,7 @@
EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kDecayTimeValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getDecayTimeValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDecayTimeTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string decayTime = std::to_string(std::get<1>(info.param));
@@ -421,7 +543,7 @@
EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kDecayHfRatioValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getDecayHfRatioValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string decayHfRatio = std::to_string(std::get<1>(info.param));
@@ -459,7 +581,7 @@
EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kLevelValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getLevelValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDecayHfRatioTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string level = std::to_string(std::get<1>(info.param));
@@ -496,7 +618,7 @@
EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kDelayValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getDelayValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDelayTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string delay = std::to_string(std::get<1>(info.param));
@@ -533,7 +655,7 @@
EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kDiffusionValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getDiffusionValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDiffusionTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string diffusion = std::to_string(std::get<1>(info.param));
@@ -570,7 +692,7 @@
EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kEnvReverbTypeUUID)),
- testing::ValuesIn(kDensityValues)),
+ testing::ValuesIn(EnvironmentalReverbHelper::getDensityValues())),
[](const testing::TestParamInfo<EnvironmentalReverbDensityTest::ParamType>& info) {
auto descriptor = std::get<0>(info.param).second;
std::string density = std::to_string(std::get<1>(info.param));
diff --git a/automotive/can/aidl/default/tools/configurator/canprototools.cpp b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
index 2aea315..84edd94 100644
--- a/automotive/can/aidl/default/tools/configurator/canprototools.cpp
+++ b/automotive/can/aidl/default/tools/configurator/canprototools.cpp
@@ -51,15 +51,20 @@
return std::string(buff, 0, std::min(n, got));
}
-std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
- std::ifstream cfg_stream(filepath);
-
- // text headers that would be present in a plaintext proto config file.
+/*
+ parseConfigFile *used to* contain the body of parseConfigStream. However, it seems there's some
+ sort of odd behavior with IstreamInputStream and/or TextFormat::Parse, which causes HW Address
+ Sanitizer to flag a "tag-mismatch" in this function. Having the ifstream defined in a wrapper
+ function seems to solve this problem. The exact cause of this problem is yet unknown, but probably
+ lies somewhere in the protobuf implementation.
+*/
+static __attribute__((noinline)) std::optional<CanBusConfig> parseConfigStream(
+ std::ifstream& cfg_stream) {
static const std::array<std::string, 3> text_headers = {"buses", "#", "controller"};
auto cfg_file_snippet = readString(cfg_stream, 10);
if (!cfg_file_snippet.has_value()) {
- LOG(ERROR) << "Can't open " << filepath << " for reading";
+ LOG(ERROR) << "Can't read config from stream (maybe failed to open file?)";
return std::nullopt;
}
cfg_stream.seekg(0);
@@ -77,16 +82,25 @@
if (text_format) {
google::protobuf::io::IstreamInputStream pb_stream(&cfg_stream);
if (!google::protobuf::TextFormat::Parse(&pb_stream, &config)) {
- LOG(ERROR) << "Failed to parse (text format) " << filepath;
+ LOG(ERROR) << "Parsing text format config failed";
return std::nullopt;
}
} else if (!config.ParseFromIstream(&cfg_stream)) {
- LOG(ERROR) << "Failed to parse (binary format) " << filepath;
+ LOG(ERROR) << "Parsing binary format config failed";
return std::nullopt;
}
return config;
}
+std::optional<CanBusConfig> parseConfigFile(const std::string& filepath) {
+ std::ifstream cfg_stream(filepath);
+ auto cfg_maybe = parseConfigStream(cfg_stream);
+ if (!cfg_maybe.has_value()) {
+ LOG(ERROR) << "Failed to parse " << filepath;
+ }
+ return cfg_maybe;
+}
+
std::optional<BusConfig> fromPbBus(const Bus& pb_bus) {
BusConfig bus_cfg = {};
bus_cfg.name = pb_bus.name();
diff --git a/automotive/vehicle/Android.bp b/automotive/vehicle/Android.bp
new file mode 100644
index 0000000..f4a7cd1
--- /dev/null
+++ b/automotive/vehicle/Android.bp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_defaults {
+ name: "VehicleHalInterfaceDefaults",
+ static_libs: [
+ "android.hardware.automotive.vehicle-V2-ndk",
+ ],
+}
diff --git a/automotive/vehicle/aidl/impl/Android.bp b/automotive/vehicle/aidl/impl/Android.bp
index 73f7df0..d2c5145 100644
--- a/automotive/vehicle/aidl/impl/Android.bp
+++ b/automotive/vehicle/aidl/impl/Android.bp
@@ -19,13 +19,6 @@
}
cc_defaults {
- name: "VehicleHalInterfaceDefaults",
- static_libs: [
- "android.hardware.automotive.vehicle-V2-ndk",
- ],
-}
-
-cc_defaults {
name: "VehicleHalDefaults",
static_libs: [
"android-automotive-large-parcelable-lib",
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 80c299d..8181769 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -1744,6 +1744,77 @@
}
},
{
+ "property": "VehicleProperty::HW_KEY_INPUT_V2",
+ "defaultValue": {
+ "int32Values": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "int64Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER"
+ }
+ ]
+ },
+ {
+ "property": "VehicleProperty::HW_MOTION_INPUT",
+ "defaultValue": {
+ "int32Values": [
+ 0,
+ 0,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0
+ ],
+ "floatValues": [
+ 0,
+ 0,
+ 0,
+ 0
+ ],
+ "int64Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_LEFT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_RIGHT"
+ },
+ {
+ "areaId": "Constants::SEAT_2_CENTER"
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::HW_ROTARY_INPUT",
"defaultValue": {
"int32Values": [
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
index e515bad..956c7c0 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/include/FakeVehicleHardware.h
@@ -194,7 +194,7 @@
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
ValueResultType getEchoReverseBytes(
const aidl::android::hardware::automotive::vehicle::VehiclePropValue& value) const;
- bool isHvacPropAndHvacNotAvailable(int32_t propId);
+ bool isHvacPropAndHvacNotAvailable(int32_t propId) const;
std::unordered_map<int32_t, ConfigDeclaration> loadConfigDeclarations();
@@ -236,10 +236,19 @@
const aidl::android::hardware::automotive::vehicle::SetValueRequest& request);
std::string genFakeDataCommand(const std::vector<std::string>& options);
+ void sendHvacPropertiesCurrentValues();
static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwInputKeyProp(
aidl::android::hardware::automotive::vehicle::VehicleHwKeyInputAction action,
int32_t keyCode, int32_t targetDisplay);
+ static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwKeyInputV2Prop(
+ int32_t area, int32_t targetDisplay, int32_t keyCode, int32_t action,
+ int32_t repeatCount);
+ static aidl::android::hardware::automotive::vehicle::VehiclePropValue createHwMotionInputProp(
+ int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+ int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[],
+ float yData[], float pressure[], float size[]);
+
static std::string genFakeDataHelp();
static std::string parseErrMsg(std::string fieldName, std::string value, std::string type);
};
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
index dd76524..a9dced9 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/src/FakeVehicleHardware.cpp
@@ -295,7 +295,7 @@
return {};
}
-bool FakeVehicleHardware::isHvacPropAndHvacNotAvailable(int32_t propId) {
+bool FakeVehicleHardware::isHvacPropAndHvacNotAvailable(int32_t propId) const {
std::unordered_set<int32_t> powerProps(std::begin(HVAC_POWER_PROPERTIES),
std::end(HVAC_POWER_PROPERTIES));
if (powerProps.count(propId)) {
@@ -366,6 +366,11 @@
return getUserHalProp(value);
}
+ if (isHvacPropAndHvacNotAvailable(propId)) {
+ *isSpecialValue = true;
+ return StatusError(StatusCode::NOT_AVAILABLE) << "hvac not available";
+ }
+
switch (propId) {
case OBD2_FREEZE_FRAME:
*isSpecialValue = true;
@@ -408,6 +413,27 @@
return std::move(gotValue);
}
+void FakeVehicleHardware::sendHvacPropertiesCurrentValues() {
+ for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
+ int powerPropId = HVAC_POWER_PROPERTIES[i];
+ auto powerPropResults = mServerSidePropStore->readValuesForProperty(powerPropId);
+ if (!powerPropResults.ok()) {
+ ALOGW("failed to get power prop 0x%x, error: %s", powerPropId,
+ getErrorMsg(powerPropResults).c_str());
+ continue;
+ }
+ auto& powerPropValues = powerPropResults.value();
+ for (size_t j = 0; j < powerPropValues.size(); j++) {
+ auto powerPropValue = std::move(powerPropValues[j]);
+ powerPropValue->status = VehiclePropertyStatus::AVAILABLE;
+ powerPropValue->timestamp = elapsedRealtimeNano();
+ // This will trigger a property change event for the current hvac property value.
+ mServerSidePropStore->writeValue(std::move(powerPropValue), /*updateStatus=*/true,
+ VehiclePropertyStore::EventMode::ALWAYS);
+ }
+ }
+}
+
VhalResult<void> FakeVehicleHardware::maybeSetSpecialValue(const VehiclePropValue& value,
bool* isSpecialValue) {
*isSpecialValue = false;
@@ -419,6 +445,13 @@
return setUserHalProp(value);
}
+ if (propId == toInt(VehicleProperty::HVAC_POWER_ON) && value.value.int32Values.size() == 1 &&
+ value.value.int32Values[0] == 1) {
+ // If we are turning HVAC power on, send current hvac property values through on change
+ // event.
+ sendHvacPropertiesCurrentValues();
+ }
+
if (isHvacPropAndHvacNotAvailable(propId)) {
*isSpecialValue = true;
return StatusError(StatusCode::NOT_AVAILABLE) << "hvac not available";
@@ -672,6 +705,14 @@
--genfakedata --keypress [keyCode(int32)] [display[int32]]: Generate key press.
+--genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]] [action[int32]]
+ [repeatCount(int32)]
+
+--genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]] [action[int32]]
+ [buttonState(int32)] --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+ [pressure(float)] [size(float)]
+ Generate a motion input event. --pointer option can be specified multiple times.
+
)";
}
@@ -802,6 +843,135 @@
onValueChangeCallback(
createHwInputKeyProp(VehicleHwKeyInputAction::ACTION_UP, keyCode, display));
return "keypress event generated successfully";
+ } else if (command == "--keyinputv2") {
+ int32_t area;
+ int32_t display;
+ int32_t keyCode;
+ int32_t action;
+ int32_t repeatCount;
+ // --genfakedata --keyinputv2 [area(int32)] [display(int32)] [keyCode[int32]]
+ // [action[int32]] [repeatCount(int32)]
+ if (options.size() != 7) {
+ return "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n";
+ }
+ if (!android::base::ParseInt(options[2], &area)) {
+ return parseErrMsg("area", options[2], "int");
+ }
+ if (!android::base::ParseInt(options[3], &display)) {
+ return parseErrMsg("display", options[3], "int");
+ }
+ if (!android::base::ParseInt(options[4], &keyCode)) {
+ return parseErrMsg("keyCode", options[4], "int");
+ }
+ if (!android::base::ParseInt(options[5], &action)) {
+ return parseErrMsg("action", options[5], "int");
+ }
+ if (!android::base::ParseInt(options[6], &repeatCount)) {
+ return parseErrMsg("repeatCount", options[6], "int");
+ }
+ // Send back to HAL
+ onValueChangeCallback(createHwKeyInputV2Prop(area, display, keyCode, action, repeatCount));
+ return StringPrintf(
+ "keyinputv2 event generated successfully with area:%d, display:%d,"
+ " keyCode:%d, action:%d, repeatCount:%d",
+ area, display, keyCode, action, repeatCount);
+
+ } else if (command == "--motioninput") {
+ int32_t area;
+ int32_t display;
+ int32_t inputType;
+ int32_t action;
+ int32_t buttonState;
+ int32_t pointerCount;
+
+ // --genfakedata --motioninput [area(int32)] [display(int32)] [inputType[int32]]
+ // [action[int32]] [buttonState(int32)] [pointerCount(int32)]
+ // --pointer [pointerId(int32)] [toolType(int32)] [xData(float)] [yData(float)]
+ // [pressure(float)] [size(float)]
+ int optionsSize = (int)options.size();
+ if (optionsSize / 7 < 2) {
+ return "incorrect argument count, need at least 14 arguments for --genfakedata "
+ "--motioninput including at least 1 --pointer\n";
+ }
+
+ if (optionsSize % 7 != 0) {
+ return "incorrect argument count, need 6 arguments for every --pointer\n";
+ }
+ pointerCount = (int)optionsSize / 7 - 1;
+
+ if (!android::base::ParseInt(options[2], &area)) {
+ return parseErrMsg("area", options[2], "int");
+ }
+ if (!android::base::ParseInt(options[3], &display)) {
+ return parseErrMsg("display", options[3], "int");
+ }
+ if (!android::base::ParseInt(options[4], &inputType)) {
+ return parseErrMsg("inputType", options[4], "int");
+ }
+ if (!android::base::ParseInt(options[5], &action)) {
+ return parseErrMsg("action", options[5], "int");
+ }
+ if (!android::base::ParseInt(options[6], &buttonState)) {
+ return parseErrMsg("buttonState", options[6], "int");
+ }
+
+ int32_t pointerId[pointerCount];
+ int32_t toolType[pointerCount];
+ float xData[pointerCount];
+ float yData[pointerCount];
+ float pressure[pointerCount];
+ float size[pointerCount];
+
+ for (int i = 7, pc = 0; i < optionsSize; i += 7, pc += 1) {
+ int offset = i;
+ if (options[offset] != "--pointer") {
+ return "--pointer is needed for the motion input\n";
+ }
+ offset += 1;
+ if (!android::base::ParseInt(options[offset], &pointerId[pc])) {
+ return parseErrMsg("pointerId", options[offset], "int");
+ }
+ offset += 1;
+ if (!android::base::ParseInt(options[offset], &toolType[pc])) {
+ return parseErrMsg("toolType", options[offset], "int");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &xData[pc])) {
+ return parseErrMsg("xData", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &yData[pc])) {
+ return parseErrMsg("yData", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &pressure[pc])) {
+ return parseErrMsg("pressure", options[offset], "float");
+ }
+ offset += 1;
+ if (!android::base::ParseFloat(options[offset], &size[pc])) {
+ return parseErrMsg("size", options[offset], "float");
+ }
+ }
+
+ // Send back to HAL
+ onValueChangeCallback(createHwMotionInputProp(area, display, inputType, action, buttonState,
+ pointerCount, pointerId, toolType, xData,
+ yData, pressure, size));
+
+ std::string successMessage = StringPrintf(
+ "motion event generated successfully with area:%d, display:%d,"
+ " inputType:%d, action:%d, buttonState:%d, pointerCount:%d\n",
+ area, display, inputType, action, buttonState, pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ successMessage += StringPrintf(
+ "Pointer #%d {\n"
+ " id:%d , tooltype:%d \n"
+ " x:%f , y:%f\n"
+ " pressure: %f, data: %f\n"
+ "}\n",
+ i, pointerId[i], toolType[i], xData[i], yData[i], pressure[i], size[i]);
+ }
+ return successMessage;
}
return StringPrintf("Unknown command: \"%s\"\n%s", command.c_str(), genFakeDataHelp().c_str());
@@ -819,6 +989,59 @@
return value;
}
+VehiclePropValue FakeVehicleHardware::createHwKeyInputV2Prop(int32_t area, int32_t targetDisplay,
+ int32_t keyCode, int32_t action,
+ int32_t repeatCount) {
+ VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_KEY_INPUT_V2),
+ .areaId = area,
+ .timestamp = elapsedRealtimeNano(),
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int32Values = {targetDisplay, keyCode, action, repeatCount},
+ .value.int64Values = {elapsedRealtimeNano()}};
+ return value;
+}
+
+VehiclePropValue FakeVehicleHardware::createHwMotionInputProp(
+ int32_t area, int32_t display, int32_t inputType, int32_t action, int32_t buttonState,
+ int32_t pointerCount, int32_t pointerId[], int32_t toolType[], float xData[], float yData[],
+ float pressure[], float size[]) {
+ std::vector<int> intValues;
+ intValues.push_back(display);
+ intValues.push_back(inputType);
+ intValues.push_back(action);
+ intValues.push_back(buttonState);
+ intValues.push_back(pointerCount);
+ for (int i = 0; i < pointerCount; i++) {
+ intValues.push_back(pointerId[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ intValues.push_back(toolType[i]);
+ }
+
+ std::vector<float> floatValues;
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(xData[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(yData[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(pressure[i]);
+ }
+ for (int i = 0; i < pointerCount; i++) {
+ floatValues.push_back(size[i]);
+ }
+
+ VehiclePropValue value = {.prop = toInt(VehicleProperty::HW_MOTION_INPUT),
+ .areaId = area,
+ .timestamp = elapsedRealtimeNano(),
+ .status = VehiclePropertyStatus::AVAILABLE,
+ .value.int32Values = intValues,
+ .value.floatValues = floatValues,
+ .value.int64Values = {elapsedRealtimeNano()}};
+ return value;
+}
+
void FakeVehicleHardware::eventFromVehicleBus(const VehiclePropValue& value) {
mServerSidePropStore->writeValue(mValuePool->obtain(value));
}
diff --git a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
index 0184462..67b1aa4 100644
--- a/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
+++ b/automotive/vehicle/aidl/impl/fake_impl/hardware/test/FakeVehicleHardwareTest.cpp
@@ -61,6 +61,7 @@
using ::android::base::ScopedLockAssertion;
using ::android::base::StringPrintf;
using ::android::base::unexpected;
+using ::testing::AnyOfArray;
using ::testing::ContainerEq;
using ::testing::ContainsRegex;
using ::testing::Eq;
@@ -1140,6 +1141,71 @@
EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE);
}
+TEST_F(FakeVehicleHardwareTest, testGetHvacPropNotAvailable) {
+ StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .areaId = HVAC_ALL,
+ .value.int32Values = {0}});
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
+ int powerPropId = HVAC_POWER_PROPERTIES[i];
+ auto getValueResult = getValue(VehiclePropValue{
+ .prop = powerPropId,
+ .areaId = HVAC_ALL,
+ });
+
+ EXPECT_FALSE(getValueResult.ok());
+ EXPECT_EQ(getValueResult.error(), StatusCode::NOT_AVAILABLE);
+ }
+}
+
+TEST_F(FakeVehicleHardwareTest, testSetHvacPropNotAvailable) {
+ StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .areaId = HVAC_ALL,
+ .value.int32Values = {0}});
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
+ int powerPropId = HVAC_POWER_PROPERTIES[i];
+ status = setValue(VehiclePropValue{
+ .prop = powerPropId,
+ .areaId = HVAC_ALL,
+ });
+
+ EXPECT_EQ(status, StatusCode::NOT_AVAILABLE);
+ }
+}
+
+TEST_F(FakeVehicleHardwareTest, testHvacPowerOnSendCurrentHvacPropValues) {
+ StatusCode status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .areaId = HVAC_ALL,
+ .value.int32Values = {0}});
+
+ ASSERT_EQ(status, StatusCode::OK);
+
+ clearChangedProperties();
+
+ status = setValue(VehiclePropValue{.prop = toInt(VehicleProperty::HVAC_POWER_ON),
+ .areaId = HVAC_ALL,
+ .value.int32Values = {1}});
+
+ auto events = getChangedProperties();
+ // If we turn HVAC power on, we expect to receive one property event for every HVAC prop areas
+ // plus one event for HVAC_POWER_ON.
+ std::vector<int32_t> changedPropIds;
+ for (size_t i = 0; i < sizeof(HVAC_POWER_PROPERTIES) / sizeof(int32_t); i++) {
+ changedPropIds.push_back(HVAC_POWER_PROPERTIES[i]);
+ }
+ changedPropIds.push_back(toInt(VehicleProperty::HVAC_POWER_ON));
+ ASSERT_EQ(events.size(), changedPropIds.size());
+ for (const auto& event : events) {
+ EXPECT_EQ(event.areaId, HVAC_ALL);
+ EXPECT_THAT(event.prop, AnyOfArray(changedPropIds));
+ }
+}
+
TEST_F(FakeVehicleHardwareTest, testGetUserPropertySetOnly) {
for (VehicleProperty prop : std::vector<VehicleProperty>({
VehicleProperty::INITIAL_USER_INFO,
@@ -1776,7 +1842,61 @@
"failed to parse keyCode as int: \"0.1\""},
{"genfakedata_keypress_invalid_display",
{"--genfakedata", "--keypress", "1", "0.1"},
- "failed to parse display as int: \"0.1\""}};
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_keyinputv2_incorrect_arguments",
+ {"--genfakedata", "--keyinputv2", "1", "1"},
+ "incorrect argument count, need 7 arguments for --genfakedata --keyinputv2\n"},
+ {"genfakedata_keyinputv2_invalid_area",
+ {"--genfakedata", "--keyinputv2", "0.1", "1", "1", "1", "1"},
+ "failed to parse area as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_display",
+ {"--genfakedata", "--keyinputv2", "1", "0.1", "1", "1", "1"},
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_keycode",
+ {"--genfakedata", "--keyinputv2", "1", "1", "0.1", "1", "1"},
+ "failed to parse keyCode as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_action",
+ {"--genfakedata", "--keyinputv2", "1", "1", "1", "0.1", "1"},
+ "failed to parse action as int: \"0.1\""},
+ {"genfakedata_keyinputv2_invalid_repeatcount",
+ {"--genfakedata", "--keyinputv2", "1", "1", "1", "1", "0.1"},
+ "failed to parse repeatCount as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_argument_count",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1"},
+ "incorrect argument count, need at least 14 arguments for --genfakedata "
+ "--motioninput including at least 1 --pointer\n"},
+ {"genfakedata_motioninput_pointer_invalid_argument_count",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "1", "1",
+ "1", "1", "1", "--pointer"},
+ "incorrect argument count, need 6 arguments for every --pointer\n"},
+ {"genfakedata_motioninput_invalid_area",
+ {"--genfakedata", "--motioninput", "0.1", "1", "1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse area as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_display",
+ {"--genfakedata", "--motioninput", "1", "0.1", "1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse display as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_inputtype",
+ {"--genfakedata", "--motioninput", "1", "1", "0.1", "1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse inputType as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_action",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "0.1", "1", "--pointer", "1", "1",
+ "1", "1", "1", "1"},
+ "failed to parse action as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_buttonstate",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "0.1", "--pointer", "1", "1",
+ "1.2", "1.2", "1.2", "1.2"},
+ "failed to parse buttonState as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_pointerid",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "0.1", "1",
+ "1.2", "1", "1", "1"},
+ "failed to parse pointerId as int: \"0.1\""},
+ {"genfakedata_motioninput_invalid_tooltype",
+ {"--genfakedata", "--motioninput", "1", "1", "1", "1", "1", "--pointer", "1", "0.1",
+ "1.2", "1", "1", "1"},
+ "failed to parse toolType as int: \"0.1\""}};
}
TEST_P(FakeVehicleHardwareOptionsTest, testInvalidOptions) {
@@ -1965,6 +2085,78 @@
EXPECT_EQ(2, events[1].value.int32Values[2]);
}
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataKeyInputV2) {
+ std::vector<std::string> options = {"--genfakedata", "--keyinputv2", "1", "2", "3", "4", "5"};
+
+ DumpResult result = getHardware()->dump(options);
+
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+ auto events = getChangedProperties();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_EQ(toInt(VehicleProperty::HW_KEY_INPUT_V2), events[0].prop);
+ ASSERT_EQ(4u, events[0].value.int32Values.size());
+ EXPECT_EQ(2, events[0].value.int32Values[0]);
+ EXPECT_EQ(3, events[0].value.int32Values[1]);
+ EXPECT_EQ(4, events[0].value.int32Values[2]);
+ EXPECT_EQ(5, events[0].value.int32Values[3]);
+ ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
+TEST_F(FakeVehicleHardwareTest, testDebugGenFakeDataMotionInput) {
+ std::vector<std::string> options = {"--genfakedata",
+ "--motioninput",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "--pointer",
+ "11",
+ "22",
+ "33.3",
+ "44.4",
+ "55.5",
+ "66.6",
+ "--pointer",
+ "21",
+ "32",
+ "43.3",
+ "54.4",
+ "65.5",
+ "76.6"};
+
+ DumpResult result = getHardware()->dump(options);
+
+ ASSERT_FALSE(result.callerShouldDumpState);
+ ASSERT_THAT(result.buffer, HasSubstr("successfully"));
+
+ auto events = getChangedProperties();
+ ASSERT_EQ(1u, events.size());
+ EXPECT_EQ(toInt(VehicleProperty::HW_MOTION_INPUT), events[0].prop);
+ ASSERT_EQ(9u, events[0].value.int32Values.size());
+ EXPECT_EQ(2, events[0].value.int32Values[0]);
+ EXPECT_EQ(3, events[0].value.int32Values[1]);
+ EXPECT_EQ(4, events[0].value.int32Values[2]);
+ EXPECT_EQ(5, events[0].value.int32Values[3]);
+ EXPECT_EQ(2, events[0].value.int32Values[4]);
+ EXPECT_EQ(11, events[0].value.int32Values[5]);
+ EXPECT_EQ(21, events[0].value.int32Values[6]);
+ EXPECT_EQ(22, events[0].value.int32Values[7]);
+ EXPECT_EQ(32, events[0].value.int32Values[8]);
+ ASSERT_EQ(8u, events[0].value.floatValues.size());
+ EXPECT_FLOAT_EQ(33.3, events[0].value.floatValues[0]);
+ EXPECT_FLOAT_EQ(43.3, events[0].value.floatValues[1]);
+ EXPECT_FLOAT_EQ(44.4, events[0].value.floatValues[2]);
+ EXPECT_FLOAT_EQ(54.4, events[0].value.floatValues[3]);
+ EXPECT_FLOAT_EQ(55.5, events[0].value.floatValues[4]);
+ EXPECT_FLOAT_EQ(65.5, events[0].value.floatValues[5]);
+ EXPECT_FLOAT_EQ(66.6, events[0].value.floatValues[6]);
+ EXPECT_FLOAT_EQ(76.6, events[0].value.floatValues[7]);
+ ASSERT_EQ(1u, events[0].value.int64Values.size());
+}
+
TEST_F(FakeVehicleHardwareTest, testGetEchoReverseBytes) {
ASSERT_EQ(setValue(VehiclePropValue{
.prop = ECHO_REVERSE_BYTES,
diff --git a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
index c8b5c65..f8a4e7d 100644
--- a/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
+++ b/automotive/vehicle/aidl/impl/vhal/src/VehicleService.cpp
@@ -27,6 +27,13 @@
using ::android::hardware::automotive::vehicle::fake::FakeVehicleHardware;
int main(int /* argc */, char* /* argv */[]) {
+ ALOGI("Starting thread pool...");
+ if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
+ ALOGE("%s", "failed to set thread pool max thread count");
+ return 1;
+ }
+ ABinderProcess_startThreadPool();
+
std::unique_ptr<FakeVehicleHardware> hardware = std::make_unique<FakeVehicleHardware>();
std::shared_ptr<DefaultVehicleHal> vhal =
::ndk::SharedRefBase::make<DefaultVehicleHal>(std::move(hardware));
@@ -39,12 +46,6 @@
return 1;
}
- if (!ABinderProcess_setThreadPoolMaxThreadCount(4)) {
- ALOGE("%s", "failed to set thread pool max thread count");
- return 1;
- }
- ABinderProcess_startThreadPool();
-
ALOGI("Vehicle Service Ready");
ABinderProcess_joinThreadPool();
diff --git a/automotive/vehicle/vhal_static_cpp_lib.mk b/automotive/vehicle/vhal_static_cpp_lib.mk
new file mode 100644
index 0000000..b15b26c
--- /dev/null
+++ b/automotive/vehicle/vhal_static_cpp_lib.mk
@@ -0,0 +1,18 @@
+# Copyright (C) 2023 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This make file contains the latest version of static cpp libraries for VHAL
+# interface and VHAL properties.
+
+LOCAL_STATIC_LIBRARIES += android.hardware.automotive.vehicle-V2-ndk
diff --git a/camera/device/3.2/default/convert.cpp b/camera/device/3.2/default/convert.cpp
index 06ad7e9..2075607 100644
--- a/camera/device/3.2/default/convert.cpp
+++ b/camera/device/3.2/default/convert.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "android.hardware.camera.device@3.2-convert-impl"
#include <log/log.h>
+#include <system/camera_metadata.h>
#include "include/convert.h"
@@ -43,6 +44,13 @@
ALOGE("%s: input CameraMetadata is corrupt!", __FUNCTION__);
return false;
}
+
+ if (validate_camera_metadata_structure((camera_metadata_t*)data, /*expected_size=*/NULL) !=
+ OK) {
+ ALOGE("%s: Failed to validate the metadata structure", __FUNCTION__);
+ return false;
+ }
+
*dst = (camera_metadata_t*) data;
return true;
}
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index 8b8a4bc..f13d6b2 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -17,7 +17,10 @@
#ifndef HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
#define HARDWARE_INTERFACES_CAMERA_PROVIDER_AIDL_VTS_CAMERA_AIDL_TEST_H_
+// TODO: LOG_TAG should not be in header
+#ifndef LOG_TAG
#define LOG_TAG "camera_aidl_hal_test"
+#endif
#include <string>
#include <unordered_map>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index 9ccb6ec..1403ec4 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -1,12 +1,4 @@
<compatibility-matrix version="1.0" type="framework" level="8">
- <hal format="hidl" optional="true">
- <name>android.hardware.atrace</name>
- <version>1.0</version>
- <interface>
- <name>IAtraceDevice</name>
- <instance>default</instance>
- </interface>
- </hal>
<hal format="hidl" optional="false">
<name>android.hardware.audio</name>
<version>6.0</version>
@@ -307,6 +299,7 @@
<instance>default</instance>
</interface>
</hal>
+ <!-- Either the native or the HIDL mapper HAL must exist on the device -->
<hal format="hidl" optional="true">
<name>android.hardware.graphics.mapper</name>
<!-- New, non-Go devices should use 4.0, tested in vts_treble_vintf_vendor_test -->
@@ -609,6 +602,14 @@
<instance>default</instance>
</interface>
</hal>
+ <hal format="hidl" optional="true">
+ <name>android.hardware.soundtrigger</name>
+ <version>2.3</version>
+ <interface>
+ <name>ISoundTriggerHw</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
<hal format="aidl" optional="true">
<name>android.hardware.soundtrigger3</name>
<version>1</version>
@@ -765,9 +766,10 @@
<instance>default</instance>
</interface>
</hal>
- <hal format="native">
+ <!-- Either the native or the HIDL mapper HAL must exist on the device -->
+ <hal format="native" optional="true">
<name>mapper</name>
- <version>1.0</version>
+ <version>5.0</version>
<interface>
<name>I</name>
<regex-instance>.*</regex-instance>
diff --git a/contexthub/1.0/default/OWNERS b/contexthub/1.0/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.0/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/default/OWNERS b/contexthub/1.1/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.1/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.1/vts/functional/OWNERS b/contexthub/1.1/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.1/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.2/default/OWNERS b/contexthub/1.2/default/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/1.2/default/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/1.2/vts/functional/OWNERS b/contexthub/1.2/vts/functional/OWNERS
deleted file mode 100644
index 2cf5bca..0000000
--- a/contexthub/1.2/vts/functional/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-# Bug component: 156070
-include ../../../1.0/vts/functional/OWNERS
diff --git a/contexthub/1.0/vts/functional/OWNERS b/contexthub/OWNERS
similarity index 81%
rename from contexthub/1.0/vts/functional/OWNERS
rename to contexthub/OWNERS
index f254cd5..d5cfc2e 100644
--- a/contexthub/1.0/vts/functional/OWNERS
+++ b/contexthub/OWNERS
@@ -1,5 +1,4 @@
# Bug component: 156070
-#Context Hub team
arthuri@google.com
bduddie@google.com
stange@google.com
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
index 272d768..c1f4df8 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHub.aidl
@@ -46,5 +46,6 @@
void onHostEndpointConnected(in android.hardware.contexthub.HostEndpointInfo hostEndpointInfo);
void onHostEndpointDisconnected(char hostEndpointId);
long[] getPreloadedNanoappIds();
+ void onNanSessionStateChanged(in boolean state);
const int EX_CONTEXT_HUB_UNSPECIFIED = -1;
}
diff --git a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
index f81f7cf..e72ae73 100644
--- a/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/aidl_api/android.hardware.contexthub/current/android/hardware/contexthub/IContextHubCallback.aidl
@@ -38,4 +38,6 @@
void handleContextHubMessage(in android.hardware.contexthub.ContextHubMessage msg, in String[] msgContentPerms);
void handleContextHubAsyncEvent(in android.hardware.contexthub.AsyncEventType evt);
void handleTransactionResult(in int transactionId, in boolean success);
+ void handleNanSessionRequest(in boolean enable);
+ const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
}
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
index 9fa67a5..7f50730 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHub.aidl
@@ -204,6 +204,19 @@
long[] getPreloadedNanoappIds();
/**
+ * Invoked when the state of the NAN session requested through handleNanSessionRequest()
+ * changes. This function may be invoked without a corresponding handleNanSessionRequest to
+ * indicate if a NAN session was terminated without a request due to resource limitations.
+ *
+ * If the state becomes disabled without an explicit request from the HAL, the HAL MUST
+ * explicitly invoke handleNanSessionRequest() at a later point in time to attempt to
+ * re-enable NAN.
+ *
+ * @param state True if the NAN session is currently enabled.
+ */
+ void onNanSessionStateChanged(in boolean state);
+
+ /**
* Error codes that are used as service specific errors with the AIDL return
* value EX_SERVICE_SPECIFIC.
*/
diff --git a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
index e385d48..cff1893 100644
--- a/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
+++ b/contexthub/aidl/android/hardware/contexthub/IContextHubCallback.aidl
@@ -74,4 +74,25 @@
*
*/
void handleTransactionResult(in int transactionId, in boolean success);
+
+ /**
+ * This callback is passed by the Contexthub service to the HAL implementation to allow the HAL
+ * to request a WiFi NAN session is created to allow the Contexthub to be able to utilize NAN
+ * functionality.
+ *
+ * onNanSessionStateChanged() will be invoked asynchronously after the NAN session request has
+ * been completed. This must be done within CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS. If the
+ * request times out, onNanSessionStateChanged() will be invoked with the state that the session
+ * was previously in.
+ *
+ * @param enable Whether the NAN session should be enabled or disabled depending on whether the
+ * Contexthub needs access to NAN.
+ */
+ void handleNanSessionRequest(in boolean enable);
+
+ /**
+ * Amount of time, in milliseconds, that a handleNanSessionRequest can be pending before the
+ * Contexthub service must respond.
+ */
+ const int CONTEXTHUB_NAN_TRANSACTION_TIMEOUT_MS = 10000;
}
diff --git a/contexthub/aidl/default/ContextHub.cpp b/contexthub/aidl/default/ContextHub.cpp
index ac1dc46..615ac5c 100644
--- a/contexthub/aidl/default/ContextHub.cpp
+++ b/contexthub/aidl/default/ContextHub.cpp
@@ -87,6 +87,10 @@
return ndk::ScopedAStatus::ok();
}
+ScopedAStatus ContextHub::onNanSessionStateChanged(bool /*sin_state*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus ContextHub::registerCallback(int32_t in_contextHubId,
const std::shared_ptr<IContextHubCallback>& in_cb) {
if (in_contextHubId == kMockHubId) {
diff --git a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
index 4aeb948..b3998b9 100644
--- a/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
+++ b/contexthub/aidl/default/include/contexthub-impl/ContextHub.h
@@ -47,6 +47,7 @@
::ndk::ScopedAStatus onHostEndpointConnected(const HostEndpointInfo& in_info) override;
::ndk::ScopedAStatus onHostEndpointDisconnected(char16_t in_hostEndpointId) override;
+ ::ndk::ScopedAStatus onNanSessionStateChanged(bool in_state) override;
private:
static constexpr uint32_t kMockHubId = 0;
diff --git a/contexthub/aidl/vts/OWNERS b/contexthub/aidl/vts/OWNERS
deleted file mode 100644
index 150818d..0000000
--- a/contexthub/aidl/vts/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-file:/contexthub/common/vts/OWNERS
diff --git a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
index 8104f27..4731648 100644
--- a/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
+++ b/contexthub/aidl/vts/VtsAidlHalContextHubTargetTest.cpp
@@ -100,6 +100,8 @@
Status handleTransactionResult(int32_t /* transactionId */, bool /* success */) override {
return Status::ok();
}
+
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
};
TEST_P(ContextHubAidl, TestRegisterCallback) {
@@ -131,6 +133,8 @@
return Status::ok();
}
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
std::promise<std::vector<NanoappInfo>> promise;
};
@@ -194,6 +198,8 @@
return Status::ok();
}
+ Status handleNanSessionRequest(bool /* enable */) override { return Status::ok(); }
+
uint32_t expectedTransactionId = 0;
std::promise<bool> promise;
};
@@ -354,6 +360,11 @@
ASSERT_TRUE(contextHub->onHostEndpointDisconnected(kHostEndpointId).isOk());
}
+TEST_P(ContextHubAidl, TestNanSessionStateChange) {
+ ASSERT_TRUE(contextHub->onNanSessionStateChanged(true /*state*/).isOk());
+ ASSERT_TRUE(contextHub->onNanSessionStateChanged(false /*state*/).isOk());
+}
+
std::string PrintGeneratedTest(const testing::TestParamInfo<ContextHubAidl::ParamType>& info) {
return std::string("CONTEXT_HUB_ID_") + std::to_string(std::get<1>(info.param));
}
diff --git a/contexthub/common/default/1.X/OWNERS b/contexthub/common/default/1.X/OWNERS
deleted file mode 100644
index 90c2330..0000000
--- a/contexthub/common/default/1.X/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-arthuri@google.com
-bduddie@google.com
-stange@google.com
diff --git a/contexthub/common/vts/OWNERS b/contexthub/common/vts/OWNERS
deleted file mode 100644
index 161b2f0..0000000
--- a/contexthub/common/vts/OWNERS
+++ /dev/null
@@ -1,8 +0,0 @@
-#Context Hub team
-arthuri@google.com
-bduddie@google.com
-stange@google.com
-
-#VTS team
-dshi@google.com
-trong@google.com
diff --git a/graphics/Android.bp b/graphics/Android.bp
index 4898dbe..2fbcb41 100644
--- a/graphics/Android.bp
+++ b/graphics/Android.bp
@@ -21,6 +21,9 @@
static_libs: [
"android.hardware.graphics.allocator-V2-ndk",
],
+ defaults: [
+ "android.hardware.graphics.common-ndk_static",
+ ],
}
cc_defaults {
@@ -28,6 +31,9 @@
shared_libs: [
"android.hardware.graphics.allocator-V2-ndk",
],
+ defaults: [
+ "android.hardware.graphics.common-ndk_shared",
+ ],
}
cc_defaults {
diff --git a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index 980e246..49c2497 100644
--- a/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/aidl_api/android.hardware.graphics.allocator/current/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -41,4 +41,5 @@
android.hardware.graphics.common.PixelFormat format = android.hardware.graphics.common.PixelFormat.UNSPECIFIED;
android.hardware.graphics.common.BufferUsage usage = android.hardware.graphics.common.BufferUsage.CPU_READ_NEVER;
long reservedSize;
+ android.hardware.graphics.common.ExtendableType[] additionalOptions;
}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
index 0774e25..76f1c95 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/AllocationResult.aidl
@@ -18,13 +18,17 @@
import android.hardware.common.NativeHandle;
- /**
+/**
* Result of an IAllocator::allocate call.
*
* @sa +ndk libnativewindow#AHardwareBuffer_Desc
*/
@VintfStability
parcelable AllocationResult {
+ /**
+ * The number of pixels between two consecutive rows of an allocated buffer, when the concept
+ * of consecutive rows is defined. Otherwise, it has no meaning.
+ */
int stride;
NativeHandle[] buffers;
-}
\ No newline at end of file
+}
diff --git a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
index ffc50b8..50aa2b7 100644
--- a/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
+++ b/graphics/allocator/aidl/android/hardware/graphics/allocator/BufferDescriptorInfo.aidl
@@ -17,6 +17,7 @@
package android.hardware.graphics.allocator;
import android.hardware.graphics.common.BufferUsage;
+import android.hardware.graphics.common.ExtendableType;
import android.hardware.graphics.common.PixelFormat;
@VintfStability
@@ -54,6 +55,9 @@
/**
* Buffer usage mask; valid flags can be found in the definition of
* BufferUsage.aidl in graphics/common
+ *
+ * The allocator must report isSupported() == false and reject any allocations
+ * with unrecognized buffer usages.
*/
BufferUsage usage = BufferUsage.CPU_READ_NEVER;
@@ -62,4 +66,16 @@
* See getReservedRegion for more information.
*/
long reservedSize;
+
+ /**
+ * Extensible additional options that can be set.
+ *
+ * This is intended for options that do not change the overall usage, but which do impact
+ * how a buffer is allocated. An example of this is compression level, such as for
+ * the EGL_EXT_surface_compression extension.
+ *
+ * The allocator must report isSupported() == false and reject any allocations
+ * with unrecognized options.
+ */
+ ExtendableType[] additionalOptions;
}
diff --git a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
index 09f1c15..4778020 100644
--- a/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
+++ b/graphics/allocator/aidl/vts/VtsHalGraphicsAllocatorAidl_TargetTest.cpp
@@ -217,6 +217,8 @@
}
return ret;
}
+
+ int32_t allocatorVersion() const { return mIAllocatorVersion; }
};
BufferHandle::~BufferHandle() {
@@ -309,6 +311,62 @@
EXPECT_GE(buffer->stride(), 64);
}
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownUsages) {
+ if (allocatorVersion() < 2) {
+ GTEST_SKIP() << "Must be version 2+";
+ return;
+ }
+
+ constexpr auto FirstInvalidV2Usage = static_cast<BufferUsage>(1LL << 33);
+
+ BufferUsage invalidUsage;
+ if (allocatorVersion() == 2) {
+ invalidUsage = FirstInvalidV2Usage;
+ } else {
+ GTEST_FAIL() << "Unknown version " << allocatorVersion();
+ }
+
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ .reservedSize = 0,
+ };
+
+ // First make sure we can allocate a known usage buffer as expected
+ EXPECT_TRUE(isSupported(info));
+ EXPECT_TRUE(allocate(info));
+
+ // Now add the unknown bit and verify it's rejected
+ info.usage |= invalidUsage;
+ EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL usage";
+ EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL usage";
+}
+
+TEST_P(GraphicsAllocatorAidlTests, RejectsUnknownOptions) {
+ if (allocatorVersion() < 2) {
+ GTEST_SKIP() << "Must be version 2+";
+ return;
+ }
+
+ BufferDescriptorInfo info{
+ .name = {"CPU_8888"},
+ .width = 64,
+ .height = 64,
+ .layerCount = 1,
+ .format = PixelFormat::RGBA_8888,
+ .usage = BufferUsage::CPU_READ_OFTEN | BufferUsage::CPU_WRITE_OFTEN,
+ .reservedSize = 0,
+ };
+ info.additionalOptions.push_back({"android.hardware.graphics.common.NotARealOption", 1});
+
+ EXPECT_FALSE(isSupported(info)) << "isSupported() returned true for unknown-to-HAL option";
+ EXPECT_FALSE(allocate(info)) << "allocate succeeded for unknown-to-HAL option";
+}
+
TEST_P(GraphicsFrontBufferTests, FrontBufferGpuToCpu) {
BufferDescriptorInfo info{
.name = {"CPU_8888"},
diff --git a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
index 06b31a2..6e2e106 100644
--- a/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/aidl_api/android.hardware.graphics.common/current/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -58,4 +58,5 @@
CTA861_3 = 20,
SMPTE2094_40 = 21,
SMPTE2094_10 = 22,
+ STRIDE = 23,
}
diff --git a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
index 4bca795..8cfdae6 100644
--- a/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
+++ b/graphics/common/aidl/android/hardware/graphics/common/StandardMetadataType.aidl
@@ -368,4 +368,17 @@
* If this is unset when encoded into a byte stream, the byte stream is empty.
*/
SMPTE2094_10 = 22,
+
+ /**
+ * Can be used to get the stride in pixels of the buffer allocation. This is the number of
+ * pixels between two consecutive rows of an allocated buffer, when the concept of consecutive
+ * rows is defined. Otherwise, it has no meaning.
+ *
+ * Must match the value returned in android.hardware.graphics.allocator.AllocationResult#stride
+ *
+ * This is required metadata in mapper5 and should be read-only.
+ *
+ * The metadata type is a uint32_t.
+ */
+ STRIDE = 23,
}
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.cpp b/graphics/composer/aidl/vts/VtsComposerClient.cpp
index 00b578b..43f4b84 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.cpp
+++ b/graphics/composer/aidl/vts/VtsComposerClient.cpp
@@ -404,14 +404,31 @@
return {std::move(configs.first), vtsDisplays};
}
for (int config : configs.second) {
- auto status = updateDisplayProperties(&vtsDisplay, config);
+ auto status = addDisplayConfig(&vtsDisplay, config);
if (!status.isOk()) {
- ALOGE("Unable to get the displays for test, failed to update the properties "
+ ALOGE("Unable to get the displays for test, failed to add config "
"for display %" PRId64,
display);
return {std::move(status), vtsDisplays};
}
}
+
+ auto config = getActiveConfig(display);
+ if (!config.first.isOk()) {
+ ALOGE("Unable to get the displays for test, failed to get active config "
+ "for display %" PRId64, display);
+ return {std::move(config.first), vtsDisplays};
+ }
+
+ auto status = updateDisplayProperties(&vtsDisplay, config.second);
+ if (!status.isOk()) {
+ ALOGE("Unable to get the displays for test, "
+ "failed to update the properties "
+ "for display %" PRId64,
+ display);
+ return {std::move(status), vtsDisplays};
+ }
+
vtsDisplays.emplace_back(vtsDisplay);
addDisplayToDisplayResources(display, /*isVirtual*/ false);
}
@@ -420,7 +437,7 @@
}
}
-ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+ScopedAStatus VtsComposerClient::addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config) {
const auto width =
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
const auto height =
@@ -431,7 +448,6 @@
getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::CONFIG_GROUP);
if (width.first.isOk() && height.first.isOk() && vsyncPeriod.first.isOk() &&
configGroup.first.isOk()) {
- vtsDisplay->setDimensions(width.second, height.second);
vtsDisplay->addDisplayConfig(config, {vsyncPeriod.second, configGroup.second});
return ScopedAStatus::ok();
}
@@ -442,6 +458,21 @@
return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
}
+ScopedAStatus VtsComposerClient::updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config) {
+ const auto width =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::WIDTH);
+ const auto height =
+ getDisplayAttribute(vtsDisplay->getDisplayId(), config, DisplayAttribute::HEIGHT);
+ if (width.first.isOk() && height.first.isOk()) {
+ vtsDisplay->setDimensions(width.second, height.second);
+ return ScopedAStatus::ok();
+ }
+
+ LOG(ERROR) << "Failed to update display property for width: " << width.first.isOk()
+ << ", height: " << height.first.isOk();
+ return ScopedAStatus::fromServiceSpecificError(IComposerClient::EX_BAD_CONFIG);
+}
+
ScopedAStatus VtsComposerClient::addDisplayToDisplayResources(int64_t display, bool isVirtual) {
if (mDisplayResources.insert({display, DisplayResource(isVirtual)}).second) {
return ScopedAStatus::ok();
diff --git a/graphics/composer/aidl/vts/VtsComposerClient.h b/graphics/composer/aidl/vts/VtsComposerClient.h
index e61fde9..c4bc464 100644
--- a/graphics/composer/aidl/vts/VtsComposerClient.h
+++ b/graphics/composer/aidl/vts/VtsComposerClient.h
@@ -178,6 +178,7 @@
std::pair<ScopedAStatus, OverlayProperties> getOverlaySupport();
private:
+ ScopedAStatus addDisplayConfig(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus updateDisplayProperties(VtsDisplay* vtsDisplay, int32_t config);
ScopedAStatus addDisplayToDisplayResources(int64_t display, bool isVirtual);
diff --git a/graphics/mapper/stable-c/README.md b/graphics/mapper/stable-c/README.md
new file mode 100644
index 0000000..30f3ccc
--- /dev/null
+++ b/graphics/mapper/stable-c/README.md
@@ -0,0 +1,110 @@
+# IMapper "stable-c" HAL
+
+Starting with gralloc version 5, IMapper is now exposed as a C API instead of through HIDL or AIDL.
+This is due to HIDL being deprecated, and AIDL not wanting to support a pass-through mode & pointers
+for just a couple of clients such as IMapper. So instead a stable C API is used to fill this gap.
+
+## Implementing
+
+To provide an implementation a library implementing the AIMapper API interface should be provided
+in `/vendor/lib[64]/hw/mapper.<imapper_suffix>.so`. The `<imapper_suffix>` should be specified
+as the `<instance>` in the VINTF manifest `<interface>` section. For example:
+```xml
+<manifest version="1.0" type="device">
+ <hal format="native">
+ <name>mapper</name>
+ <version>5.0</version>
+ <interface>
+ <name>I</name>
+ <instance>minigbm</instance>
+ </interface>
+ </hal>
+</manifest>
+```
+defines that the IMapper 5.0 library is provided by `/vendor/lib[64]/hw/mapper.minigbm.so`.
+
+This library must export the following `extern "C"` symbols:
+
+### `ANDROID_HAL_STABLEC_VERSION`
+
+This is a uint32_t that should simply be set to the exported AIMapper version. For example:
+```c++
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+```
+
+### `AIMapper_loadIMapper`
+
+This is what should actually load the HAL interface. The full type signature is
+```c++
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation)
+```
+
+See `include/android/hardware/graphics/mapper/IMapper.h` for complete documentation on what
+this function must return.
+
+To make it easier to implement this C API, a header-only helper library is provided called
+`libimapper_providerutils`. This library handles mapping from the C API struct to a C++ class
+as well as provides helpers for encoding & decoding metadata, largely replacing the role that
+`libgralloctypes` filled with IMapper 4.
+
+To use this library, create a class that extends from `IMapperV5Impl` and use `IMapperProvider` to
+implement `AIMapper_loadIMapper`:
+
+```c++
+// The IMapper interface itself
+#include <android/hardware/graphics/mapper/IMapper.h>
+// Helpers for reading & writing metadata
+#include <android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h>
+// Helper for providing the implementation interface
+#include <android/hardware/graphics/mapper/utils/IMapperProvider.h>
+
+// Define an IMapperV5 implementation
+class CrosGrallocMapperV5 final : public vendor::mapper::IMapperV5Impl {
+ // Override all the methods of IMapperV5Impl
+ AIMapper_Error importBuffer(const native_handle_t* _Nonnull handle,
+ buffer_handle_t _Nullable* _Nonnull outBufferHandle) override;
+ [etc...]
+};
+
+// Expose the required C symbols
+
+extern "C" uint32_t ANDROID_HAL_STABLEC_VERSION = AIMAPPER_VERSION_5;
+
+extern "C" AIMapper_Error AIMapper_loadIMapper(AIMapper* _Nullable* _Nonnull outImplementation) {
+ // Define an IMapperProvider for our V5 implementation
+ static vendor::mapper::IMapperProvider<CrosGrallocMapperV5> provider;
+ return provider.load(outImplementation);
+}
+```
+
+A complete example, including using IMapperMetadataTypes, can be found in the cuttlefish
+implementation in `//external/minigbm/cros_gralloc/mapper_stablec`
+
+### Testing
+
+As with HIDL & AIDL HALs, a VTS test is provided to validate the implementation. It is found in the
+`vts` folder and may be run using `$ atest VtsHalGraphicsMapperStableC_TargetTest`
+
+## Using
+
+It is strongly recommended that clients use either the `AHardwareBuffer` (preferred) or
+`GraphicBufferMapper` (from libui) APIs to use the mapper HAL rather than attempting to use
+`AIMapper` directly.
+
+## Version changes
+
+### Version 5
+
+* Initial introduction of this HAL interface
+* Largely feature-equivalent to IMapper4
+* Requires allocator-V2
+* Removes `BufferDescriptorInfo`;
+* IsSupported has moved to IAllocator
+* Removes `validateBufferSize`, validation is instead handled by clients using metadata queries
+* Getting the following StandardMetadataType is now mandatory:
+ * STRIDE
+* Setting the following StandardMetadataTypes is now mandatory:
+ * DATASPACE
+ * SMPTE2086
+ * CTA861_3
+ * BLEND_MODE
diff --git a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
index 102dada..0e6d3dc 100644
--- a/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
+++ b/graphics/mapper/stable-c/implutils/include/android/hardware/graphics/mapper/utils/IMapperMetadataTypes.h
@@ -563,6 +563,7 @@
DEFINE_TYPE(CTA861_3, std::optional<Cta861_3>);
DEFINE_TYPE(SMPTE2094_10, std::optional<std::vector<uint8_t>>);
DEFINE_TYPE(SMPTE2094_40, std::optional<std::vector<uint8_t>>);
+DEFINE_TYPE(STRIDE, uint32_t);
#undef DEFINE_TYPE
diff --git a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
index 85246ee..2c06353 100644
--- a/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
+++ b/graphics/mapper/stable-c/vts/VtsHalGraphicsMapperStableC_TargetTest.cpp
@@ -154,6 +154,7 @@
std::shared_ptr<IAllocator> mAllocator;
AIMapper* mIMapper = nullptr;
AIMapper_loadIMapperFn mIMapperLoader;
+ int32_t* mIMapperHALVersion = nullptr;
protected:
void Initialize(std::shared_ptr<IAllocator> allocator) {
@@ -171,10 +172,12 @@
ASSERT_NE(nullptr, mIMapperLoader) << "AIMapper_locaIMapper missing from " << lib_name;
ASSERT_EQ(AIMAPPER_ERROR_NONE, mIMapperLoader(&mIMapper));
ASSERT_NE(mIMapper, nullptr);
+ mIMapperHALVersion = (int32_t*)dlsym(so, "ANDROID_HAL_MAPPER_VERSION");
}
public:
AIMapper_loadIMapperFn getIMapperLoader() const { return mIMapperLoader; }
+ int32_t* getHalVersion() const { return mIMapperHALVersion; }
std::unique_ptr<BufferAllocation> allocate(const BufferDescriptorInfo& descriptorInfo) {
AllocationResult result;
@@ -557,6 +560,15 @@
void TearDown() override {}
};
+TEST_P(GraphicsMapperStableCTests, VersionChecks) {
+ ASSERT_NE(nullptr, getHalVersion()) << "Resolving ANDROID_HAL_MAPPER_VERSION symbol failed";
+ int32_t halVersion = *getHalVersion();
+ EXPECT_EQ(halVersion, AIMAPPER_VERSION_5) << "Unrecognized ANDROID_HAL_MAPPER_VERSION";
+ EXPECT_EQ(mapper()->version, AIMAPPER_VERSION_5) << "Unrecognized AIMapper::version";
+ EXPECT_EQ(halVersion, mapper()->version)
+ << "AIMapper version & ANDROID_HAL_MAPPER_VERSION don't agree";
+}
+
TEST_P(GraphicsMapperStableCTests, AllV5CallbacksDefined) {
ASSERT_GE(mapper()->version, AIMAPPER_VERSION_5);
@@ -1557,6 +1569,16 @@
}
}
+TEST_P(GraphicsMapperStableCTests, GetStride) {
+ auto buffer = allocateGeneric();
+ ASSERT_TRUE(buffer);
+ auto bufferHandle = buffer->import();
+ ASSERT_TRUE(bufferHandle);
+ auto value = getStandardMetadata<StandardMetadataType::STRIDE>(*bufferHandle);
+ ASSERT_TRUE(value.has_value());
+ EXPECT_EQ(buffer->stride(), *value);
+}
+
TEST_P(GraphicsMapperStableCTests, SupportsRequiredGettersSetters) {
auto buffer = allocateGeneric();
ASSERT_TRUE(buffer);
@@ -1587,6 +1609,7 @@
StandardMetadataType::BLEND_MODE,
StandardMetadataType::SMPTE2086,
StandardMetadataType::CTA861_3,
+ StandardMetadataType::STRIDE,
};
std::vector<StandardMetadataType> requiredSetters = {
diff --git a/radio/aidl/Android.bp b/radio/aidl/Android.bp
index 9caa97a..e8cebd7 100644
--- a/radio/aidl/Android.bp
+++ b/radio/aidl/Android.bp
@@ -163,7 +163,12 @@
enabled: true,
},
java: {
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.btservices",
+ ],
sdk_version: "module_current",
+ min_sdk_version: "Tiramisu",
},
},
diff --git a/radio/aidl/vts/VtsHalRadioTargetTest.cpp b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
index c25f930..33a0d7d 100644
--- a/radio/aidl/vts/VtsHalRadioTargetTest.cpp
+++ b/radio/aidl/vts/VtsHalRadioTargetTest.cpp
@@ -56,7 +56,7 @@
testing::ValuesIn(android::getAidlHalInstanceNames(IRadioNetwork::descriptor)),
android::PrintInstanceNameToString);
-GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(RadioSapTest);
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SapTest);
INSTANTIATE_TEST_SUITE_P(PerInstance, SapTest,
testing::ValuesIn(android::getAidlHalInstanceNames(ISap::descriptor)),
android::PrintInstanceNameToString);
diff --git a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
index c506667..ff710f1 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl
@@ -222,7 +222,7 @@
* 2 : bstr ; KID : EEK ID
* 3 : -25, ; Algorithm : ECDH-ES + HKDF-256
* -1 : 4, ; Curve : X25519
- * -2 : bstr ; X25519 public key
+ * -2 : bstr ; X25519 public key, little-endian
* }
*
* EekP256 = { ; COSE_Key
@@ -440,6 +440,9 @@
*
* ; The following section defines some types that are reused throughout the above
* ; data structures.
+ * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+ * ; - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+ * ; - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
* PubKeyEd25519 = { ; COSE_Key
* 1 : 1, ; Key type : octet key pair
* 3 : AlgorithmEdDSA, ; Algorithm : EdDSA
@@ -451,8 +454,8 @@
* 1 : 2, ; Key type : EC2
* 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
* -1 : 1, ; Curve: P256
- * -2 : bstr, ; X coordinate
- * -3 : bstr ; Y coordinate
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr ; Y coordinate, big-endian
* }
*
* AlgorithmES256 = -7
diff --git a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
index 275e322..1e41d1b 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/MacedPublicKey.aidl
@@ -36,12 +36,15 @@
* ]
*
* ; NOTE: -70000 is deprecated for v3 HAL implementations.
+ * ; NOTE: Integer encoding is different for Ed25519 and P256 keys:
+ * ; - Ed25519 is LE: https://www.rfc-editor.org/rfc/rfc8032#section-3.1
+ * ; - P256 is BE: https://www.secg.org/sec1-v2.pdf#page=19 (section 2.3.7)
* PublicKey = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* 3 : -7, ; Algorithm : ES256
* -1 : 1, ; Curve : P256
- * -2 : bstr, ; X coordinate, little-endian
- * -3 : bstr, ; Y coordinate, little-endian
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr, ; Y coordinate, big-endian
* -70000 : nil ; Presence indicates this is a test key. If set, K_mac is
* ; all zeros.
* },
diff --git a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
index d59508b..3f699bc 100644
--- a/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/rkp/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -209,7 +209,7 @@
* PubKeyX25519 = { ; COSE_Key
* 1 : 1, ; Key type : Octet Key Pair
* -1 : 4, ; Curve : X25519
- * -2 : bstr ; Sender X25519 public key
+ * -2 : bstr ; Sender X25519 public key, little-endian
* }
*
* PubKeyEd25519 = { ; COSE_Key
@@ -222,16 +222,16 @@
* PubKeyEcdhP256 = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* -1 : 1, ; Curve : P256
- * -2 : bstr ; Sender X coordinate
- * -3 : bstr ; Sender Y coordinate
+ * -2 : bstr ; Sender X coordinate, big-endian
+ * -3 : bstr ; Sender Y coordinate, big-endian
* }
*
* PubKeyECDSA256 = { ; COSE_Key
* 1 : 2, ; Key type : EC2
* 3 : AlgorithmES256, ; Algorithm : ECDSA w/ SHA-256
* -1 : 1, ; Curve: P256
- * -2 : bstr, ; X coordinate
- * -3 : bstr ; Y coordinate
+ * -2 : bstr, ; X coordinate, big-endian
+ * -3 : bstr ; Y coordinate, big-endian
* }
*
* AlgorithmES256 = -7
diff --git a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index aebcf67..bbda56d 100644
--- a/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/rkp/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -223,6 +223,20 @@
ASSERT_TRUE(provisionable_->getHardwareInfo(&hwInfo).isOk());
const std::set<int> validCurves = {RpcHardwareInfo::CURVE_P256, RpcHardwareInfo::CURVE_25519};
+ // First check for the implementations that supports only IRPC V3+.
+ if (rpcHardwareInfo.versionNumber >= VERSION_WITHOUT_TEST_MODE) {
+ bytevec keysToSignMac;
+ DeviceInfo deviceInfo;
+ ProtectedData protectedData;
+ auto status = provisionable_->generateCertificateRequest(false, {}, {}, {}, &deviceInfo,
+ &protectedData, &keysToSignMac);
+ if (!status.isOk() &&
+ (status.getServiceSpecificError() == BnRemotelyProvisionedComponent::STATUS_REMOVED)) {
+ ASSERT_EQ(hwInfo.supportedEekCurve, RpcHardwareInfo::CURVE_NONE)
+ << "Invalid curve: " << hwInfo.supportedEekCurve;
+ return;
+ }
+ }
ASSERT_EQ(validCurves.count(hwInfo.supportedEekCurve), 1)
<< "Invalid curve: " << hwInfo.supportedEekCurve;
}
diff --git a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
index d87f1f4..aec9954 100644
--- a/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
+++ b/usb/aidl/vts/VtsAidlUsbTargetTest.cpp
@@ -307,7 +307,7 @@
}
}
}
- EXPECT_LE(1, disabledCount);
+ EXPECT_GE(1, disabledCount);
ALOGI("UsbAidlTest DataStatusCheck end");
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
index f800e8f..2ebe145 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/IWifiChip.aidl
@@ -80,24 +80,25 @@
void startLoggingToDebugRingBuffer(in String ringName, in android.hardware.wifi.WifiDebugRingBufferVerboseLevel verboseLevel, in int maxIntervalInSec, in int minDataSizeInBytes);
void stopLoggingToDebugRingBuffer();
void triggerSubsystemRestart();
- const int NO_POWER_CAP_CONSTANT = 2147483647;
+ void enableStaChannelForPeerNetwork(in android.hardware.wifi.IWifiChip.ChannelCategoryMask channelCategoryEnableFlag);
+ const int NO_POWER_CAP_CONSTANT = 0x7FFFFFFF;
@Backing(type="int") @VintfStability
enum ChipCapabilityMask {
- DEBUG_MEMORY_FIRMWARE_DUMP = 1,
- DEBUG_MEMORY_DRIVER_DUMP = 2,
- DEBUG_RING_BUFFER_CONNECT_EVENT = 4,
- DEBUG_RING_BUFFER_POWER_EVENT = 8,
- DEBUG_RING_BUFFER_WAKELOCK_EVENT = 16,
- DEBUG_RING_BUFFER_VENDOR_DATA = 32,
- DEBUG_HOST_WAKE_REASON_STATS = 64,
- DEBUG_ERROR_ALERTS = 128,
- SET_TX_POWER_LIMIT = 256,
- D2D_RTT = 512,
- D2AP_RTT = 1024,
- USE_BODY_HEAD_SAR = 2048,
- SET_LATENCY_MODE = 4096,
- P2P_RAND_MAC = 8192,
- WIGIG = 16384,
+ DEBUG_MEMORY_FIRMWARE_DUMP = (1 << 0),
+ DEBUG_MEMORY_DRIVER_DUMP = (1 << 1),
+ DEBUG_RING_BUFFER_CONNECT_EVENT = (1 << 2),
+ DEBUG_RING_BUFFER_POWER_EVENT = (1 << 3),
+ DEBUG_RING_BUFFER_WAKELOCK_EVENT = (1 << 4),
+ DEBUG_RING_BUFFER_VENDOR_DATA = (1 << 5),
+ DEBUG_HOST_WAKE_REASON_STATS = (1 << 6),
+ DEBUG_ERROR_ALERTS = (1 << 7),
+ SET_TX_POWER_LIMIT = (1 << 8),
+ D2D_RTT = (1 << 9),
+ D2AP_RTT = (1 << 10),
+ USE_BODY_HEAD_SAR = (1 << 11),
+ SET_LATENCY_MODE = (1 << 12),
+ P2P_RAND_MAC = (1 << 13),
+ WIGIG = (1 << 14),
}
@VintfStability
parcelable ChipConcurrencyCombinationLimit {
@@ -129,9 +130,9 @@
}
@Backing(type="int") @VintfStability
enum CoexRestriction {
- WIFI_DIRECT = 1,
- SOFTAP = 2,
- WIFI_AWARE = 4,
+ WIFI_DIRECT = (1 << 0),
+ SOFTAP = (1 << 1),
+ WIFI_AWARE = (1 << 2),
}
@VintfStability
parcelable CoexUnsafeChannel {
@@ -159,8 +160,13 @@
}
@Backing(type="int") @VintfStability
enum UsableChannelFilter {
- CELLULAR_COEXISTENCE = 1,
- CONCURRENCY = 2,
- NAN_INSTANT_MODE = 4,
+ CELLULAR_COEXISTENCE = (1 << 0),
+ CONCURRENCY = (1 << 1),
+ NAN_INSTANT_MODE = (1 << 2),
+ }
+ @Backing(type="int") @VintfStability
+ enum ChannelCategoryMask {
+ INDOOR_CHANNEL = (1 << 0),
+ DFS_CHANNEL = (1 << 1),
}
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
index 5b59945..cb5a95c 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanCapabilities.aidl
@@ -52,4 +52,5 @@
boolean supports6g;
boolean supportsHe;
boolean supportsPairing;
+ boolean supportsSetClusterId;
}
diff --git a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl
index 682699e..99f2af7 100644
--- a/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl
+++ b/wifi/aidl/aidl_api/android.hardware.wifi/current/android/hardware/wifi/NanConfigRequestSupplemental.aidl
@@ -40,4 +40,5 @@
boolean enableRanging;
boolean enableInstantCommunicationMode;
int instantModeChannel;
+ int clusterId;
}
diff --git a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
index 64692af..5ffea56 100644
--- a/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
+++ b/wifi/aidl/android/hardware/wifi/IWifiChip.aidl
@@ -1106,4 +1106,29 @@
* |WifiStatusCode.ERROR_UNKNOWN|
*/
void triggerSubsystemRestart();
+
+ /**
+ * Channel category mask.
+ */
+ @VintfStability
+ @Backing(type="int")
+ enum ChannelCategoryMask {
+ INDOOR_CHANNEL = 1 << 0,
+ DFS_CHANNEL = 1 << 1,
+ }
+
+ /**
+ * API to enable or disable the feature of allowing current STA-connected channel for WFA GO,
+ * SAP and Aware when the regulatory allows.
+ * If the channel category is enabled and allowed by the regulatory, the HAL method
+ * getUsableChannels() will contain the current STA-connected channel if that channel belongs
+ * to that category.
+ * @param channelCategoryEnableFlag bitmask of |ChannelCategoryMask|.
+ * For each bit, 1 enables the channel category and 0 disables that channel category.
+ * @throws ServiceSpecificException with one of the following values:
+ * |WifiStatusCode.ERROR_WIFI_CHIP_INVALID|,
+ * |WifiStatusCode.ERROR_NOT_SUPPORTED|,
+ * |WifiStatusCode.FAILURE_UNKNOWN|
+ */
+ void enableStaChannelForPeerNetwork(in ChannelCategoryMask channelCategoryEnableFlag);
}
diff --git a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
index 0955b4c..4160176 100644
--- a/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanCapabilities.aidl
@@ -97,4 +97,8 @@
* Flag to indicate if NAN pairing is supported.
*/
boolean supportsPairing;
+ /**
+ * Flag to indicate if NAN setting cluster ID is supported.
+ */
+ boolean supportsSetClusterId;
}
diff --git a/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl b/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl
index eb01a9f..338a549 100644
--- a/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl
+++ b/wifi/aidl/android/hardware/wifi/NanConfigRequestSupplemental.aidl
@@ -60,4 +60,8 @@
* Controls which channel NAN instant communication mode operates on.
*/
int instantModeChannel;
+ /**
+ * Controls which cluster to join.
+ */
+ int clusterId;
}
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 5e80ff9..ba7d2db 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -1706,6 +1706,8 @@
legacy_request->enable_instant_mode = aidl_request2.enableInstantCommunicationMode;
legacy_request->config_instant_mode_channel = 1;
legacy_request->instant_mode_channel = aidl_request2.instantModeChannel;
+ legacy_request->config_cluster_id = 1;
+ legacy_request->cluster_id_val = aidl_request2.clusterId;
return true;
}
@@ -2245,6 +2247,7 @@
aidl_response->supports6g = legacy_response.is_6g_supported;
aidl_response->supportsHe = legacy_response.is_he_supported;
aidl_response->supportsPairing = legacy_response.is_pairing_supported;
+ aidl_response->supportsSetClusterId = legacy_response.is_set_cluster_id_supported;
return true;
}
@@ -3311,6 +3314,19 @@
return true;
}
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask) {
+ uint32_t channel_category_mask = 0;
+ if (aidl_channel_category_mask &
+ static_cast<int32_t>(IWifiChip::ChannelCategoryMask::INDOOR_CHANNEL)) {
+ channel_category_mask |= legacy_hal::WIFI_INDOOR_CHANNEL;
+ }
+ if (aidl_channel_category_mask &
+ static_cast<int32_t>(IWifiChip::ChannelCategoryMask::DFS_CHANNEL)) {
+ channel_category_mask |= legacy_hal::WIFI_DFS_CHANNEL;
+ }
+ return channel_category_mask;
+}
+
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/aidl_struct_util.h b/wifi/aidl/default/aidl_struct_util.h
index e478fed..6407d32 100644
--- a/wifi/aidl/default/aidl_struct_util.h
+++ b/wifi/aidl/default/aidl_struct_util.h
@@ -200,6 +200,7 @@
bool convertLegacyNanBootstrappingConfirmIndToAidl(
const legacy_hal::NanBootstrappingConfirmInd& legacy_ind,
NanBootstrappingConfirmInd* aidl_ind);
+uint32_t convertAidlChannelCategoryToLegacy(uint32_t aidl_channel_category_mask);
} // namespace aidl_struct_util
} // namespace wifi
} // namespace hardware
diff --git a/wifi/aidl/default/wifi_chip.cpp b/wifi/aidl/default/wifi_chip.cpp
index 4061699..5597001 100644
--- a/wifi/aidl/default/wifi_chip.cpp
+++ b/wifi/aidl/default/wifi_chip.cpp
@@ -34,6 +34,7 @@
using aidl::android::hardware::wifi::IfaceType;
using aidl::android::hardware::wifi::IWifiChip;
using CoexRestriction = aidl::android::hardware::wifi::IWifiChip::CoexRestriction;
+using ChannelCategoryMask = aidl::android::hardware::wifi::IWifiChip::ChannelCategoryMask;
using android::base::unique_fd;
constexpr char kCpioMagic[] = "070701";
@@ -685,6 +686,13 @@
&WifiChip::getWifiChipCapabilitiesInternal, _aidl_return);
}
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetwork(
+ ChannelCategoryMask in_channelCategoryEnableFlag) {
+ return validateAndCall(this, WifiStatusCode::ERROR_WIFI_CHIP_INVALID,
+ &WifiChip::enableStaChannelForPeerNetworkInternal,
+ in_channelCategoryEnableFlag);
+}
+
void WifiChip::invalidateAndRemoveAllIfaces() {
invalidateAndClearBridgedApAll();
invalidateAndClearAll(ap_ifaces_);
@@ -1428,6 +1436,14 @@
return {aidl_chip_capabilities, ndk::ScopedAStatus::ok()};
}
+ndk::ScopedAStatus WifiChip::enableStaChannelForPeerNetworkInternal(
+ ChannelCategoryMask channelCategoryEnableFlag) {
+ auto legacy_status = legacy_hal_.lock()->enableStaChannelForPeerNetwork(
+ aidl_struct_util::convertAidlChannelCategoryToLegacy(
+ static_cast<uint32_t>(channelCategoryEnableFlag)));
+ return createWifiStatusFromLegacyError(legacy_status);
+}
+
ndk::ScopedAStatus WifiChip::triggerSubsystemRestartInternal() {
auto legacy_status = legacy_hal_.lock()->triggerSubsystemRestart();
return createWifiStatusFromLegacyError(legacy_status);
diff --git a/wifi/aidl/default/wifi_chip.h b/wifi/aidl/default/wifi_chip.h
index 7b04e85..c69c7fe 100644
--- a/wifi/aidl/default/wifi_chip.h
+++ b/wifi/aidl/default/wifi_chip.h
@@ -145,6 +145,8 @@
ndk::ScopedAStatus getSupportedRadioCombinationsMatrix(
WifiRadioCombinationMatrix* _aidl_return) override;
ndk::ScopedAStatus getWifiChipCapabilities(WifiChipCapabilities* _aidl_return) override;
+ ndk::ScopedAStatus enableStaChannelForPeerNetwork(
+ ChannelCategoryMask in_channelCategoryEnableFlag) override;
binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
private:
@@ -214,6 +216,8 @@
ndk::ScopedAStatus setCountryCodeInternal(const std::array<uint8_t, 2>& in_code);
std::pair<std::vector<WifiUsableChannel>, ndk::ScopedAStatus> getUsableChannelsInternal(
WifiBand band, WifiIfaceMode ifaceModeMask, UsableChannelFilter filterMask);
+ ndk::ScopedAStatus enableStaChannelForPeerNetworkInternal(
+ ChannelCategoryMask channelCategoryEnableFlag);
ndk::ScopedAStatus handleChipConfiguration(std::unique_lock<std::recursive_mutex>* lock,
int32_t mode_id);
ndk::ScopedAStatus registerDebugRingBufferCallback();
diff --git a/wifi/aidl/default/wifi_legacy_hal.cpp b/wifi/aidl/default/wifi_legacy_hal.cpp
index 54e91d4..f03835f 100644
--- a/wifi/aidl/default/wifi_legacy_hal.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal.cpp
@@ -1835,6 +1835,11 @@
return {status, chip_capabilities};
}
+wifi_error WifiLegacyHal::enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag) {
+ return global_func_table_.wifi_enable_sta_channel_for_peer_network(global_handle_,
+ channelCategoryEnableFlag);
+}
+
void WifiLegacyHal::invalidate() {
global_handle_ = nullptr;
iface_name_to_handle_.clear();
diff --git a/wifi/aidl/default/wifi_legacy_hal.h b/wifi/aidl/default/wifi_legacy_hal.h
index 5620280..2300cb7 100644
--- a/wifi/aidl/default/wifi_legacy_hal.h
+++ b/wifi/aidl/default/wifi_legacy_hal.h
@@ -256,12 +256,14 @@
using ::WIFI_CHAN_WIDTH_80;
using ::WIFI_CHAN_WIDTH_80P80;
using ::WIFI_CHAN_WIDTH_INVALID;
+using ::wifi_channel_category;
using ::wifi_channel_info;
using ::wifi_channel_stat;
using ::wifi_channel_width;
using ::wifi_chip_capabilities;
using ::wifi_coex_restriction;
using ::wifi_coex_unsafe_channel;
+using ::WIFI_DFS_CHANNEL;
using ::WIFI_DUAL_STA_NON_TRANSIENT_UNBIASED;
using ::WIFI_DUAL_STA_TRANSIENT_PREFER_PRIMARY;
using ::wifi_error;
@@ -278,6 +280,7 @@
using ::WIFI_ERROR_UNKNOWN;
using ::wifi_gscan_capabilities;
using ::wifi_hal_fn;
+using ::WIFI_INDOOR_CHANNEL;
using ::wifi_information_element;
using ::WIFI_INTERFACE_IBSS;
using ::WIFI_INTERFACE_MESH;
@@ -755,6 +758,7 @@
wifi_error getWifiCachedScanResults(const std::string& iface_name,
const CachedScanResultsCallbackHandlers& handler);
std::pair<wifi_error, wifi_chip_capabilities> getWifiChipCapabilities();
+ wifi_error enableStaChannelForPeerNetwork(uint32_t channelCategoryEnableFlag);
private:
// Retrieve interface handles for all the available interfaces.
diff --git a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
index a0cb2c0..11da373 100644
--- a/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
+++ b/wifi/aidl/default/wifi_legacy_hal_stubs.cpp
@@ -172,6 +172,7 @@
populateStubFor(&hal_fn->wifi_enable_tx_power_limits);
populateStubFor(&hal_fn->wifi_get_cached_scan_results);
populateStubFor(&hal_fn->wifi_get_chip_capabilities);
+ populateStubFor(&hal_fn->wifi_enable_sta_channel_for_peer_network);
return true;
}