Merge "Add hotword flags to audio input flags"
diff --git a/audio/aidl/Android.bp b/audio/aidl/Android.bp
index 42a4ac1..ef51361 100644
--- a/audio/aidl/Android.bp
+++ b/audio/aidl/Android.bp
@@ -114,11 +114,11 @@
"android/hardware/audio/core/AudioRoute.aidl",
"android/hardware/audio/core/IConfig.aidl",
"android/hardware/audio/core/IModule.aidl",
- "android/hardware/audio/core/ISoundDose.aidl",
"android/hardware/audio/core/IStreamCallback.aidl",
"android/hardware/audio/core/IStreamCommon.aidl",
"android/hardware/audio/core/IStreamIn.aidl",
"android/hardware/audio/core/IStreamOut.aidl",
+ "android/hardware/audio/core/IStreamOutEventCallback.aidl",
"android/hardware/audio/core/ITelephony.aidl",
"android/hardware/audio/core/MicrophoneDynamicInfo.aidl",
"android/hardware/audio/core/MicrophoneInfo.aidl",
@@ -132,6 +132,7 @@
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
"android.hardware.audio.common-V1",
+ "android.hardware.audio.core.sounddose-V1",
"android.hardware.audio.effect-V1",
"android.media.audio.common.types-V2",
],
@@ -177,7 +178,7 @@
"android.hardware.audio_defaults",
],
srcs: [
- "android/hardware/audio/core/ISoundDose.aidl",
+ "android/hardware/audio/core/sounddose/ISoundDose.aidl",
],
imports: [
"android.media.audio.common.types-V2",
diff --git a/audio/aidl/TEST_MAPPING b/audio/aidl/TEST_MAPPING
index cafbf59..a166e61 100644
--- a/audio/aidl/TEST_MAPPING
+++ b/audio/aidl/TEST_MAPPING
@@ -13,6 +13,9 @@
"name": "VtsHalDownmixTargetTest"
},
{
+ "name": "VtsHalEnvironmentalReverbTargetTest"
+ },
+ {
"name": "VtsHalEqualizerTargetTest"
},
{
@@ -22,12 +25,18 @@
"name": "VtsHalLoudnessEnhancerTargetTest"
},
{
+ "name": "VtsHalPresetReverbTargetTest"
+ },
+ {
"name": "VtsHalVirtualizerTargetTest"
},
{
"name": "VtsHalVisualizerTargetTest"
},
{
+ "name": "VtsHalVolumeTargetTest"
+ },
+ {
"name": "VtsHalAECTargetTest"
},
{
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
similarity index 88%
rename from audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
rename to audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
index bc010ca..3b5d2d0 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -31,18 +31,18 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.core;
+package android.hardware.audio.core.sounddose;
@VintfStability
interface ISoundDose {
void setOutputRs2(float rs2ValueDbA);
float getOutputRs2();
- void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
+ void registerSoundDoseCallback(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback callback);
const int DEFAULT_MAX_RS2 = 100;
const int MIN_RS2 = 80;
@VintfStability
interface IHalSoundDoseCallback {
oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
- oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
+ oneway void onNewMelValues(in android.hardware.audio.core.sounddose.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
@VintfStability
parcelable MelRecord {
float[] melValues;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
index dd2279d..a029d43 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IModule.aidl
@@ -46,6 +46,7 @@
android.hardware.audio.core.AudioRoute[] getAudioRoutesForAudioPort(int portId);
android.hardware.audio.core.IModule.OpenInputStreamReturn openInputStream(in android.hardware.audio.core.IModule.OpenInputStreamArguments args);
android.hardware.audio.core.IModule.OpenOutputStreamReturn openOutputStream(in android.hardware.audio.core.IModule.OpenOutputStreamArguments args);
+ android.hardware.audio.core.IModule.SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
android.hardware.audio.core.AudioPatch setAudioPatch(in android.hardware.audio.core.AudioPatch requested);
boolean setAudioPortConfig(in android.media.audio.common.AudioPortConfig requested, out android.media.audio.common.AudioPortConfig suggested);
void resetAudioPatch(int patchId);
@@ -60,7 +61,7 @@
void updateAudioMode(android.hardware.audio.core.AudioMode mode);
void updateScreenRotation(android.hardware.audio.core.IModule.ScreenRotation rotation);
void updateScreenState(boolean isTurnedOn);
- @nullable android.hardware.audio.core.ISoundDose getSoundDose();
+ @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose();
int generateHwAvSyncId();
android.hardware.audio.core.VendorParameter[] getVendorParameters(in @utf8InCpp String[] ids);
void setVendorParameters(in android.hardware.audio.core.VendorParameter[] parameters, boolean async);
@@ -84,12 +85,20 @@
@nullable android.media.audio.common.AudioOffloadInfo offloadInfo;
long bufferSizeFrames;
@nullable android.hardware.audio.core.IStreamCallback callback;
+ @nullable android.hardware.audio.core.IStreamOutEventCallback eventCallback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
android.hardware.audio.core.IStreamOut stream;
android.hardware.audio.core.StreamDescriptor desc;
}
+ @VintfStability
+ parcelable SupportedPlaybackRateFactors {
+ float minSpeed;
+ float maxSpeed;
+ float minPitch;
+ float maxPitch;
+ }
@Backing(type="int") @VintfStability
enum ScreenRotation {
DEG_0 = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ISoundDose.aidl
deleted file mode 100644
index bc010ca..0000000
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/ISoundDose.aidl
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-///////////////////////////////////////////////////////////////////////////////
-// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
-///////////////////////////////////////////////////////////////////////////////
-
-// This file is a snapshot of an AIDL file. Do not edit it manually. There are
-// two cases:
-// 1). this is a frozen version file - do not edit this in any case.
-// 2). this is a 'current' file. If you make a backwards compatible change to
-// the interface (from the latest frozen version), the build system will
-// prompt you to update this file with `m <name>-update-api`.
-//
-// You must not make a backward incompatible change to any AIDL file built
-// with the aidl_interface module type with versions property set. The module
-// type is used to build AIDL files in a way that they can be used across
-// independently updatable components of the system. If a device is shipped
-// with such a backward incompatible change, it has a high risk of breaking
-// later when a module using the interface is updated, e.g., Mainline modules.
-
-package android.hardware.audio.core;
-@VintfStability
-interface ISoundDose {
- void setOutputRs2(float rs2ValueDbA);
- float getOutputRs2();
- void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
- const int DEFAULT_MAX_RS2 = 100;
- const int MIN_RS2 = 80;
- @VintfStability
- interface IHalSoundDoseCallback {
- oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
- oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
- @VintfStability
- parcelable MelRecord {
- float[] melValues;
- long timestamp;
- }
- }
-}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
index 68f1ff3..1041943 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamIn.aidl
@@ -43,7 +43,7 @@
void updateMetadata(in android.hardware.audio.common.SinkMetadata sinkMetadata);
float[] getHwGain();
void setHwGain(in float[] channelGains);
- const int MIC_FIELD_DIMENSION_WIDE_ANGLE = -1;
+ const int MIC_FIELD_DIMENSION_WIDE_ANGLE = (-1);
const int MIC_FIELD_DIMENSION_NO_ZOOM = 0;
const int MIC_FIELD_DIMENSION_MAX_ZOOM = 1;
const int HW_GAIN_MIN = 0;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
index 092b801..46acc11 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOut.aidl
@@ -38,6 +38,16 @@
void updateMetadata(in android.hardware.audio.common.SourceMetadata sourceMetadata);
float[] getHwVolume();
void setHwVolume(in float[] channelVolumes);
+ float getAudioDescriptionMixLevel();
+ void setAudioDescriptionMixLevel(float leveldB);
+ android.media.audio.common.AudioDualMonoMode getDualMonoMode();
+ void setDualMonoMode(android.media.audio.common.AudioDualMonoMode mode);
+ android.media.audio.common.AudioLatencyMode[] getRecommendedLatencyModes();
+ void setLatencyMode(android.media.audio.common.AudioLatencyMode mode);
+ android.media.audio.common.AudioPlaybackRate getPlaybackRateParameters();
+ void setPlaybackRateParameters(in android.media.audio.common.AudioPlaybackRate playbackRate);
+ void selectPresentation(int presentationId, int programId);
const int HW_VOLUME_MIN = 0;
const int HW_VOLUME_MAX = 1;
+ const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
similarity index 71%
copy from audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
copy to audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
index bc010ca..31cf0b7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -33,20 +33,7 @@
package android.hardware.audio.core;
@VintfStability
-interface ISoundDose {
- void setOutputRs2(float rs2ValueDbA);
- float getOutputRs2();
- void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
- const int DEFAULT_MAX_RS2 = 100;
- const int MIN_RS2 = 80;
- @VintfStability
- interface IHalSoundDoseCallback {
- oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
- oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
- @VintfStability
- parcelable MelRecord {
- float[] melValues;
- long timestamp;
- }
- }
+interface IStreamOutEventCallback {
+ oneway void onCodecFormatChanged(in byte[] audioMetadata);
+ oneway void onRecommendedLatencyModeChanged(in android.media.audio.common.AudioLatencyMode[] modes);
}
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
index 68c7f88..b77afe3 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/MicrophoneInfo.aidl
@@ -37,15 +37,15 @@
@utf8InCpp String id;
android.media.audio.common.AudioDevice device;
android.hardware.audio.core.MicrophoneInfo.Location location = android.hardware.audio.core.MicrophoneInfo.Location.UNKNOWN;
- int group = -1;
- int indexInTheGroup = -1;
+ int group = GROUP_UNKNOWN;
+ int indexInTheGroup = INDEX_IN_THE_GROUP_UNKNOWN;
@nullable android.hardware.audio.core.MicrophoneInfo.Sensitivity sensitivity;
android.hardware.audio.core.MicrophoneInfo.Directionality directionality = android.hardware.audio.core.MicrophoneInfo.Directionality.UNKNOWN;
android.hardware.audio.core.MicrophoneInfo.FrequencyResponsePoint[] frequencyResponse;
@nullable android.hardware.audio.core.MicrophoneInfo.Coordinate position;
@nullable android.hardware.audio.core.MicrophoneInfo.Coordinate orientation;
- const int GROUP_UNKNOWN = -1;
- const int INDEX_IN_THE_GROUP_UNKNOWN = -1;
+ const int GROUP_UNKNOWN = (-1);
+ const int INDEX_IN_THE_GROUP_UNKNOWN = (-1);
@Backing(type="int") @VintfStability
enum Location {
UNKNOWN = 0,
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
index 3a4271b..a65d7b7 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.core/current/android/hardware/audio/core/StreamDescriptor.aidl
@@ -39,12 +39,12 @@
int frameSizeBytes;
long bufferSizeFrames;
android.hardware.audio.core.StreamDescriptor.AudioBuffer audio;
- const int LATENCY_UNKNOWN = -1;
+ const int LATENCY_UNKNOWN = (-1);
@FixedSize @VintfStability
parcelable Position {
- long frames = -1;
- long timeNs = -1;
- const long UNKNOWN = -1;
+ long frames = UNKNOWN;
+ long timeNs = UNKNOWN;
+ const long UNKNOWN = (-1);
}
@Backing(type="int") @VintfStability
enum State {
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
index 09ad015..f8baa2a 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/BassBoost.aidl
@@ -36,8 +36,6 @@
union BassBoost {
android.hardware.audio.effect.VendorExtension vendor;
int strengthPm;
- const int MIN_PER_MILLE_STRENGTH = 0;
- const int MAX_PER_MILLE_STRENGTH = 1000;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -46,6 +44,7 @@
@VintfStability
parcelable Capability {
ParcelableHolder extension;
+ int maxStrengthPm;
boolean strengthSupported;
}
}
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 fcf08c3..0e61932 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,6 +44,22 @@
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;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
index deaff90..9fdd692 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Virtualizer.aidl
@@ -36,8 +36,6 @@
union Virtualizer {
android.hardware.audio.effect.VendorExtension vendor;
int strengthPm;
- const int MIN_PER_MILLE_STRENGTH = 0;
- const int MAX_PER_MILLE_STRENGTH = 1000;
@VintfStability
union Id {
int vendorExtensionTag;
@@ -46,6 +44,7 @@
@VintfStability
parcelable Capability {
android.hardware.audio.effect.VendorExtension extension;
+ int maxStrengthPm;
boolean strengthSupported;
}
}
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 9ee19f0..25f0b73 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
@@ -38,7 +38,7 @@
android.hardware.audio.effect.VendorExtension vendor;
android.hardware.audio.effect.Visualizer.GetOnlyParameters getOnlyParameters;
android.hardware.audio.effect.Visualizer.SetOnlyParameters setOnlyParameters;
- int captureSizeBytes;
+ int captureSamples;
android.hardware.audio.effect.Visualizer.ScalingMode scalingMode;
android.hardware.audio.effect.Visualizer.MeasurementMode measurementMode;
@VintfStability
@@ -52,12 +52,12 @@
parcelable Capability {
android.hardware.audio.effect.VendorExtension extension;
int maxLatencyMs;
- android.hardware.audio.effect.Visualizer.CaptureSizeRange captureSizeRange;
+ android.hardware.audio.effect.Visualizer.CaptureSamplesRange captureSampleRange;
}
@VintfStability
- parcelable CaptureSizeRange {
- int minBytes;
- int maxBytes;
+ parcelable CaptureSamplesRange {
+ int min;
+ int max;
}
@VintfStability
enum ScalingMode {
@@ -72,7 +72,7 @@
@VintfStability
union GetOnlyParameters {
android.hardware.audio.effect.Visualizer.GetOnlyParameters.Measurement measurement;
- byte[] captureBytes;
+ byte[] captureSampleBuffer;
@VintfStability
parcelable Measurement {
int rms;
diff --git a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
index 8c836b0..6259cfb 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/aidl_api/android.hardware.audio.effect/current/android/hardware/audio/effect/Volume.aidl
@@ -45,6 +45,7 @@
@VintfStability
parcelable Capability {
android.hardware.audio.effect.VendorExtension extension;
- int maxLevel;
+ int minLevelDb;
+ int maxLevelDb;
}
}
diff --git a/audio/aidl/android/hardware/audio/core/IModule.aidl b/audio/aidl/android/hardware/audio/core/IModule.aidl
index b278ac4..4779f1f 100644
--- a/audio/aidl/android/hardware/audio/core/IModule.aidl
+++ b/audio/aidl/android/hardware/audio/core/IModule.aidl
@@ -21,19 +21,21 @@
import android.hardware.audio.core.AudioMode;
import android.hardware.audio.core.AudioPatch;
import android.hardware.audio.core.AudioRoute;
-import android.hardware.audio.core.ISoundDose;
import android.hardware.audio.core.IStreamCallback;
import android.hardware.audio.core.IStreamIn;
import android.hardware.audio.core.IStreamOut;
+import android.hardware.audio.core.IStreamOutEventCallback;
import android.hardware.audio.core.ITelephony;
import android.hardware.audio.core.MicrophoneInfo;
import android.hardware.audio.core.ModuleDebug;
import android.hardware.audio.core.StreamDescriptor;
import android.hardware.audio.core.VendorParameter;
+import android.hardware.audio.core.sounddose.ISoundDose;
import android.hardware.audio.effect.IEffect;
import android.media.audio.common.AudioOffloadInfo;
import android.media.audio.common.AudioPort;
import android.media.audio.common.AudioPortConfig;
+import android.media.audio.common.Float;
/**
* Each instance of IModule corresponds to a separate audio module. The system
@@ -389,6 +391,8 @@
long bufferSizeFrames;
/** Client callback interface for the non-blocking output mode. */
@nullable IStreamCallback callback;
+ /** Optional callback to notify client about stream events. */
+ @nullable IStreamOutEventCallback eventCallback;
}
@VintfStability
parcelable OpenOutputStreamReturn {
@@ -398,6 +402,33 @@
OpenOutputStreamReturn openOutputStream(in OpenOutputStreamArguments args);
/**
+ * Get supported ranges of playback rate factors.
+ *
+ * See 'PlaybackRate' for the information on the playback rate parameters.
+ * This method provides supported ranges (inclusive) for the speed factor
+ * and the pitch factor.
+ *
+ * If the HAL module supports setting the playback rate, it is recommended
+ * to support speed and pitch factor values at least in the range from 0.5f
+ * to 2.0f.
+ *
+ * @throws EX_UNSUPPORTED_OPERATION If setting of playback rate parameters
+ * is not supported by the module.
+ */
+ @VintfStability
+ parcelable SupportedPlaybackRateFactors {
+ /** The minimum allowed speed factor. */
+ float minSpeed;
+ /** The maximum allowed speed factor. */
+ float maxSpeed;
+ /** The minimum allowed pitch factor. */
+ float minPitch;
+ /** The maximum allowed pitch factor. */
+ float maxPitch;
+ }
+ SupportedPlaybackRateFactors getSupportedPlaybackRateFactors();
+
+ /**
* Set an audio patch.
*
* This method creates new or updates an existing audio patch. If the
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
index 85da00d..b60b0fd 100644
--- a/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
+++ b/audio/aidl/android/hardware/audio/core/IStreamOut.aidl
@@ -18,6 +18,9 @@
import android.hardware.audio.common.SourceMetadata;
import android.hardware.audio.core.IStreamCommon;
+import android.media.audio.common.AudioDualMonoMode;
+import android.media.audio.common.AudioLatencyMode;
+import android.media.audio.common.AudioPlaybackRate;
/**
* This interface provides means for sending audio data to output devices.
@@ -86,4 +89,140 @@
* @throws EX_UNSUPPORTED_OPERATION If hardware volume control is not supported.
*/
void setHwVolume(in float[] channelVolumes);
+
+ // aidl: Constant of type float is not supported (b/251286924).
+ // const float AUDIO_DESCRIPTION_MIX_LEVEL_MIN = -Inf;
+ const int AUDIO_DESCRIPTION_MIX_LEVEL_MAX = 48;
+ /**
+ * Returns the Audio Description Mix level in dB.
+ *
+ * The level is applied to streams incorporating a secondary Audio
+ * Description stream. It specifies the relative level of mixing for
+ * the Audio Description with a reference to the Main Audio.
+ *
+ * The value of the relative level is in the range from negative infinity
+ * to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+ *
+ * @return The current Audio Description Mix Level in dB.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ float getAudioDescriptionMixLevel();
+ /**
+ * Sets the Audio Description Mix level in dB.
+ *
+ * For streams incorporating a secondary Audio Description stream the
+ * relative level of mixing of the Audio Description to the Main Audio is
+ * controlled by this method.
+ *
+ * The value of the relative level must be in the range from negative
+ * infinity to +48, see AUDIO_DESCRIPTION_MIX_LEVEL_* constants.
+ *
+ * @param leveldB Audio Description Mix Level in dB.
+ * @throws EX_ILLEGAL_ARGUMENT If the provided value is out of range.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+ */
+ void setAudioDescriptionMixLevel(float leveldB);
+
+ /**
+ * Returns the Dual Mono mode presentation setting.
+ *
+ * @return The current setting of Dual Mono mode.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ AudioDualMonoMode getDualMonoMode();
+ /**
+ * Sets the Dual Mono mode presentation on the output device.
+ *
+ * The Dual Mono mode is generally applied to stereo audio streams
+ * where the left and right channels come from separate sources.
+ *
+ * @param mode Selected Dual Mono mode.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+ */
+ void setDualMonoMode(AudioDualMonoMode mode);
+
+ /**
+ * Retrieve supported latency modes.
+ *
+ * Indicates which latency modes are currently supported on this output
+ * stream. If the transport protocol (for example, Bluetooth A2DP) used by
+ * this output stream to reach the output device supports variable latency
+ * modes, the HAL indicates which modes are currently supported. The client
+ * can then call setLatencyMode() with one of the supported modes to select
+ * the desired operation mode.
+ *
+ * Implementation for this method is mandatory only on specific spatial
+ * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+ * be routed to a BT classic sink.
+ *
+ * @return Currently supported latency modes.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ AudioLatencyMode[] getRecommendedLatencyModes();
+ /**
+ * Sets the latency mode.
+ *
+ * The requested mode must be one of the modes returned by the
+ * 'getRecommendedLatencyModes()' method.
+ *
+ * Implementation for this method is mandatory only on specific spatial
+ * audio streams indicated by AUDIO_OUTPUT_FLAG_SPATIALIZER flag if they can
+ * be routed to a BT classic sink.
+ *
+ * @throws EX_ILLEGAL_ARGUMENT If the specified mode is not supported.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If setting of this parameter is not supported.
+ */
+ void setLatencyMode(AudioLatencyMode mode);
+
+ /**
+ * Retrieve current playback rate parameters.
+ *
+ * @return Current playback parameters.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If the information is unavailable.
+ */
+ AudioPlaybackRate getPlaybackRateParameters();
+ /**
+ * Set playback rate parameters.
+ *
+ * Sets the playback rate parameters that control playback behavior. This
+ * is normally used when playing encoded content and decoding is performed
+ * in hardware. Otherwise, the client can apply necessary transformations
+ * itself.
+ *
+ * The range of supported values for speed and pitch factors is provided by
+ * the 'IModule.getSupportedPlaybackRateFactors' method. Out of range speed
+ * and pitch values must not be rejected if the fallback mode is 'MUTE'.
+ *
+ * @param playbackRate Playback parameters to set.
+ * @throws EX_ILLEGAL_ARGUMENT If provided parameters are out of acceptable range.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If setting playback rate parameters
+ * is not supported.
+ */
+ void setPlaybackRateParameters(in AudioPlaybackRate playbackRate);
+
+ /**
+ * Select presentation and program from for decoding.
+ *
+ * Selects a presentation for decoding from a next generation media stream
+ * (as defined per ETSI TS 103 190-2) and a program within the presentation.
+ * The client must obtain valid presentation and program IDs from the media
+ * stream on its own.
+ *
+ * @param presentationId Selected audio presentation.
+ * @param programId Refinement for the presentation.
+ * @throws EX_ILLEGAL_ARGUMENT If the HAL module is unable to locate
+ * the specified presentation or program in
+ * the media stream.
+ * @throws EX_ILLEGAL_STATE If the stream is closed.
+ * @throws EX_UNSUPPORTED_OPERATION If presentation selection is not supported.
+ */
+ void selectPresentation(int presentationId, int programId);
}
diff --git a/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
new file mode 100644
index 0000000..75d7385
--- /dev/null
+++ b/audio/aidl/android/hardware/audio/core/IStreamOutEventCallback.aidl
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.audio.core;
+
+import android.media.audio.common.AudioLatencyMode;
+
+/**
+ * This interface provides means for asynchronous notification of the client
+ * by an output stream.
+ */
+@VintfStability
+oneway interface IStreamOutEventCallback {
+ /**
+ * Codec format changed notification.
+ *
+ * onCodecFormatChanged returns an AudioMetadata object in read-only
+ * ByteString format. It represents the most recent codec format decoded by
+ * a HW audio decoder.
+ *
+ * Codec format is an optional message from HW audio decoders. It serves to
+ * notify the application about the codec format and audio objects contained
+ * within the compressed audio stream for control, informational,
+ * and display purposes.
+ *
+ * audioMetadata ByteString is convertible to an AudioMetadata object
+ * through both a C++ and a C API present in Metadata.h [1], or through a
+ * Java API present in AudioMetadata.java [2].
+ *
+ * The ByteString format is a stable format used for parcelling
+ * (marshalling) across JNI, AIDL, and HIDL interfaces. The test for R
+ * compatibility for native marshalling is TEST(metadata_tests,
+ * compatibility_R) [3]. The test for R compatibility for JNI marshalling
+ * is android.media.cts.AudioMetadataTest#testCompatibilityR [4].
+ *
+ * Android R defined keys are as follows [2]:
+ * "bitrate", int32
+ * "channel-mask", int32
+ * "mime", string
+ * "sample-rate", int32
+ * "bit-width", int32
+ * "has-atmos", int32
+ * "audio-encoding", int32
+ *
+ * Android S in addition adds the following keys:
+ * "presentation-id", int32
+ * "program-id", int32
+ * "presentation-content-classifier", int32
+ * presentation-content-classifier key values can be referenced from
+ * frameworks/base/media/java/android/media/AudioPresentation.java
+ * i.e. AudioPresentation.ContentClassifier
+ * It can contain any of the below values
+ * CONTENT_UNKNOWN = -1,
+ * CONTENT_MAIN = 0,
+ * CONTENT_MUSIC_AND_EFFECTS = 1,
+ * CONTENT_VISUALLY_IMPAIRED = 2,
+ * CONTENT_HEARING_IMPAIRED = 3,
+ * CONTENT_DIALOG = 4,
+ * CONTENT_COMMENTARY = 5,
+ * CONTENT_EMERGENCY = 6,
+ * CONTENT_VOICEOVER = 7
+ * "presentation-language", string // represents ISO 639-2 (three letter code)
+ *
+ * Parceling Format:
+ * All values are native endian order. [1]
+ *
+ * using type_size_t = uint32_t;
+ * using index_size_t = uint32_t;
+ * using datum_size_t = uint32_t;
+ *
+ * Permitted type indexes are
+ * TYPE_NONE = 0, // Reserved
+ * TYPE_INT32 = 1,
+ * TYPE_INT64 = 2,
+ * TYPE_FLOAT = 3,
+ * TYPE_DOUBLE = 4,
+ * TYPE_STRING = 5,
+ * TYPE_DATA = 6, // A data table of <String, Datum>
+ *
+ * Datum = {
+ * (type_size_t) Type (the type index from type_as_value<T>.)
+ * (datum_size_t) Size (size of the Payload)
+ * (byte string) Payload<Type>
+ * }
+ *
+ * The data is specified in native endian order. Since the size of the
+ * Payload is always present, unknown types may be skipped.
+ *
+ * Payload<Fixed-size Primitive_Value>
+ * [ sizeof(Primitive_Value) in raw bytes ]
+ *
+ * Example of Payload<Int32> of 123:
+ * Payload<Int32>
+ * [ value of 123 ] = 0x7b 0x00 0x00 0x00 123
+ *
+ * Payload<String>
+ * [ (index_size_t) length, not including zero terminator.]
+ * [ (length) raw bytes ]
+ *
+ * Example of Payload<String> of std::string("hi"):
+ * [ (index_size_t) length ] = 0x02 0x00 0x00 0x00 2 strlen("hi")
+ * [ raw bytes "hi" ] = 0x68 0x69 "hi"
+ *
+ * Payload<Data>
+ * [ (index_size_t) entries ]
+ * [ raw bytes (entry 1) Key (Payload<String>)
+ * Value (Datum)
+ * ... (until #entries) ]
+ *
+ * Example of Payload<Data> of {{"hello", "world"},
+ * {"value", (int32_t)1000}};
+ * [ (index_size_t) #entries ] = 0x02 0x00 0x00 0x00 2 entries
+ * Key (Payload<String>)
+ * [ index_size_t length ] = 0x05 0x00 0x00 0x00 5 strlen("hello")
+ * [ raw bytes "hello" ] = 0x68 0x65 0x6c 0x6c 0x6f "hello"
+ * Value (Datum)
+ * [ (type_size_t) type ] = 0x05 0x00 0x00 0x00 5 (TYPE_STRING)
+ * [ (datum_size_t) size ] = 0x09 0x00 0x00 0x00 sizeof(index_size_t) +
+ * strlen("world")
+ * Payload<String>
+ * [ (index_size_t) length ] = 0x05 0x00 0x00 0x00 5 strlen("world")
+ * [ raw bytes "world" ] = 0x77 0x6f 0x72 0x6c 0x64 "world"
+ * Key (Payload<String>)
+ * [ index_size_t length ] = 0x05 0x00 0x00 0x00 5 strlen("value")
+ * [ raw bytes "value" ] = 0x76 0x61 0x6c 0x75 0x65 "value"
+ * Value (Datum)
+ * [ (type_size_t) type ] = 0x01 0x00 0x00 0x00 1 (TYPE_INT32)
+ * [ (datum_size_t) size ] = 0x04 0x00 0x00 0x00 4 sizeof(int32_t)
+ * Payload<Int32>
+ * [ raw bytes 1000 ] = 0xe8 0x03 0x00 0x00 1000
+ *
+ * The contents of audioMetadata is a Payload<Data>.
+ * An implementation dependent detail is that the Keys are always
+ * stored sorted, so the byte string representation generated is unique.
+ *
+ * Vendor keys are allowed for informational and debugging purposes.
+ * Vendor keys should consist of the vendor company name followed
+ * by a dot; for example, "vendorCompany.someVolume" [2].
+ *
+ * [1] system/media/audio_utils/include/audio_utils/Metadata.h
+ * [2] frameworks/base/media/java/android/media/AudioMetadata.java
+ * [3] system/media/audio_utils/tests/metadata_tests.cpp
+ * [4] cts/tests/tests/media/src/android/media/cts/AudioMetadataTest.java
+ *
+ * @param audioMetadata A buffer containing decoded format changes
+ * reported by codec. The buffer contains data that can be transformed
+ * to audio metadata, which is a C++ object based map.
+ */
+ void onCodecFormatChanged(in byte[] audioMetadata);
+
+ /**
+ * Called with the new list of supported latency modes when a change occurs.
+ */
+ void onRecommendedLatencyModeChanged(in AudioLatencyMode[] modes);
+}
diff --git a/audio/aidl/android/hardware/audio/core/ISoundDose.aidl b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
similarity index 98%
rename from audio/aidl/android/hardware/audio/core/ISoundDose.aidl
rename to audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
index 89fd69b..953ab62 100644
--- a/audio/aidl/android/hardware/audio/core/ISoundDose.aidl
+++ b/audio/aidl/android/hardware/audio/core/sounddose/ISoundDose.aidl
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.audio.core;
+package android.hardware.audio.core.sounddose;
import android.media.audio.common.AudioDevice;
diff --git a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
index 9e5d8aa..6a94242 100644
--- a/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
+++ b/audio/aidl/android/hardware/audio/effect/BassBoost.aidl
@@ -52,6 +52,10 @@
*/
ParcelableHolder extension;
/**
+ * Maximum possible per mille strength.
+ */
+ int maxStrengthPm;
+ /**
* Indicates whether setting strength is supported. False value indicates only one strength
* is supported and setParameter() method will return EX_ILLEGAL_ARGUMENT.
*/
@@ -59,23 +63,14 @@
}
/**
- * Minimal possible per mille strength.
- */
- const int MIN_PER_MILLE_STRENGTH = 0;
-
- /**
- * Maximum possible per mille strength.
- */
- const int MAX_PER_MILLE_STRENGTH = 1000;
-
- /**
* The per mille strength of the bass boost effect.
*
* If the implementation does not support per mille accuracy for setting the strength, it is
* allowed to round the given strength to the nearest supported value. In this case {@link
* #IEffect.getParameter()} method should return the rounded value that was actually set.
*
- * The valid range for strength is [0, 1000].
+ * The value of the strength must be non-negative and not exceed the value specified by
+ * the 'maxStrengthPm' capability.
*/
int strengthPm;
}
diff --git a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
index 3df0d27..81c0dde 100644
--- a/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
+++ b/audio/aidl/android/hardware/audio/effect/EnvironmentalReverb.aidl
@@ -56,37 +56,109 @@
}
/**
+ * 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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
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.
*/
int densityPm;
+
/**
* Bypass reverb and copy input to output if set to true.
*/
diff --git a/audio/aidl/android/hardware/audio/effect/IEffect.aidl b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
index 3b957d7..6097f34 100644
--- a/audio/aidl/android/hardware/audio/effect/IEffect.aidl
+++ b/audio/aidl/android/hardware/audio/effect/IEffect.aidl
@@ -34,12 +34,10 @@
/**
* One of Binder STATUS_* statuses:
* - STATUS_OK: the command has completed successfully;
- * - STATUS_BAD_VALUE: invalid value in the 'Command' structure;
- * - STATUS_INVALID_OPERATION: the mix port is not connected
- * to any producer or consumer, thus
- * positions can not be reported;
- * - STATUS_NOT_ENOUGH_DATA: a read or write error has
- * occurred for the 'audio.fmq' queue;
+ * - STATUS_BAD_VALUE: invalid parameters or state detected in effects;
+ * - STATUS_INVALID_OPERATION: an internal error happens in effect audio buffer processing;
+ * - STATUS_NOT_ENOUGH_DATA: a read or write error has occurred for the 'inputDataMQ' or
+ * 'outputDataMQ';
*
*/
int status;
diff --git a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
index 90ec6f8..5f385a6 100644
--- a/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Virtualizer.aidl
@@ -53,6 +53,10 @@
*/
VendorExtension extension;
/**
+ * Maximum possible per mille strength.
+ */
+ int maxStrengthPm;
+ /**
* Indicates whether setting strength is supported. False value indicates only one strength
* is supported and setParameter() method will always return EX_ILLEGAL_ARGUMENT.
*/
@@ -60,23 +64,14 @@
}
/**
- * Minimal possible per mille strength.
- */
- const int MIN_PER_MILLE_STRENGTH = 0;
-
- /**
- * Maximum possible per mille strength.
- */
- const int MAX_PER_MILLE_STRENGTH = 1000;
-
- /**
* The per mille strength of the virtualizer effect.
*
* If the implementation does not support per mille accuracy for setting the strength, it is
* allowed to round the given strength to the nearest supported value. In this case {@link
* #IEffect.getParameter()} method should return the rounded value that was actually set.
*
- * The valid range for strength is [0, 1000].
+ * The value of the strength must be non-negative and not exceed the value specified by
+ * the 'maxStrengthPm' capability.
*/
int strengthPm;
}
diff --git a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
index 4c1b71a..dfe29c8 100644
--- a/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Visualizer.aidl
@@ -63,16 +63,16 @@
/**
* Capture size range.
*/
- CaptureSizeRange captureSizeRange;
+ CaptureSamplesRange captureSampleRange;
}
/**
- * Supported capture size range in bytes.
+ * Supported capture size range in samples.
*/
@VintfStability
- parcelable CaptureSizeRange {
- int minBytes;
- int maxBytes;
+ parcelable CaptureSamplesRange {
+ int min;
+ int max;
}
/**
@@ -131,9 +131,9 @@
Measurement measurement;
/**
- * Gets the latest PCM capture, size of returned vector equals to @c captureSize.
+ * Get the latest captureSamples of PCM samples (8 bits per sample).
*/
- byte[] captureBytes;
+ byte[] captureSampleBuffer;
}
GetOnlyParameters getOnlyParameters;
@@ -152,10 +152,10 @@
SetOnlyParameters setOnlyParameters;
/**
- * Current capture size in bytes. The capture size must be a power of 2 in the range
+ * Current capture size in number of samples. The capture size must be inside
* Capability.captureSizeRange.
*/
- int captureSizeBytes;
+ int captureSamples;
/**
* Visualizer capture mode
*/
diff --git a/audio/aidl/android/hardware/audio/effect/Volume.aidl b/audio/aidl/android/hardware/audio/effect/Volume.aidl
index a3ce2f6..5033881 100644
--- a/audio/aidl/android/hardware/audio/effect/Volume.aidl
+++ b/audio/aidl/android/hardware/audio/effect/Volume.aidl
@@ -52,13 +52,18 @@
VendorExtension extension;
/**
- * Volume strength supported in dB.
+ * Minimum Volume level supported in dB.
*/
- int maxLevel;
+ int minLevelDb;
+
+ /**
+ * Maximum Volume level supported in dB.
+ */
+ int maxLevelDb;
}
/**
- * Current level in dB.
+ * Current level in dB with supported minimum and maximum level specified in capability.
*/
int levelDb;
/**
diff --git a/audio/aidl/common/include/Utils.h b/audio/aidl/common/include/Utils.h
index 990cff9..8f0c986 100644
--- a/audio/aidl/common/include/Utils.h
+++ b/audio/aidl/common/include/Utils.h
@@ -48,7 +48,8 @@
}
constexpr size_t getChannelCount(
- const ::aidl::android::media::audio::common::AudioChannelLayout& layout) {
+ const ::aidl::android::media::audio::common::AudioChannelLayout& layout,
+ int32_t mask = std::numeric_limits<int32_t>::max()) {
using Tag = ::aidl::android::media::audio::common::AudioChannelLayout::Tag;
switch (layout.getTag()) {
case Tag::none:
@@ -56,11 +57,11 @@
case Tag::invalid:
return 0;
case Tag::indexMask:
- return __builtin_popcount(layout.get<Tag::indexMask>());
+ return __builtin_popcount(layout.get<Tag::indexMask>() & mask);
case Tag::layoutMask:
- return __builtin_popcount(layout.get<Tag::layoutMask>());
+ return __builtin_popcount(layout.get<Tag::layoutMask>() & mask);
case Tag::voiceMask:
- return __builtin_popcount(layout.get<Tag::voiceMask>());
+ return __builtin_popcount(layout.get<Tag::voiceMask>() & mask);
}
return 0;
}
diff --git a/audio/aidl/default/Android.bp b/audio/aidl/default/Android.bp
index a938551..8cd56c0 100644
--- a/audio/aidl/default/Android.bp
+++ b/audio/aidl/default/Android.bp
@@ -95,6 +95,7 @@
defaults: [
"aidlaudioservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
"latest_android_hardware_audio_core_ndk_shared",
],
static_libs: [
@@ -149,18 +150,21 @@
vintf_fragments: ["android.hardware.audio.effect.service-aidl.xml"],
defaults: ["aidlaudioeffectservice_defaults"],
shared_libs: [
+ "libaecsw",
+ "libagcsw",
"libbassboostsw",
"libbundleaidl",
"libdownmixaidl",
"libdynamicsprocessingsw",
"libenvreverbsw",
"libequalizersw",
- "libhapticgeneratorsw",
+ "libhapticgeneratoraidl",
"libloudnessenhanceraidl",
+ "libnssw",
"libpresetreverbsw",
"libtinyxml2",
"libvirtualizersw",
- "libvisualizersw",
+ "libvisualizeraidl",
"libvolumesw",
],
srcs: [
diff --git a/audio/aidl/default/EffectImpl.cpp b/audio/aidl/default/EffectImpl.cpp
index 139f262..b24ca63 100644
--- a/audio/aidl/default/EffectImpl.cpp
+++ b/audio/aidl/default/EffectImpl.cpp
@@ -21,6 +21,7 @@
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::PcmType;
extern "C" binder_exception_t destroyEffect(const std::shared_ptr<IEffect>& instanceSp) {
State state;
@@ -40,6 +41,10 @@
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) {
LOG(DEBUG) << __func__;
+ // effect only support 32bits float
+ RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
+ common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
+ EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
RETURN_OK_IF(mState != State::INIT);
auto context = createContext(common);
RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
diff --git a/audio/aidl/default/Module.cpp b/audio/aidl/default/Module.cpp
index 4a424bd..b58c562 100644
--- a/audio/aidl/default/Module.cpp
+++ b/audio/aidl/default/Module.cpp
@@ -32,6 +32,7 @@
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioFormatDescription;
@@ -603,6 +604,13 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Module::getSupportedPlaybackRateFactors(
+ SupportedPlaybackRateFactors* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
ndk::ScopedAStatus Module::setAudioPatch(const AudioPatch& in_requested, AudioPatch* _aidl_return) {
LOG(DEBUG) << __func__ << ": requested patch " << in_requested.toString();
if (in_requested.sourcePortConfigIds.empty()) {
@@ -939,7 +947,7 @@
ndk::ScopedAStatus Module::getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) {
if (mSoundDose == nullptr) {
- mSoundDose = ndk::SharedRefBase::make<SoundDose>();
+ mSoundDose = ndk::SharedRefBase::make<sounddose::SoundDose>();
mSoundDoseBinder = mSoundDose->asBinder();
AIBinder_setMinSchedulerPolicy(mSoundDoseBinder.get(), SCHED_NORMAL,
ANDROID_PRIORITY_AUDIO);
diff --git a/audio/aidl/default/SoundDose.cpp b/audio/aidl/default/SoundDose.cpp
index 3d222a8..be9f93a 100644
--- a/audio/aidl/default/SoundDose.cpp
+++ b/audio/aidl/default/SoundDose.cpp
@@ -20,7 +20,7 @@
#include <android-base/logging.h>
-namespace aidl::android::hardware::audio::core {
+namespace aidl::android::hardware::audio::core::sounddose {
ndk::ScopedAStatus SoundDose::setOutputRs2(float in_rs2ValueDbA) {
if (in_rs2ValueDbA < MIN_RS2 || in_rs2ValueDbA > DEFAULT_MAX_RS2) {
@@ -54,4 +54,4 @@
return ndk::ScopedAStatus::ok();
}
-} // namespace aidl::android::hardware::audio::core
+} // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/Stream.cpp b/audio/aidl/default/Stream.cpp
index bb123a2..a490a2a 100644
--- a/audio/aidl/default/Stream.cpp
+++ b/audio/aidl/default/Stream.cpp
@@ -27,7 +27,10 @@
using aidl::android::hardware::audio::common::SinkMetadata;
using aidl::android::hardware::audio::common::SourceMetadata;
using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDualMonoMode;
+using aidl::android::media::audio::common::AudioLatencyMode;
using aidl::android::media::audio::common::AudioOffloadInfo;
+using aidl::android::media::audio::common::AudioPlaybackRate;
using android::hardware::audio::common::getChannelCount;
using android::hardware::audio::common::getFrameSizeInBytes;
@@ -724,4 +727,55 @@
return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
}
+ndk::ScopedAStatus StreamOut::getAudioDescriptionMixLevel(float* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setAudioDescriptionMixLevel(float in_leveldB) {
+ LOG(DEBUG) << __func__ << ": description mix level " << in_leveldB;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getDualMonoMode(AudioDualMonoMode* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setDualMonoMode(AudioDualMonoMode in_mode) {
+ LOG(DEBUG) << __func__ << ": dual mono mode " << toString(in_mode);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getRecommendedLatencyModes(
+ std::vector<AudioLatencyMode>* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setLatencyMode(AudioLatencyMode in_mode) {
+ LOG(DEBUG) << __func__ << ": latency mode " << toString(in_mode);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::getPlaybackRateParameters(AudioPlaybackRate* _aidl_return) {
+ LOG(DEBUG) << __func__;
+ (void)_aidl_return;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::setPlaybackRateParameters(const AudioPlaybackRate& in_playbackRate) {
+ LOG(DEBUG) << __func__ << ": " << in_playbackRate.toString();
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ndk::ScopedAStatus StreamOut::selectPresentation(int32_t in_presentationId, int32_t in_programId) {
+ LOG(DEBUG) << __func__ << ": presentationId " << in_presentationId << ", programId "
+ << in_programId;
+ return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
} // namespace aidl::android::hardware::audio::core
diff --git a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
index 809812a..5f1bc46 100644
--- a/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
+++ b/audio/aidl/default/acousticEchoCanceler/AcousticEchoCancelerSw.h
@@ -37,7 +37,7 @@
int getEchoDelay() const { return mEchoDelayUs; }
private:
- int mEchoDelayUs;
+ int mEchoDelayUs = 0;
};
class AcousticEchoCancelerSw final : public EffectImpl {
diff --git a/audio/aidl/default/audio_effects_config.xml b/audio/aidl/default/audio_effects_config.xml
index a958eaf..9670e9c 100644
--- a/audio/aidl/default/audio_effects_config.xml
+++ b/audio/aidl/default/audio_effects_config.xml
@@ -35,13 +35,13 @@
<library name="downmix" path="libdownmixaidl.so"/>
<library name="dynamics_processingsw" path="libdynamicsprocessingsw.so"/>
<library name="equalizersw" path="libequalizersw.so"/>
- <library name="haptic_generatorsw" path="libhapticgeneratorsw.so"/>
+ <library name="haptic_generator" path="libhapticgeneratoraidl.so"/>
<library name="loudness_enhancer" path="libloudnessenhanceraidl.so"/>
<library name="nssw" path="libnssw.so"/>
<library name="env_reverbsw" path="libenvreverbsw.so"/>
<library name="preset_reverbsw" path="libpresetreverbsw.so"/>
<library name="virtualizersw" path="libvirtualizersw.so"/>
- <library name="visualizersw" path="libvisualizersw.so"/>
+ <library name="visualizer" path="libvisualizeraidl.so"/>
<library name="volumesw" path="libvolumesw.so"/>
</libraries>
@@ -73,7 +73,7 @@
</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="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
+ <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"/>
<effect name="noise_suppression" library="nssw" uuid="c06c8400-8e06-11e0-9cb6-0002a5d5c51b"/>
@@ -82,8 +82,8 @@
<libsw library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
<libsw library="bundle" uuid="1d4033c0-8557-11df-9f2d-0002a5d5c51b"/>
</effectProxy>
- <effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>
- <effect name="volume" library="volumesw" uuid="fa81a718-588b-11ed-9b6a-0242ac120002"/>
+ <effect name="visualizer" library="visualizer" uuid="d069d9e0-8329-11df-9168-0002a5d5c51b"/>
+ <effect name="volume" library="bundle" uuid="119341a0-8469-11df-81f9-0002a5d5c51b"/>
<effectProxy name="equalizer" uuid="c8e70ecd-48ca-456e-8a4f-0002a5d5c51b">
<libsw library="equalizersw" uuid="0bed4300-847d-11df-bb17-0002a5d5c51b"/>
<libsw library="bundle" uuid="ce772f20-847d-11df-bb17-0002a5d5c51b"/>
diff --git a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
index e23fec0..2724835 100644
--- a/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
+++ b/audio/aidl/default/automaticGainControl/AutomaticGainControlSw.h
@@ -41,9 +41,10 @@
int getSaturationMargin();
private:
- int mDigitalGain;
- AutomaticGainControl::LevelEstimator mLevelEstimator;
- int mSaturationMargin;
+ int mDigitalGain = 0;
+ AutomaticGainControl::LevelEstimator mLevelEstimator =
+ AutomaticGainControl::LevelEstimator::RMS;
+ int mSaturationMargin = 0;
};
class AutomaticGainControlSw final : public EffectImpl {
diff --git a/audio/aidl/default/bassboost/BassBoostSw.cpp b/audio/aidl/default/bassboost/BassBoostSw.cpp
index 8e4779d..0c7ebe1 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.cpp
+++ b/audio/aidl/default/bassboost/BassBoostSw.cpp
@@ -62,7 +62,8 @@
const std::string BassBoostSw::kEffectName = "BassBoostSw";
const bool BassBoostSw::kStrengthSupported = true;
-const BassBoost::Capability BassBoostSw::kCapability = {.strengthSupported = kStrengthSupported};
+const BassBoost::Capability BassBoostSw::kCapability = {.maxStrengthPm = 1000,
+ .strengthSupported = kStrengthSupported};
const Descriptor BassBoostSw::kDescriptor = {
.common = {.id = {.type = kBassBoostTypeUUID,
.uuid = kBassBoostSwImplUUID,
@@ -171,4 +172,14 @@
return {STATUS_OK, samples, samples};
}
+RetCode BassBoostSwContext::setBbStrengthPm(int strength) {
+ if (strength < 0 || strength > BassBoostSw::kCapability.maxStrengthPm) {
+ LOG(ERROR) << __func__ << " invalid strength: " << strength;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new strength
+ mStrength = strength;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/bassboost/BassBoostSw.h b/audio/aidl/default/bassboost/BassBoostSw.h
index 411b9c9..65c01c8 100644
--- a/audio/aidl/default/bassboost/BassBoostSw.h
+++ b/audio/aidl/default/bassboost/BassBoostSw.h
@@ -33,20 +33,11 @@
LOG(DEBUG) << __func__;
}
- RetCode setBbStrengthPm(int strength) {
- if (strength < BassBoost::MIN_PER_MILLE_STRENGTH ||
- strength > BassBoost::MAX_PER_MILLE_STRENGTH) {
- LOG(ERROR) << __func__ << " invalid strength: " << strength;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new strength
- mStrength = strength;
- return RetCode::SUCCESS;
- }
+ RetCode setBbStrengthPm(int strength);
int getBbStrengthPm() const { return mStrength; }
private:
- int mStrength;
+ int mStrength = 0;
};
class BassBoostSw final : public EffectImpl {
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.cpp b/audio/aidl/default/envReverb/EnvReverbSw.cpp
index a107064..9d7159a 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.cpp
+++ b/audio/aidl/default/envReverb/EnvReverbSw.cpp
@@ -60,7 +60,8 @@
namespace aidl::android::hardware::audio::effect {
const std::string EnvReverbSw::kEffectName = "EnvReverbSw";
-const EnvironmentalReverb::Capability EnvReverbSw::kCapability;
+const EnvironmentalReverb::Capability EnvReverbSw::kCapability = {
+ .maxDecayTimeMs = EnvironmentalReverb::MAX_DECAY_TIME_MS};
const Descriptor EnvReverbSw::kDescriptor = {
.common = {.id = {.type = kEnvReverbTypeUUID,
.uuid = kEnvReverbSwImplUUID,
@@ -82,16 +83,140 @@
RETURN_IF(Parameter::Specific::environmentalReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::environmentalReverb>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
+ auto tag = erParam.getTag();
+
+ switch (tag) {
+ case EnvironmentalReverb::roomLevelMb: {
+ RETURN_IF(mContext->setErRoomLevel(erParam.get<EnvironmentalReverb::roomLevelMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setRoomLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::roomHfLevelMb: {
+ RETURN_IF(
+ mContext->setErRoomHfLevel(erParam.get<EnvironmentalReverb::roomHfLevelMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setRoomHfLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::decayTimeMs: {
+ RETURN_IF(mContext->setErDecayTime(erParam.get<EnvironmentalReverb::decayTimeMs>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDecayTimeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::decayHfRatioPm: {
+ RETURN_IF(
+ mContext->setErDecayHfRatio(
+ erParam.get<EnvironmentalReverb::decayHfRatioPm>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDecayHfRatioFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::levelMb: {
+ RETURN_IF(mContext->setErLevel(erParam.get<EnvironmentalReverb::levelMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::delayMs: {
+ RETURN_IF(mContext->setErDelay(erParam.get<EnvironmentalReverb::delayMs>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDelayFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::diffusionPm: {
+ RETURN_IF(mContext->setErDiffusion(erParam.get<EnvironmentalReverb::diffusionPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDiffusionFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::densityPm: {
+ RETURN_IF(mContext->setErDensity(erParam.get<EnvironmentalReverb::densityPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDensityFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::bypass: {
+ RETURN_IF(mContext->setErBypass(erParam.get<EnvironmentalReverb::bypass>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setBypassFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus EnvReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::environmentalReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::environmentalReverb>(mSpecificParam);
+ auto erId = id.get<Parameter::Id::environmentalReverbTag>();
+ auto erIdTag = erId.getTag();
+ switch (erIdTag) {
+ case EnvironmentalReverb::Id::commonTag:
+ return getParameterEnvironmentalReverb(erId.get<EnvironmentalReverb::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(erIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus EnvReverbSw::getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ EnvironmentalReverb erParam;
+ switch (tag) {
+ case EnvironmentalReverb::roomLevelMb: {
+ erParam.set<EnvironmentalReverb::roomLevelMb>(mContext->getErRoomLevel());
+ break;
+ }
+ case EnvironmentalReverb::roomHfLevelMb: {
+ erParam.set<EnvironmentalReverb::roomHfLevelMb>(mContext->getErRoomHfLevel());
+ break;
+ }
+ case EnvironmentalReverb::decayTimeMs: {
+ erParam.set<EnvironmentalReverb::decayTimeMs>(mContext->getErDecayTime());
+ break;
+ }
+ case EnvironmentalReverb::decayHfRatioPm: {
+ erParam.set<EnvironmentalReverb::decayHfRatioPm>(mContext->getErDecayHfRatio());
+ break;
+ }
+ case EnvironmentalReverb::levelMb: {
+ erParam.set<EnvironmentalReverb::levelMb>(mContext->getErLevel());
+ break;
+ }
+ case EnvironmentalReverb::delayMs: {
+ erParam.set<EnvironmentalReverb::delayMs>(mContext->getErDelay());
+ break;
+ }
+ case EnvironmentalReverb::diffusionPm: {
+ erParam.set<EnvironmentalReverb::diffusionPm>(mContext->getErDiffusion());
+ break;
+ }
+ case EnvironmentalReverb::densityPm: {
+ erParam.set<EnvironmentalReverb::densityPm>(mContext->getErDensity());
+ break;
+ }
+ case EnvironmentalReverb::bypass: {
+ erParam.set<EnvironmentalReverb::bypass>(mContext->getErBypass());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::environmentalReverb>(erParam);
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/default/envReverb/EnvReverbSw.h b/audio/aidl/default/envReverb/EnvReverbSw.h
index b8761a6..f521215 100644
--- a/audio/aidl/default/envReverb/EnvReverbSw.h
+++ b/audio/aidl/default/envReverb/EnvReverbSw.h
@@ -32,7 +32,120 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ 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;
+ }
+ int getErDensity() const { return mDensity; }
+
+ RetCode setErBypass(bool bypass) {
+ // TODO : Add implementation to apply new bypass
+ mBypass = bypass;
+ return RetCode::SUCCESS;
+ }
+ 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 mDecayTime = 1000; // Default decay time
+ int mDecayHfRatio = 500; // Default decay hf ratio
+ int mLevel = EnvironmentalReverb::MIN_LEVEL_MB; // Default level
+ int mDelay = 40; // Default delay
+ int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM; // Default diffusion
+ int mDensity = EnvironmentalReverb::MAX_DENSITY_PM; // Default density
+ bool mBypass = false; // Default bypass
};
class EnvReverbSw final : public EffectImpl {
@@ -60,7 +173,7 @@
private:
std::shared_ptr<EnvReverbSwContext> mContext;
- /* parameters */
- EnvironmentalReverb mSpecificParam;
+ ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/include/core-impl/Module.h b/audio/aidl/default/include/core-impl/Module.h
index aa05d2a..faca61e 100644
--- a/audio/aidl/default/include/core-impl/Module.h
+++ b/audio/aidl/default/include/core-impl/Module.h
@@ -66,6 +66,8 @@
in_args,
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn* _aidl_return)
override;
+ ndk::ScopedAStatus getSupportedPlaybackRateFactors(
+ SupportedPlaybackRateFactors* _aidl_return) override;
ndk::ScopedAStatus setAudioPatch(const AudioPatch& in_requested,
AudioPatch* _aidl_return) override;
ndk::ScopedAStatus setAudioPortConfig(
@@ -86,7 +88,7 @@
ndk::ScopedAStatus updateScreenRotation(
::aidl::android::hardware::audio::core::IModule::ScreenRotation in_rotation) override;
ndk::ScopedAStatus updateScreenState(bool in_isTurnedOn) override;
- ndk::ScopedAStatus getSoundDose(std::shared_ptr<ISoundDose>* _aidl_return) override;
+ ndk::ScopedAStatus getSoundDose(std::shared_ptr<sounddose::ISoundDose>* _aidl_return) override;
ndk::ScopedAStatus generateHwAvSyncId(int32_t* _aidl_return) override;
ndk::ScopedAStatus getVendorParameters(const std::vector<std::string>& in_ids,
std::vector<VendorParameter>* _aidl_return) override;
@@ -138,7 +140,7 @@
bool mMasterMute = false;
float mMasterVolume = 1.0f;
bool mMicMute = false;
- std::shared_ptr<ISoundDose> mSoundDose;
+ std::shared_ptr<sounddose::ISoundDose> mSoundDose;
ndk::SpAIBinder mSoundDoseBinder;
};
diff --git a/audio/aidl/default/include/core-impl/SoundDose.h b/audio/aidl/default/include/core-impl/SoundDose.h
index 54a6cbf..306aa04 100644
--- a/audio/aidl/default/include/core-impl/SoundDose.h
+++ b/audio/aidl/default/include/core-impl/SoundDose.h
@@ -18,12 +18,12 @@
#include <mutex>
-#include <aidl/android/hardware/audio/core/BnSoundDose.h>
+#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
#include <aidl/android/media/audio/common/AudioDevice.h>
using aidl::android::media::audio::common::AudioDevice;
-namespace aidl::android::hardware::audio::core {
+namespace aidl::android::hardware::audio::core::sounddose {
class SoundDose : public BnSoundDose {
public:
@@ -39,4 +39,4 @@
float mRs2Value;
};
-} // namespace aidl::android::hardware::audio::core
+} // namespace aidl::android::hardware::audio::core::sounddose
diff --git a/audio/aidl/default/include/core-impl/Stream.h b/audio/aidl/default/include/core-impl/Stream.h
index a5d240f..5abd4de 100644
--- a/audio/aidl/default/include/core-impl/Stream.h
+++ b/audio/aidl/default/include/core-impl/Stream.h
@@ -367,6 +367,23 @@
}
ndk::ScopedAStatus getHwVolume(std::vector<float>* _aidl_return) override;
ndk::ScopedAStatus setHwVolume(const std::vector<float>& in_channelVolumes) override;
+ ndk::ScopedAStatus getAudioDescriptionMixLevel(float* _aidl_return) override;
+ ndk::ScopedAStatus setAudioDescriptionMixLevel(float in_leveldB) override;
+ ndk::ScopedAStatus getDualMonoMode(
+ ::aidl::android::media::audio::common::AudioDualMonoMode* _aidl_return) override;
+ ndk::ScopedAStatus setDualMonoMode(
+ ::aidl::android::media::audio::common::AudioDualMonoMode in_mode) override;
+ ndk::ScopedAStatus getRecommendedLatencyModes(
+ std::vector<::aidl::android::media::audio::common::AudioLatencyMode>* _aidl_return)
+ override;
+ ndk::ScopedAStatus setLatencyMode(
+ ::aidl::android::media::audio::common::AudioLatencyMode in_mode) override;
+ ndk::ScopedAStatus getPlaybackRateParameters(
+ ::aidl::android::media::audio::common::AudioPlaybackRate* _aidl_return) override;
+ ndk::ScopedAStatus setPlaybackRateParameters(
+ const ::aidl::android::media::audio::common::AudioPlaybackRate& in_playbackRate)
+ override;
+ ndk::ScopedAStatus selectPresentation(int32_t in_presentationId, int32_t in_programId) override;
public:
static ndk::ScopedAStatus createInstance(
diff --git a/audio/aidl/default/include/effect-impl/EffectUUID.h b/audio/aidl/default/include/effect-impl/EffectUUID.h
index 951007d..6eec29e 100644
--- a/audio/aidl/default/include/effect-impl/EffectUUID.h
+++ b/audio/aidl/default/include/effect-impl/EffectUUID.h
@@ -147,6 +147,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 97c4acd1-8b82-4f2f-832e-c2fe5d7a9931
+static const AudioUuid kHapticGeneratorImplUUID = {static_cast<int32_t>(0x97c4acd1),
+ 0x8b82,
+ 0x4f2f,
+ 0x832e,
+ {0xc2, 0xfe, 0x5d, 0x7a, 0x99, 0x31}};
// fe3199be-aed0-413f-87bb-11260eb63cf1
static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
0xaed0,
@@ -237,6 +243,13 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// d069d9e0-8329-11df-9168-0002a5d5c51b
+// {0xd069d9e0, 0x8329, 0x11df, 0x9168, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+static const AudioUuid kVisualizerImplUUID = {static_cast<int32_t>(0xd069d9e0),
+ 0x8329,
+ 0x11df,
+ 0x9168,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// fa81a2b8-588b-11ed-9b6a-0242ac120002
static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
0x588b,
@@ -249,6 +262,12 @@
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 119341a0-8469-11df-81f9-0002a5d5c51b
+static const AudioUuid kVolumeBundleImplUUID = {static_cast<int32_t>(0x119341a0),
+ 0x8469,
+ 0x11df,
+ 0x81f9,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
/**
* @brief A map between effect name and effect type UUID.
diff --git a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
index 0c03038..f39d8e5 100644
--- a/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
+++ b/audio/aidl/default/noiseSuppression/NoiseSuppressionSw.h
@@ -37,7 +37,7 @@
NoiseSuppression::Level getLevel();
private:
- NoiseSuppression::Level mLevel;
+ NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
};
class NoiseSuppressionSw final : public EffectImpl {
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.cpp b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
index 1b9d614..d038596 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.cpp
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.cpp
@@ -21,6 +21,7 @@
#include <unordered_set>
#include <android-base/logging.h>
+#include <android/binder_enums.h>
#include <fmq/AidlMessageQueue.h>
#include "PresetReverbSw.h"
@@ -60,7 +61,13 @@
namespace aidl::android::hardware::audio::effect {
const std::string PresetReverbSw::kEffectName = "PresetReverbSw";
-const PresetReverb::Capability PresetReverbSw::kCapability;
+
+const std::vector<PresetReverb::Presets> kSupportedPresets{
+ ndk::enum_range<PresetReverb::Presets>().begin(),
+ ndk::enum_range<PresetReverb::Presets>().end()};
+
+const PresetReverb::Capability PresetReverbSw::kCapability = {.supportedPresets =
+ kSupportedPresets};
const Descriptor PresetReverbSw::kDescriptor = {
.common = {.id = {.type = kPresetReverbTypeUUID,
.uuid = kPresetReverbSwImplUUID,
@@ -82,16 +89,59 @@
RETURN_IF(Parameter::Specific::presetReverb != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::presetReverb>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& prParam = specific.get<Parameter::Specific::presetReverb>();
+ auto tag = prParam.getTag();
+
+ switch (tag) {
+ case PresetReverb::preset: {
+ RETURN_IF(
+ mContext->setPRPreset(prParam.get<PresetReverb::preset>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPresetFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus PresetReverbSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::presetReverbTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::presetReverb>(mSpecificParam);
+ auto prId = id.get<Parameter::Id::presetReverbTag>();
+ auto prIdTag = prId.getTag();
+ switch (prIdTag) {
+ case PresetReverb::Id::commonTag:
+ return getParameterPresetReverb(prId.get<PresetReverb::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus PresetReverbSw::getParameterPresetReverb(const PresetReverb::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ PresetReverb prParam;
+ switch (tag) {
+ case PresetReverb::preset: {
+ prParam.set<PresetReverb::preset>(mContext->getPRPreset());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::presetReverb>(prParam);
return ndk::ScopedAStatus::ok();
}
diff --git a/audio/aidl/default/presetReverb/PresetReverbSw.h b/audio/aidl/default/presetReverb/PresetReverbSw.h
index 43ed36e..eb1d80a 100644
--- a/audio/aidl/default/presetReverb/PresetReverbSw.h
+++ b/audio/aidl/default/presetReverb/PresetReverbSw.h
@@ -32,7 +32,15 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+ RetCode setPRPreset(PresetReverb::Presets preset) {
+ // TODO : Add implementation to modify Presets
+ mPreset = preset;
+ return RetCode::SUCCESS;
+ }
+ PresetReverb::Presets getPRPreset() const { return mPreset; }
+
+ private:
+ PresetReverb::Presets mPreset = PresetReverb::Presets::NONE;
};
class PresetReverbSw final : public EffectImpl {
@@ -60,7 +68,8 @@
private:
std::shared_ptr<PresetReverbSwContext> mContext;
- /* parameters */
- PresetReverb mSpecificParam;
+
+ ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Tag& tag,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.cpp b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
index f4aa67c..cc51937 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.cpp
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.cpp
@@ -61,8 +61,8 @@
const std::string VirtualizerSw::kEffectName = "VirtualizerSw";
const bool VirtualizerSw::kStrengthSupported = true;
-const Virtualizer::Capability VirtualizerSw::kCapability = {.strengthSupported =
- kStrengthSupported};
+const Virtualizer::Capability VirtualizerSw::kCapability = {
+ .maxStrengthPm = 1000, .strengthSupported = kStrengthSupported};
const Descriptor VirtualizerSw::kDescriptor = {
.common = {.id = {.type = kVirtualizerTypeUUID,
.uuid = kVirtualizerSwImplUUID,
@@ -172,4 +172,14 @@
return {STATUS_OK, samples, samples};
}
+RetCode VirtualizerSwContext::setVrStrength(int strength) {
+ if (strength < 0 || strength > VirtualizerSw::kCapability.maxStrengthPm) {
+ LOG(ERROR) << __func__ << " invalid strength: " << strength;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new strength
+ mStrength = strength;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/virtualizer/VirtualizerSw.h b/audio/aidl/default/virtualizer/VirtualizerSw.h
index 05974a8..0f294cd 100644
--- a/audio/aidl/default/virtualizer/VirtualizerSw.h
+++ b/audio/aidl/default/virtualizer/VirtualizerSw.h
@@ -32,20 +32,11 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- RetCode setVrStrength(int strength) {
- if (strength < Virtualizer::MIN_PER_MILLE_STRENGTH ||
- strength > Virtualizer::MAX_PER_MILLE_STRENGTH) {
- LOG(ERROR) << __func__ << " invalid strength " << strength;
- return RetCode::ERROR_ILLEGAL_PARAMETER;
- }
- // TODO : Add implementation to apply new strength
- mStrength = strength;
- return RetCode::SUCCESS;
- }
+ RetCode setVrStrength(int strength);
int getVrStrength() const { return mStrength; }
private:
- int mStrength;
+ int mStrength = 0;
};
class VirtualizerSw final : public EffectImpl {
diff --git a/audio/aidl/default/visualizer/VisualizerSw.cpp b/audio/aidl/default/visualizer/VisualizerSw.cpp
index 37eb30b..735180e 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.cpp
+++ b/audio/aidl/default/visualizer/VisualizerSw.cpp
@@ -56,9 +56,12 @@
const std::string VisualizerSw::kEffectName = "VisualizerSw";
/* capabilities */
-const Visualizer::CaptureSizeRange mCaptureSizeRange = {MIN_CAPTURE_SIZE, MAX_CAPTURE_SIZE};
-const Visualizer::Capability VisualizerSw::kCapability = {.maxLatencyMs = MAX_LATENCY,
- .captureSizeRange = mCaptureSizeRange};
+const Visualizer::CaptureSamplesRange VisualizerSwContext::kCaptureSamplesRange = {
+ VisualizerSwContext::kMinCaptureSize, VisualizerSwContext::kMaxCaptureSize};
+const Visualizer::Capability VisualizerSw::kCapability = {
+ .maxLatencyMs = VisualizerSwContext::kMaxLatencyMs,
+ .captureSampleRange = VisualizerSwContext::kCaptureSamplesRange};
+
const Descriptor VisualizerSw::kDescriptor = {
.common = {.id = {.type = kVisualizerTypeUUID,
.uuid = kVisualizerSwImplUUID,
@@ -84,8 +87,8 @@
auto tag = vsParam.getTag();
switch (tag) {
- case Visualizer::captureSizeBytes: {
- RETURN_IF(mContext->setVsCaptureSize(vsParam.get<Visualizer::captureSizeBytes>()) !=
+ case Visualizer::captureSamples: {
+ RETURN_IF(mContext->setVsCaptureSize(vsParam.get<Visualizer::captureSamples>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "captureSizeNotSupported");
return ndk::ScopedAStatus::ok();
@@ -159,8 +162,8 @@
Visualizer vsParam;
switch (tag) {
- case Visualizer::captureSizeBytes: {
- vsParam.set<Visualizer::captureSizeBytes>(mContext->getVsCaptureSize());
+ case Visualizer::captureSamples: {
+ vsParam.set<Visualizer::captureSamples>(mContext->getVsCaptureSize());
break;
}
case Visualizer::scalingMode: {
@@ -190,9 +193,9 @@
mContext->getVsMeasurement());
break;
}
- case Visualizer::GetOnlyParameters::captureBytes: {
- getOnlyParam.set<Visualizer::GetOnlyParameters::captureBytes>(
- mContext->getVsCaptureBytes());
+ case Visualizer::GetOnlyParameters::captureSampleBuffer: {
+ getOnlyParam.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(
+ mContext->getVsCaptureSampleBuffer());
break;
}
default: {
diff --git a/audio/aidl/default/visualizer/VisualizerSw.h b/audio/aidl/default/visualizer/VisualizerSw.h
index a95537c..3c9e6d2 100644
--- a/audio/aidl/default/visualizer/VisualizerSw.h
+++ b/audio/aidl/default/visualizer/VisualizerSw.h
@@ -22,24 +22,24 @@
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
-#define MIN_CAPTURE_SIZE 128
-#define MAX_CAPTURE_SIZE 1024
-#define MAX_LATENCY 3000
-#define CAPTURE_BUF_SIZE 65536
-
namespace aidl::android::hardware::audio::effect {
class VisualizerSwContext final : public EffectContext {
public:
+ static const int kMinCaptureSize = 0x80;
+ static const int kMaxCaptureSize = 0x400;
+ static const int kMaxLatencyMs = 3000;
+ static const int kMaxCaptureBufSize = 0xffff;
+ static const Visualizer::CaptureSamplesRange kCaptureSamplesRange;
VisualizerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
- mCaptureBytes.resize(CAPTURE_BUF_SIZE);
- fill(mCaptureBytes.begin(), mCaptureBytes.end(), 0x80);
+ mCaptureSampleBuffer.resize(kMaxCaptureBufSize);
+ fill(mCaptureSampleBuffer.begin(), mCaptureSampleBuffer.end(), 0x80);
}
RetCode setVsCaptureSize(int captureSize) {
- if (captureSize < MIN_CAPTURE_SIZE || captureSize > MAX_CAPTURE_SIZE) {
+ if (captureSize < kMinCaptureSize || captureSize > kMaxCaptureSize) {
LOG(ERROR) << __func__ << " invalid captureSize " << captureSize;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
@@ -64,7 +64,7 @@
Visualizer::MeasurementMode getVsMeasurementMode() const { return mMeasurementMode; }
RetCode setVsLatency(int latency) {
- if (latency < 0 || latency > MAX_LATENCY) {
+ if (latency < 0 || latency > kMaxLatencyMs) {
LOG(ERROR) << __func__ << " invalid latency " << latency;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
@@ -74,15 +74,15 @@
}
Visualizer::GetOnlyParameters::Measurement getVsMeasurement() const { return mMeasurement; }
- std::vector<uint8_t> getVsCaptureBytes() const { return mCaptureBytes; }
+ std::vector<uint8_t> getVsCaptureSampleBuffer() const { return mCaptureSampleBuffer; }
private:
- int mCaptureSize = MAX_CAPTURE_SIZE;
+ int mCaptureSize = kMaxCaptureSize;
Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
- int mLatency;
+ int mLatency = 0;
const Visualizer::GetOnlyParameters::Measurement mMeasurement = {0, 0};
- std::vector<uint8_t> mCaptureBytes;
+ std::vector<uint8_t> mCaptureSampleBuffer;
};
class VisualizerSw final : public EffectImpl {
diff --git a/audio/aidl/default/volume/VolumeSw.cpp b/audio/aidl/default/volume/VolumeSw.cpp
index 6fce16e..64301dc 100644
--- a/audio/aidl/default/volume/VolumeSw.cpp
+++ b/audio/aidl/default/volume/VolumeSw.cpp
@@ -60,7 +60,7 @@
namespace aidl::android::hardware::audio::effect {
const std::string VolumeSw::kEffectName = "VolumeSw";
-const Volume::Capability VolumeSw::kCapability;
+const Volume::Capability VolumeSw::kCapability = {.minLevelDb = -9600, .maxLevelDb = 0};
const Descriptor VolumeSw::kDescriptor = {
.common = {.id = {.type = kVolumeTypeUUID,
.uuid = kVolumeSwImplUUID,
@@ -82,16 +82,66 @@
RETURN_IF(Parameter::Specific::volume != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
- mSpecificParam = specific.get<Parameter::Specific::volume>();
- LOG(DEBUG) << __func__ << " success with: " << specific.toString();
- return ndk::ScopedAStatus::ok();
+ auto& volParam = specific.get<Parameter::Specific::volume>();
+ auto tag = volParam.getTag();
+
+ switch (tag) {
+ case Volume::levelDb: {
+ RETURN_IF(mContext->setVolLevel(volParam.get<Volume::levelDb>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "LevelNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Volume::mute: {
+ RETURN_IF(mContext->setVolMute(volParam.get<Volume::mute>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "MuteNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VolumeTagNotSupported");
+ }
+ }
}
ndk::ScopedAStatus VolumeSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::volumeTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
- specific->set<Parameter::Specific::volume>(mSpecificParam);
+ auto volId = id.get<Parameter::Id::volumeTag>();
+ auto volIdTag = volId.getTag();
+ switch (volIdTag) {
+ case Volume::Id::commonTag:
+ return getParameterVolume(volId.get<Volume::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VolumeTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus VolumeSw::getParameterVolume(const Volume::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ Volume volParam;
+ switch (tag) {
+ case Volume::levelDb: {
+ volParam.set<Volume::levelDb>(mContext->getVolLevel());
+ break;
+ }
+ case Volume::mute: {
+ volParam.set<Volume::mute>(mContext->getVolMute());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VolumeTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::volume>(volParam);
return ndk::ScopedAStatus::ok();
}
@@ -126,4 +176,20 @@
return {STATUS_OK, samples, samples};
}
+RetCode VolumeSwContext::setVolLevel(int level) {
+ if (level < VolumeSw::kCapability.minLevelDb || level > VolumeSw::kCapability.maxLevelDb) {
+ LOG(ERROR) << __func__ << " invalid level " << level;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ // TODO : Add implementation to apply new level
+ mLevel = level;
+ return RetCode::SUCCESS;
+}
+
+RetCode VolumeSwContext::setVolMute(bool mute) {
+ // TODO : Add implementation to modify mute
+ mMute = mute;
+ return RetCode::SUCCESS;
+}
+
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/default/volume/VolumeSw.h b/audio/aidl/default/volume/VolumeSw.h
index 3bd29b9..b6f6077 100644
--- a/audio/aidl/default/volume/VolumeSw.h
+++ b/audio/aidl/default/volume/VolumeSw.h
@@ -32,7 +32,18 @@
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
- // TODO: add specific context here
+
+ RetCode setVolLevel(int level);
+
+ int getVolLevel() const { return mLevel; }
+
+ RetCode setVolMute(bool mute);
+
+ bool getVolMute() const { return mMute; }
+
+ private:
+ int mLevel = 0;
+ bool mMute = false;
};
class VolumeSw final : public EffectImpl {
@@ -60,7 +71,7 @@
private:
std::shared_ptr<VolumeSwContext> mContext;
- /* parameters */
- Volume mSpecificParam;
+
+ ndk::ScopedAStatus getParameterVolume(const Volume::Tag& tag, Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
index 7dda011..148720c 100644
--- a/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
+++ b/audio/aidl/sounddose/aidl_api/android.hardware.audio.sounddose/current/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -34,5 +34,5 @@
package android.hardware.audio.sounddose;
@VintfStability
interface ISoundDoseFactory {
- @nullable android.hardware.audio.core.ISoundDose getSoundDose(in @utf8InCpp String module);
+ @nullable android.hardware.audio.core.sounddose.ISoundDose getSoundDose(in @utf8InCpp String module);
}
diff --git a/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
index 3487237..4079fe8 100644
--- a/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
+++ b/audio/aidl/sounddose/android/hardware/audio/sounddose/ISoundDoseFactory.aidl
@@ -16,7 +16,7 @@
package android.hardware.audio.sounddose;
-import android.hardware.audio.core.ISoundDose;
+import android.hardware.audio.core.sounddose.ISoundDose;
/**
* This interface is used to provide an easy way to implement the ISoundDose interface
diff --git a/audio/aidl/sounddose/default/SoundDoseFactory.cpp b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
index 50796d0..83a592b 100644
--- a/audio/aidl/sounddose/default/SoundDoseFactory.cpp
+++ b/audio/aidl/sounddose/default/SoundDoseFactory.cpp
@@ -23,7 +23,7 @@
namespace aidl::android::hardware::audio::sounddose {
-using ::aidl::android::hardware::audio::core::SoundDose;
+using ::aidl::android::hardware::audio::core::sounddose::SoundDose;
ndk::ScopedAStatus SoundDoseFactory::getSoundDose(const std::string& in_module,
std::shared_ptr<ISoundDose>* _aidl_return) {
diff --git a/audio/aidl/sounddose/default/include/SoundDoseFactory.h b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
index 4cf3277..ced4291 100644
--- a/audio/aidl/sounddose/default/include/SoundDoseFactory.h
+++ b/audio/aidl/sounddose/default/include/SoundDoseFactory.h
@@ -16,7 +16,7 @@
#pragma once
-#include <aidl/android/hardware/audio/core/ISoundDose.h>
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
#include <aidl/android/hardware/audio/sounddose/BnSoundDoseFactory.h>
#include <android/binder_interface_utils.h>
@@ -24,7 +24,7 @@
namespace aidl::android::hardware::audio::sounddose {
-using ::aidl::android::hardware::audio::core::ISoundDose;
+using ::aidl::android::hardware::audio::core::sounddose::ISoundDose;
class SoundDoseFactory : public BnSoundDoseFactory {
public:
diff --git a/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
index 7448c1f..df35bae 100644
--- a/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
+++ b/audio/aidl/sounddose/vts/VtsHalSoundDoseFactoryTargetTest.cpp
@@ -47,7 +47,7 @@
using namespace android;
-using aidl::android::hardware::audio::core::ISoundDose;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
class SoundDoseFactory : public testing::TestWithParam<std::string> {
diff --git a/audio/aidl/vts/Android.bp b/audio/aidl/vts/Android.bp
index 8a5a25c..becdf1b 100644
--- a/audio/aidl/vts/Android.bp
+++ b/audio/aidl/vts/Android.bp
@@ -44,6 +44,7 @@
defaults: [
"VtsHalAudioTargetTestDefaults",
"latest_android_hardware_audio_core_ndk_static",
+ "latest_android_hardware_audio_core_sounddose_ndk_static",
],
shared_libs: [
"libcutils",
@@ -80,6 +81,12 @@
}
cc_test {
+ name: "VtsHalEnvironmentalReverbTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalEnvironmentalReverbTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalEqualizerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalEqualizerTargetTest.cpp"],
@@ -98,6 +105,12 @@
}
cc_test {
+ name: "VtsHalPresetReverbTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalPresetReverbTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalVirtualizerTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalVirtualizerTargetTest.cpp"],
@@ -110,6 +123,12 @@
}
cc_test {
+ name: "VtsHalVolumeTargetTest",
+ defaults: ["VtsHalAudioTargetTestDefaults"],
+ srcs: ["VtsHalVolumeTargetTest.cpp"],
+}
+
+cc_test {
name: "VtsHalAECTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalAECTargetTest.cpp"],
diff --git a/audio/aidl/vts/VtsHalAECTargetTest.cpp b/audio/aidl/vts/VtsHalAECTargetTest.cpp
index a06ab42..c3427c8 100644
--- a/audio/aidl/vts/VtsHalAECTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAECTargetTest.cpp
@@ -14,12 +14,14 @@
* limitations under the License.
*/
+#include <Utils.h>
#include <aidl/Vintf.h>
#include <algorithm>
+#include <string>
+#include <unordered_set>
#define LOG_TAG "VtsHalAECParamTest"
-#include <Utils.h>
#include "EffectHelper.h"
using namespace android;
@@ -69,10 +71,6 @@
return specific;
}
- static const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList;
- static const std::vector<int> kEchoDelayValues;
- static const std::vector<bool> kMobileModeValues;
-
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
@@ -155,9 +153,11 @@
}
}
- static std::vector<int> getEchoDelayTestValues() {
+ static std::unordered_set<int> getEchoDelayTestValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kAcousticEchoCancelerTypeUUID);
const auto max = std::max_element(
- kFactoryDescList.begin(), kFactoryDescList.end(),
+ 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::acousticEchoCanceler>()
@@ -165,25 +165,20 @@
b.second.capability.get<Capability::acousticEchoCanceler>()
.maxEchoDelayUs;
});
- if (max == kFactoryDescList.end()) {
+ if (max == descList.end()) {
return {0};
}
int maxDelay =
max->second.capability.get<Capability::acousticEchoCanceler>().maxEchoDelayUs;
return {-1, 0, maxDelay - 1, maxDelay, maxDelay + 1};
}
+ static std::unordered_set<bool> getMobileModeValues() { return {true, false}; }
private:
std::vector<std::pair<AcousticEchoCanceler::Tag, AcousticEchoCanceler>> mTags;
void CleanUp() { mTags.clear(); }
};
-const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> AECParamTest::kFactoryDescList =
- EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
- kAcousticEchoCancelerTypeUUID);
-const std::vector<int> AECParamTest::kEchoDelayValues = AECParamTest::getEchoDelayTestValues();
-const std::vector<bool> AECParamTest::kMobileModeValues = {true, false};
-
TEST_P(AECParamTest, SetAndGetEchoDelay) {
EXPECT_NO_FATAL_FAILURE(addEchoDelayParam(mEchoDelay));
SetAndGetParameters();
@@ -194,20 +189,24 @@
SetAndGetParameters();
}
-INSTANTIATE_TEST_SUITE_P(AECParamTest, AECParamTest,
- ::testing::Combine(testing::ValuesIn(AECParamTest::kFactoryDescList),
- testing::ValuesIn(AECParamTest::kEchoDelayValues),
- testing::ValuesIn(AECParamTest::kMobileModeValues)),
- [](const testing::TestParamInfo<AECParamTest::ParamType>& info) {
- auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
- std::string name = "Implementor_" + descriptor.common.implementor +
- "_name_" + descriptor.common.name + "_UUID_" +
- descriptor.common.id.uuid.toString();
- std::replace_if(
- name.begin(), name.end(),
- [](const char c) { return !std::isalnum(c); }, '_');
- return name;
- });
+INSTANTIATE_TEST_SUITE_P(
+ AECParamTest, AECParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kAcousticEchoCancelerTypeUUID)),
+ testing::ValuesIn(AECParamTest::getEchoDelayTestValues()),
+ testing::ValuesIn(AECParamTest::getMobileModeValues())),
+ [](const testing::TestParamInfo<AECParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string echoDelay = std::to_string(std::get<PARAM_ECHO_DELAY>(info.param));
+ std::string mobileMode = std::get<PARAM_MOBILE_MODE>(info.param) ? "true" : "false";
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_EchoDelay_" + echoDelay +
+ "_MobileMode_" + mobileMode;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AECParamTest);
diff --git a/audio/aidl/vts/VtsHalAGCTargetTest.cpp b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
index ea3654f..3448ae2 100644
--- a/audio/aidl/vts/VtsHalAGCTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAGCTargetTest.cpp
@@ -14,11 +14,13 @@
* limitations under the License.
*/
+#include <Utils.h>
#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
#define LOG_TAG "VtsHalAGCParamTest"
-#include <Utils.h>
#include "EffectHelper.h"
using namespace android;
@@ -77,11 +79,6 @@
}
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
- static const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList;
- static const std::vector<int> kDigitalGainValues;
- static const std::vector<int> kSaturationMarginValues;
- static const std::vector<AutomaticGainControl::LevelEstimator> kLevelEstimatorValues;
-
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
@@ -158,9 +155,11 @@
return false;
}
}
- static std::vector<int> getDigitalGainValues() {
+ static std::unordered_set<int> getDigitalGainValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kAutomaticGainControlTypeUUID);
const auto max = std::max_element(
- kFactoryDescList.begin(), kFactoryDescList.end(),
+ 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::automaticGainControl>()
@@ -168,16 +167,18 @@
b.second.capability.get<Capability::automaticGainControl>()
.maxFixedDigitalGainMb;
});
- if (max == kFactoryDescList.end()) {
+ if (max == descList.end()) {
return {0};
}
int maxGain = max->second.capability.get<Capability::automaticGainControl>()
.maxFixedDigitalGainMb;
return {-1, 0, maxGain - 1, maxGain, maxGain + 1};
}
- static std::vector<int> getSaturationMarginValues() {
+ static std::unordered_set<int> getSaturationMarginValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kAutomaticGainControlTypeUUID);
const auto max = std::max_element(
- kFactoryDescList.begin(), kFactoryDescList.end(),
+ 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::automaticGainControl>()
@@ -185,28 +186,23 @@
b.second.capability.get<Capability::automaticGainControl>()
.maxSaturationMarginMb;
});
- if (max == kFactoryDescList.end()) {
+ if (max == descList.end()) {
return {0};
}
int maxMargin = max->second.capability.get<Capability::automaticGainControl>()
.maxSaturationMarginMb;
return {-1, 0, maxMargin - 1, maxMargin, maxMargin + 1};
}
+ static std::unordered_set<AutomaticGainControl::LevelEstimator> getLevelEstimatorValues() {
+ return {ndk::enum_range<AutomaticGainControl::LevelEstimator>().begin(),
+ ndk::enum_range<AutomaticGainControl::LevelEstimator>().end()};
+ }
private:
std::vector<std::pair<AutomaticGainControl::Tag, AutomaticGainControl>> mTags;
void CleanUp() { mTags.clear(); }
};
-const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> AGCParamTest::kFactoryDescList =
- EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
- kAutomaticGainControlTypeUUID);
-const std::vector<int> AGCParamTest::kDigitalGainValues = AGCParamTest::getDigitalGainValues();
-const std::vector<int> AGCParamTest::kSaturationMarginValues =
- AGCParamTest::getSaturationMarginValues();
-const std::vector<AutomaticGainControl::LevelEstimator> AGCParamTest::kLevelEstimatorValues = {
- AutomaticGainControl::LevelEstimator::RMS, AutomaticGainControl::LevelEstimator::PEAK};
-
TEST_P(AGCParamTest, SetAndGetDigitalGainParam) {
EXPECT_NO_FATAL_FAILURE(addDigitalGainParam(mGain));
SetAndGetParameters();
@@ -226,9 +222,9 @@
AGCParamTest, AGCParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kAutomaticGainControlTypeUUID)),
- testing::ValuesIn(AGCParamTest::kDigitalGainValues),
- testing::ValuesIn(AGCParamTest::kSaturationMarginValues),
- testing::ValuesIn(AGCParamTest::kLevelEstimatorValues)),
+ testing::ValuesIn(AGCParamTest::getDigitalGainValues()),
+ testing::ValuesIn(AGCParamTest::getSaturationMarginValues()),
+ testing::ValuesIn(AGCParamTest::getLevelEstimatorValues())),
[](const testing::TestParamInfo<AGCParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string gain = std::to_string(std::get<PARAM_DIGITAL_GAIN>(info.param));
diff --git a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
index 2508afd..bd2c79d 100644
--- a/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalAudioCoreModuleTargetTest.cpp
@@ -36,8 +36,8 @@
#include <aidl/Vintf.h>
#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/IModule.h>
-#include <aidl/android/hardware/audio/core/ISoundDose.h>
#include <aidl/android/hardware/audio/core/ITelephony.h>
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
#include <aidl/android/media/audio/common/AudioIoFlags.h>
#include <aidl/android/media/audio/common/AudioOutputFlags.h>
#include <android-base/chrono_utils.h>
@@ -57,7 +57,6 @@
using aidl::android::hardware::audio::core::AudioPatch;
using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IModule;
-using aidl::android::hardware::audio::core::ISoundDose;
using aidl::android::hardware::audio::core::IStreamCommon;
using aidl::android::hardware::audio::core::IStreamIn;
using aidl::android::hardware::audio::core::IStreamOut;
@@ -67,14 +66,18 @@
using aidl::android::hardware::audio::core::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
using aidl::android::hardware::audio::core::VendorParameter;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
using aidl::android::media::audio::common::AudioContentType;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioDualMonoMode;
using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioLatencyMode;
using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPlaybackRate;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortDeviceExt;
@@ -2392,6 +2395,192 @@
<< "when no async callback is provided for a non-blocking mix port";
}
+TEST_P(AudioStreamOut, AudioDescriptionMixLevel) {
+ const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No output mix ports";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+ WithStream<IStreamOut> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(
+ TestAccessors<float>(stream.get(), &IStreamOut::getAudioDescriptionMixLevel,
+ &IStreamOut::setAudioDescriptionMixLevel,
+ {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX,
+ IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX - 1, 0,
+ -INFINITY /*IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MIN*/},
+ {IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 2,
+ IStreamOut::AUDIO_DESCRIPTION_MIX_LEVEL_MAX * 1.1f},
+ &isSupported));
+ if (isSupported) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Audio description mix level is not supported";
+ }
+}
+
+TEST_P(AudioStreamOut, DualMonoMode) {
+ const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No output mix ports";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+ WithStream<IStreamOut> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioDualMonoMode>(
+ stream.get(), &IStreamOut::getDualMonoMode, &IStreamOut::setDualMonoMode,
+ std::vector<AudioDualMonoMode>(enum_range<AudioDualMonoMode>().begin(),
+ enum_range<AudioDualMonoMode>().end()),
+ {}, &isSupported));
+ if (isSupported) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Audio dual mono mode is not supported";
+ }
+}
+
+TEST_P(AudioStreamOut, LatencyMode) {
+ const auto ports = moduleConfig->getOutputMixPorts(false /*attachedOnly*/);
+ if (ports.empty()) {
+ GTEST_SKIP() << "No output mix ports";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : ports) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+ WithStream<IStreamOut> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ bool isSupported = false;
+ std::vector<AudioLatencyMode> supportedModes;
+ ndk::ScopedAStatus status = stream.get()->getRecommendedLatencyModes(&supportedModes);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) continue;
+ if (!status.isOk()) {
+ ADD_FAILURE() << "When latency modes are supported, getRecommendedLatencyModes "
+ << "must succeed on a non-closed stream, but it failed with " << status;
+ continue;
+ }
+ std::set<AudioLatencyMode> unsupportedModes(enum_range<AudioLatencyMode>().begin(),
+ enum_range<AudioLatencyMode>().end());
+ for (const auto mode : supportedModes) {
+ unsupportedModes.erase(mode);
+ ndk::ScopedAStatus status = stream.get()->setLatencyMode(mode);
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ ADD_FAILURE() << "When latency modes are supported, both getRecommendedLatencyModes"
+ << " and setLatencyMode must be supported";
+ }
+ EXPECT_IS_OK(status) << "Setting of supported latency mode must succeed";
+ }
+ for (const auto mode : unsupportedModes) {
+ EXPECT_STATUS(EX_ILLEGAL_ARGUMENT, stream.get()->setLatencyMode(mode));
+ }
+ if (isSupported) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Audio latency modes are not supported";
+ }
+}
+
+TEST_P(AudioStreamOut, PlaybackRate) {
+ static const auto kStatuses = {EX_NONE, EX_UNSUPPORTED_OPERATION};
+ const auto offloadMixPorts =
+ moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+ if (offloadMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for compressed offload that could be routed to attached devices";
+ }
+ ndk::ScopedAStatus status;
+ IModule::SupportedPlaybackRateFactors factors;
+ EXPECT_STATUS(kStatuses, status = module.get()->getSupportedPlaybackRateFactors(&factors));
+ if (status.getExceptionCode() == EX_UNSUPPORTED_OPERATION) {
+ GTEST_SKIP() << "Audio playback rate configuration is not supported";
+ }
+ EXPECT_LE(factors.minSpeed, factors.maxSpeed);
+ EXPECT_LE(factors.minPitch, factors.maxPitch);
+ EXPECT_LE(factors.minSpeed, 1.0f);
+ EXPECT_GE(factors.maxSpeed, 1.0f);
+ EXPECT_LE(factors.minPitch, 1.0f);
+ EXPECT_GE(factors.maxPitch, 1.0f);
+ constexpr auto tsDefault = AudioPlaybackRate::TimestretchMode::DEFAULT;
+ constexpr auto tsVoice = AudioPlaybackRate::TimestretchMode::VOICE;
+ constexpr auto fbFail = AudioPlaybackRate::TimestretchFallbackMode::FAIL;
+ constexpr auto fbMute = AudioPlaybackRate::TimestretchFallbackMode::MUTE;
+ const std::vector<AudioPlaybackRate> validValues = {
+ AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbFail},
+ AudioPlaybackRate{1.0f, 1.0f, tsDefault, fbMute},
+ AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsDefault, fbMute},
+ AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsDefault, fbMute},
+ AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbMute},
+ AudioPlaybackRate{1.0f, 1.0f, tsVoice, fbFail},
+ AudioPlaybackRate{factors.maxSpeed, factors.maxPitch, tsVoice, fbMute},
+ AudioPlaybackRate{factors.minSpeed, factors.minPitch, tsVoice, fbMute},
+ // Out of range speed / pitch values must not be rejected if the fallback mode is "mute"
+ AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsDefault, fbMute},
+ AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsDefault, fbMute},
+ AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch * 2, tsVoice, fbMute},
+ AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch / 2, tsVoice, fbMute},
+ };
+ const std::vector<AudioPlaybackRate> invalidValues = {
+ AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsDefault, fbFail},
+ AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsDefault, fbFail},
+ AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsDefault, fbFail},
+ AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsDefault, fbFail},
+ AudioPlaybackRate{factors.maxSpeed, factors.maxPitch * 2, tsVoice, fbFail},
+ AudioPlaybackRate{factors.maxSpeed * 2, factors.maxPitch, tsVoice, fbFail},
+ AudioPlaybackRate{factors.minSpeed, factors.minPitch / 2, tsVoice, fbFail},
+ AudioPlaybackRate{factors.minSpeed / 2, factors.minPitch, tsVoice, fbFail},
+ AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+ AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT},
+ AudioPlaybackRate{1.0f, 1.0f, tsDefault,
+ AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT},
+ };
+ bool atLeastOneSupports = false;
+ for (const auto& port : offloadMixPorts) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+ WithStream<IStreamOut> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ bool isSupported = false;
+ EXPECT_NO_FATAL_FAILURE(TestAccessors<AudioPlaybackRate>(
+ stream.get(), &IStreamOut::getPlaybackRateParameters,
+ &IStreamOut::setPlaybackRateParameters, validValues, invalidValues, &isSupported));
+ if (isSupported) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Audio playback rate configuration is not supported";
+ }
+}
+
+TEST_P(AudioStreamOut, SelectPresentation) {
+ static const auto kStatuses = {EX_ILLEGAL_ARGUMENT, EX_UNSUPPORTED_OPERATION};
+ const auto offloadMixPorts =
+ moduleConfig->getOffloadMixPorts(true /*attachedOnly*/, false /*singlePort*/);
+ if (offloadMixPorts.empty()) {
+ GTEST_SKIP()
+ << "No mix port for compressed offload that could be routed to attached devices";
+ }
+ bool atLeastOneSupports = false;
+ for (const auto& port : offloadMixPorts) {
+ const auto portConfig = moduleConfig->getSingleConfigForMixPort(false, port);
+ ASSERT_TRUE(portConfig.has_value()) << "No profiles specified for output mix port";
+ WithStream<IStreamOut> stream(portConfig.value());
+ ASSERT_NO_FATAL_FAILURE(stream.SetUp(module.get(), kDefaultBufferSizeFrames));
+ ndk::ScopedAStatus status;
+ EXPECT_STATUS(kStatuses, status = stream.get()->selectPresentation(0, 0));
+ if (status.getExceptionCode() != EX_UNSUPPORTED_OPERATION) atLeastOneSupports = true;
+ }
+ if (!atLeastOneSupports) {
+ GTEST_SKIP() << "Presentation selection is not supported";
+ }
+}
+
class StreamLogicDefaultDriver : public StreamLogicDriver {
public:
explicit StreamLogicDefaultDriver(std::shared_ptr<StateSequence> commands)
diff --git a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
index 724a9c3..d49a865 100644
--- a/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalBassBoostTargetTest.cpp
@@ -46,15 +46,6 @@
* otherwise expect EX_ILLEGAL_ARGUMENT.
*/
-const std::vector<int> kStrengthValues = {
- std::numeric_limits<int>::min(),
- BassBoost::MIN_PER_MILLE_STRENGTH - 1,
- BassBoost::MIN_PER_MILLE_STRENGTH,
- (BassBoost::MIN_PER_MILLE_STRENGTH + BassBoost::MAX_PER_MILLE_STRENGTH) >> 1,
- BassBoost::MAX_PER_MILLE_STRENGTH,
- BassBoost::MAX_PER_MILLE_STRENGTH + 2,
- std::numeric_limits<int>::max()};
-
class BassBoostParamTest : public ::testing::TestWithParam<BassBoostParamTestParam>,
public EffectHelper {
public:
@@ -81,7 +72,7 @@
}
Parameter::Specific getDefaultParamSpecific() {
- BassBoost bb = BassBoost::make<BassBoost::strengthPm>(BassBoost::MIN_PER_MILLE_STRENGTH);
+ BassBoost bb = BassBoost::make<BassBoost::strengthPm>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::bassBoost>(bb);
return specific;
@@ -91,7 +82,7 @@
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
- int mParamStrength = BassBoost::MIN_PER_MILLE_STRENGTH;
+ int mParamStrength = 0;
void SetAndGetBassBoostParameters() {
for (auto& it : mTags) {
@@ -146,8 +137,29 @@
}
bool isStrengthInRange(const BassBoost::Capability& cap, int strength) const {
- return cap.strengthSupported && strength >= BassBoost::MIN_PER_MILLE_STRENGTH &&
- strength <= BassBoost::MAX_PER_MILLE_STRENGTH;
+ return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+ }
+
+ static std::vector<int> getStrengthTestValues(
+ std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+ const auto max = std::max_element(
+ kFactoryDescList.begin(), kFactoryDescList.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::bassBoost>().maxStrengthPm <
+ b.second.capability.get<Capability::bassBoost>().maxStrengthPm;
+ });
+ if (max == kFactoryDescList.end()) {
+ return {0};
+ }
+ int maxStrength = max->second.capability.get<Capability::bassBoost>().maxStrengthPm;
+ return {std::numeric_limits<int>::min(),
+ -1,
+ 0,
+ maxStrength >> 1,
+ maxStrength,
+ maxStrength + 1,
+ std::numeric_limits<int>::max()};
}
private:
@@ -162,9 +174,12 @@
INSTANTIATE_TEST_SUITE_P(
BassBoostTest, BassBoostParamTest,
- ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
- IFactory::descriptor, kBassBoostTypeUUID)),
- testing::ValuesIn(kStrengthValues)),
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kBassBoostTypeUUID)),
+ testing::ValuesIn(BassBoostParamTest::getStrengthTestValues(
+ EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kBassBoostTypeUUID)))),
[](const testing::TestParamInfo<BassBoostParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
diff --git a/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
new file mode 100644
index 0000000..e99c4a4
--- /dev/null
+++ b/audio/aidl/vts/VtsHalEnvironmentalReverbTargetTest.cpp
@@ -0,0 +1,629 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalEnvironmentalReverbTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.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::EnvironmentalReverb;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEnvReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ * Testing parameter range, assuming the parameter supported by effect is in this range.
+ * This range is verified with IEffect.getDescriptor() and range defined in the documentation, for
+ * 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:
+ EnvironmentalReverbHelper(std::pair<std::shared_ptr<IFactory>, Descriptor> pair) {
+ std::tie(mFactory, mDescriptor) = pair;
+ }
+
+ void SetUpReverb() {
+ 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 */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+
+ void TearDownReverb() {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ EnvironmentalReverb er = EnvironmentalReverb::make<EnvironmentalReverb::roomLevelMb>(
+ EnvironmentalReverb::MIN_ROOM_LEVEL_MB);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::environmentalReverb>(er);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ 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 mDecayTime = 1000;
+ int mDecayHfRatio = 500;
+ int mLevel = EnvironmentalReverb::MIN_LEVEL_MB;
+ int mDelay = 40;
+ int mDiffusion = EnvironmentalReverb::MAX_DIFFUSION_PM;
+ int mDensity = EnvironmentalReverb::MAX_DENSITY_PM;
+ bool mBypass = false;
+
+ void SetAndGetReverbParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& er = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isTagInRange(it.first, it.second, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::environmentalReverb>(er);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_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;
+ EnvironmentalReverb::Id erId;
+ erId.set<EnvironmentalReverb::Id::commonTag>(tag);
+ id.set<Parameter::Id::environmentalReverbTag>(erId);
+ // if set success, then get should match
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+ }
+
+ void addRoomLevelParam() {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::roomLevelMb>(mRoomLevel);
+ mTags.push_back({EnvironmentalReverb::roomLevelMb, er});
+ }
+
+ void addRoomHfLevelParam(int roomHfLevel) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::roomHfLevelMb>(roomHfLevel);
+ mTags.push_back({EnvironmentalReverb::roomHfLevelMb, er});
+ }
+
+ void addDecayTimeParam(int decayTime) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::decayTimeMs>(decayTime);
+ mTags.push_back({EnvironmentalReverb::decayTimeMs, er});
+ }
+
+ void addDecayHfRatioParam(int decayHfRatio) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::decayHfRatioPm>(decayHfRatio);
+ mTags.push_back({EnvironmentalReverb::decayHfRatioPm, er});
+ }
+
+ void addLevelParam(int level) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::levelMb>(level);
+ mTags.push_back({EnvironmentalReverb::levelMb, er});
+ }
+
+ void addDelayParam(int delay) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::delayMs>(delay);
+ mTags.push_back({EnvironmentalReverb::delayMs, er});
+ }
+
+ void addDiffusionParam(int diffusion) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::diffusionPm>(diffusion);
+ mTags.push_back({EnvironmentalReverb::diffusionPm, er});
+ }
+
+ void addDensityParam(int density) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::densityPm>(density);
+ mTags.push_back({EnvironmentalReverb::densityPm, er});
+ }
+
+ void addBypassParam(bool bypass) {
+ EnvironmentalReverb er;
+ er.set<EnvironmentalReverb::bypass>(bypass);
+ mTags.push_back({EnvironmentalReverb::bypass, er});
+ }
+
+ bool isTagInRange(const EnvironmentalReverb::Tag& tag, const EnvironmentalReverb er,
+ const Descriptor& desc) const {
+ const EnvironmentalReverb::Capability& erCap =
+ desc.capability.get<Capability::environmentalReverb>();
+ switch (tag) {
+ case EnvironmentalReverb::roomLevelMb: {
+ int roomLevel = er.get<EnvironmentalReverb::roomLevelMb>();
+ return isRoomLevelInRange(roomLevel);
+ }
+ case EnvironmentalReverb::roomHfLevelMb: {
+ int roomHfLevel = er.get<EnvironmentalReverb::roomHfLevelMb>();
+ return isRoomHfLevelInRange(roomHfLevel);
+ }
+ case EnvironmentalReverb::decayTimeMs: {
+ int decayTime = er.get<EnvironmentalReverb::decayTimeMs>();
+ return isDecayTimeInRange(erCap, decayTime);
+ }
+ case EnvironmentalReverb::decayHfRatioPm: {
+ int decayHfRatio = er.get<EnvironmentalReverb::decayHfRatioPm>();
+ return isDecayHfRatioInRange(decayHfRatio);
+ }
+ case EnvironmentalReverb::levelMb: {
+ int level = er.get<EnvironmentalReverb::levelMb>();
+ return isLevelInRange(level);
+ }
+ case EnvironmentalReverb::delayMs: {
+ int delay = er.get<EnvironmentalReverb::delayMs>();
+ return isDelayInRange(delay);
+ }
+ case EnvironmentalReverb::diffusionPm: {
+ int diffusion = er.get<EnvironmentalReverb::diffusionPm>();
+ return isDiffusionInRange(diffusion);
+ }
+ case EnvironmentalReverb::densityPm: {
+ int density = er.get<EnvironmentalReverb::densityPm>();
+ return isDensityInRange(density);
+ }
+ case EnvironmentalReverb::bypass: {
+ return true;
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool isRoomLevelInRange(int roomLevel) const {
+ return roomLevel >= EnvironmentalReverb::MIN_ROOM_LEVEL_MB &&
+ roomLevel <= EnvironmentalReverb::MAX_ROOM_LEVEL_MB;
+ }
+
+ bool isRoomHfLevelInRange(int roomHfLevel) const {
+ return roomHfLevel >= EnvironmentalReverb::MIN_ROOM_HF_LEVEL_MB &&
+ roomHfLevel <= EnvironmentalReverb::MAX_ROOM_HF_LEVEL_MB;
+ }
+
+ 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;
+ }
+
+ bool isDecayHfRatioInRange(int decayHfRatio) const {
+ return decayHfRatio >= EnvironmentalReverb::MIN_DECAY_HF_RATIO_PM &&
+ decayHfRatio <= EnvironmentalReverb::MAX_DECAY_HF_RATIO_PM;
+ }
+
+ bool isLevelInRange(int level) const {
+ return level >= EnvironmentalReverb::MIN_LEVEL_MB &&
+ level <= EnvironmentalReverb::MAX_LEVEL_MB;
+ }
+
+ bool isDelayInRange(int delay) const {
+ return delay >= EnvironmentalReverb::MIN_DELAY_MS &&
+ delay <= EnvironmentalReverb::MAX_DELAY_MS;
+ }
+
+ bool isDiffusionInRange(int diffusion) const {
+ return diffusion >= EnvironmentalReverb::MIN_DIFFUSION_PM &&
+ diffusion <= EnvironmentalReverb::MAX_DIFFUSION_PM;
+ }
+
+ bool isDensityInRange(int density) const {
+ return density >= EnvironmentalReverb::MIN_DENSITY_PM &&
+ density <= EnvironmentalReverb::MAX_DENSITY_PM;
+ }
+
+ private:
+ std::vector<std::pair<EnvironmentalReverb::Tag, EnvironmentalReverb>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+class EnvironmentalReverbRoomLevelTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbRoomLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mRoomLevel = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomLevelTest, SetAndGetRoomLevel) {
+ EXPECT_NO_FATAL_FAILURE(addRoomLevelParam());
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbRoomLevelTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kRoomLevelValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_roomLevel" + roomLevel;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomLevelTest);
+
+class EnvironmentalReverbRoomHfLevelTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbRoomHfLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mRoomHfLevel = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbRoomHfLevelTest, SetAndGetRoomHfLevel) {
+ EXPECT_NO_FATAL_FAILURE(addRoomHfLevelParam(mRoomHfLevel));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbRoomHfLevelTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kRoomHfLevelValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_roomHfLevel" + roomHfLevel;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbRoomHfLevelTest);
+
+class EnvironmentalReverbDecayTimeTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDecayTimeTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mDecayTime = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayTimeTest, SetAndGetDecayTime) {
+ EXPECT_NO_FATAL_FAILURE(addDecayTimeParam(mDecayTime));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDecayTimeTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kDecayTimeValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_decayTime" + decayTime;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayTimeTest);
+
+class EnvironmentalReverbDecayHfRatioTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDecayHfRatioTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mDecayHfRatio = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDecayHfRatioTest, SetAndGetDecayHfRatio) {
+ EXPECT_NO_FATAL_FAILURE(addDecayHfRatioParam(mDecayHfRatio));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDecayHfRatioTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kDecayHfRatioValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_decayHfRatio" +
+ decayHfRatio;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDecayHfRatioTest);
+
+class EnvironmentalReverbLevelTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbLevelTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mLevel = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbLevelTest, SetAndGetLevel) {
+ EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbLevelTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kLevelValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_level" + level;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbLevelTest);
+
+class EnvironmentalReverbDelayTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDelayTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mDelay = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDelayTest, SetAndGetDelay) {
+ EXPECT_NO_FATAL_FAILURE(addDelayParam(mDelay));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDelayTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kDelayValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_delay" + delay;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDelayTest);
+
+class EnvironmentalReverbDiffusionTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDiffusionTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mDiffusion = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDiffusionTest, SetAndGetDiffusion) {
+ EXPECT_NO_FATAL_FAILURE(addDiffusionParam(mDiffusion));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDiffusionTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kDiffusionValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_diffusion" + diffusion;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDiffusionTest);
+
+class EnvironmentalReverbDensityTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbDensityTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mDensity = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbDensityTest, SetAndGetDensity) {
+ EXPECT_NO_FATAL_FAILURE(addDensityParam(mDensity));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbDensityTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::ValuesIn(kDensityValues)),
+ [](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));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_density" + density;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbDensityTest);
+
+class EnvironmentalReverbBypassTest
+ : public ::testing::TestWithParam<
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, bool>>,
+ public EnvironmentalReverbHelper {
+ public:
+ EnvironmentalReverbBypassTest() : EnvironmentalReverbHelper(std::get<0>(GetParam())) {
+ mBypass = std::get<1>(GetParam());
+ }
+
+ void SetUp() override { SetUpReverb(); }
+
+ void TearDown() override { TearDownReverb(); }
+};
+
+TEST_P(EnvironmentalReverbBypassTest, SetAndGetBypass) {
+ EXPECT_NO_FATAL_FAILURE(addBypassParam(mBypass));
+ SetAndGetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ EnvironmentalReverbTest, EnvironmentalReverbBypassTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kEnvReverbTypeUUID)),
+ testing::Bool()),
+ [](const testing::TestParamInfo<EnvironmentalReverbBypassTest::ParamType>& info) {
+ auto descriptor = std::get<0>(info.param).second;
+ std::string bypass = std::to_string(std::get<1>(info.param));
+
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_bypass" + bypass;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(EnvironmentalReverbBypassTest);
+
+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/VtsHalHapticGeneratorTargetTest.cpp b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
index a1daec2..d1f3b97 100644
--- a/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalHapticGeneratorTargetTest.cpp
@@ -18,6 +18,9 @@
#include <Utils.h>
#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
#include "EffectHelper.h"
using namespace android;
@@ -61,9 +64,8 @@
const std::vector<int> kHapticScaleIdValues = {MIN_ID, 0, MAX_ID};
const std::vector<HapticGenerator::VibratorScale> kVibratorScaleValues = {
- HapticGenerator::VibratorScale::MUTE, HapticGenerator::VibratorScale::VERY_LOW,
- HapticGenerator::VibratorScale::LOW, HapticGenerator::VibratorScale::NONE,
- HapticGenerator::VibratorScale::HIGH, HapticGenerator::VibratorScale::VERY_HIGH};
+ ndk::enum_range<HapticGenerator::VibratorScale>().begin(),
+ ndk::enum_range<HapticGenerator::VibratorScale>().end()};
const std::vector<float> kResonantFrequencyValues = {MIN_FLOAT, 100, MAX_FLOAT};
const std::vector<float> kQFactorValues = {MIN_FLOAT, 100, MAX_FLOAT};
diff --git a/audio/aidl/vts/VtsHalNSTargetTest.cpp b/audio/aidl/vts/VtsHalNSTargetTest.cpp
index 186cb68..93ad86d 100644
--- a/audio/aidl/vts/VtsHalNSTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalNSTargetTest.cpp
@@ -14,11 +14,14 @@
* limitations under the License.
*/
+#include <Utils.h>
#include <aidl/Vintf.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
#define LOG_TAG "VtsHalNSParamTest"
-#include <Utils.h>
+#include <aidl/android/hardware/audio/effect/NoiseSuppression.h>
#include "EffectHelper.h"
using namespace android;
@@ -68,9 +71,6 @@
}
static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
- static const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList;
- static const std::vector<NoiseSuppression::Level> kLevelValues;
-
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
@@ -113,19 +113,16 @@
ns.set<NoiseSuppression::level>(level);
mTags.push_back({NoiseSuppression::level, ns});
}
+ static std::unordered_set<NoiseSuppression::Level> getLevelValues() {
+ return {ndk::enum_range<NoiseSuppression::Level>().begin(),
+ ndk::enum_range<NoiseSuppression::Level>().end()};
+ }
private:
std::vector<std::pair<NoiseSuppression::Tag, NoiseSuppression>> mTags;
void CleanUp() { mTags.clear(); }
};
-const std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList =
- EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
- kNoiseSuppressionTypeUUID);
-const std::vector<NoiseSuppression::Level> NSParamTest::kLevelValues = {
- NoiseSuppression::Level::LOW, NoiseSuppression::Level::MEDIUM,
- NoiseSuppression::Level::HIGH};
-
TEST_P(NSParamTest, SetAndGetLevel) {
EXPECT_NO_FATAL_FAILURE(addLevelParam(mLevel));
SetAndGetParameters();
@@ -135,7 +132,7 @@
NSParamTest, NSParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kNoiseSuppressionTypeUUID)),
- testing::ValuesIn(NSParamTest::kLevelValues)),
+ testing::ValuesIn(NSParamTest::getLevelValues())),
[](const testing::TestParamInfo<NSParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string level = aidl::android::hardware::audio::effect::toString(
diff --git a/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
new file mode 100644
index 0000000..19d5747
--- /dev/null
+++ b/audio/aidl/vts/VtsHalPresetReverbTargetTest.cpp
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalPresetReverbTargetTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.h>
+#include <android/binder_enums.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::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kEffectNullUuid;
+using aidl::android::hardware::audio::effect::kPresetReverbTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::PresetReverb;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_PRESETS };
+using PresetReverbParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, PresetReverb::Presets>;
+
+// Testing for enum values
+const std::vector<PresetReverb::Presets> kPresetsValues{
+ ndk::enum_range<PresetReverb::Presets>().begin(),
+ ndk::enum_range<PresetReverb::Presets>().end()};
+
+class PresetReverbParamTest : public ::testing::TestWithParam<PresetReverbParamTestParam>,
+ public EffectHelper {
+ public:
+ PresetReverbParamTest() : mParamPresets(std::get<PARAM_PRESETS>(GetParam())) {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ 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 */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ PresetReverb::Presets mParamPresets = PresetReverb::Presets::NONE;
+
+ void SetAndGetPresetReverbParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& pr = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ const bool valid = isTagInRange(it.first, it.second, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::presetReverb>(pr);
+ expectParam.set<Parameter::specific>(specific);
+ // All values are valid, set parameter should succeed
+ EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // get parameter
+ Parameter getParam;
+ Parameter::Id id;
+ PresetReverb::Id prId;
+ prId.set<PresetReverb::Id::commonTag>(tag);
+ id.set<Parameter::Id::presetReverbTag>(prId);
+ EXPECT_STATUS(expected, mEffect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam);
+ }
+ }
+
+ void addPresetsParam(PresetReverb::Presets preset) {
+ PresetReverb pr;
+ pr.set<PresetReverb::preset>(preset);
+ mTags.push_back({PresetReverb::preset, pr});
+ }
+
+ bool isTagInRange(const PresetReverb::Tag& tag, const PresetReverb& pr,
+ const Descriptor& desc) const {
+ const PresetReverb::Capability& prCap = desc.capability.get<Capability::presetReverb>();
+ switch (tag) {
+ case PresetReverb::preset: {
+ PresetReverb::Presets preset = pr.get<PresetReverb::preset>();
+ return isPresetInRange(prCap, preset);
+ }
+ default:
+ return false;
+ }
+ return false;
+ }
+
+ bool isPresetInRange(const PresetReverb::Capability& cap, PresetReverb::Presets preset) const {
+ for (auto i : cap.supportedPresets) {
+ if (preset == i) return true;
+ }
+ return false;
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ PresetReverb pr = PresetReverb::make<PresetReverb::preset>(PresetReverb::Presets::NONE);
+ Parameter::Specific specific =
+ Parameter::Specific::make<Parameter::Specific::presetReverb>(pr);
+ return specific;
+ }
+
+ private:
+ std::vector<std::pair<PresetReverb::Tag, PresetReverb>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(PresetReverbParamTest, SetAndGetPresets) {
+ EXPECT_NO_FATAL_FAILURE(addPresetsParam(mParamPresets));
+ SetAndGetPresetReverbParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ PresetReverbTest, PresetReverbParamTest,
+ ::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kPresetReverbTypeUUID)),
+ testing::ValuesIn(kPresetsValues)),
+ [](const testing::TestParamInfo<PresetReverbParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string preset =
+ std::to_string(static_cast<int>(std::get<PARAM_PRESETS>(info.param)));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_preset" + preset;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PresetReverbParamTest);
+
+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/VtsHalVirtualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
index 61776b2..090de17 100644
--- a/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVirtualizerTargetTest.cpp
@@ -44,11 +44,6 @@
* otherwise expect EX_ILLEGAL_ARGUMENT.
*/
-const std::vector<int> kStrengthValues = {
- std::numeric_limits<int>::min(), Virtualizer::MIN_PER_MILLE_STRENGTH - 1,
- Virtualizer::MIN_PER_MILLE_STRENGTH, Virtualizer::MAX_PER_MILLE_STRENGTH,
- Virtualizer::MAX_PER_MILLE_STRENGTH + 1, std::numeric_limits<int>::max()};
-
class VirtualizerParamTest : public ::testing::TestWithParam<VirtualizerParamTestParam>,
public EffectHelper {
public:
@@ -75,8 +70,7 @@
}
Parameter::Specific getDefaultParamSpecific() {
- Virtualizer vr =
- Virtualizer::make<Virtualizer::strengthPm>(Virtualizer::MIN_PER_MILLE_STRENGTH);
+ Virtualizer vr = Virtualizer::make<Virtualizer::strengthPm>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::virtualizer>(vr);
return specific;
@@ -86,7 +80,7 @@
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
- int mParamStrength = Virtualizer::MIN_PER_MILLE_STRENGTH;
+ int mParamStrength = 0;
void SetAndGetVirtualizerParameters() {
for (auto& it : mTags) {
@@ -141,8 +135,29 @@
}
bool isStrengthInRange(const Virtualizer::Capability& cap, int strength) const {
- return cap.strengthSupported && strength >= Virtualizer::MIN_PER_MILLE_STRENGTH &&
- strength <= Virtualizer::MAX_PER_MILLE_STRENGTH;
+ return cap.strengthSupported && strength >= 0 && strength <= cap.maxStrengthPm;
+ }
+
+ static std::vector<int> getStrengthTestValues(
+ std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+ const auto max = std::max_element(
+ kFactoryDescList.begin(), kFactoryDescList.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::virtualizer>().maxStrengthPm <
+ b.second.capability.get<Capability::virtualizer>().maxStrengthPm;
+ });
+ if (max == kFactoryDescList.end()) {
+ return {0};
+ }
+ int maxStrength = max->second.capability.get<Capability::virtualizer>().maxStrengthPm;
+ return {std::numeric_limits<int>::min(),
+ -1,
+ 0,
+ maxStrength >> 1,
+ maxStrength,
+ maxStrength + 1,
+ std::numeric_limits<int>::max()};
}
private:
@@ -159,7 +174,9 @@
VirtualizerTest, VirtualizerParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kVirtualizerTypeUUID)),
- testing::ValuesIn(kStrengthValues)),
+ testing::ValuesIn(VirtualizerParamTest::getStrengthTestValues(
+ EffectFactoryHelper::getAllEffectDescriptors(
+ IFactory::descriptor, kVirtualizerTypeUUID)))),
[](const testing::TestParamInfo<VirtualizerParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string strength = std::to_string(std::get<PARAM_STRENGTH>(info.param));
diff --git a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
index a7834fb..242be3f 100644
--- a/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
+++ b/audio/aidl/vts/VtsHalVisualizerTargetTest.cpp
@@ -19,6 +19,9 @@
#define LOG_TAG "VtsHalVisualizerTest"
#include <Utils.h>
+#include <android/binder_enums.h>
+#include <unordered_set>
+
#include "EffectHelper.h"
using namespace android;
@@ -46,18 +49,6 @@
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, Visualizer::ScalingMode,
Visualizer::MeasurementMode, int>;
-const int MIN_CAPTURE_SIZE = 128;
-const int MAX_CAPTURE_SIZE = 1024;
-const int MAX_LATENCY = 3000;
-
-const std::vector<int> kCaptureSizeValues = {MIN_CAPTURE_SIZE - 1, MIN_CAPTURE_SIZE,
- MAX_CAPTURE_SIZE, MAX_CAPTURE_SIZE + 1};
-const std::vector<Visualizer::ScalingMode> kScalingModeValues = {
- Visualizer::ScalingMode::NORMALIZED, Visualizer::ScalingMode::AS_PLAYED};
-const std::vector<Visualizer::MeasurementMode> kMeasurementModeValues = {
- Visualizer::MeasurementMode::NONE, Visualizer::MeasurementMode::PEAK_RMS};
-const std::vector<int> kLatencyValues = {-1, 0, MAX_LATENCY, MAX_LATENCY + 1};
-
class VisualizerParamTest : public ::testing::TestWithParam<VisualizerParamTestParam>,
public EffectHelper {
public:
@@ -86,9 +77,9 @@
ASSERT_NO_FATAL_FAILURE(close(mEffect));
ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
}
-
Parameter::Specific getDefaultParamSpecific() {
- Visualizer vs = Visualizer::make<Visualizer::captureSizeBytes>(MIN_CAPTURE_SIZE);
+ Visualizer vs = Visualizer::make<Visualizer::captureSamples>(
+ mDescriptor.capability.get<Capability::visualizer>().captureSampleRange.max);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::visualizer>(vs);
return specific;
@@ -98,7 +89,7 @@
std::shared_ptr<IFactory> mFactory;
std::shared_ptr<IEffect> mEffect;
Descriptor mDescriptor;
- int mCaptureSize = MAX_CAPTURE_SIZE;
+ int mCaptureSize;
Visualizer::ScalingMode mScalingMode = Visualizer::ScalingMode::NORMALIZED;
Visualizer::MeasurementMode mMeasurementMode = Visualizer::MeasurementMode::NONE;
int mLatency = 0;
@@ -144,7 +135,7 @@
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
- const bool valid = isSetOnlyParamTagInRange(tag, vs, desc);
+ const bool valid = isSetOnlyParamTagInRange(vs, desc);
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set parameter
@@ -184,8 +175,8 @@
void addCaptureSizeParam(int captureSize) {
Visualizer vs;
- vs.set<Visualizer::captureSizeBytes>(captureSize);
- mCommonTags.push_back({Visualizer::captureSizeBytes, vs});
+ vs.set<Visualizer::captureSamples>(captureSize);
+ mCommonTags.push_back({Visualizer::captureSamples, vs});
}
void addScalingModeParam(Visualizer::ScalingMode scalingMode) {
@@ -213,27 +204,35 @@
}
void addCaptureBytesTag() {
- mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::captureBytes);
+ mGetOnlyParamTags.push_back(Visualizer::GetOnlyParameters::captureSampleBuffer);
}
bool isTagInRange(const Visualizer::Tag& tag, const Visualizer& vs,
const Descriptor& desc) const {
const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
switch (tag) {
- case Visualizer::captureSizeBytes: {
- int captureSize = vs.get<Visualizer::captureSizeBytes>();
- return isCaptureSizeInRange(vsCap, captureSize);
+ case Visualizer::captureSamples: {
+ int captureSize = vs.get<Visualizer::captureSamples>();
+ return captureSize >= vsCap.captureSampleRange.min &&
+ captureSize <= vsCap.captureSampleRange.max;
}
case Visualizer::scalingMode:
case Visualizer::measurementMode:
return true;
+ case Visualizer::setOnlyParameters: {
+ auto setOnly = vs.get<Visualizer::setOnlyParameters>();
+ if (setOnly.getTag() != Visualizer::SetOnlyParameters::latencyMs) {
+ return false;
+ }
+ auto latencyMs = setOnly.get<Visualizer::SetOnlyParameters::latencyMs>();
+ return latencyMs >= 0 && latencyMs <= vsCap.maxLatencyMs;
+ }
default:
return false;
}
}
- bool isSetOnlyParamTagInRange(Visualizer::SetOnlyParameters::Tag, const Visualizer& vs,
- const Descriptor& desc) const {
+ bool isSetOnlyParamTagInRange(const Visualizer& vs, const Descriptor& desc) const {
const Visualizer::Capability& vsCap = desc.capability.get<Capability::visualizer>();
if (vs.getTag() != Visualizer::setOnlyParameters) return false;
Visualizer::SetOnlyParameters setOnlyParam = vs.get<Visualizer::setOnlyParameters>();
@@ -242,15 +241,53 @@
return isLatencyInRange(vsCap, latency);
}
- bool isCaptureSizeInRange(const Visualizer::Capability& cap, int captureSize) const {
- return (captureSize >= cap.captureSizeRange.minBytes &&
- captureSize <= cap.captureSizeRange.maxBytes);
- }
-
bool isLatencyInRange(const Visualizer::Capability& cap, int latency) const {
return (latency >= 0 && latency <= cap.maxLatencyMs);
}
+ static std::unordered_set<int> getCaptureSizeValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kVisualizerTypeUUID);
+ int minCaptureSize = std::numeric_limits<int>::max();
+ int maxCaptureSize = std::numeric_limits<int>::min();
+ for (const auto& it : descList) {
+ maxCaptureSize = std::max(
+ it.second.capability.get<Capability::visualizer>().captureSampleRange.max,
+ maxCaptureSize);
+ minCaptureSize = std::min(
+ it.second.capability.get<Capability ::visualizer>().captureSampleRange.min,
+ minCaptureSize);
+ }
+ return {std::numeric_limits<int>::min(), minCaptureSize - 1, minCaptureSize,
+ (minCaptureSize + maxCaptureSize) >> 1, maxCaptureSize, maxCaptureSize + 1,
+ std::numeric_limits<int>::max()};
+ }
+
+ static std::unordered_set<int> getLatencyValues() {
+ auto descList = EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kVisualizerTypeUUID);
+ 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::visualizer>().maxLatencyMs <
+ b.second.capability.get<Capability::visualizer>().maxLatencyMs;
+ });
+ if (max == descList.end()) {
+ return {0};
+ }
+ int maxDelay = max->second.capability.get<Capability::visualizer>().maxLatencyMs;
+ return {-1, 0, maxDelay >> 1, maxDelay - 1, maxDelay, maxDelay + 1};
+ }
+ static std::unordered_set<Visualizer::MeasurementMode> getMeasurementModeValues() {
+ return {ndk::enum_range<Visualizer::MeasurementMode>().begin(),
+ ndk::enum_range<Visualizer::MeasurementMode>().end()};
+ }
+ static std::unordered_set<Visualizer::ScalingMode> getScalingModeValues() {
+ return {ndk::enum_range<Visualizer::ScalingMode>().begin(),
+ ndk::enum_range<Visualizer::ScalingMode>().end()};
+ }
+
private:
std::vector<std::pair<Visualizer::Tag, Visualizer>> mCommonTags;
std::vector<std::pair<Visualizer::SetOnlyParameters::Tag, Visualizer>> mSetOnlyParamTags;
@@ -293,20 +330,20 @@
}
INSTANTIATE_TEST_SUITE_P(
- VisualizerTest, VisualizerParamTest,
+ VisualizerParamTest, VisualizerParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kVisualizerTypeUUID)),
- testing::ValuesIn(kCaptureSizeValues),
- testing::ValuesIn(kScalingModeValues),
- testing::ValuesIn(kMeasurementModeValues),
- testing::ValuesIn(kLatencyValues)),
+ testing::ValuesIn(VisualizerParamTest::getCaptureSizeValues()),
+ testing::ValuesIn(VisualizerParamTest::getScalingModeValues()),
+ testing::ValuesIn(VisualizerParamTest::getMeasurementModeValues()),
+ testing::ValuesIn(VisualizerParamTest::getLatencyValues())),
[](const testing::TestParamInfo<VisualizerParamTest::ParamType>& info) {
auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
std::string captureSize = std::to_string(std::get<PARAM_CAPTURE_SIZE>(info.param));
- std::string scalingMode =
- std::to_string(static_cast<int>(std::get<PARAM_SCALING_MODE>(info.param)));
- std::string measurementMode =
- std::to_string(static_cast<int>(std::get<PARAM_MEASUREMENT_MODE>(info.param)));
+ std::string scalingMode = aidl::android::hardware::audio::effect::toString(
+ std::get<PARAM_SCALING_MODE>(info.param));
+ std::string measurementMode = aidl::android::hardware::audio::effect::toString(
+ std::get<PARAM_MEASUREMENT_MODE>(info.param));
std::string latency = std::to_string(std::get<PARAM_LATENCY>(info.param));
std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
diff --git a/audio/aidl/vts/VtsHalVolumeTargetTest.cpp b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
new file mode 100644
index 0000000..34625e7
--- /dev/null
+++ b/audio/aidl/vts/VtsHalVolumeTargetTest.cpp
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VtsHalVolumeTest"
+
+#include <Utils.h>
+#include <aidl/Vintf.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::IEffect;
+using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::hardware::audio::effect::kVolumeTypeUUID;
+using aidl::android::hardware::audio::effect::Parameter;
+using aidl::android::hardware::audio::effect::Volume;
+
+/**
+ * Here we focus on specific parameter checking, general IEffect interfaces testing performed in
+ * VtsAudioEffectTargetTest.
+ */
+enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL, PARAM_MUTE };
+using VolumeParamTestParam =
+ std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int, bool>;
+
+class VolumeParamTest : public ::testing::TestWithParam<VolumeParamTestParam>, public EffectHelper {
+ public:
+ VolumeParamTest()
+ : mParamLevel(std::get<PARAM_LEVEL>(GetParam())),
+ mParamMute(std::get<PARAM_MUTE>(GetParam())) {
+ std::tie(mFactory, mDescriptor) = std::get<PARAM_INSTANCE_NAME>(GetParam());
+ }
+
+ void SetUp() override {
+ 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 */,
+ kInputFrameCount /* iFrameCount */, kOutputFrameCount /* oFrameCount */);
+ IEffect::OpenEffectReturn ret;
+ ASSERT_NO_FATAL_FAILURE(open(mEffect, common, specific, &ret, EX_NONE));
+ ASSERT_NE(nullptr, mEffect);
+ }
+ void TearDown() override {
+ ASSERT_NO_FATAL_FAILURE(close(mEffect));
+ ASSERT_NO_FATAL_FAILURE(destroy(mFactory, mEffect));
+ }
+
+ Parameter::Specific getDefaultParamSpecific() {
+ Volume vol = Volume::make<Volume::levelDb>(-9600);
+ Parameter::Specific specific = Parameter::Specific::make<Parameter::Specific::volume>(vol);
+ return specific;
+ }
+
+ static const long kInputFrameCount = 0x100, kOutputFrameCount = 0x100;
+ std::shared_ptr<IFactory> mFactory;
+ std::shared_ptr<IEffect> mEffect;
+ Descriptor mDescriptor;
+ int mParamLevel = 0;
+ bool mParamMute = false;
+
+ void SetAndGetParameters() {
+ for (auto& it : mTags) {
+ auto& tag = it.first;
+ auto& vol = it.second;
+
+ // validate parameter
+ Descriptor desc;
+ ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
+ // only set and get parameter if capability is valid
+ ASSERT_TRUE(isCapabilityValid(desc));
+ const bool valid = isTagInRange(it.first, it.second, desc);
+ const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
+
+ // set parameter
+ Parameter expectParam;
+ Parameter::Specific specific;
+ specific.set<Parameter::Specific::volume>(vol);
+ expectParam.set<Parameter::specific>(specific);
+ EXPECT_STATUS(expected, mEffect->setParameter(expectParam)) << expectParam.toString();
+
+ // only get if parameter is in range and set success
+ if (expected == EX_NONE) {
+ Parameter getParam;
+ Parameter::Id id;
+ Volume::Id volId;
+ volId.set<Volume::Id::commonTag>(tag);
+ id.set<Parameter::Id::volumeTag>(volId);
+ EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
+
+ EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
+ << "\ngetParam:" << getParam.toString();
+ }
+ }
+ }
+
+ void addLevelParam(int level) {
+ Volume vol;
+ vol.set<Volume::levelDb>(level);
+ mTags.push_back({Volume::levelDb, vol});
+ }
+
+ void addMuteParam(bool mute) {
+ Volume vol;
+ vol.set<Volume::mute>(mute);
+ mTags.push_back({Volume::mute, vol});
+ }
+
+ bool isCapabilityValid(const Descriptor& desc) {
+ const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+ return (volCap.minLevelDb <= volCap.maxLevelDb);
+ }
+
+ bool isTagInRange(const Volume::Tag& tag, const Volume& vol, const Descriptor& desc) const {
+ const Volume::Capability& volCap = desc.capability.get<Capability::volume>();
+ switch (tag) {
+ case Volume::levelDb: {
+ int level = vol.get<Volume::levelDb>();
+ return isLevelInRange(volCap, level);
+ }
+ case Volume::mute:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static std::vector<int> getLevelTestValues(
+ std::vector<std::pair<std::shared_ptr<IFactory>, Descriptor>> kFactoryDescList) {
+ int minLevelDb = std::numeric_limits<int>::max();
+ int maxLevelDb = std::numeric_limits<int>::min();
+ for (const auto& it : kFactoryDescList) {
+ maxLevelDb =
+ std::max(it.second.capability.get<Capability::volume>().maxLevelDb, maxLevelDb);
+ minLevelDb = std::min(it.second.capability.get<Capability ::volume>().minLevelDb,
+ minLevelDb);
+ }
+ return {minLevelDb - 1, minLevelDb, -100, maxLevelDb, maxLevelDb + 1};
+ }
+
+ bool isLevelInRange(const Volume::Capability& volCap, int level) const {
+ return level >= volCap.minLevelDb && level <= volCap.maxLevelDb;
+ }
+
+ private:
+ std::vector<std::pair<Volume::Tag, Volume>> mTags;
+ void CleanUp() { mTags.clear(); }
+};
+
+TEST_P(VolumeParamTest, SetAndGetLevel) {
+ EXPECT_NO_FATAL_FAILURE(addLevelParam(mParamLevel));
+ SetAndGetParameters();
+}
+
+TEST_P(VolumeParamTest, SetAndGetMute) {
+ EXPECT_NO_FATAL_FAILURE(addMuteParam(mParamMute));
+ SetAndGetParameters();
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ VolumeTest, VolumeParamTest,
+ ::testing::Combine(
+ testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kVolumeTypeUUID)),
+ testing::ValuesIn(VolumeParamTest::getLevelTestValues(
+ EffectFactoryHelper::getAllEffectDescriptors(IFactory::descriptor,
+ kVolumeTypeUUID))),
+ testing::Bool() /* mute */),
+ [](const testing::TestParamInfo<VolumeParamTest::ParamType>& info) {
+ auto descriptor = std::get<PARAM_INSTANCE_NAME>(info.param).second;
+ std::string level = std::to_string(std::get<PARAM_LEVEL>(info.param));
+ std::string mute = std::to_string(std::get<PARAM_MUTE>(info.param));
+ std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
+ descriptor.common.name + "_UUID_" +
+ descriptor.common.id.uuid.toString() + "_level" + level + "_mute" +
+ mute;
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(VolumeParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
index 719f752..c4c18a4 100644
--- a/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/7.0/AudioPrimaryHidlHalTest.cpp
@@ -687,7 +687,12 @@
InputStreamTest::TearDown();
}
- bool canQueryCapturePosition() const { return !xsd::isTelephonyDevice(address.deviceType); }
+ bool canQueryCapturePosition() const {
+ // See b/263305254 and b/259636577. Must use the device initially passed in
+ // as a parameter, not 'address' which gets adjusted during test setup for
+ // the telephony case.
+ return !xsd::isTelephonyDevice(getAttachedDeviceAddress().deviceType);
+ }
void createPatchIfNeeded() {
if (areAudioPatchesSupported()) {
diff --git a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 219ea3d..c3b3e00 100644
--- a/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/aidl_api/android.hardware.automotive.vehicle/current/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -68,6 +68,7 @@
RANGE_REMAINING = 291504904,
TIRE_PRESSURE = 392168201,
CRITICALLY_LOW_TIRE_PRESSURE = 392168202,
+ ENGINE_IDLE_AUTO_STOP_ENABLED = 287310624,
GEAR_SELECTION = 289408000,
CURRENT_GEAR = 289408001,
PARKING_BRAKE_ON = 287310850,
@@ -165,6 +166,7 @@
SEAT_CUSHION_SIDE_SUPPORT_MOVE = 356518816,
SEAT_LUMBAR_VERTICAL_POS = 356518817,
SEAT_LUMBAR_VERTICAL_MOVE = 356518818,
+ SEAT_WALK_IN_POS = 356518819,
SEAT_OCCUPANCY = 356518832,
WINDOW_POS = 322964416,
WINDOW_MOVE = 322964417,
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
index 47fc54b..c896d14 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/IVehicle.aidl
@@ -190,6 +190,14 @@
* what the sampleRate specified in {@code options}, the timestamp for
* the timestamp is updated 10 times/s.
*
+ * If a property is unavailable for reading because it depends on some power
+ * state which is off, property change event may not be generated until the
+ * property becomes available. For ON_CHANGE property, if the property
+ * changes from NOT_AVAILABLE to OKAY for reading some or all area(s), for
+ * each area that becomes available for reading, one property change event
+ * must be generated. The event must contain the current value for the area
+ * and must have {@code AVAILABLE} status.
+ *
* @param callback The subscription callbacks.
* {@link IVehicleCallback#onPropertyEvent} would be called when a new
* property event arrives.
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
index 23019ca..35080db 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/StatusCode.aidl
@@ -24,7 +24,11 @@
enum StatusCode {
OK = 0,
/**
- * Try again.
+ * Caller should try again.
+ *
+ * This code must be returned when an ephemeral error happens and a retry
+ * will likely succeed. E.g., when the device is currently booting up
+ * and the property is not ready yet.
*/
TRY_AGAIN = 1,
/**
@@ -32,9 +36,22 @@
*/
INVALID_ARG = 2,
/**
+ * The property is currently unavailable and will be unavailable unless
+ * some other state changes.
+ *
* This code must be returned when device that associated with the vehicle
* property is not available. For example, when client tries to set HVAC
* temperature when the whole HVAC unit is turned OFF.
+ *
+ * The difference between this and TRY_AGAIN is that if NOT_AVAILABLE is
+ * returned for a property, it will remain NOT_AVAILABLE unless some other
+ * state changes. This means a retry will likely still return NOT_AVAILABLE.
+ * However, for TRY_AGAIN error, a retry will likely return OK.
+ *
+ * When subscribing to a property that is currently unavailable for getting.
+ * VHAL must return OK even if getting/setting must return NOT_AVAILABLE.
+ * VHAL must not generate property change event when the property is not
+ * available for getting.
*/
NOT_AVAILABLE = 3,
/**
diff --git a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
index 472192f..4d0b77b 100644
--- a/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
+++ b/automotive/vehicle/aidl/android/hardware/automotive/vehicle/VehicleProperty.aidl
@@ -441,6 +441,17 @@
CRITICALLY_LOW_TIRE_PRESSURE = 0x030A + 0x10000000 + 0x07000000
+ 0x00600000, // VehiclePropertyGroup:SYSTEM,VehicleArea:WHEEL,VehiclePropertyType:FLOAT
/**
+ * Represents feature for engine idle automatic stop.
+ *
+ * If true, the vehicle may automatically shut off the engine when it is not needed and then
+ * automatically restart it when needed.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ ENGINE_IDLE_AUTO_STOP_ENABLED =
+ 0x0320 + VehiclePropertyGroup.SYSTEM + VehicleArea.GLOBAL + VehiclePropertyType.BOOLEAN,
+ /**
* Currently selected gear
*
* This is the gear selected by the user.
@@ -1912,6 +1923,27 @@
SEAT_LUMBAR_VERTICAL_MOVE =
0x0BA2 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
/**
+ * Represents property that indicates the current walk-in position of the seat.
+ *
+ * The maxInt32Value and minInt32Value in VehicleAreaConfig must be defined.
+ * The minInt32Value must be 0.
+ * All integers between minInt32Value and maxInt32Value must be supported.
+ *
+ * minInt32Value indicates the normal seat position.
+ * maxInt32Value indicates the seat is in the full walk-in position.
+ *
+ * Values in between minInt32Value and maxInt32Value indicate a transition state between the
+ * normal and walk-in positions.
+ *
+ * The area ID must match the seat that actually moves when the walk-in feature activates, not
+ * the intended seat the passengers will sit in.
+ *
+ * @change_mode VehiclePropertyChangeMode.ON_CHANGE
+ * @access VehiclePropertyAccess.READ_WRITE
+ */
+ SEAT_WALK_IN_POS =
+ 0x0BA3 + VehiclePropertyGroup.SYSTEM + VehicleArea.SEAT + VehiclePropertyType.INT32,
+ /**
* Seat Occupancy
*
* Indicates whether a particular seat is occupied or not, to the best of the car's ability
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
index c898baf..75b371f 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/AccessForVehicleProperty.h
@@ -68,6 +68,7 @@
{VehicleProperty::RANGE_REMAINING, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::TIRE_PRESSURE, VehiclePropertyAccess::READ},
{VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess::READ},
+ {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::GEAR_SELECTION, VehiclePropertyAccess::READ},
{VehicleProperty::CURRENT_GEAR, VehiclePropertyAccess::READ},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyAccess::READ},
@@ -165,6 +166,7 @@
{VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess::READ_WRITE},
+ {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyAccess::READ},
{VehicleProperty::WINDOW_POS, VehiclePropertyAccess::READ_WRITE},
{VehicleProperty::WINDOW_MOVE, VehiclePropertyAccess::READ_WRITE},
diff --git a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
index c501d9b..6e797b9 100644
--- a/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
+++ b/automotive/vehicle/aidl/generated_lib/cpp/ChangeModeForVehicleProperty.h
@@ -68,6 +68,7 @@
{VehicleProperty::RANGE_REMAINING, VehiclePropertyChangeMode::CONTINUOUS},
{VehicleProperty::TIRE_PRESSURE, VehiclePropertyChangeMode::CONTINUOUS},
{VehicleProperty::CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode::STATIC},
+ {VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::GEAR_SELECTION, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::CURRENT_GEAR, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::PARKING_BRAKE_ON, VehiclePropertyChangeMode::ON_CHANGE},
@@ -165,6 +166,7 @@
{VehicleProperty::SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
+ {VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::SEAT_OCCUPANCY, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::WINDOW_POS, VehiclePropertyChangeMode::ON_CHANGE},
{VehicleProperty::WINDOW_MOVE, VehiclePropertyChangeMode::ON_CHANGE},
diff --git a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
index ca85de5..455d3d4 100644
--- a/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/AccessForVehicleProperty.java
@@ -60,6 +60,7 @@
Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyAccess.READ),
+ Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyAccess.READ),
@@ -157,6 +158,7 @@
Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyAccess.READ_WRITE),
+ Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyAccess.READ),
Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyAccess.READ_WRITE),
Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyAccess.READ_WRITE),
diff --git a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
index 92a83a8..aaa344f 100644
--- a/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
+++ b/automotive/vehicle/aidl/generated_lib/java/ChangeModeForVehicleProperty.java
@@ -60,6 +60,7 @@
Map.entry(VehicleProperty.RANGE_REMAINING, VehiclePropertyChangeMode.CONTINUOUS),
Map.entry(VehicleProperty.TIRE_PRESSURE, VehiclePropertyChangeMode.CONTINUOUS),
Map.entry(VehicleProperty.CRITICALLY_LOW_TIRE_PRESSURE, VehiclePropertyChangeMode.STATIC),
+ Map.entry(VehicleProperty.ENGINE_IDLE_AUTO_STOP_ENABLED, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.GEAR_SELECTION, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.CURRENT_GEAR, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.PARKING_BRAKE_ON, VehiclePropertyChangeMode.ON_CHANGE),
@@ -157,6 +158,7 @@
Map.entry(VehicleProperty.SEAT_CUSHION_SIDE_SUPPORT_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_LUMBAR_VERTICAL_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
+ Map.entry(VehicleProperty.SEAT_WALK_IN_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.SEAT_OCCUPANCY, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.WINDOW_POS, VehiclePropertyChangeMode.ON_CHANGE),
Map.entry(VehicleProperty.WINDOW_MOVE, VehiclePropertyChangeMode.ON_CHANGE),
diff --git a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
index 0123521..c17a2e2 100644
--- a/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
+++ b/automotive/vehicle/aidl/impl/default_config/config/DefaultProperties.json
@@ -1208,6 +1208,26 @@
]
},
{
+ "property": "VehicleProperty::SEAT_WALK_IN_POS",
+ "defaultValue": {
+ "int32Values": [
+ 0
+ ]
+ },
+ "areas": [
+ {
+ "areaId": "Constants::SEAT_1_LEFT",
+ "minInt32Value": 0,
+ "maxInt32Value": 5
+ },
+ {
+ "areaId": "Constants::SEAT_1_RIGHT",
+ "minInt32Value": 0,
+ "maxInt32Value": 5
+ }
+ ]
+ },
+ {
"property": "VehicleProperty::SEAT_OCCUPANCY",
"areas": [
{
@@ -1956,7 +1976,8 @@
"maxFloatValue": 28.0
}
],
- "comment": "minFloatValue and maxFloatValue in area config should match corresponding values in configArray",
+ "comment":
+ "minFloatValue and maxFloatValue in area config should match corresponding values in configArray",
"configArray": [
160,
280,
@@ -2088,6 +2109,14 @@
"minSampleRate": 0.10000000149011612
},
{
+ "property": "VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED",
+ "defaultValue": {
+ "int32Values": [
+ 1
+ ]
+ }
+ },
+ {
"property": "VehicleProperty::DOOR_LOCK",
"areas": [
{
diff --git a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
index 1943c41..5595afe 100644
--- a/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
+++ b/automotive/vehicle/vts/src/VtsHalAutomotiveVehicle_TargetTest.cpp
@@ -493,6 +493,12 @@
VehicleArea::GLOBAL, VehiclePropertyType::FLOAT);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyEngineIdleAutoStopEnabledConfig) {
+ verifyProperty(VehicleProperty::ENGINE_IDLE_AUTO_STOP_ENABLED,
+ VehiclePropertyAccess::READ_WRITE, VehiclePropertyChangeMode::ON_CHANGE,
+ VehiclePropertyGroup::SYSTEM, VehicleArea::GLOBAL, VehiclePropertyType::BOOLEAN);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifyDoorChildLockEnabledConfig) {
verifyProperty(VehicleProperty::DOOR_CHILD_LOCK_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
@@ -553,6 +559,12 @@
VehicleArea::MIRROR, VehiclePropertyType::BOOLEAN);
}
+TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatWalkInPosConfig) {
+ verifyProperty(VehicleProperty::SEAT_WALK_IN_POS, VehiclePropertyAccess::READ_WRITE,
+ VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
+ VehicleArea::SEAT, VehiclePropertyType::INT32);
+}
+
TEST_P(VtsHalAutomotiveVehicleTargetTest, verifySeatEasyAccessEnabledConfig) {
verifyProperty(VehicleProperty::SEAT_EASY_ACCESS_ENABLED, VehiclePropertyAccess::READ_WRITE,
VehiclePropertyChangeMode::ON_CHANGE, VehiclePropertyGroup::SYSTEM,
diff --git a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
index ea7adc9..6010c60 100644
--- a/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
+++ b/bluetooth/1.0/vts/functional/VtsHalBluetoothV1_0TargetTest.xml
@@ -24,8 +24,10 @@
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put global ble_scan_always_enabled 0" />
- <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
- <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+ <option name="run-command" value="cmd bluetooth_manager disable" />
+ <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+ <option name="teardown-command" value="cmd bluetooth_manager enable" />
+ <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
<option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
</target_preparer>
diff --git a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
index 98b62ef..0234dc8 100644
--- a/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
+++ b/bluetooth/1.1/vts/functional/VtsHalBluetoothV1_1TargetTest.xml
@@ -22,8 +22,10 @@
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="settings put global ble_scan_always_enabled 0" />
- <option name="run-command" value="su u$(am get-current-user)_system svc bluetooth disable" />
- <option name="teardown-command" value="su u$(am get-current-user)_system svc bluetooth enable" />
+ <option name="run-command" value="cmd bluetooth_manager disable" />
+ <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+ <option name="teardown-command" value="cmd bluetooth_manager enable" />
+ <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
<option name="teardown-command" value="settings put global ble_scan_always_enabled 1" />
</target_preparer>
diff --git a/bluetooth/audio/aidl/Android.bp b/bluetooth/audio/aidl/Android.bp
index 4aea83f..618141f 100644
--- a/bluetooth/audio/aidl/Android.bp
+++ b/bluetooth/audio/aidl/Android.bp
@@ -29,7 +29,7 @@
imports: [
"android.hardware.common-V2",
"android.hardware.common.fmq-V1",
- "android.hardware.audio.common",
+ "android.hardware.audio.common-V1",
],
backend: {
cpp: {
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
index 0484d02..646c502 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/IdentifierType.aidl
@@ -110,10 +110,11 @@
HD_STATION_NAME,
/**
- * 28bit compound primary identifier for Digital Audio Broadcasting.
+ * 44bit compound primary identifier for Digital Audio Broadcasting and
+ * Digital Multimeida Broadcasting.
*
* Consists of (from the LSB):
- * - 16bit: SId;
+ * - 32bit: SId;
* - 8bit: ECC code;
* - 4bit: SCIdS.
*
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
index 3e2c9cc..d650239 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramInfo.aidl
@@ -120,7 +120,7 @@
*
* Only physical identifiers are valid:
* - AMFM_FREQUENCY_KHZ;
- * - DAB_ENSEMBLE;
+ * - DAB_FREQUENCY_KHZ;
* - DRMO_FREQUENCY_KHZ;
* - SXM_CHANNEL;
* - VENDOR_*;
diff --git a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
index 8bd3fd4..93b0e12 100644
--- a/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
+++ b/broadcastradio/aidl/android/hardware/broadcastradio/ProgramSelector.aidl
@@ -51,7 +51,8 @@
* - analogue AM/FM: AMFM_FREQUENCY_KHZ;
* - FM RDS: RDS_PI;
* - HD Radio: HD_STATION_ID_EXT;
- * - DAB: DAB_SID_EXT;
+ * - DAB/DMB: DAB_SID_EXT (when used, DAB_ENSEMBLE and DAB_FREQUENCY_KHZ
+ * must present in secondaryIds);
* - Digital Radio Mondiale: DRMO_SERVICE_ID;
* - SiriusXM: SXM_SERVICE_ID;
* - vendor-specific: VENDOR_START..VENDOR_END.
diff --git a/broadcastradio/aidl/default/BroadcastRadio.cpp b/broadcastradio/aidl/default/BroadcastRadio.cpp
index 42e550e..36520fb 100644
--- a/broadcastradio/aidl/default/BroadcastRadio.cpp
+++ b/broadcastradio/aidl/default/BroadcastRadio.cpp
@@ -589,22 +589,28 @@
}
ProgramSelector sel = {};
if (isDab) {
- if (numArgs != 4) {
+ if (numArgs != 5) {
dprintf(fd,
- "Invalid number of arguments: please provide --tune dab <SID> <ENSEMBLE>\n");
+ "Invalid number of arguments: please provide "
+ "--tune dab <SID> <ENSEMBLE> <FREQUENCY>\n");
return STATUS_BAD_VALUE;
}
int sid;
if (!utils::parseArgInt(string(args[2]), &sid)) {
- dprintf(fd, "Non-integer sid provided with tune: %s\n", string(args[2]).c_str());
+ dprintf(fd, "Non-integer sid provided with tune: %s\n", args[2]);
return STATUS_BAD_VALUE;
}
int ensemble;
if (!utils::parseArgInt(string(args[3]), &ensemble)) {
- dprintf(fd, "Non-integer ensemble provided with tune: %s\n", string(args[3]).c_str());
+ dprintf(fd, "Non-integer ensemble provided with tune: %s\n", args[3]);
return STATUS_BAD_VALUE;
}
- sel = utils::makeSelectorDab(sid, ensemble);
+ int freq;
+ if (!utils::parseArgInt(string(args[4]), &freq)) {
+ dprintf(fd, "Non-integer frequency provided with tune: %s\n", args[4]);
+ return STATUS_BAD_VALUE;
+ }
+ sel = utils::makeSelectorDab(sid, ensemble, freq);
} else {
if (numArgs != 3) {
dprintf(fd, "Invalid number of arguments: please provide --tune amfm <FREQUENCY>\n");
@@ -612,7 +618,7 @@
}
int freq;
if (!utils::parseArgInt(string(args[2]), &freq)) {
- dprintf(fd, "Non-integer frequency provided with tune: %s\n", string(args[2]).c_str());
+ dprintf(fd, "Non-integer frequency provided with tune: %s\n", args[2]);
return STATUS_BAD_VALUE;
}
sel = utils::makeSelectorAmfm(freq);
diff --git a/broadcastradio/aidl/default/VirtualProgram.cpp b/broadcastradio/aidl/default/VirtualProgram.cpp
index 0df0a82..4fe6567 100644
--- a/broadcastradio/aidl/default/VirtualProgram.cpp
+++ b/broadcastradio/aidl/default/VirtualProgram.cpp
@@ -53,7 +53,7 @@
break;
case IdentifierType::DAB_SID_EXT:
info.logicallyTunedTo = selectId(IdentifierType::DAB_SID_EXT);
- info.physicallyTunedTo = selectId(IdentifierType::DAB_ENSEMBLE);
+ info.physicallyTunedTo = selectId(IdentifierType::DAB_FREQUENCY_KHZ);
break;
case IdentifierType::DRMO_SERVICE_ID:
info.logicallyTunedTo = selectId(IdentifierType::DRMO_SERVICE_ID);
diff --git a/broadcastradio/aidl/default/VirtualRadio.cpp b/broadcastradio/aidl/default/VirtualRadio.cpp
index 851543b..126bcff 100644
--- a/broadcastradio/aidl/default/VirtualRadio.cpp
+++ b/broadcastradio/aidl/default/VirtualRadio.cpp
@@ -53,15 +53,18 @@
static VirtualRadio amFmRadioMock(
"AM/FM radio mock",
{
- {makeSelectorAmfm(94900), "Wild 94.9", "Drake ft. Rihanna", "Too Good"},
- {makeSelectorAmfm(96500), "KOIT", "Celine Dion", "All By Myself"},
- {makeSelectorAmfm(97300), "Alice@97.3", "Drops of Jupiter", "Train"},
- {makeSelectorAmfm(99700), "99.7 Now!", "The Chainsmokers", "Closer"},
- {makeSelectorAmfm(101300), "101-3 KISS-FM", "Justin Timberlake", "Rock Your Body"},
- {makeSelectorAmfm(103700), "iHeart80s @ 103.7", "Michael Jackson", "Billie Jean"},
- {makeSelectorAmfm(106100), "106 KMEL", "Drake", "Marvins Room"},
- {makeSelectorAmfm(700), "700 AM", "Artist700", "Title700"},
- {makeSelectorAmfm(1700), "1700 AM", "Artist1700", "Title1700"},
+ {makeSelectorAmfm(/* frequency= */ 94900), "Wild 94.9", "Drake ft. Rihanna",
+ "Too Good"},
+ {makeSelectorAmfm(/* frequency= */ 96500), "KOIT", "Celine Dion", "All By Myself"},
+ {makeSelectorAmfm(/* frequency= */ 97300), "Alice@97.3", "Drops of Jupiter", "Train"},
+ {makeSelectorAmfm(/* frequency= */ 99700), "99.7 Now!", "The Chainsmokers", "Closer"},
+ {makeSelectorAmfm(/* frequency= */ 101300), "101-3 KISS-FM", "Justin Timberlake",
+ "Rock Your Body"},
+ {makeSelectorAmfm(/* frequency= */ 103700), "iHeart80s @ 103.7", "Michael Jackson",
+ "Billie Jean"},
+ {makeSelectorAmfm(/* frequency= */ 106100), "106 KMEL", "Drake", "Marvins Room"},
+ {makeSelectorAmfm(/* frequency= */ 700), "700 AM", "Artist700", "Title700"},
+ {makeSelectorAmfm(/* frequency= */ 1700), "1700 AM", "Artist1700", "Title1700"},
});
// clang-format on
return amFmRadioMock;
@@ -73,9 +76,14 @@
static VirtualRadio dabRadioMock(
"DAB radio mock",
{
- {makeSelectorDab(0xA00001u, 0x0001u), "BBC Radio 1", "Khalid", "Talk"},
- {makeSelectorDab(0xB00001u, 0x1001u), "Classic FM", "Jean Sibelius", "Andante Festivo"},
- {makeSelectorDab(0xB00002u, 0x1001u), "Absolute Radio", "Coldplay", "Clocks"},
+ {makeSelectorDab(/* sidExt= */ 0xA000000001u, /* ensemble= */ 0x0001u,
+ /* freq= */ 225648), "BBC Radio 1", "Khalid", "Talk"},
+ {makeSelectorDab(/* sidExt= */ 0xB000000001u, /* ensemble= */ 0x1001u,
+ /* freq= */ 222064), "Classic FM", "Jean Sibelius", "Andante Festivo"},
+ {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
+ /* freq= */ 227360), "Absolute Radio", "Coldplay", "Clocks"},
+ {makeSelectorDab(/* sidExt= */ 0xB000000002u, /* ensemble= */ 0x1002u,
+ /* freq= */ 222064), "Absolute Radio", "Coldplay", "Clocks"},
});
// clang-format on
return dabRadioMock;
diff --git a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
index 5a56846..356673f 100644
--- a/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
+++ b/broadcastradio/aidl/vts/src/VtsHalBroadcastradioAidlTargetTest.cpp
@@ -46,6 +46,7 @@
using ::aidl::android::hardware::broadcastradio::utils::makeIdentifier;
using ::aidl::android::hardware::broadcastradio::utils::makeSelectorAmfm;
+using ::aidl::android::hardware::broadcastradio::utils::makeSelectorDab;
using ::aidl::android::hardware::broadcastradio::utils::resultToInt;
using ::ndk::ScopedAStatus;
using ::ndk::SharedRefBase;
@@ -110,8 +111,7 @@
class TunerCallbackMock : public BnTunerCallback {
public:
TunerCallbackMock();
-
- MOCK_METHOD2(onTuneFailed, ScopedAStatus(Result, const ProgramSelector&));
+ ScopedAStatus onTuneFailed(Result result, const ProgramSelector& selector) override;
MOCK_TIMEOUT_METHOD1(onCurrentProgramInfoChangedMock, ScopedAStatus(const ProgramInfo&));
ScopedAStatus onCurrentProgramInfoChanged(const ProgramInfo& info) override;
ScopedAStatus onProgramListUpdated(const ProgramListChunk& chunk) override;
@@ -154,6 +154,12 @@
EXPECT_CALL(*this, onAntennaStateChange(false)).Times(0);
}
+ScopedAStatus TunerCallbackMock::onTuneFailed(Result result, const ProgramSelector& selector) {
+ LOG(DEBUG) << "Tune failed for selector" << selector.toString();
+ EXPECT_TRUE(result == Result::CANCELED);
+ return ndk::ScopedAStatus::ok();
+}
+
ScopedAStatus TunerCallbackMock::onCurrentProgramInfoChanged(const ProgramInfo& info) {
for (const auto& id : info.selector) {
EXPECT_NE(id.type, IdentifierType::INVALID);
@@ -175,7 +181,7 @@
IdentifierType physically = info.physicallyTunedTo.type;
// ditto (see "logically" above)
EXPECT_TRUE(physically == IdentifierType::AMFM_FREQUENCY_KHZ ||
- physically == IdentifierType::DAB_ENSEMBLE ||
+ physically == IdentifierType::DAB_FREQUENCY_KHZ ||
physically == IdentifierType::DRMO_FREQUENCY_KHZ ||
physically == IdentifierType::SXM_CHANNEL ||
(physically >= IdentifierType::VENDOR_START &&
@@ -593,10 +599,43 @@
ASSERT_TRUE(halResult.isOk());
ASSERT_NE(config.size(), 0U);
- // TODO(245787803): use a DAB frequency that can actually be tuned to.
+ auto programList = getProgramList();
+
+ if (!programList) {
+ printSkipped("Empty DAB station list, tune cannot be performed");
+ return;
+ }
+
ProgramSelector sel = {};
- int64_t freq = config[config.size() / 2].frequencyKhz;
- sel.primaryId = makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq);
+ uint64_t freq = 0;
+ bool dabStationPresent = false;
+ for (auto&& programInfo : *programList) {
+ if (!utils::hasId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ)) {
+ continue;
+ }
+ for (auto&& config_entry : config) {
+ if (config_entry.frequencyKhz ==
+ utils::getId(programInfo.selector, IdentifierType::DAB_FREQUENCY_KHZ, 0)) {
+ freq = config_entry.frequencyKhz;
+ break;
+ }
+ }
+ // Do not trigger a tune request if the programList entry does not contain
+ // a valid DAB frequency.
+ if (freq == 0) {
+ continue;
+ }
+ int64_t dabSidExt = utils::getId(programInfo.selector, IdentifierType::DAB_SID_EXT, 0);
+ int64_t dabEns = utils::getId(programInfo.selector, IdentifierType::DAB_ENSEMBLE, 0);
+ sel = makeSelectorDab(dabSidExt, (int32_t)dabEns, freq);
+ dabStationPresent = true;
+ break;
+ }
+
+ if (!dabStationPresent) {
+ printSkipped("No DAB stations in the list, tune cannot be performed");
+ return;
+ }
// try tuning
ProgramInfo infoCb = {};
@@ -623,7 +662,6 @@
vector<int> freqs = bcutils::getAllIds(infoCb.selector, IdentifierType::DAB_FREQUENCY_KHZ);
EXPECT_NE(freqs.end(), find(freqs.begin(), freqs.end(), freq))
<< "DAB freq " << freq << " kHz is not sent back by callback.";
- ;
}
/**
diff --git a/broadcastradio/common/utilsaidl/Utils.cpp b/broadcastradio/common/utilsaidl/Utils.cpp
index 52c7b40..ad82366 100644
--- a/broadcastradio/common/utilsaidl/Utils.cpp
+++ b/broadcastradio/common/utilsaidl/Utils.cpp
@@ -136,7 +136,9 @@
return getHdSubchannel(b) == 0 &&
haveEqualIds(a, b, IdentifierType::AMFM_FREQUENCY_KHZ);
case IdentifierType::DAB_SID_EXT:
- return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT);
+ return haveEqualIds(a, b, IdentifierType::DAB_SID_EXT) &&
+ haveEqualIds(a, b, IdentifierType::DAB_ENSEMBLE) &&
+ haveEqualIds(a, b, IdentifierType::DAB_FREQUENCY_KHZ);
case IdentifierType::DRMO_SERVICE_ID:
return haveEqualIds(a, b, IdentifierType::DRMO_SERVICE_ID);
case IdentifierType::SXM_SERVICE_ID:
@@ -241,8 +243,8 @@
break;
}
case IdentifierType::DAB_SID_EXT: {
- int64_t sid = val & 0xFFFF; // 16bit
- val >>= 16;
+ int64_t sid = val & 0xFFFFFFFF; // 32bit
+ val >>= 32;
int64_t ecc = val & 0xFF; // 8bit
expect(sid != 0u, "DAB SId != 0");
expect(ecc >= 0xA0u && ecc <= 0xF6u, "Invalid ECC, see ETSI TS 101 756 V2.1.1");
@@ -277,13 +279,35 @@
}
bool isValid(const ProgramSelector& sel) {
- // iterate through primaryId and secondaryIds
- for (auto it = begin(sel); it != end(sel); it++) {
+ if (sel.primaryId.type != IdentifierType::AMFM_FREQUENCY_KHZ &&
+ sel.primaryId.type != IdentifierType::RDS_PI &&
+ sel.primaryId.type != IdentifierType::HD_STATION_ID_EXT &&
+ sel.primaryId.type != IdentifierType::DAB_SID_EXT &&
+ sel.primaryId.type != IdentifierType::DRMO_SERVICE_ID &&
+ sel.primaryId.type != IdentifierType::SXM_SERVICE_ID &&
+ (sel.primaryId.type < IdentifierType::VENDOR_START ||
+ sel.primaryId.type > IdentifierType::VENDOR_END)) {
+ return false;
+ }
+ if (!isValid(sel.primaryId)) {
+ return false;
+ }
+
+ bool isDab = sel.primaryId.type == IdentifierType::DAB_SID_EXT;
+ bool hasDabEnsemble = false;
+ bool hasDabFrequency = false;
+ for (auto it = sel.secondaryIds.begin(); it != sel.secondaryIds.end(); it++) {
if (!isValid(*it)) {
return false;
}
+ if (isDab && it->type == IdentifierType::DAB_ENSEMBLE) {
+ hasDabEnsemble = true;
+ }
+ if (isDab && it->type == IdentifierType::DAB_FREQUENCY_KHZ) {
+ hasDabFrequency = true;
+ }
}
- return true;
+ return !isDab || (hasDabEnsemble && hasDabFrequency);
}
ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value) {
@@ -296,16 +320,12 @@
return sel;
}
-ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble) {
+ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq) {
ProgramSelector sel = {};
- // TODO(243686545): Have a helper function to create the sidExt instead of
- // passing the whole identifier here. Something like makeDabSidExt.
sel.primaryId = makeIdentifier(IdentifierType::DAB_SID_EXT, sidExt);
vector<ProgramIdentifier> secondaryIds = {
makeIdentifier(IdentifierType::DAB_ENSEMBLE, ensemble),
- // TODO(243686545): Include frequency here when the helper method to
- // translate between ensemble and frequency is implemented.
- };
+ makeIdentifier(IdentifierType::DAB_FREQUENCY_KHZ, freq)};
sel.secondaryIds = std::move(secondaryIds);
return sel;
}
@@ -330,10 +350,6 @@
}
}
- if (!filter.includeCategories && sel.primaryId.type == IdentifierType::DAB_ENSEMBLE) {
- return false;
- }
-
return true;
}
diff --git a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
index 8ea6319..beebd03 100644
--- a/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
+++ b/broadcastradio/common/utilsaidl/include/broadcastradio-utils-aidl/Utils.h
@@ -138,7 +138,7 @@
ProgramIdentifier makeIdentifier(IdentifierType type, int64_t value);
ProgramSelector makeSelectorAmfm(int32_t frequency);
-ProgramSelector makeSelectorDab(int32_t sidExt, int32_t ensemble);
+ProgramSelector makeSelectorDab(int64_t sidExt, int32_t ensemble, int64_t freq);
bool satisfies(const ProgramFilter& filter, const ProgramSelector& sel);
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
index b836dbe..b83eb2b 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -204,6 +204,7 @@
ANDROID_SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP_MAXIMUM_RESOLUTION = 851991,
ANDROID_SCALER_MULTI_RESOLUTION_STREAM_SUPPORTED = 851992,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
+ ANDROID_SCALER_RAW_CROP_REGION = 851995,
ANDROID_SENSOR_EXPOSURE_TIME = 917504,
ANDROID_SENSOR_FRAME_DURATION = 917505,
ANDROID_SENSOR_SENSITIVITY = 917506,
diff --git a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index bfa4f1a..958fa12 100644
--- a/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/aidl_api/android.hardware.camera.metadata/current/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -44,5 +44,6 @@
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 3,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 4,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 5,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 6,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 65536,
}
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
index 83e9230..671d69d 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/CameraMetadataTag.aidl
@@ -1284,6 +1284,13 @@
*/
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES = 851994,
/**
+ * android.scaler.rawCropRegion [dynamic, int32[], public]
+ *
+ * <p>The region of the sensor that corresponds to the RAW read out for this
+ * capture when the stream use case of a RAW stream is set to CROPPED_RAW.</p>
+ */
+ ANDROID_SCALER_RAW_CROP_REGION,
+ /**
* android.sensor.exposureTime [dynamic, int64, public]
*
* <p>Duration each pixel is exposed to
diff --git a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
index daa0fd3..da27a48 100644
--- a/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
+++ b/camera/metadata/aidl/android/hardware/camera/metadata/ScalerAvailableStreamUseCases.aidl
@@ -35,5 +35,6 @@
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3L,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4L,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5L,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 0x6L,
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000L,
}
diff --git a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
index 747ea33..4d4bb26 100644
--- a/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
+++ b/camera/provider/aidl/vts/VtsAidlHalCameraProvider_TargetTest.cpp
@@ -3035,115 +3035,22 @@
}
}
+TEST_P(CameraAidlTest, configureStreamsUseCasesCroppedRaw) {
+ AvailableStream rawStreamThreshold =
+ {INT_MAX, INT_MAX, static_cast<int32_t>(PixelFormat::RAW16)};
+ configureStreamUseCaseInternal(rawStreamThreshold);
+}
+
// Verify that valid stream use cases can be configured successfully, and invalid use cases
// fail stream configuration.
TEST_P(CameraAidlTest, configureStreamsUseCases) {
- std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
-
- for (const auto& name : cameraDeviceNames) {
- CameraMetadata meta;
- std::shared_ptr<ICameraDevice> cameraDevice;
-
- openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
- &cameraDevice /*out*/);
-
- camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
- // Check if camera support depth only
- if (isDepthOnly(staticMeta)) {
- ndk::ScopedAStatus ret = mSession->close();
- mSession = nullptr;
- ASSERT_TRUE(ret.isOk());
- continue;
- }
-
- std::vector<AvailableStream> outputPreviewStreams;
- AvailableStream previewThreshold = {kMaxPreviewWidth, kMaxPreviewHeight,
- static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
- ASSERT_EQ(Status::OK,
- getAvailableOutputStreams(staticMeta, outputPreviewStreams, &previewThreshold));
- ASSERT_NE(0u, outputPreviewStreams.size());
-
- // Combine valid and invalid stream use cases
- std::vector<int64_t> useCases(kMandatoryUseCases);
- useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL + 1);
-
- std::vector<int64_t> supportedUseCases;
- camera_metadata_ro_entry entry;
- auto retcode = find_camera_metadata_ro_entry(
- staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
- if ((0 == retcode) && (entry.count > 0)) {
- supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
- entry.data.i64 + entry.count);
- } else {
- supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
- }
-
- std::vector<Stream> streams(1);
- streams[0] = {0,
- StreamType::OUTPUT,
- outputPreviewStreams[0].width,
- outputPreviewStreams[0].height,
- static_cast<PixelFormat>(outputPreviewStreams[0].format),
- static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
- GRALLOC1_CONSUMER_USAGE_CPU_READ),
- Dataspace::UNKNOWN,
- StreamRotation::ROTATION_0,
- std::string(),
- 0,
- -1,
- {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
- RequestAvailableDynamicRangeProfilesMap::
- ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
-
- int32_t streamConfigCounter = 0;
- CameraMetadata req;
- StreamConfiguration config;
- RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
- ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &req);
- ASSERT_TRUE(ret.isOk());
- config.sessionParams = req;
-
- for (int64_t useCase : useCases) {
- bool useCaseSupported = std::find(supportedUseCases.begin(), supportedUseCases.end(),
- useCase) != supportedUseCases.end();
-
- streams[0].useCase = static_cast<
- aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases>(
- useCase);
- config.streams = streams;
- config.operationMode = StreamConfigurationMode::NORMAL_MODE;
- config.streamConfigCounter = streamConfigCounter;
- config.multiResolutionInputImage = false;
-
- bool combSupported;
- ret = cameraDevice->isStreamCombinationSupported(config, &combSupported);
- if (static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED) ==
- ret.getServiceSpecificError()) {
- continue;
- }
-
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(combSupported, useCaseSupported);
-
- std::vector<HalStream> halStreams;
- ret = mSession->configureStreams(config, &halStreams);
- ALOGI("configureStreams returns status: %d", ret.getServiceSpecificError());
- if (useCaseSupported) {
- ASSERT_TRUE(ret.isOk());
- ASSERT_EQ(1u, halStreams.size());
- } else {
- ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
- ret.getServiceSpecificError());
- }
- }
- ret = mSession->close();
- mSession = nullptr;
- ASSERT_TRUE(ret.isOk());
- }
+ AvailableStream previewStreamThreshold =
+ {kMaxPreviewWidth, kMaxPreviewHeight, static_cast<int32_t>(PixelFormat::YCBCR_420_888)};
+ configureStreamUseCaseInternal(previewStreamThreshold);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(CameraAidlTest);
INSTANTIATE_TEST_SUITE_P(
PerInstance, CameraAidlTest,
testing::ValuesIn(android::getAidlHalInstanceNames(ICameraProvider::descriptor)),
- android::hardware::PrintInstanceNameToString);
\ No newline at end of file
+ android::hardware::PrintInstanceNameToString);
diff --git a/camera/provider/aidl/vts/camera_aidl_test.cpp b/camera/provider/aidl/vts/camera_aidl_test.cpp
index b9e30ab..974223d 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.cpp
+++ b/camera/provider/aidl/vts/camera_aidl_test.cpp
@@ -321,8 +321,8 @@
if (entry.data.i64[i] == ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT) {
supportDefaultUseCase = true;
}
- ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL ||
- entry.data.i64[i] >=
+ ASSERT_TRUE(entry.data.i64[i] <= ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW
+ || entry.data.i64[i] >=
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START);
}
ASSERT_TRUE(supportDefaultUseCase);
@@ -2164,6 +2164,121 @@
}
}
+void CameraAidlTest::configureStreamUseCaseInternal(const AvailableStream &threshold) {
+ std::vector<std::string> cameraDeviceNames = getCameraDeviceNames(mProvider);
+
+ for (const auto& name : cameraDeviceNames) {
+ CameraMetadata meta;
+ std::shared_ptr<ICameraDevice> cameraDevice;
+
+ openEmptyDeviceSession(name, mProvider, &mSession /*out*/, &meta /*out*/,
+ &cameraDevice /*out*/);
+
+ camera_metadata_t* staticMeta = reinterpret_cast<camera_metadata_t*>(meta.metadata.data());
+ // Check if camera support depth only
+ if (isDepthOnly(staticMeta) ||
+ (threshold.format == static_cast<int32_t>(PixelFormat::RAW16) &&
+ !supportsCroppedRawUseCase(staticMeta))) {
+ ndk::ScopedAStatus ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+ continue;
+ }
+
+ std::vector<AvailableStream> outputPreviewStreams;
+
+ ASSERT_EQ(Status::OK,
+ getAvailableOutputStreams(staticMeta, outputPreviewStreams, &threshold));
+ ASSERT_NE(0u, outputPreviewStreams.size());
+
+ // Combine valid and invalid stream use cases
+ std::vector<int64_t> useCases(kMandatoryUseCases);
+ useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW + 1);
+
+ std::vector<int64_t> supportedUseCases;
+ if (threshold.format == static_cast<int32_t>(PixelFormat::RAW16)) {
+ // If the format is RAW16, supported use case is only CROPPED_RAW.
+ // All others are unsupported for this format.
+ useCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW);
+ supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW);
+ supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+ } else {
+ camera_metadata_ro_entry entry;
+ auto retcode = find_camera_metadata_ro_entry(
+ staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES, &entry);
+ if ((0 == retcode) && (entry.count > 0)) {
+ supportedUseCases.insert(supportedUseCases.end(), entry.data.i64,
+ entry.data.i64 + entry.count);
+ } else {
+ supportedUseCases.push_back(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT);
+ }
+ }
+
+ std::vector<Stream> streams(1);
+ streams[0] = {0,
+ StreamType::OUTPUT,
+ outputPreviewStreams[0].width,
+ outputPreviewStreams[0].height,
+ static_cast<PixelFormat>(outputPreviewStreams[0].format),
+ static_cast<::aidl::android::hardware::graphics::common::BufferUsage>(
+ GRALLOC1_CONSUMER_USAGE_CPU_READ),
+ Dataspace::UNKNOWN,
+ StreamRotation::ROTATION_0,
+ std::string(),
+ 0,
+ -1,
+ {SensorPixelMode::ANDROID_SENSOR_PIXEL_MODE_DEFAULT},
+ RequestAvailableDynamicRangeProfilesMap::
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD};
+
+ int32_t streamConfigCounter = 0;
+ CameraMetadata req;
+ StreamConfiguration config;
+ RequestTemplate reqTemplate = RequestTemplate::STILL_CAPTURE;
+ ndk::ScopedAStatus ret = mSession->constructDefaultRequestSettings(reqTemplate, &req);
+ ASSERT_TRUE(ret.isOk());
+ config.sessionParams = req;
+
+ for (int64_t useCase : useCases) {
+ bool useCaseSupported = std::find(supportedUseCases.begin(), supportedUseCases.end(),
+ useCase) != supportedUseCases.end();
+
+ streams[0].useCase = static_cast<
+ aidl::android::hardware::camera::metadata::ScalerAvailableStreamUseCases>(
+ useCase);
+ config.streams = streams;
+ config.operationMode = StreamConfigurationMode::NORMAL_MODE;
+ config.streamConfigCounter = streamConfigCounter;
+ config.multiResolutionInputImage = false;
+
+ bool combSupported;
+ ret = cameraDevice->isStreamCombinationSupported(config, &combSupported);
+ if (static_cast<int32_t>(Status::OPERATION_NOT_SUPPORTED) ==
+ ret.getServiceSpecificError()) {
+ continue;
+ }
+
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(combSupported, useCaseSupported);
+
+ std::vector<HalStream> halStreams;
+ ret = mSession->configureStreams(config, &halStreams);
+ ALOGI("configureStreams returns status: %d", ret.getServiceSpecificError());
+ if (useCaseSupported) {
+ ASSERT_TRUE(ret.isOk());
+ ASSERT_EQ(1u, halStreams.size());
+ } else {
+ ASSERT_EQ(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT),
+ ret.getServiceSpecificError());
+ }
+ }
+ ret = mSession->close();
+ mSession = nullptr;
+ ASSERT_TRUE(ret.isOk());
+ }
+
+}
+
void CameraAidlTest::configureSingleStream(
const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
const AvailableStream* previewThreshold, uint64_t bufferUsage, RequestTemplate reqTemplate,
@@ -3039,6 +3154,21 @@
return false;
}
+bool CameraAidlTest::supportsCroppedRawUseCase(const camera_metadata_t *staticMeta) {
+ camera_metadata_ro_entry availableStreamUseCasesEntry;
+ int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES,
+ &availableStreamUseCasesEntry);
+ if (rc == 0) {
+ for (size_t i = 0; i < availableStreamUseCasesEntry.count; i++) {
+ if (availableStreamUseCasesEntry.data.i64[i] ==
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool CameraAidlTest::isPerFrameControl(const camera_metadata_t* staticMeta) {
camera_metadata_ro_entry syncLatencyEntry;
int rc = find_camera_metadata_ro_entry(staticMeta, ANDROID_SYNC_MAX_LATENCY,
diff --git a/camera/provider/aidl/vts/camera_aidl_test.h b/camera/provider/aidl/vts/camera_aidl_test.h
index b6e398b..8b8a4bc 100644
--- a/camera/provider/aidl/vts/camera_aidl_test.h
+++ b/camera/provider/aidl/vts/camera_aidl_test.h
@@ -223,6 +223,8 @@
int32_t* partialResultCount /*out*/, bool* useHalBufManager /*out*/,
std::shared_ptr<DeviceCb>* cb /*out*/, uint32_t streamConfigCounter = 0);
+ void configureStreamUseCaseInternal(const AvailableStream &threshold);
+
void configureSingleStream(
const std::string& name, const std::shared_ptr<ICameraProvider>& provider,
const AvailableStream* previewThreshold, uint64_t bufferUsage,
@@ -410,6 +412,7 @@
int32_t frameCount, const bool *overrideSequence, const bool *expectedResults);
bool supportZoomSettingsOverride(const camera_metadata_t* staticMeta);
+ bool supportsCroppedRawUseCase(const camera_metadata_t *staticMeta);
bool isPerFrameControl(const camera_metadata_t* staticMeta);
protected:
diff --git a/common/fmq/aidl/Android.bp b/common/fmq/aidl/Android.bp
index 0715575..058ddb5 100644
--- a/common/fmq/aidl/Android.bp
+++ b/common/fmq/aidl/Android.bp
@@ -33,6 +33,7 @@
apex_available: [
"//apex_available:platform",
"com.android.btservices",
+ "com.android.media.swcodec",
],
min_sdk_version: "29",
},
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index b2433e9..e7bb282 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -268,7 +268,7 @@
</hal>
<hal format="aidl" optional="true">
<name>android.hardware.gnss</name>
- <version>3</version>
+ <version>2-3</version>
<interface>
<name>IGnss</name>
<instance>default</instance>
diff --git a/compatibility_matrices/exclude/fcm_exclude.cpp b/compatibility_matrices/exclude/fcm_exclude.cpp
index cf1e138..3c0c5f1 100644
--- a/compatibility_matrices/exclude/fcm_exclude.cpp
+++ b/compatibility_matrices/exclude/fcm_exclude.cpp
@@ -52,6 +52,7 @@
"android.hardware.radio.config@1.2",
// AIDL
"android.hardware.audio.common",
+ "android.hardware.audio.core.sounddose",
"android.hardware.biometrics.common",
"android.hardware.camera.metadata",
"android.hardware.camera.device",
diff --git a/input/processor/aidl/Android.bp b/input/processor/aidl/Android.bp
index 773bb49..f1a73d2 100644
--- a/input/processor/aidl/Android.bp
+++ b/input/processor/aidl/Android.bp
@@ -13,7 +13,7 @@
vendor_available: true,
srcs: ["android/hardware/input/processor/*.aidl"],
imports: [
- "android.hardware.input.common",
+ "android.hardware.input.common-V1",
],
stability: "vintf",
backend: {
diff --git a/media/bufferpool/aidl/Android.bp b/media/bufferpool/aidl/Android.bp
index 5ea2948..b01cdbe 100644
--- a/media/bufferpool/aidl/Android.bp
+++ b/media/bufferpool/aidl/Android.bp
@@ -40,6 +40,11 @@
},
ndk: {
enabled: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
},
},
}
diff --git a/media/bufferpool/aidl/default/Accessor.cpp b/media/bufferpool/aidl/default/Accessor.cpp
new file mode 100644
index 0000000..3d206ac
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.cpp
@@ -0,0 +1,509 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AidlBufferPoolAcc"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+
+#include "Accessor.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+ static constexpr nsecs_t kEvictGranularityNs = 1000000000; // 1 sec
+ static constexpr nsecs_t kEvictDurationNs = 5000000000; // 5 secs
+}
+
+#ifdef __ANDROID_VNDK__
+static constexpr uint32_t kSeqIdVndkBit = 1U << 31;
+#else
+static constexpr uint32_t kSeqIdVndkBit = 0;
+#endif
+
+static constexpr uint32_t kSeqIdMax = 0x7fffffff;
+uint32_t Accessor::sSeqId = time(nullptr) & kSeqIdMax;
+
+namespace {
+// anonymous namespace
+static std::shared_ptr<ConnectionDeathRecipient> sConnectionDeathRecipient =
+ std::make_shared<ConnectionDeathRecipient>();
+
+void serviceDied(void *cookie) {
+ if (sConnectionDeathRecipient) {
+ sConnectionDeathRecipient->onDead(cookie);
+ }
+}
+}
+
+std::shared_ptr<ConnectionDeathRecipient> Accessor::getConnectionDeathRecipient() {
+ return sConnectionDeathRecipient;
+}
+
+ConnectionDeathRecipient::ConnectionDeathRecipient() {
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(serviceDied));
+}
+
+void ConnectionDeathRecipient::add(
+ int64_t connectionId,
+ const std::shared_ptr<Accessor> &accessor) {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mAccessors.find(connectionId) == mAccessors.end()) {
+ mAccessors.insert(std::make_pair(connectionId, accessor));
+ }
+}
+
+void ConnectionDeathRecipient::remove(int64_t connectionId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mAccessors.erase(connectionId);
+ auto it = mConnectionToCookie.find(connectionId);
+ if (it != mConnectionToCookie.end()) {
+ void * cookie = it->second;
+ mConnectionToCookie.erase(it);
+ auto cit = mCookieToConnections.find(cookie);
+ if (cit != mCookieToConnections.end()) {
+ cit->second.erase(connectionId);
+ if (cit->second.size() == 0) {
+ mCookieToConnections.erase(cit);
+ }
+ }
+ }
+}
+
+void ConnectionDeathRecipient::addCookieToConnection(
+ void *cookie,
+ int64_t connectionId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ if (mAccessors.find(connectionId) == mAccessors.end()) {
+ return;
+ }
+ mConnectionToCookie.insert(std::make_pair(connectionId, cookie));
+ auto it = mCookieToConnections.find(cookie);
+ if (it != mCookieToConnections.end()) {
+ it->second.insert(connectionId);
+ } else {
+ mCookieToConnections.insert(std::make_pair(
+ cookie, std::set<int64_t>{connectionId}));
+ }
+}
+
+void ConnectionDeathRecipient::onDead(void *cookie) {
+ std::map<int64_t, const std::weak_ptr<Accessor>> connectionsToClose;
+ {
+ std::lock_guard<std::mutex> lock(mLock);
+
+ auto it = mCookieToConnections.find(cookie);
+ if (it != mCookieToConnections.end()) {
+ for (auto conIt = it->second.begin(); conIt != it->second.end(); ++conIt) {
+ auto accessorIt = mAccessors.find(*conIt);
+ if (accessorIt != mAccessors.end()) {
+ connectionsToClose.insert(std::make_pair(*conIt, accessorIt->second));
+ mAccessors.erase(accessorIt);
+ }
+ mConnectionToCookie.erase(*conIt);
+ }
+ mCookieToConnections.erase(it);
+ }
+ }
+
+ if (connectionsToClose.size() > 0) {
+ std::shared_ptr<Accessor> accessor;
+ for (auto it = connectionsToClose.begin(); it != connectionsToClose.end(); ++it) {
+ accessor = it->second.lock();
+
+ if (accessor) {
+ accessor->close(it->first);
+ ALOGD("connection %lld closed on death", (long long)it->first);
+ }
+ }
+ }
+}
+
+AIBinder_DeathRecipient *ConnectionDeathRecipient::getRecipient() {
+ return mDeathRecipient.get();
+}
+
+::ndk::ScopedAStatus Accessor::connect(const std::shared_ptr<::aidl::android::hardware::media::bufferpool2::IObserver>& in_observer, ::aidl::android::hardware::media::bufferpool2::IAccessor::ConnectionInfo* _aidl_return) {
+ std::shared_ptr<Connection> connection;
+ ConnectionId connectionId;
+ uint32_t msgId;
+ StatusDescriptor statusDesc;
+ InvalidationDescriptor invDesc;
+ BufferPoolStatus status = connect(
+ in_observer, false, &connection, &connectionId, &msgId, &statusDesc, &invDesc);
+ if (status == ResultStatus::OK) {
+ _aidl_return->connection = connection;
+ _aidl_return->connectionId = connectionId;
+ _aidl_return->msgId = msgId;
+ _aidl_return->toFmqDesc = std::move(statusDesc);
+ _aidl_return->fromFmqDesc = std::move(invDesc);
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+}
+
+Accessor::Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator)
+ : mAllocator(allocator), mScheduleEvictTs(0) {}
+
+Accessor::~Accessor() {
+}
+
+bool Accessor::isValid() {
+ return mBufferPool.isValid();
+}
+
+BufferPoolStatus Accessor::flush() {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.flush(ref<Accessor>());
+ return ResultStatus::OK;
+}
+
+BufferPoolStatus Accessor::allocate(
+ ConnectionId connectionId,
+ const std::vector<uint8_t> ¶ms,
+ BufferId *bufferId, const native_handle_t** handle) {
+ std::unique_lock<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ BufferPoolStatus status = ResultStatus::OK;
+ if (!mBufferPool.getFreeBuffer(mAllocator, params, bufferId, handle)) {
+ lock.unlock();
+ std::shared_ptr<BufferPoolAllocation> alloc;
+ size_t allocSize;
+ status = mAllocator->allocate(params, &alloc, &allocSize);
+ lock.lock();
+ if (status == ResultStatus::OK) {
+ status = mBufferPool.addNewBuffer(alloc, allocSize, params, bufferId, handle);
+ }
+ ALOGV("create a buffer %d : %u %p",
+ status == ResultStatus::OK, *bufferId, *handle);
+ }
+ if (status == ResultStatus::OK) {
+ // TODO: handle ownBuffer failure
+ mBufferPool.handleOwnBuffer(connectionId, *bufferId);
+ }
+ mBufferPool.cleanUp();
+ scheduleEvictIfNeeded();
+ return status;
+}
+
+BufferPoolStatus Accessor::fetch(
+ ConnectionId connectionId, TransactionId transactionId,
+ BufferId bufferId, const native_handle_t** handle) {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ auto found = mBufferPool.mTransactions.find(transactionId);
+ if (found != mBufferPool.mTransactions.end() &&
+ contains(&mBufferPool.mPendingTransactions,
+ connectionId, transactionId)) {
+ if (found->second->mSenderValidated &&
+ found->second->mStatus == BufferStatus::TRANSFER_FROM &&
+ found->second->mBufferId == bufferId) {
+ found->second->mStatus = BufferStatus::TRANSFER_FETCH;
+ auto bufferIt = mBufferPool.mBuffers.find(bufferId);
+ if (bufferIt != mBufferPool.mBuffers.end()) {
+ mBufferPool.mStats.onBufferFetched();
+ *handle = bufferIt->second->handle();
+ return ResultStatus::OK;
+ }
+ }
+ }
+ mBufferPool.cleanUp();
+ scheduleEvictIfNeeded();
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Accessor::connect(
+ const std::shared_ptr<IObserver> &observer, bool local,
+ std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ StatusDescriptor* statusDescPtr,
+ InvalidationDescriptor* invDescPtr) {
+ std::shared_ptr<Connection> newConnection = ::ndk::SharedRefBase::make<Connection>();
+ BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+ {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ if (newConnection) {
+ int32_t pid = getpid();
+ ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+ status = mBufferPool.mObserver.open(id, statusDescPtr);
+ if (status == ResultStatus::OK) {
+ newConnection->initialize(ref<Accessor>(), id);
+ *connection = newConnection;
+ *pConnectionId = id;
+ *pMsgId = mBufferPool.mInvalidation.mInvalidationId;
+ mBufferPool.mConnectionIds.insert(id);
+ mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
+ mBufferPool.mInvalidation.onConnect(id, observer);
+ if (sSeqId == kSeqIdMax) {
+ sSeqId = 0;
+ } else {
+ ++sSeqId;
+ }
+ }
+
+ }
+ mBufferPool.processStatusMessages();
+ mBufferPool.cleanUp();
+ scheduleEvictIfNeeded();
+ }
+ if (!local && status == ResultStatus::OK) {
+ std::shared_ptr<Accessor> accessor(ref<Accessor>());
+ sConnectionDeathRecipient->add(*pConnectionId, accessor);
+ }
+ return status;
+}
+
+BufferPoolStatus Accessor::close(ConnectionId connectionId) {
+ {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ ALOGV("connection close %lld: %u", (long long)connectionId, mBufferPool.mInvalidation.mId);
+ mBufferPool.processStatusMessages();
+ mBufferPool.handleClose(connectionId);
+ mBufferPool.mObserver.close(connectionId);
+ mBufferPool.mInvalidation.onClose(connectionId);
+ // Since close# will be called after all works are finished, it is OK to
+ // evict unused buffers.
+ mBufferPool.cleanUp(true);
+ scheduleEvictIfNeeded();
+ }
+ sConnectionDeathRecipient->remove(connectionId);
+ return ResultStatus::OK;
+}
+
+void Accessor::cleanUp(bool clearCache) {
+ // transaction timeout, buffer caching TTL handling
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.cleanUp(clearCache);
+}
+
+void Accessor::handleInvalidateAck() {
+ std::map<ConnectionId, const std::shared_ptr<IObserver>> observers;
+ uint32_t invalidationId;
+ {
+ std::lock_guard<std::mutex> lock(mBufferPool.mMutex);
+ mBufferPool.processStatusMessages();
+ mBufferPool.mInvalidation.onHandleAck(&observers, &invalidationId);
+ }
+ // Do not hold lock for send invalidations
+ size_t deadClients = 0;
+ for (auto it = observers.begin(); it != observers.end(); ++it) {
+ const std::shared_ptr<IObserver> observer = it->second;
+ if (observer) {
+ ::ndk::ScopedAStatus status = observer->onMessage(it->first, invalidationId);
+ if (!status.isOk()) {
+ ++deadClients;
+ }
+ }
+ }
+ if (deadClients > 0) {
+ ALOGD("During invalidation found %zu dead clients", deadClients);
+ }
+}
+
+void Accessor::invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready) {
+ constexpr uint32_t NUM_SPIN_TO_INCREASE_SLEEP = 1024;
+ constexpr uint32_t NUM_SPIN_TO_LOG = 1024*8;
+ constexpr useconds_t MAX_SLEEP_US = 10000;
+ uint32_t numSpin = 0;
+ useconds_t sleepUs = 1;
+
+ while(true) {
+ std::map<uint32_t, const std::weak_ptr<Accessor>> copied;
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ while (!ready) {
+ numSpin = 0;
+ sleepUs = 1;
+ cv.wait(lock);
+ }
+ copied.insert(accessors.begin(), accessors.end());
+ }
+ std::list<ConnectionId> erased;
+ for (auto it = copied.begin(); it != copied.end(); ++it) {
+ const std::shared_ptr<Accessor> acc = it->second.lock();
+ if (!acc) {
+ erased.push_back(it->first);
+ } else {
+ acc->handleInvalidateAck();
+ }
+ }
+ {
+ std::unique_lock<std::mutex> lock(mutex);
+ for (auto it = erased.begin(); it != erased.end(); ++it) {
+ accessors.erase(*it);
+ }
+ if (accessors.size() == 0) {
+ ready = false;
+ } else {
+ // N.B. Since there is not a efficient way to wait over FMQ,
+ // polling over the FMQ is the current way to prevent draining
+ // CPU.
+ lock.unlock();
+ ++numSpin;
+ if (numSpin % NUM_SPIN_TO_INCREASE_SLEEP == 0 &&
+ sleepUs < MAX_SLEEP_US) {
+ sleepUs *= 10;
+ }
+ if (numSpin % NUM_SPIN_TO_LOG == 0) {
+ ALOGW("invalidator thread spinning");
+ }
+ ::usleep(sleepUs);
+ }
+ }
+ }
+}
+
+Accessor::AccessorInvalidator::AccessorInvalidator() : mReady(false) {
+ std::thread invalidator(
+ invalidatorThread,
+ std::ref(mAccessors),
+ std::ref(mMutex),
+ std::ref(mCv),
+ std::ref(mReady));
+ invalidator.detach();
+}
+
+void Accessor::AccessorInvalidator::addAccessor(
+ uint32_t accessorId, const std::weak_ptr<Accessor> &accessor) {
+ bool notify = false;
+ std::unique_lock<std::mutex> lock(mMutex);
+ if (mAccessors.find(accessorId) == mAccessors.end()) {
+ if (!mReady) {
+ mReady = true;
+ notify = true;
+ }
+ mAccessors.emplace(accessorId, accessor);
+ ALOGV("buffer invalidation added bp:%u %d", accessorId, notify);
+ }
+ lock.unlock();
+ if (notify) {
+ mCv.notify_one();
+ }
+}
+
+void Accessor::AccessorInvalidator::delAccessor(uint32_t accessorId) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mAccessors.erase(accessorId);
+ ALOGV("buffer invalidation deleted bp:%u", accessorId);
+ if (mAccessors.size() == 0) {
+ mReady = false;
+ }
+}
+
+std::unique_ptr<Accessor::AccessorInvalidator> Accessor::sInvalidator;
+
+void Accessor::createInvalidator() {
+ if (!sInvalidator) {
+ sInvalidator = std::make_unique<Accessor::AccessorInvalidator>();
+ }
+}
+
+void Accessor::evictorThread(
+ std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv) {
+ std::list<const std::weak_ptr<Accessor>> evictList;
+ while (true) {
+ int expired = 0;
+ int evicted = 0;
+ {
+ nsecs_t now = systemTime();
+ std::unique_lock<std::mutex> lock(mutex);
+ while (accessors.size() == 0) {
+ cv.wait(lock);
+ }
+ auto it = accessors.begin();
+ while (it != accessors.end()) {
+ if (now > (it->second + kEvictDurationNs)) {
+ ++expired;
+ evictList.push_back(it->first);
+ it = accessors.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ // evict idle accessors;
+ for (auto it = evictList.begin(); it != evictList.end(); ++it) {
+ const std::shared_ptr<Accessor> accessor = it->lock();
+ if (accessor) {
+ accessor->cleanUp(true);
+ ++evicted;
+ }
+ }
+ if (expired > 0) {
+ ALOGD("evictor expired: %d, evicted: %d", expired, evicted);
+ }
+ evictList.clear();
+ ::usleep(kEvictGranularityNs / 1000);
+ }
+}
+
+Accessor::AccessorEvictor::AccessorEvictor() {
+ std::thread evictor(
+ evictorThread,
+ std::ref(mAccessors),
+ std::ref(mMutex),
+ std::ref(mCv));
+ evictor.detach();
+}
+
+void Accessor::AccessorEvictor::addAccessor(
+ const std::weak_ptr<Accessor> &accessor, nsecs_t ts) {
+ std::lock_guard<std::mutex> lock(mMutex);
+ bool notify = mAccessors.empty();
+ auto it = mAccessors.find(accessor);
+ if (it == mAccessors.end()) {
+ mAccessors.emplace(accessor, ts);
+ } else {
+ it->second = ts;
+ }
+ if (notify) {
+ mCv.notify_one();
+ }
+}
+
+std::unique_ptr<Accessor::AccessorEvictor> Accessor::sEvictor;
+
+void Accessor::createEvictor() {
+ if (!sEvictor) {
+ sEvictor = std::make_unique<Accessor::AccessorEvictor>();
+ }
+}
+
+void Accessor::scheduleEvictIfNeeded() {
+ nsecs_t now = systemTime();
+
+ if (now > (mScheduleEvictTs + kEvictGranularityNs)) {
+ mScheduleEvictTs = now;
+ sEvictor->addAccessor(ref<Accessor>(), now);
+ }
+}
+
+} // namespace aidl::android::hardware::media::bufferpool2::implemntation {
diff --git a/media/bufferpool/aidl/default/Accessor.h b/media/bufferpool/aidl/default/Accessor.h
new file mode 100644
index 0000000..85e2fa7
--- /dev/null
+++ b/media/bufferpool/aidl/default/Accessor.h
@@ -0,0 +1,238 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/BnAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <memory>
+#include <map>
+#include <set>
+#include <condition_variable>
+
+#include "BufferPool.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Connection;
+using ::aidl::android::hardware::media::bufferpool2::IObserver;
+using ::aidl::android::hardware::media::bufferpool2::IAccessor;
+
+/**
+ * Receives death notifications from remote connections.
+ * On death notifications, the connections are closed and used resources
+ * are released.
+ */
+struct ConnectionDeathRecipient {
+ ConnectionDeathRecipient();
+ /**
+ * Registers a newly connected connection from remote processes.
+ */
+ void add(int64_t connectionId, const std::shared_ptr<Accessor> &accessor);
+
+ /**
+ * Removes a connection.
+ */
+ void remove(int64_t connectionId);
+
+ void addCookieToConnection(void *cookie, int64_t connectionId);
+
+ void onDead(void *cookie);
+
+ AIBinder_DeathRecipient *getRecipient();
+
+private:
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ std::mutex mLock;
+ std::map<void *, std::set<int64_t>> mCookieToConnections;
+ std::map<int64_t, void *> mConnectionToCookie;
+ std::map<int64_t, const std::weak_ptr<Accessor>> mAccessors;
+};
+
+/**
+ * A buffer pool accessor which enables a buffer pool to communicate with buffer
+ * pool clients. 1:1 correspondense holds between a buffer pool and an accessor.
+ */
+struct Accessor : public BnAccessor {
+ // Methods from ::aidl::android::hardware::media::bufferpool2::IAccessor.
+ ::ndk::ScopedAStatus connect(const std::shared_ptr<IObserver>& in_observer,
+ IAccessor::ConnectionInfo* _aidl_return) override;
+
+ /**
+ * Creates a buffer pool accessor which uses the specified allocator.
+ *
+ * @param allocator buffer allocator.
+ */
+ explicit Accessor(const std::shared_ptr<BufferPoolAllocator> &allocator);
+
+ /** Destructs a buffer pool accessor. */
+ ~Accessor();
+
+ /** Returns whether the accessor is valid. */
+ bool isValid();
+
+ /** Invalidates all buffers which are owned by bufferpool */
+ BufferPoolStatus flush();
+
+ /** Allocates a buffer from a buffer pool.
+ *
+ * @param connectionId the connection id of the client.
+ * @param params the allocation parameters.
+ * @param bufferId the id of the allocated buffer.
+ * @param handle the native handle of the allocated buffer.
+ *
+ * @return OK when a buffer is successfully allocated.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus allocate(
+ ConnectionId connectionId,
+ const std::vector<uint8_t>& params,
+ BufferId *bufferId,
+ const native_handle_t** handle);
+
+ /**
+ * Fetches a buffer for the specified transaction.
+ *
+ * @param connectionId the id of receiving connection(client).
+ * @param transactionId the id of the transfer transaction.
+ * @param bufferId the id of the buffer to be fetched.
+ * @param handle the native handle of the fetched buffer.
+ *
+ * @return OK when a buffer is successfully fetched.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus fetch(
+ ConnectionId connectionId,
+ TransactionId transactionId,
+ BufferId bufferId,
+ const native_handle_t** handle);
+
+ /**
+ * Makes a connection to the buffer pool. The buffer pool client uses the
+ * created connection in order to communicate with the buffer pool. An
+ * FMQ for buffer status message is also created for the client.
+ *
+ * @param observer client observer for buffer invalidation
+ * @param local true when a connection request comes from local process,
+ * false otherwise.
+ * @param connection created connection
+ * @param pConnectionId the id of the created connection
+ * @param pMsgId the id of the recent buffer pool message
+ * @param statusDescPtr FMQ descriptor for shared buffer status message
+ * queue between a buffer pool and the client.
+ * @param invDescPtr FMQ descriptor for buffer invalidation message
+ * queue from a buffer pool to the client.
+ *
+ * @return OK when a connection is successfully made.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus connect(
+ const std::shared_ptr<IObserver>& observer,
+ bool local,
+ std::shared_ptr<Connection> *connection, ConnectionId *pConnectionId,
+ uint32_t *pMsgId,
+ StatusDescriptor* statusDescPtr,
+ InvalidationDescriptor* invDescPtr);
+
+ /**
+ * Closes the specified connection to the client.
+ *
+ * @param connectionId the id of the connection.
+ *
+ * @return OK when the connection is closed.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus close(ConnectionId connectionId);
+
+ /**
+ * Processes pending buffer status messages and performs periodic cache
+ * cleaning.
+ *
+ * @param clearCache if clearCache is true, it frees all buffers waiting
+ * to be recycled.
+ */
+ void cleanUp(bool clearCache);
+
+ /**
+ * ACK on buffer invalidation messages
+ */
+ void handleInvalidateAck();
+
+ /**
+ * Gets a death_recipient for remote connection death.
+ */
+ static std::shared_ptr<ConnectionDeathRecipient> getConnectionDeathRecipient();
+
+ static void createInvalidator();
+
+ static void createEvictor();
+
+private:
+ // ConnectionId = pid : (timestamp_created + seqId)
+ // in order to guarantee uniqueness for each connection
+ static uint32_t sSeqId;
+
+ const std::shared_ptr<BufferPoolAllocator> mAllocator;
+ nsecs_t mScheduleEvictTs;
+ BufferPool mBufferPool;
+
+ struct AccessorInvalidator {
+ std::map<uint32_t, const std::weak_ptr<Accessor>> mAccessors;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+ bool mReady;
+
+ AccessorInvalidator();
+ void addAccessor(uint32_t accessorId, const std::weak_ptr<Accessor> &accessor);
+ void delAccessor(uint32_t accessorId);
+ };
+
+ static std::unique_ptr<AccessorInvalidator> sInvalidator;
+
+ static void invalidatorThread(
+ std::map<uint32_t, const std::weak_ptr<Accessor>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv,
+ bool &ready);
+
+ struct AccessorEvictor {
+ std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> mAccessors;
+ std::mutex mMutex;
+ std::condition_variable mCv;
+
+ AccessorEvictor();
+ void addAccessor(const std::weak_ptr<Accessor> &accessor, nsecs_t ts);
+ };
+
+ static std::unique_ptr<AccessorEvictor> sEvictor;
+
+ static void evictorThread(
+ std::map<const std::weak_ptr<Accessor>, nsecs_t, std::owner_less<>> &accessors,
+ std::mutex &mutex,
+ std::condition_variable &cv);
+
+ void scheduleEvictIfNeeded();
+
+ friend struct BufferPool;
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Android.bp b/media/bufferpool/aidl/default/Android.bp
new file mode 100644
index 0000000..11a6163
--- /dev/null
+++ b/media/bufferpool/aidl/default/Android.bp
@@ -0,0 +1,50 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_library {
+ name: "libstagefright_aidl_bufferpool2",
+ vendor_available: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ "test_com.android.media.swcodec",
+ ],
+ srcs: [
+ "Accessor.cpp",
+ "BufferPool.cpp",
+ "BufferPoolClient.cpp",
+ "BufferStatus.cpp",
+ "ClientManager.cpp",
+ "Connection.cpp",
+ "Observer.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "android.hardware.media.bufferpool2-V1-ndk",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ ],
+ export_shared_lib_headers: [
+ "libfmq",
+ "android.hardware.media.bufferpool2-V1-ndk",
+ ],
+ double_loadable: true,
+ cflags: [
+ "-DBUFFERPOOL_CLONE_HANDLES",
+ ],
+}
diff --git a/media/bufferpool/aidl/default/BufferPool.cpp b/media/bufferpool/aidl/default/BufferPool.cpp
new file mode 100644
index 0000000..ed4574f
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.cpp
@@ -0,0 +1,540 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlBufferPool"
+//#define LOG_NDEBUG 0
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <time.h>
+#include <unistd.h>
+#include <utils/Log.h>
+#include <thread>
+#include "Accessor.h"
+#include "BufferPool.h"
+#include "Connection.h"
+#include "DataHelper.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+namespace {
+ static constexpr int64_t kCleanUpDurationMs = 500; // 0.5 sec
+ static constexpr int64_t kLogDurationMs = 5000; // 5 secs
+
+ static constexpr size_t kMinAllocBytesForEviction = 1024*1024*15;
+ static constexpr size_t kMinBufferCountForEviction = 25;
+ static constexpr size_t kMaxUnusedBufferCount = 64;
+ static constexpr size_t kUnusedBufferCountTarget = kMaxUnusedBufferCount - 16;
+}
+
+BufferPool::BufferPool()
+ : mTimestampMs(::android::elapsedRealtime()),
+ mLastCleanUpMs(mTimestampMs),
+ mLastLogMs(mTimestampMs),
+ mSeq(0),
+ mStartSeq(0) {
+ mValid = mInvalidationChannel.isValid();
+}
+
+
+// Statistics helper
+template<typename T, typename S>
+int percentage(T base, S total) {
+ return int(total ? 0.5 + 100. * static_cast<S>(base) / total : 0);
+}
+
+std::atomic<std::uint32_t> BufferPool::Invalidation::sInvSeqId(0);
+
+BufferPool::~BufferPool() {
+ std::lock_guard<std::mutex> lock(mMutex);
+ ALOGD("Destruction - bufferpool2 %p "
+ "cached: %zu/%zuM, %zu/%d%% in use; "
+ "allocs: %zu, %d%% recycled; "
+ "transfers: %zu, %d%% unfetched",
+ this, mStats.mBuffersCached, mStats.mSizeCached >> 20,
+ mStats.mBuffersInUse, percentage(mStats.mBuffersInUse, mStats.mBuffersCached),
+ mStats.mTotalAllocations, percentage(mStats.mTotalRecycles, mStats.mTotalAllocations),
+ mStats.mTotalTransfers,
+ percentage(mStats.mTotalTransfers - mStats.mTotalFetches, mStats.mTotalTransfers));
+}
+
+void BufferPool::Invalidation::onConnect(
+ ConnectionId conId, const std::shared_ptr<IObserver>& observer) {
+ mAcks[conId] = mInvalidationId; // starts from current invalidationId
+ mObservers.insert(std::make_pair(conId, observer));
+}
+
+void BufferPool::Invalidation::onClose(ConnectionId conId) {
+ mAcks.erase(conId);
+ mObservers.erase(conId);
+}
+
+void BufferPool::Invalidation::onAck(
+ ConnectionId conId,
+ uint32_t msgId) {
+ auto it = mAcks.find(conId);
+ if (it == mAcks.end()) {
+ ALOGW("ACK from inconsistent connection! %lld", (long long)conId);
+ return;
+ }
+ if (isMessageLater(msgId, it->second)) {
+ mAcks[conId] = msgId;
+ }
+}
+
+void BufferPool::Invalidation::onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel) {
+ for (auto it = mPendings.begin(); it != mPendings.end();) {
+ if (it->isInvalidated(bufferId)) {
+ uint32_t msgId = 0;
+ if (it->mNeedsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ channel.postInvalidation(msgId, it->mFrom, it->mTo);
+ it = mPendings.erase(it);
+ continue;
+ }
+ ++it;
+ }
+}
+
+void BufferPool::Invalidation::onInvalidationRequest(
+ bool needsAck,
+ uint32_t from,
+ uint32_t to,
+ size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor> &impl) {
+ uint32_t msgId = 0;
+ if (needsAck) {
+ msgId = ++mInvalidationId;
+ if (msgId == 0) {
+ // wrap happens
+ msgId = ++mInvalidationId;
+ }
+ }
+ ALOGV("bufferpool2 invalidation requested and queued");
+ if (left == 0) {
+ channel.postInvalidation(msgId, from, to);
+ } else {
+ ALOGV("bufferpoo2 invalidation requested and pending");
+ Pending pending(needsAck, from, to, left, impl);
+ mPendings.push_back(pending);
+ }
+ Accessor::sInvalidator->addAccessor(mId, impl);
+}
+
+void BufferPool::Invalidation::onHandleAck(
+ std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+ uint32_t *invalidationId) {
+ if (mInvalidationId != 0) {
+ *invalidationId = mInvalidationId;
+ std::set<int> deads;
+ for (auto it = mAcks.begin(); it != mAcks.end(); ++it) {
+ if (it->second != mInvalidationId) {
+ const std::shared_ptr<IObserver> observer = mObservers[it->first];
+ if (observer) {
+ observers->emplace(it->first, observer);
+ ALOGV("connection %lld will call observer (%u: %u)",
+ (long long)it->first, it->second, mInvalidationId);
+ // N.B: onMessage will be called later. ignore possibility of
+ // onMessage# oneway call being lost.
+ it->second = mInvalidationId;
+ } else {
+ ALOGV("bufferpool2 observer died %lld", (long long)it->first);
+ deads.insert(it->first);
+ }
+ }
+ }
+ if (deads.size() > 0) {
+ for (auto it = deads.begin(); it != deads.end(); ++it) {
+ onClose(*it);
+ }
+ }
+ }
+ if (mPendings.size() == 0) {
+ // All invalidation Ids are synced and no more pending invalidations.
+ Accessor::sInvalidator->delAccessor(mId);
+ }
+}
+
+bool BufferPool::handleOwnBuffer(
+ ConnectionId connectionId, BufferId bufferId) {
+
+ bool added = insert(&mUsingBuffers, connectionId, bufferId);
+ if (added) {
+ auto iter = mBuffers.find(bufferId);
+ iter->second->mOwnerCount++;
+ }
+ insert(&mUsingConnections, bufferId, connectionId);
+ return added;
+}
+
+bool BufferPool::handleReleaseBuffer(
+ ConnectionId connectionId, BufferId bufferId) {
+ bool deleted = erase(&mUsingBuffers, connectionId, bufferId);
+ if (deleted) {
+ auto iter = mBuffers.find(bufferId);
+ iter->second->mOwnerCount--;
+ if (iter->second->mOwnerCount == 0 &&
+ iter->second->mTransactionCount == 0) {
+ if (!iter->second->mInvalidated) {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(iter->second->mAllocSize);
+ mStats.onBufferEvicted(iter->second->mAllocSize);
+ mBuffers.erase(iter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
+ }
+ }
+ erase(&mUsingConnections, bufferId, connectionId);
+ ALOGV("release buffer %u : %d", bufferId, deleted);
+ return deleted;
+}
+
+bool BufferPool::handleTransferTo(const BufferStatusMessage &message) {
+ auto completed = mCompletedTransactions.find(
+ message.transactionId);
+ if (completed != mCompletedTransactions.end()) {
+ // already completed
+ mCompletedTransactions.erase(completed);
+ return true;
+ }
+ // the buffer should exist and be owned.
+ auto bufferIter = mBuffers.find(message.bufferId);
+ if (bufferIter == mBuffers.end() ||
+ !contains(&mUsingBuffers, message.connectionId, FromAidl(message.bufferId))) {
+ return false;
+ }
+ auto found = mTransactions.find(message.transactionId);
+ if (found != mTransactions.end()) {
+ // transfer_from was received earlier.
+ found->second->mSender = message.connectionId;
+ found->second->mSenderValidated = true;
+ return true;
+ }
+ if (mConnectionIds.find(message.targetConnectionId) == mConnectionIds.end()) {
+ // N.B: it could be fake or receive connection already closed.
+ ALOGD("bufferpool2 %p receiver connection %lld is no longer valid",
+ this, (long long)message.targetConnectionId);
+ return false;
+ }
+ mStats.onBufferSent();
+ mTransactions.insert(std::make_pair(
+ message.transactionId,
+ std::make_unique<TransactionStatus>(message, mTimestampMs)));
+ insert(&mPendingTransactions, message.targetConnectionId,
+ FromAidl(message.transactionId));
+ bufferIter->second->mTransactionCount++;
+ return true;
+}
+
+bool BufferPool::handleTransferFrom(const BufferStatusMessage &message) {
+ auto found = mTransactions.find(message.transactionId);
+ if (found == mTransactions.end()) {
+ // TODO: is it feasible to check ownership here?
+ mStats.onBufferSent();
+ mTransactions.insert(std::make_pair(
+ message.transactionId,
+ std::make_unique<TransactionStatus>(message, mTimestampMs)));
+ insert(&mPendingTransactions, message.connectionId,
+ FromAidl(message.transactionId));
+ auto bufferIter = mBuffers.find(message.bufferId);
+ bufferIter->second->mTransactionCount++;
+ } else {
+ if (message.connectionId == found->second->mReceiver) {
+ found->second->mStatus = BufferStatus::TRANSFER_FROM;
+ }
+ }
+ return true;
+}
+
+bool BufferPool::handleTransferResult(const BufferStatusMessage &message) {
+ auto found = mTransactions.find(message.transactionId);
+ if (found != mTransactions.end()) {
+ bool deleted = erase(&mPendingTransactions, message.connectionId,
+ FromAidl(message.transactionId));
+ if (deleted) {
+ if (!found->second->mSenderValidated) {
+ mCompletedTransactions.insert(message.transactionId);
+ }
+ auto bufferIter = mBuffers.find(message.bufferId);
+ if (message.status == BufferStatus::TRANSFER_OK) {
+ handleOwnBuffer(message.connectionId, message.bufferId);
+ }
+ bufferIter->second->mTransactionCount--;
+ if (bufferIter->second->mOwnerCount == 0
+ && bufferIter->second->mTransactionCount == 0) {
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(message.bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(message.bufferId, mInvalidationChannel);
+ }
+ }
+ mTransactions.erase(found);
+ }
+ ALOGV("transfer finished %llu %u - %d", (unsigned long long)message.transactionId,
+ message.bufferId, deleted);
+ return deleted;
+ }
+ ALOGV("transfer not found %llu %u", (unsigned long long)message.transactionId,
+ message.bufferId);
+ return false;
+}
+
+void BufferPool::processStatusMessages() {
+ std::vector<BufferStatusMessage> messages;
+ mObserver.getBufferStatusChanges(messages);
+ mTimestampMs = ::android::elapsedRealtime();
+ for (BufferStatusMessage& message: messages) {
+ bool ret = false;
+ switch (message.status) {
+ case BufferStatus::NOT_USED:
+ ret = handleReleaseBuffer(
+ message.connectionId, message.bufferId);
+ break;
+ case BufferStatus::USED:
+ // not happening
+ break;
+ case BufferStatus::TRANSFER_TO:
+ ret = handleTransferTo(message);
+ break;
+ case BufferStatus::TRANSFER_FROM:
+ ret = handleTransferFrom(message);
+ break;
+ case BufferStatus::TRANSFER_TIMEOUT:
+ // TODO
+ break;
+ case BufferStatus::TRANSFER_LOST:
+ // TODO
+ break;
+ case BufferStatus::TRANSFER_FETCH:
+ // not happening
+ break;
+ case BufferStatus::TRANSFER_OK:
+ case BufferStatus::TRANSFER_ERROR:
+ ret = handleTransferResult(message);
+ break;
+ case BufferStatus::INVALIDATION_ACK:
+ mInvalidation.onAck(message.connectionId, message.bufferId);
+ ret = true;
+ break;
+ }
+ if (ret == false) {
+ ALOGW("buffer status message processing failure - message : %d connection : %lld",
+ message.status, (long long)message.connectionId);
+ }
+ }
+ messages.clear();
+}
+
+bool BufferPool::handleClose(ConnectionId connectionId) {
+ // Cleaning buffers
+ auto buffers = mUsingBuffers.find(connectionId);
+ if (buffers != mUsingBuffers.end()) {
+ for (const BufferId& bufferId : buffers->second) {
+ bool deleted = erase(&mUsingConnections, bufferId, connectionId);
+ if (deleted) {
+ auto bufferIter = mBuffers.find(bufferId);
+ bufferIter->second->mOwnerCount--;
+ if (bufferIter->second->mOwnerCount == 0 &&
+ bufferIter->second->mTransactionCount == 0) {
+ // TODO: handle freebuffer insert fail
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
+ }
+ }
+ }
+ mUsingBuffers.erase(buffers);
+ }
+
+ // Cleaning transactions
+ auto pending = mPendingTransactions.find(connectionId);
+ if (pending != mPendingTransactions.end()) {
+ for (const TransactionId& transactionId : pending->second) {
+ auto iter = mTransactions.find(transactionId);
+ if (iter != mTransactions.end()) {
+ if (!iter->second->mSenderValidated) {
+ mCompletedTransactions.insert(transactionId);
+ }
+ BufferId bufferId = iter->second->mBufferId;
+ auto bufferIter = mBuffers.find(bufferId);
+ bufferIter->second->mTransactionCount--;
+ if (bufferIter->second->mOwnerCount == 0 &&
+ bufferIter->second->mTransactionCount == 0) {
+ // TODO: handle freebuffer insert fail
+ if (!bufferIter->second->mInvalidated) {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mFreeBuffers.insert(bufferId);
+ } else {
+ mStats.onBufferUnused(bufferIter->second->mAllocSize);
+ mStats.onBufferEvicted(bufferIter->second->mAllocSize);
+ mBuffers.erase(bufferIter);
+ mInvalidation.onBufferInvalidated(bufferId, mInvalidationChannel);
+ }
+ }
+ mTransactions.erase(iter);
+ }
+ }
+ }
+ mConnectionIds.erase(connectionId);
+ return true;
+}
+
+bool BufferPool::getFreeBuffer(
+ const std::shared_ptr<BufferPoolAllocator> &allocator,
+ const std::vector<uint8_t> ¶ms, BufferId *pId,
+ const native_handle_t** handle) {
+ auto bufferIt = mFreeBuffers.begin();
+ for (;bufferIt != mFreeBuffers.end(); ++bufferIt) {
+ BufferId bufferId = *bufferIt;
+ if (allocator->compatible(params, mBuffers[bufferId]->mConfig)) {
+ break;
+ }
+ }
+ if (bufferIt != mFreeBuffers.end()) {
+ BufferId id = *bufferIt;
+ mFreeBuffers.erase(bufferIt);
+ mStats.onBufferRecycled(mBuffers[id]->mAllocSize);
+ *handle = mBuffers[id]->handle();
+ *pId = id;
+ ALOGV("recycle a buffer %u %p", id, *handle);
+ return true;
+ }
+ return false;
+}
+
+BufferPoolStatus BufferPool::addNewBuffer(
+ const std::shared_ptr<BufferPoolAllocation> &alloc,
+ const size_t allocSize,
+ const std::vector<uint8_t> ¶ms,
+ BufferId *pId,
+ const native_handle_t** handle) {
+
+ BufferId bufferId = mSeq++;
+ if (mSeq == Connection::SYNC_BUFFERID) {
+ mSeq = 0;
+ }
+ std::unique_ptr<InternalBuffer> buffer =
+ std::make_unique<InternalBuffer>(
+ bufferId, alloc, allocSize, params);
+ if (buffer) {
+ auto res = mBuffers.insert(std::make_pair(
+ bufferId, std::move(buffer)));
+ if (res.second) {
+ mStats.onBufferAllocated(allocSize);
+ *handle = alloc->handle();
+ *pId = bufferId;
+ return ResultStatus::OK;
+ }
+ }
+ return ResultStatus::NO_MEMORY;
+}
+
+void BufferPool::cleanUp(bool clearCache) {
+ if (clearCache || mTimestampMs > mLastCleanUpMs + kCleanUpDurationMs ||
+ mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+ mLastCleanUpMs = mTimestampMs;
+ if (mTimestampMs > mLastLogMs + kLogDurationMs ||
+ mStats.buffersNotInUse() > kMaxUnusedBufferCount) {
+ mLastLogMs = mTimestampMs;
+ ALOGD("bufferpool2 %p : %zu(%zu size) total buffers - "
+ "%zu(%zu size) used buffers - %zu/%zu (recycle/alloc) - "
+ "%zu/%zu (fetch/transfer)",
+ this, mStats.mBuffersCached, mStats.mSizeCached,
+ mStats.mBuffersInUse, mStats.mSizeInUse,
+ mStats.mTotalRecycles, mStats.mTotalAllocations,
+ mStats.mTotalFetches, mStats.mTotalTransfers);
+ }
+ for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+ if (!clearCache && mStats.buffersNotInUse() <= kUnusedBufferCountTarget &&
+ (mStats.mSizeCached < kMinAllocBytesForEviction ||
+ mBuffers.size() < kMinBufferCountForEviction)) {
+ break;
+ }
+ auto it = mBuffers.find(*freeIt);
+ if (it != mBuffers.end() &&
+ it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+ mStats.onBufferEvicted(it->second->mAllocSize);
+ mBuffers.erase(it);
+ freeIt = mFreeBuffers.erase(freeIt);
+ } else {
+ ++freeIt;
+ ALOGW("bufferpool2 inconsistent!");
+ }
+ }
+ }
+}
+
+void BufferPool::invalidate(
+ bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor> &impl) {
+ for (auto freeIt = mFreeBuffers.begin(); freeIt != mFreeBuffers.end();) {
+ if (isBufferInRange(from, to, *freeIt)) {
+ auto it = mBuffers.find(*freeIt);
+ if (it != mBuffers.end() &&
+ it->second->mOwnerCount == 0 && it->second->mTransactionCount == 0) {
+ mStats.onBufferEvicted(it->second->mAllocSize);
+ mBuffers.erase(it);
+ freeIt = mFreeBuffers.erase(freeIt);
+ continue;
+ } else {
+ ALOGW("bufferpool2 inconsistent!");
+ }
+ }
+ ++freeIt;
+ }
+
+ size_t left = 0;
+ for (auto it = mBuffers.begin(); it != mBuffers.end(); ++it) {
+ if (isBufferInRange(from, to, it->first)) {
+ it->second->invalidate();
+ ++left;
+ }
+ }
+ mInvalidation.onInvalidationRequest(needsAck, from, to, left, mInvalidationChannel, impl);
+}
+
+void BufferPool::flush(const std::shared_ptr<Accessor> &impl) {
+ BufferId from = mStartSeq;
+ BufferId to = mSeq;
+ mStartSeq = mSeq;
+ // TODO: needsAck params
+ ALOGV("buffer invalidation request bp:%u %u %u", mInvalidation.mId, from, to);
+ if (from != to) {
+ invalidate(true, from, to, impl);
+ }
+}
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPool.h b/media/bufferpool/aidl/default/BufferPool.h
new file mode 100644
index 0000000..1529a53
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPool.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <vector>
+#include <mutex>
+#include <condition_variable>
+#include <utils/Timers.h>
+
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using BufferStatus = aidl::android::hardware::media::bufferpool2::BufferStatus;
+using BufferStatusMessage = aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+
+struct Accessor;
+struct InternalBuffer;
+struct TransactionStatus;
+
+/**
+ * Buffer pool implementation.
+ *
+ * Handles buffer status messages. Handles buffer allocation/recycling.
+ * Handles buffer transfer between buffer pool clients.
+ */
+struct BufferPool {
+private:
+ std::mutex mMutex;
+ int64_t mTimestampMs;
+ int64_t mLastCleanUpMs;
+ int64_t mLastLogMs;
+ BufferId mSeq;
+ BufferId mStartSeq;
+ bool mValid;
+ BufferStatusObserver mObserver;
+ BufferInvalidationChannel mInvalidationChannel;
+
+ std::map<ConnectionId, std::set<BufferId>> mUsingBuffers;
+ std::map<BufferId, std::set<ConnectionId>> mUsingConnections;
+
+ std::map<ConnectionId, std::set<TransactionId>> mPendingTransactions;
+ // Transactions completed before TRANSFER_TO message arrival.
+ // Fetch does not occur for the transactions.
+ // Only transaction id is kept for the transactions in short duration.
+ std::set<TransactionId> mCompletedTransactions;
+ // Currently active(pending) transations' status & information.
+ std::map<TransactionId, std::unique_ptr<TransactionStatus>>
+ mTransactions;
+
+ std::map<BufferId, std::unique_ptr<InternalBuffer>> mBuffers;
+ std::set<BufferId> mFreeBuffers;
+ std::set<ConnectionId> mConnectionIds;
+
+ struct Invalidation {
+ static std::atomic<std::uint32_t> sInvSeqId;
+
+ struct Pending {
+ bool mNeedsAck;
+ uint32_t mFrom;
+ uint32_t mTo;
+ size_t mLeft;
+ const std::weak_ptr<Accessor> mImpl;
+ Pending(bool needsAck, uint32_t from, uint32_t to, size_t left,
+ const std::shared_ptr<Accessor> &impl)
+ : mNeedsAck(needsAck),
+ mFrom(from),
+ mTo(to),
+ mLeft(left),
+ mImpl(impl)
+ {}
+
+ bool isInvalidated(uint32_t bufferId) {
+ return isBufferInRange(mFrom, mTo, bufferId) && --mLeft == 0;
+ }
+ };
+
+ std::list<Pending> mPendings;
+ std::map<ConnectionId, uint32_t> mAcks;
+ std::map<ConnectionId, const std::shared_ptr<IObserver>> mObservers;
+ uint32_t mInvalidationId;
+ uint32_t mId;
+
+ Invalidation() : mInvalidationId(0), mId(sInvSeqId.fetch_add(1)) {}
+
+ void onConnect(ConnectionId conId, const std::shared_ptr<IObserver> &observer);
+
+ void onClose(ConnectionId conId);
+
+ void onAck(ConnectionId conId, uint32_t msgId);
+
+ void onBufferInvalidated(
+ BufferId bufferId,
+ BufferInvalidationChannel &channel);
+
+ void onInvalidationRequest(
+ bool needsAck, uint32_t from, uint32_t to, size_t left,
+ BufferInvalidationChannel &channel,
+ const std::shared_ptr<Accessor> &impl);
+
+ void onHandleAck(
+ std::map<ConnectionId, const std::shared_ptr<IObserver>> *observers,
+ uint32_t *invalidationId);
+ } mInvalidation;
+ /// Buffer pool statistics which tracks allocation and transfer statistics.
+ struct Stats {
+ /// Total size of allocations which are used or available to use.
+ /// (bytes or pixels)
+ size_t mSizeCached;
+ /// # of cached buffers which are used or available to use.
+ size_t mBuffersCached;
+ /// Total size of allocations which are currently used. (bytes or pixels)
+ size_t mSizeInUse;
+ /// # of currently used buffers
+ size_t mBuffersInUse;
+
+ /// # of allocations called on bufferpool. (# of fetched from BlockPool)
+ size_t mTotalAllocations;
+ /// # of allocations that were served from the cache.
+ /// (# of allocator alloc prevented)
+ size_t mTotalRecycles;
+ /// # of buffer transfers initiated.
+ size_t mTotalTransfers;
+ /// # of transfers that had to be fetched.
+ size_t mTotalFetches;
+
+ Stats()
+ : mSizeCached(0), mBuffersCached(0), mSizeInUse(0), mBuffersInUse(0),
+ mTotalAllocations(0), mTotalRecycles(0), mTotalTransfers(0), mTotalFetches(0) {}
+
+ /// # of currently unused buffers
+ size_t buffersNotInUse() const {
+ ALOG_ASSERT(mBuffersCached >= mBuffersInUse);
+ return mBuffersCached - mBuffersInUse;
+ }
+
+ /// A new buffer is allocated on an allocation request.
+ void onBufferAllocated(size_t allocSize) {
+ mSizeCached += allocSize;
+ mBuffersCached++;
+
+ mSizeInUse += allocSize;
+ mBuffersInUse++;
+
+ mTotalAllocations++;
+ }
+
+ /// A buffer is evicted and destroyed.
+ void onBufferEvicted(size_t allocSize) {
+ mSizeCached -= allocSize;
+ mBuffersCached--;
+ }
+
+ /// A buffer is recycled on an allocation request.
+ void onBufferRecycled(size_t allocSize) {
+ mSizeInUse += allocSize;
+ mBuffersInUse++;
+
+ mTotalAllocations++;
+ mTotalRecycles++;
+ }
+
+ /// A buffer is available to be recycled.
+ void onBufferUnused(size_t allocSize) {
+ mSizeInUse -= allocSize;
+ mBuffersInUse--;
+ }
+
+ /// A buffer transfer is initiated.
+ void onBufferSent() {
+ mTotalTransfers++;
+ }
+
+ /// A buffer fetch is invoked by a buffer transfer.
+ void onBufferFetched() {
+ mTotalFetches++;
+ }
+ } mStats;
+
+ bool isValid() {
+ return mValid;
+ }
+
+ void invalidate(bool needsAck, BufferId from, BufferId to,
+ const std::shared_ptr<Accessor> &impl);
+
+ static void createInvalidator();
+
+public:
+ /** Creates a buffer pool. */
+ BufferPool();
+
+ /** Destroys a buffer pool. */
+ ~BufferPool();
+
+ /**
+ * Processes all pending buffer status messages, and returns the result.
+ * Each status message is handled by methods with 'handle' prefix.
+ */
+ void processStatusMessages();
+
+ /**
+ * Handles a buffer being owned by a connection.
+ *
+ * @param connectionId the id of the buffer owning connection.
+ * @param bufferId the id of the buffer.
+ *
+ * @return {@code true} when the buffer is owned,
+ * {@code false} otherwise.
+ */
+ bool handleOwnBuffer(ConnectionId connectionId, BufferId bufferId);
+
+ /**
+ * Handles a buffer being released by a connection.
+ *
+ * @param connectionId the id of the buffer owning connection.
+ * @param bufferId the id of the buffer.
+ *
+ * @return {@code true} when the buffer ownership is released,
+ * {@code false} otherwise.
+ */
+ bool handleReleaseBuffer(ConnectionId connectionId, BufferId bufferId);
+
+ /**
+ * Handles a transfer transaction start message from the sender.
+ *
+ * @param message a buffer status message for the transaction.
+ *
+ * @result {@code true} when transfer_to message is acknowledged,
+ * {@code false} otherwise.
+ */
+ bool handleTransferTo(const BufferStatusMessage &message);
+
+ /**
+ * Handles a transfer transaction being acked by the receiver.
+ *
+ * @param message a buffer status message for the transaction.
+ *
+ * @result {@code true} when transfer_from message is acknowledged,
+ * {@code false} otherwise.
+ */
+ bool handleTransferFrom(const BufferStatusMessage &message);
+
+ /**
+ * Handles a transfer transaction result message from the receiver.
+ *
+ * @param message a buffer status message for the transaction.
+ *
+ * @result {@code true} when the existing transaction is finished,
+ * {@code false} otherwise.
+ */
+ bool handleTransferResult(const BufferStatusMessage &message);
+
+ /**
+ * Handles a connection being closed, and returns the result. All the
+ * buffers and transactions owned by the connection will be cleaned up.
+ * The related FMQ will be cleaned up too.
+ *
+ * @param connectionId the id of the connection.
+ *
+ * @result {@code true} when the connection existed,
+ * {@code false} otherwise.
+ */
+ bool handleClose(ConnectionId connectionId);
+
+ /**
+ * Recycles a existing free buffer if it is possible.
+ *
+ * @param allocator the buffer allocator
+ * @param params the allocation parameters.
+ * @param pId the id of the recycled buffer.
+ * @param handle the native handle of the recycled buffer.
+ *
+ * @return {@code true} when a buffer is recycled, {@code false}
+ * otherwise.
+ */
+ bool getFreeBuffer(
+ const std::shared_ptr<BufferPoolAllocator> &allocator,
+ const std::vector<uint8_t> ¶ms,
+ BufferId *pId, const native_handle_t **handle);
+
+ /**
+ * Adds a newly allocated buffer to bufferpool.
+ *
+ * @param alloc the newly allocated buffer.
+ * @param allocSize the size of the newly allocated buffer.
+ * @param params the allocation parameters.
+ * @param pId the buffer id for the newly allocated buffer.
+ * @param handle the native handle for the newly allocated buffer.
+ *
+ * @return OK when an allocation is successfully allocated.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus addNewBuffer(
+ const std::shared_ptr<BufferPoolAllocation> &alloc,
+ const size_t allocSize,
+ const std::vector<uint8_t> ¶ms,
+ BufferId *pId,
+ const native_handle_t **handle);
+
+ /**
+ * Processes pending buffer status messages and performs periodic cache
+ * cleaning.
+ *
+ * @param clearCache if clearCache is true, it frees all buffers
+ * waiting to be recycled.
+ */
+ void cleanUp(bool clearCache = false);
+
+ /**
+ * Processes pending buffer status messages and invalidate all current
+ * free buffers. Active buffers are invalidated after being inactive.
+ */
+ void flush(const std::shared_ptr<Accessor> &impl);
+
+ friend struct Accessor;
+};
+
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.cpp b/media/bufferpool/aidl/default/BufferPoolClient.cpp
new file mode 100644
index 0000000..e9777d8
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.cpp
@@ -0,0 +1,858 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlBufferPoolCli"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <utils/Log.h>
+#include "BufferPoolClient.h"
+#include "Accessor.h"
+#include "Connection.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IConnection;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+static constexpr int64_t kReceiveTimeoutMs = 2000; // 2s
+static constexpr int kPostMaxRetry = 3;
+static constexpr int kCacheTtlMs = 1000;
+static constexpr size_t kMaxCachedBufferCount = 64;
+static constexpr size_t kCachedBufferCountTarget = kMaxCachedBufferCount - 16;
+
+class BufferPoolClient::Impl
+ : public std::enable_shared_from_this<BufferPoolClient::Impl> {
+public:
+ explicit Impl(const std::shared_ptr<Accessor> &accessor,
+ const std::shared_ptr<IObserver> &observer);
+
+ explicit Impl(const std::shared_ptr<IAccessor> &accessor,
+ const std::shared_ptr<IObserver> &observer);
+
+ bool isValid() {
+ return mValid;
+ }
+
+ bool isLocal() {
+ return mValid && mLocal;
+ }
+
+ ConnectionId getConnectionId() {
+ return mConnectionId;
+ }
+
+ std::shared_ptr<IAccessor> &getAccessor() {
+ return mAccessor;
+ }
+
+ bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+ void receiveInvalidation(uint32_t msgID);
+
+ BufferPoolStatus flush();
+
+ BufferPoolStatus allocate(const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ BufferPoolStatus receive(
+ TransactionId transactionId, BufferId bufferId,
+ int64_t timestampMs,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer);
+
+ void postBufferRelease(BufferId bufferId);
+
+ bool postSend(
+ BufferId bufferId, ConnectionId receiver,
+ TransactionId *transactionId, int64_t *timestampMs);
+private:
+
+ bool postReceive(
+ BufferId bufferId, TransactionId transactionId,
+ int64_t timestampMs);
+
+ bool postReceiveResult(
+ BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync);
+
+ void trySyncFromRemote();
+
+ bool syncReleased(uint32_t msgId = 0);
+
+ void evictCaches(bool clearCache = false);
+
+ void invalidateBuffer(BufferId id);
+
+ void invalidateRange(BufferId from, BufferId to);
+
+ BufferPoolStatus allocateBufferHandle(
+ const std::vector<uint8_t>& params, BufferId *bufferId,
+ native_handle_t **handle);
+
+ BufferPoolStatus fetchBufferHandle(
+ TransactionId transactionId, BufferId bufferId,
+ native_handle_t **handle);
+
+ struct BlockPoolDataDtor;
+ struct ClientBuffer;
+
+ bool mLocal;
+ bool mValid;
+ std::shared_ptr<IAccessor> mAccessor;
+ std::shared_ptr<Connection> mLocalConnection;
+ std::shared_ptr<IConnection> mRemoteConnection;
+ uint32_t mSeqId;
+ ConnectionId mConnectionId;
+ int64_t mLastEvictCacheMs;
+ std::unique_ptr<BufferInvalidationListener> mInvalidationListener;
+
+ // CachedBuffers
+ struct BufferCache {
+ std::mutex mLock;
+ bool mCreating;
+ std::condition_variable mCreateCv;
+ std::map<BufferId, std::unique_ptr<ClientBuffer>> mBuffers;
+ int mActive;
+ int64_t mLastChangeMs;
+
+ BufferCache() : mCreating(false), mActive(0),
+ mLastChangeMs(::android::elapsedRealtime()) {}
+
+ void incActive_l() {
+ ++mActive;
+ mLastChangeMs = ::android::elapsedRealtime();
+ }
+
+ void decActive_l() {
+ --mActive;
+ mLastChangeMs = ::android::elapsedRealtime();
+ }
+
+ int cachedBufferCount() const {
+ return mBuffers.size() - mActive;
+ }
+ } mCache;
+
+ // FMQ - release notifier
+ struct ReleaseCache {
+ std::mutex mLock;
+ std::list<BufferId> mReleasingIds;
+ std::list<BufferId> mReleasedIds;
+ uint32_t mInvalidateId; // TODO: invalidation ACK to bufferpool
+ bool mInvalidateAck;
+ std::unique_ptr<BufferStatusChannel> mStatusChannel;
+
+ ReleaseCache() : mInvalidateId(0), mInvalidateAck(true) {}
+ } mReleasing;
+
+ // This lock is held during synchronization from remote side.
+ // In order to minimize remote calls and locking duration, this lock is held
+ // by best effort approach using try_lock().
+ std::mutex mRemoteSyncLock;
+};
+
+struct BufferPoolClient::Impl::BlockPoolDataDtor {
+ BlockPoolDataDtor(const std::shared_ptr<BufferPoolClient::Impl> &impl)
+ : mImpl(impl) {}
+
+ void operator()(BufferPoolData *buffer) {
+ BufferId id = buffer->mId;
+ delete buffer;
+
+ auto impl = mImpl.lock();
+ if (impl && impl->isValid()) {
+ impl->postBufferRelease(id);
+ }
+ }
+ const std::weak_ptr<BufferPoolClient::Impl> mImpl;
+};
+
+struct BufferPoolClient::Impl::ClientBuffer {
+private:
+ int64_t mExpireMs;
+ bool mHasCache;
+ ConnectionId mConnectionId;
+ BufferId mId;
+ native_handle_t *mHandle;
+ std::weak_ptr<BufferPoolData> mCache;
+
+ void updateExpire() {
+ mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+ }
+
+public:
+ ClientBuffer(
+ ConnectionId connectionId, BufferId id, native_handle_t *handle)
+ : mHasCache(false), mConnectionId(connectionId),
+ mId(id), mHandle(handle) {
+ mExpireMs = ::android::elapsedRealtime() + kCacheTtlMs;
+ }
+
+ ~ClientBuffer() {
+ if (mHandle) {
+ native_handle_close(mHandle);
+ native_handle_delete(mHandle);
+ }
+ }
+
+ BufferId id() const {
+ return mId;
+ }
+
+ bool expire() const {
+ int64_t now = ::android::elapsedRealtime();
+ return now >= mExpireMs;
+ }
+
+ bool hasCache() const {
+ return mHasCache;
+ }
+
+ std::shared_ptr<BufferPoolData> fetchCache(native_handle_t **pHandle) {
+ if (mHasCache) {
+ std::shared_ptr<BufferPoolData> cache = mCache.lock();
+ if (cache) {
+ *pHandle = mHandle;
+ }
+ return cache;
+ }
+ return nullptr;
+ }
+
+ std::shared_ptr<BufferPoolData> createCache(
+ const std::shared_ptr<BufferPoolClient::Impl> &impl,
+ native_handle_t **pHandle) {
+ if (!mHasCache) {
+ // Allocates a raw ptr in order to avoid sending #postBufferRelease
+ // from deleter, in case of native_handle_clone failure.
+ BufferPoolData *ptr = new BufferPoolData(mConnectionId, mId);
+ if (ptr) {
+ std::shared_ptr<BufferPoolData> cache(ptr, BlockPoolDataDtor(impl));
+ if (cache) {
+ mCache = cache;
+ mHasCache = true;
+ *pHandle = mHandle;
+ return cache;
+ }
+ }
+ if (ptr) {
+ delete ptr;
+ }
+ }
+ return nullptr;
+ }
+
+ bool onCacheRelease() {
+ if (mHasCache) {
+ // TODO: verify mCache is not valid;
+ updateExpire();
+ mHasCache = false;
+ return true;
+ }
+ return false;
+ }
+};
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<Accessor> &accessor,
+ const std::shared_ptr<IObserver> &observer)
+ : mLocal(true), mValid(false), mAccessor(accessor), mSeqId(0),
+ mLastEvictCacheMs(::android::elapsedRealtime()) {
+ StatusDescriptor statusDesc;
+ InvalidationDescriptor invDesc;
+ BufferPoolStatus status = accessor->connect(
+ observer, true,
+ &mLocalConnection, &mConnectionId, &mReleasing.mInvalidateId,
+ &statusDesc, &invDesc);
+ if (status == ResultStatus::OK) {
+ mReleasing.mStatusChannel =
+ std::make_unique<BufferStatusChannel>(statusDesc);
+ mInvalidationListener =
+ std::make_unique<BufferInvalidationListener>(invDesc);
+ mValid = mReleasing.mStatusChannel &&
+ mReleasing.mStatusChannel->isValid() &&
+ mInvalidationListener &&
+ mInvalidationListener->isValid();
+ }
+}
+
+BufferPoolClient::Impl::Impl(const std::shared_ptr<IAccessor> &accessor,
+ const std::shared_ptr<IObserver> &observer)
+ : mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
+ mLastEvictCacheMs(::android::elapsedRealtime()) {
+ IAccessor::ConnectionInfo conInfo;
+ bool valid = false;
+ if(accessor->connect(observer, &conInfo).isOk()) {
+ auto channel = std::make_unique<BufferStatusChannel>(conInfo.toFmqDesc);
+ auto observer = std::make_unique<BufferInvalidationListener>(conInfo.fromFmqDesc);
+
+ if (channel && channel->isValid()
+ && observer && observer->isValid()) {
+ mRemoteConnection = conInfo.connection;
+ mConnectionId = conInfo.connectionId;
+ mReleasing.mInvalidateId = conInfo.msgId;
+ mReleasing.mStatusChannel = std::move(channel);
+ mInvalidationListener = std::move(observer);
+ valid = true;
+ }
+ }
+ mValid = valid;
+}
+
+bool BufferPoolClient::Impl::isActive(int64_t *lastTransactionMs, bool clearCache) {
+ bool active = false;
+ {
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches(clearCache);
+ *lastTransactionMs = mCache.mLastChangeMs;
+ active = mCache.mActive > 0;
+ }
+ if (mValid && mLocal && mLocalConnection) {
+ mLocalConnection->cleanUp(clearCache);
+ return true;
+ }
+ return active;
+}
+
+void BufferPoolClient::Impl::receiveInvalidation(uint32_t messageId) {
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased(messageId);
+ // TODO: evict cache required?
+}
+
+BufferPoolStatus BufferPoolClient::Impl::flush() {
+ if (!mLocal || !mLocalConnection || !mValid) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ {
+ std::unique_lock<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches();
+ return mLocalConnection->flush();
+ }
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocate(
+ const std::vector<uint8_t> ¶ms,
+ native_handle_t **pHandle,
+ std::shared_ptr<BufferPoolData> *buffer) {
+ if (!mLocal || !mLocalConnection || !mValid) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ BufferId bufferId;
+ native_handle_t *handle = nullptr;
+ buffer->reset();
+ BufferPoolStatus status = allocateBufferHandle(params, &bufferId, &handle);
+ if (status == ResultStatus::OK) {
+ if (handle) {
+ std::unique_lock<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches();
+ auto cacheIt = mCache.mBuffers.find(bufferId);
+ if (cacheIt != mCache.mBuffers.end()) {
+ // TODO: verify it is recycled. (not having active ref)
+ mCache.mBuffers.erase(cacheIt);
+ }
+ auto clientBuffer = std::make_unique<ClientBuffer>(
+ mConnectionId, bufferId, handle);
+ if (clientBuffer) {
+ auto result = mCache.mBuffers.insert(std::make_pair(
+ bufferId, std::move(clientBuffer)));
+ if (result.second) {
+ *buffer = result.first->second->createCache(
+ shared_from_this(), pHandle);
+ if (*buffer) {
+ mCache.incActive_l();
+ }
+ }
+ }
+ }
+ if (!*buffer) {
+ ALOGV("client cache creation failure %d: %lld",
+ handle != nullptr, (long long)mConnectionId);
+ status = ResultStatus::NO_MEMORY;
+ postBufferRelease(bufferId);
+ }
+ }
+ return status;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::receive(
+ TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+ native_handle_t **pHandle,
+ std::shared_ptr<BufferPoolData> *buffer) {
+ if (!mValid) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ if (timestampMs != 0) {
+ timestampMs += kReceiveTimeoutMs;
+ }
+ if (!postReceive(bufferId, transactionId, timestampMs)) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+ buffer->reset();
+ while(1) {
+ std::unique_lock<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ evictCaches();
+ auto cacheIt = mCache.mBuffers.find(bufferId);
+ if (cacheIt != mCache.mBuffers.end()) {
+ if (cacheIt->second->hasCache()) {
+ *buffer = cacheIt->second->fetchCache(pHandle);
+ if (!*buffer) {
+ // check transfer time_out
+ lock.unlock();
+ std::this_thread::yield();
+ continue;
+ }
+ ALOGV("client receive from reference %lld", (long long)mConnectionId);
+ break;
+ } else {
+ *buffer = cacheIt->second->createCache(shared_from_this(), pHandle);
+ if (*buffer) {
+ mCache.incActive_l();
+ }
+ ALOGV("client receive from cache %lld", (long long)mConnectionId);
+ break;
+ }
+ } else {
+ if (!mCache.mCreating) {
+ mCache.mCreating = true;
+ lock.unlock();
+ native_handle_t* handle = nullptr;
+ status = fetchBufferHandle(transactionId, bufferId, &handle);
+ lock.lock();
+ if (status == ResultStatus::OK) {
+ if (handle) {
+ auto clientBuffer = std::make_unique<ClientBuffer>(
+ mConnectionId, bufferId, handle);
+ if (clientBuffer) {
+ auto result = mCache.mBuffers.insert(
+ std::make_pair(bufferId, std::move(
+ clientBuffer)));
+ if (result.second) {
+ *buffer = result.first->second->createCache(
+ shared_from_this(), pHandle);
+ if (*buffer) {
+ mCache.incActive_l();
+ }
+ }
+ }
+ }
+ if (!*buffer) {
+ status = ResultStatus::NO_MEMORY;
+ }
+ }
+ mCache.mCreating = false;
+ lock.unlock();
+ mCache.mCreateCv.notify_all();
+ break;
+ }
+ mCache.mCreateCv.wait(lock);
+ }
+ }
+ bool needsSync = false;
+ bool posted = postReceiveResult(bufferId, transactionId,
+ *buffer ? true : false, &needsSync);
+ ALOGV("client receive %lld - %u : %s (%d)", (long long)mConnectionId, bufferId,
+ *buffer ? "ok" : "fail", posted);
+ if (mValid && mLocal && mLocalConnection) {
+ mLocalConnection->cleanUp(false);
+ }
+ if (needsSync && mRemoteConnection) {
+ trySyncFromRemote();
+ }
+ if (*buffer) {
+ if (!posted) {
+ buffer->reset();
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ return ResultStatus::OK;
+ }
+ return status;
+}
+
+
+void BufferPoolClient::Impl::postBufferRelease(BufferId bufferId) {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ mReleasing.mReleasingIds.push_back(bufferId);
+ mReleasing.mStatusChannel->postBufferRelease(
+ mConnectionId, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+}
+
+// TODO: revise ad-hoc posting data structure
+bool BufferPoolClient::Impl::postSend(
+ BufferId bufferId, ConnectionId receiver,
+ TransactionId *transactionId, int64_t *timestampMs) {
+ {
+ // TODO: don't need to call syncReleased every time
+ std::lock_guard<std::mutex> lock(mCache.mLock);
+ syncReleased();
+ }
+ bool ret = false;
+ bool needsSync = false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ *timestampMs = ::android::elapsedRealtime();
+ *transactionId = (mConnectionId << 32) | mSeqId++;
+ // TODO: retry, add timeout, target?
+ ret = mReleasing.mStatusChannel->postBufferStatusMessage(
+ *transactionId, bufferId, BufferStatus::TRANSFER_TO, mConnectionId,
+ receiver, mReleasing.mReleasingIds, mReleasing.mReleasedIds);
+ needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+ }
+ if (mValid && mLocal && mLocalConnection) {
+ mLocalConnection->cleanUp(false);
+ }
+ if (needsSync && mRemoteConnection) {
+ trySyncFromRemote();
+ }
+ return ret;
+}
+
+bool BufferPoolClient::Impl::postReceive(
+ BufferId bufferId, TransactionId transactionId, int64_t timestampMs) {
+ for (int i = 0; i < kPostMaxRetry; ++i) {
+ std::unique_lock<std::mutex> lock(mReleasing.mLock);
+ int64_t now = ::android::elapsedRealtime();
+ if (timestampMs == 0 || now < timestampMs) {
+ bool result = mReleasing.mStatusChannel->postBufferStatusMessage(
+ transactionId, bufferId, BufferStatus::TRANSFER_FROM,
+ mConnectionId, -1, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ if (result) {
+ return true;
+ }
+ lock.unlock();
+ std::this_thread::yield();
+ } else {
+ mReleasing.mStatusChannel->postBufferStatusMessage(
+ transactionId, bufferId, BufferStatus::TRANSFER_TIMEOUT,
+ mConnectionId, -1, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ return false;
+ }
+ }
+ return false;
+}
+
+bool BufferPoolClient::Impl::postReceiveResult(
+ BufferId bufferId, TransactionId transactionId, bool result, bool *needsSync) {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ // TODO: retry, add timeout
+ bool ret = mReleasing.mStatusChannel->postBufferStatusMessage(
+ transactionId, bufferId,
+ result ? BufferStatus::TRANSFER_OK : BufferStatus::TRANSFER_ERROR,
+ mConnectionId, -1, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ *needsSync = !mLocal && mReleasing.mStatusChannel->needsSync();
+ return ret;
+}
+
+void BufferPoolClient::Impl::trySyncFromRemote() {
+ if (mRemoteSyncLock.try_lock()) {
+ bool needsSync = false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ needsSync = mReleasing.mStatusChannel->needsSync();
+ }
+ if (needsSync) {
+ if (!mRemoteConnection->sync().isOk()) {
+ ALOGD("sync from client %lld failed: bufferpool process died.",
+ (long long)mConnectionId);
+ }
+ }
+ mRemoteSyncLock.unlock();
+ }
+}
+
+// should have mCache.mLock
+bool BufferPoolClient::Impl::syncReleased(uint32_t messageId) {
+ bool cleared = false;
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (mReleasing.mReleasingIds.size() > 0) {
+ mReleasing.mStatusChannel->postBufferRelease(
+ mConnectionId, mReleasing.mReleasingIds,
+ mReleasing.mReleasedIds);
+ }
+ if (mReleasing.mReleasedIds.size() > 0) {
+ for (BufferId& id: mReleasing.mReleasedIds) {
+ ALOGV("client release buffer %lld - %u", (long long)mConnectionId, id);
+ auto found = mCache.mBuffers.find(id);
+ if (found != mCache.mBuffers.end()) {
+ if (found->second->onCacheRelease()) {
+ mCache.decActive_l();
+ } else {
+ // should not happen!
+ ALOGW("client %lld cache release status inconsistent!",
+ (long long)mConnectionId);
+ }
+ } else {
+ // should not happen!
+ ALOGW("client %lld cache status inconsistent!", (long long)mConnectionId);
+ }
+ }
+ mReleasing.mReleasedIds.clear();
+ cleared = true;
+ }
+ }
+ std::vector<BufferInvalidationMessage> invalidations;
+ mInvalidationListener->getInvalidations(invalidations);
+ uint32_t lastMsgId = 0;
+ if (invalidations.size() > 0) {
+ for (auto it = invalidations.begin(); it != invalidations.end(); ++it) {
+ if (it->messageId != 0) {
+ lastMsgId = it->messageId;
+ }
+ if (it->fromBufferId == it->toBufferId) {
+ // TODO: handle fromBufferId = UINT32_MAX
+ invalidateBuffer(it->fromBufferId);
+ } else {
+ invalidateRange(it->fromBufferId, it->toBufferId);
+ }
+ }
+ }
+ {
+ std::lock_guard<std::mutex> lock(mReleasing.mLock);
+ if (lastMsgId != 0) {
+ if (isMessageLater(lastMsgId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = lastMsgId;
+ mReleasing.mInvalidateAck = false;
+ }
+ } else if (messageId != 0) {
+ // messages are drained.
+ if (isMessageLater(messageId, mReleasing.mInvalidateId)) {
+ mReleasing.mInvalidateId = messageId;
+ mReleasing.mInvalidateAck = true;
+ }
+ }
+ if (!mReleasing.mInvalidateAck) {
+ // post ACK
+ mReleasing.mStatusChannel->postBufferInvalidateAck(
+ mConnectionId,
+ mReleasing.mInvalidateId, &mReleasing.mInvalidateAck);
+ ALOGV("client %lld invalidateion ack (%d) %u",
+ (long long)mConnectionId,
+ mReleasing.mInvalidateAck, mReleasing.mInvalidateId);
+ }
+ }
+ return cleared;
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::evictCaches(bool clearCache) {
+ int64_t now = ::android::elapsedRealtime();
+ if (now >= mLastEvictCacheMs + kCacheTtlMs ||
+ clearCache || mCache.cachedBufferCount() > kMaxCachedBufferCount) {
+ size_t evicted = 0;
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+ if (!it->second->hasCache() && (it->second->expire() ||
+ clearCache || mCache.cachedBufferCount() > kCachedBufferCountTarget)) {
+ it = mCache.mBuffers.erase(it);
+ ++evicted;
+ } else {
+ ++it;
+ }
+ }
+ ALOGV("cache count %lld : total %zu, active %d, evicted %zu",
+ (long long)mConnectionId, mCache.mBuffers.size(), mCache.mActive, evicted);
+ mLastEvictCacheMs = now;
+ }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateBuffer(BufferId id) {
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end(); ++it) {
+ if (id == it->second->id()) {
+ if (!it->second->hasCache()) {
+ mCache.mBuffers.erase(it);
+ ALOGV("cache invalidated %lld : buffer %u",
+ (long long)mConnectionId, id);
+ } else {
+ ALOGW("Inconsistent invalidation %lld : activer buffer!! %u",
+ (long long)mConnectionId, (unsigned int)id);
+ }
+ break;
+ }
+ }
+}
+
+// should have mCache.mLock
+void BufferPoolClient::Impl::invalidateRange(BufferId from, BufferId to) {
+ size_t invalidated = 0;
+ for (auto it = mCache.mBuffers.begin(); it != mCache.mBuffers.end();) {
+ if (!it->second->hasCache()) {
+ BufferId bid = it->second->id();
+ if (from < to) {
+ if (from <= bid && bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ } else {
+ if (from <= bid || bid < to) {
+ ++invalidated;
+ it = mCache.mBuffers.erase(it);
+ continue;
+ }
+ }
+ }
+ ++it;
+ }
+ ALOGV("cache invalidated %lld : # of invalidated %zu",
+ (long long)mConnectionId, invalidated);
+}
+
+BufferPoolStatus BufferPoolClient::Impl::allocateBufferHandle(
+ const std::vector<uint8_t>& params, BufferId *bufferId,
+ native_handle_t** handle) {
+ if (mLocalConnection) {
+ const native_handle_t* allocHandle = nullptr;
+ BufferPoolStatus status = mLocalConnection->allocate(
+ params, bufferId, &allocHandle);
+ if (status == ResultStatus::OK) {
+ *handle = native_handle_clone(allocHandle);
+ }
+ ALOGV("client allocate result %lld %d : %u clone %p",
+ (long long)mConnectionId, status == ResultStatus::OK,
+ *handle ? *bufferId : 0 , *handle);
+ return status;
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::Impl::fetchBufferHandle(
+ TransactionId transactionId, BufferId bufferId,
+ native_handle_t **handle) {
+ std::shared_ptr<IConnection> connection;
+ if (mLocal) {
+ connection = mLocalConnection;
+ } else {
+ connection = mRemoteConnection;
+ }
+ std::vector<FetchInfo> infos;
+ std::vector<FetchResult> results;
+ infos.emplace_back(FetchInfo{ToAidl(transactionId), ToAidl(bufferId)});
+ ndk::ScopedAStatus status = connection->fetch(infos, &results);
+ if (!status.isOk()) {
+ BufferPoolStatus svcSpecific = status.getServiceSpecificError();
+ return svcSpecific ? svcSpecific : ResultStatus::CRITICAL_ERROR;
+ }
+ if (results[0].getTag() == FetchResult::buffer) {
+ *handle = ::android::dupFromAidl(results[0].get<FetchResult::buffer>().buffer);
+ return ResultStatus::OK;
+ }
+ return results[0].get<FetchResult::failure>();
+}
+
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+ const std::shared_ptr<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+ const std::shared_ptr<IObserver> &observer) {
+ mImpl = std::make_shared<Impl>(accessor, observer);
+}
+
+BufferPoolClient::~BufferPoolClient() {
+ // TODO: how to handle orphaned buffers?
+}
+
+bool BufferPoolClient::isValid() {
+ return mImpl && mImpl->isValid();
+}
+
+bool BufferPoolClient::isLocal() {
+ return mImpl && mImpl->isLocal();
+}
+
+bool BufferPoolClient::isActive(int64_t *lastTransactionMs, bool clearCache) {
+ if (!isValid()) {
+ *lastTransactionMs = 0;
+ return false;
+ }
+ return mImpl->isActive(lastTransactionMs, clearCache);
+}
+
+ConnectionId BufferPoolClient::getConnectionId() {
+ if (isValid()) {
+ return mImpl->getConnectionId();
+ }
+ return -1;
+}
+
+BufferPoolStatus BufferPoolClient::getAccessor(std::shared_ptr<IAccessor> *accessor) {
+ if (isValid()) {
+ *accessor = mImpl->getAccessor();
+ return ResultStatus::OK;
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+void BufferPoolClient::receiveInvalidation(uint32_t msgId) {
+ ALOGV("bufferpool2 client recv inv %u", msgId);
+ if (isValid()) {
+ mImpl->receiveInvalidation(msgId);
+ }
+}
+
+BufferPoolStatus BufferPoolClient::flush() {
+ if (isValid()) {
+ return mImpl->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::allocate(
+ const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer) {
+ if (isValid()) {
+ return mImpl->allocate(params, handle, buffer);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::receive(
+ TransactionId transactionId, BufferId bufferId, int64_t timestampMs,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+ if (isValid()) {
+ return mImpl->receive(transactionId, bufferId, timestampMs, handle, buffer);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus BufferPoolClient::postSend(
+ ConnectionId receiverId,
+ const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId,
+ int64_t *timestampMs) {
+ if (isValid()) {
+ bool result = mImpl->postSend(
+ buffer->mId, receiverId, transactionId, timestampMs);
+ return result ? ResultStatus::OK : ResultStatus::CRITICAL_ERROR;
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferPoolClient.h b/media/bufferpool/aidl/default/BufferPoolClient.h
new file mode 100644
index 0000000..80fd43e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferPoolClient.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+#include <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/IObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+using aidl::android::hardware::media::bufferpool2::IObserver;
+
+struct Accessor;
+
+/**
+ * A buffer pool client for a buffer pool. For a specific buffer pool, at most
+ * one buffer pool client exists per process. This class will not be exposed
+ * outside. A buffer pool client will be used via ClientManager.
+ */
+class BufferPoolClient {
+public:
+ /**
+ * Creates a buffer pool client from a local buffer pool
+ * (via ClientManager#create).
+ */
+ explicit BufferPoolClient(const std::shared_ptr<Accessor> &accessor,
+ const std::shared_ptr<IObserver> &observer);
+
+ /**
+ * Creates a buffer pool client from a remote buffer pool
+ * (via ClientManager#registerSender).
+ * Note: A buffer pool client created with remote buffer pool cannot
+ * allocate a buffer.
+ */
+ explicit BufferPoolClient(const std::shared_ptr<IAccessor> &accessor,
+ const std::shared_ptr<IObserver> &observer);
+
+ /** Destructs a buffer pool client. */
+ ~BufferPoolClient();
+
+private:
+ bool isValid();
+
+ bool isLocal();
+
+ bool isActive(int64_t *lastTransactionMs, bool clearCache);
+
+ ConnectionId getConnectionId();
+
+ BufferPoolStatus getAccessor(std::shared_ptr<IAccessor> *accessor);
+
+ void receiveInvalidation(uint32_t msgId);
+
+ BufferPoolStatus flush();
+
+ BufferPoolStatus allocate(const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ BufferPoolStatus receive(TransactionId transactionId,
+ BufferId bufferId,
+ int64_t timestampMs,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ BufferPoolStatus postSend(ConnectionId receiver,
+ const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId,
+ int64_t *timestampMs);
+
+ class Impl;
+ std::shared_ptr<Impl> mImpl;
+
+ friend struct ClientManager;
+ friend struct Observer;
+};
+
+} // namespace aidl::android::hardware::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/BufferStatus.cpp b/media/bufferpool/aidl/default/BufferStatus.cpp
new file mode 100644
index 0000000..19caa1e
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.cpp
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlBufferPoolStatus"
+//#define LOG_NDEBUG 0
+
+#include <thread>
+#include <time.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatus.h>
+#include "BufferStatus.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BufferStatus;
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId) {
+ return curMsgId != prevMsgId && curMsgId - prevMsgId < prevMsgId - curMsgId;
+}
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId) {
+ if (from < to) {
+ return from <= bufferId && bufferId < to;
+ } else { // wrap happens
+ return from <= bufferId || bufferId < to;
+ }
+}
+
+static constexpr int kNumElementsInQueue = 1024*16;
+static constexpr int kMinElementsToSyncInQueue = 128;
+
+BufferPoolStatus BufferStatusObserver::open(
+ ConnectionId id, StatusDescriptor* fmqDescPtr) {
+ if (mBufferStatusQueues.find(id) != mBufferStatusQueues.end()) {
+ ALOGE("connection id collision %lld", (unsigned long long)id);
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ auto queue = std::make_unique<BufferStatusQueue>(kNumElementsInQueue);
+ if (!queue || queue->isValid() == false) {
+ return ResultStatus::NO_MEMORY;
+ }
+ *fmqDescPtr = queue->dupeDesc();
+ auto result = mBufferStatusQueues.insert(
+ std::make_pair(id, std::move(queue)));
+ if (!result.second) {
+ return ResultStatus::NO_MEMORY;
+ }
+ return ResultStatus::OK;
+}
+
+BufferPoolStatus BufferStatusObserver::close(ConnectionId id) {
+ if (mBufferStatusQueues.find(id) == mBufferStatusQueues.end()) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ mBufferStatusQueues.erase(id);
+ return ResultStatus::OK;
+}
+
+void BufferStatusObserver::getBufferStatusChanges(std::vector<BufferStatusMessage> &messages) {
+ for (auto it = mBufferStatusQueues.begin(); it != mBufferStatusQueues.end(); ++it) {
+ BufferStatusMessage message;
+ size_t avail = it->second->availableToRead();
+ while (avail > 0) {
+ if (!it->second->read(&message, 1)) {
+ // Since available # of reads are already confirmed,
+ // this should not happen.
+ // TODO: error handling (spurious client?)
+ ALOGW("FMQ message cannot be read from %lld", (long long)it->first);
+ return;
+ }
+ message.connectionId = it->first;
+ messages.push_back(message);
+ --avail;
+ }
+ }
+}
+
+BufferStatusChannel::BufferStatusChannel(
+ const StatusDescriptor &fmqDesc) {
+ auto queue = std::make_unique<BufferStatusQueue>(fmqDesc);
+ if (!queue || queue->isValid() == false) {
+ mValid = false;
+ return;
+ }
+ mValid = true;
+ mBufferStatusQueue = std::move(queue);
+}
+
+bool BufferStatusChannel::isValid() {
+ return mValid;
+}
+
+bool BufferStatusChannel::needsSync() {
+ if (mValid) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ return avail + kMinElementsToSyncInQueue < kNumElementsInQueue;
+ }
+ return false;
+}
+
+void BufferStatusChannel::postBufferRelease(
+ ConnectionId connectionId,
+ std::list<BufferId> &pending, std::list<BufferId> &posted) {
+ if (mValid && pending.size() > 0) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ avail = std::min(avail, pending.size());
+ BufferStatusMessage message;
+ for (size_t i = 0 ; i < avail; ++i) {
+ BufferId id = pending.front();
+ message.status = BufferStatus::NOT_USED;
+ message.bufferId = id;
+ message.connectionId = connectionId;
+ if (!mBufferStatusQueue->write(&message, 1)) {
+ // Since available # of writes are already confirmed,
+ // this should not happen.
+ // TODO: error handing?
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return;
+ }
+ pending.pop_front();
+ posted.push_back(id);
+ }
+ }
+}
+
+void BufferStatusChannel::postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool *invalidated) {
+ if (mValid && !*invalidated) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ if (avail > 0) {
+ BufferStatusMessage message;
+ message.status = BufferStatus::INVALIDATION_ACK;
+ message.bufferId = invalidateId;
+ message.connectionId = connectionId;
+ if (!mBufferStatusQueue->write(&message, 1)) {
+ // Since available # of writes are already confirmed,
+ // this should not happen.
+ // TODO: error handing?
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return;
+ }
+ *invalidated = true;
+ }
+ }
+}
+
+bool BufferStatusChannel::postBufferStatusMessage(
+ TransactionId transactionId, BufferId bufferId,
+ BufferStatus status, ConnectionId connectionId, ConnectionId targetId,
+ std::list<BufferId> &pending, std::list<BufferId> &posted) {
+ if (mValid) {
+ size_t avail = mBufferStatusQueue->availableToWrite();
+ size_t numPending = pending.size();
+ if (avail >= numPending + 1) {
+ BufferStatusMessage release, message;
+ for (size_t i = 0; i < numPending; ++i) {
+ BufferId id = pending.front();
+ release.status = BufferStatus::NOT_USED;
+ release.bufferId = id;
+ release.connectionId = connectionId;
+ if (!mBufferStatusQueue->write(&release, 1)) {
+ // Since available # of writes are already confirmed,
+ // this should not happen.
+ // TODO: error handling?
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return false;
+ }
+ pending.pop_front();
+ posted.push_back(id);
+ }
+ message.transactionId = transactionId;
+ message.bufferId = bufferId;
+ message.status = status;
+ message.connectionId = connectionId;
+ message.targetConnectionId = targetId;
+ // TODO : timesatamp
+ message.timestampUs = 0;
+ if (!mBufferStatusQueue->write(&message, 1)) {
+ // Since available # of writes are already confirmed,
+ // this should not happen.
+ ALOGW("FMQ message cannot be sent from %lld", (long long)connectionId);
+ return false;
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+BufferInvalidationListener::BufferInvalidationListener(
+ const InvalidationDescriptor &fmqDesc) {
+ std::unique_ptr<BufferInvalidationQueue> queue =
+ std::make_unique<BufferInvalidationQueue>(fmqDesc);
+ if (!queue || queue->isValid() == false) {
+ mValid = false;
+ return;
+ }
+ mValid = true;
+ mBufferInvalidationQueue = std::move(queue);
+ // drain previous messages
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (avail > 0) {
+ mBufferInvalidationQueue->read(temp.data(), avail);
+ }
+}
+
+void BufferInvalidationListener::getInvalidations(
+ std::vector<BufferInvalidationMessage> &messages) {
+ // Try twice in case of overflow.
+ // TODO: handling overflow though it may not happen.
+ for (int i = 0; i < 2; ++i) {
+ size_t avail = std::min(
+ mBufferInvalidationQueue->availableToRead(), (size_t) kNumElementsInQueue);
+ if (avail > 0) {
+ std::vector<BufferInvalidationMessage> temp(avail);
+ if (mBufferInvalidationQueue->read(temp.data(), avail)) {
+ messages.reserve(messages.size() + avail);
+ for (auto it = temp.begin(); it != temp.end(); ++it) {
+ messages.push_back(*it);
+ }
+ break;
+ }
+ } else {
+ return;
+ }
+ }
+}
+
+bool BufferInvalidationListener::isValid() {
+ return mValid;
+}
+
+BufferInvalidationChannel::BufferInvalidationChannel()
+ : mValid(true),
+ mBufferInvalidationQueue(
+ std::make_unique<BufferInvalidationQueue>(kNumElementsInQueue, true)) {
+ if (!mBufferInvalidationQueue || mBufferInvalidationQueue->isValid() == false) {
+ mValid = false;
+ }
+}
+
+bool BufferInvalidationChannel::isValid() {
+ return mValid;
+}
+
+void BufferInvalidationChannel::getDesc(InvalidationDescriptor *fmqDescPtr) {
+ if (mValid) {
+ *fmqDescPtr = mBufferInvalidationQueue->dupeDesc();
+ }
+ // TODO: writing invalid descriptor?
+}
+
+void BufferInvalidationChannel::postInvalidation(
+ uint32_t msgId, BufferId fromId, BufferId toId) {
+ BufferInvalidationMessage message;
+
+ message.messageId = msgId;
+ message.fromBufferId = fromId;
+ message.toBufferId = toId;
+ // TODO: handle failure (it does not happen normally.)
+ mBufferInvalidationQueue->write(&message);
+}
+
+} // namespace ::aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/BufferStatus.h b/media/bufferpool/aidl/default/BufferStatus.h
new file mode 100644
index 0000000..3dd92f4
--- /dev/null
+++ b/media/bufferpool/aidl/default/BufferStatus.h
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <bufferpool2/BufferPoolTypes.h>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <vector>
+#include <list>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+bool isMessageLater(uint32_t curMsgId, uint32_t prevMsgId);
+
+bool isBufferInRange(BufferId from, BufferId to, BufferId bufferId);
+
+/**
+ * A collection of buffer status message FMQ for a buffer pool. buffer
+ * ownership/status change messages are sent via the FMQs from the clients.
+ */
+class BufferStatusObserver {
+private:
+ std::map<ConnectionId, std::unique_ptr<BufferStatusQueue>>
+ mBufferStatusQueues;
+
+public:
+ /** Creates a buffer status message FMQ for the specified
+ * connection(client).
+ *
+ * @param connectionId connection Id of the specified client.
+ * @param fmqDescPtr ptr of created FMQ's descriptor.
+ *
+ * @return OK if FMQ is created successfully.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus open(ConnectionId id, StatusDescriptor* _Nonnull fmqDescPtr);
+
+ /** Closes a buffer status message FMQ for the specified
+ * connection(client).
+ *
+ * @param connectionId connection Id of the specified client.
+ *
+ * @return OK if the specified connection is closed successfully.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus close(ConnectionId id);
+
+ /** Retrieves all pending FMQ buffer status messages from clients.
+ *
+ * @param messages retrieved pending messages.
+ */
+ void getBufferStatusChanges(std::vector<BufferStatusMessage> &messages);
+};
+
+/**
+ * A buffer status message FMQ for a buffer pool client. Buffer ownership/status
+ * change messages are sent via the fmq to the buffer pool.
+ */
+class BufferStatusChannel {
+private:
+ bool mValid;
+ std::unique_ptr<BufferStatusQueue> mBufferStatusQueue;
+
+public:
+ /**
+ * Connects to a buffer status message FMQ from a descriptor of
+ * the created FMQ.
+ *
+ * @param fmqDesc Descriptor of the created FMQ.
+ */
+ BufferStatusChannel(const StatusDescriptor &fmqDesc);
+
+ /** Returns whether the FMQ is connected successfully. */
+ bool isValid();
+
+ /** Returns whether the FMQ needs to be synced from the buffer pool */
+ bool needsSync();
+
+ /**
+ * Posts a buffer release message to the buffer pool.
+ *
+ * @param connectionId connection Id of the client.
+ * @param pending currently pending buffer release messages.
+ * @param posted posted buffer release messages.
+ */
+ void postBufferRelease(
+ ConnectionId connectionId,
+ std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+ /**
+ * Posts a buffer status message regarding the specified buffer
+ * transfer transaction.
+ *
+ * @param transactionId Id of the specified transaction.
+ * @param bufferId buffer Id of the specified transaction.
+ * @param status new status of the buffer.
+ * @param connectionId connection Id of the client.
+ * @param targetId connection Id of the receiver(only when the sender
+ * posts a status message).
+ * @param pending currently pending buffer release messages.
+ * @param posted posted buffer release messages.
+ *
+ * @return {@code true} when the specified message is posted,
+ * {@code false} otherwise.
+ */
+ bool postBufferStatusMessage(
+ TransactionId transactionId,
+ BufferId bufferId,
+ BufferStatus status,
+ ConnectionId connectionId,
+ ConnectionId targetId,
+ std::list<BufferId> &pending, std::list<BufferId> &posted);
+
+ /**
+ * Posts a buffer invaliadation message to the buffer pool.
+ *
+ * @param connectionId connection Id of the client.
+ * @param invalidateId invalidation ack to the buffer pool.
+ * if invalidation id is zero, the ack will not be
+ * posted.
+ * @param invalidated sets {@code true} only when the invalidation ack is
+ * posted.
+ */
+ void postBufferInvalidateAck(
+ ConnectionId connectionId,
+ uint32_t invalidateId,
+ bool* _Nonnull invalidated);
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool client. Buffer invalidation
+ * messages are received via the fmq from the buffer pool. Buffer invalidation
+ * messages are handled as soon as possible.
+ */
+class BufferInvalidationListener {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Connects to a buffer invalidation FMQ from a descriptor of the created FMQ.
+ *
+ * @param fmqDesc Descriptor of the created FMQ.
+ */
+ BufferInvalidationListener(const InvalidationDescriptor &fmqDesc);
+
+ /** Retrieves all pending buffer invalidation messages from the buffer pool.
+ *
+ * @param messages retrieved pending messages.
+ */
+ void getInvalidations(std::vector<BufferInvalidationMessage> &messages);
+
+ /** Returns whether the FMQ is connected successfully. */
+ bool isValid();
+};
+
+/**
+ * A buffer invalidation FMQ for a buffer pool. A buffer pool will send buffer
+ * invalidation messages to the clients via the FMQ. The FMQ is shared among
+ * buffer pool clients.
+ */
+class BufferInvalidationChannel {
+private:
+ bool mValid;
+ std::unique_ptr<BufferInvalidationQueue> mBufferInvalidationQueue;
+
+public:
+ /**
+ * Creates a buffer invalidation FMQ for a buffer pool.
+ */
+ BufferInvalidationChannel();
+
+ /** Returns whether the FMQ is connected successfully. */
+ bool isValid();
+
+ /**
+ * Retrieves the descriptor of a buffer invalidation FMQ. the descriptor may
+ * be passed to the client for buffer invalidation handling.
+ *
+ * @param fmqDescPtr ptr of created FMQ's descriptor.
+ */
+ void getDesc(InvalidationDescriptor* _Nonnull fmqDescPtr);
+
+ /** Posts a buffer invalidation for invalidated buffers.
+ *
+ * @param msgId Invalidation message id which is used when clients send
+ * acks back via BufferStatusMessage
+ * @param fromId The start bufferid of the invalidated buffers(inclusive)
+ * @param toId The end bufferId of the invalidated buffers(inclusive)
+ */
+ void postInvalidation(uint32_t msgId, BufferId fromId, BufferId toId);
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/ClientManager.cpp b/media/bufferpool/aidl/default/ClientManager.cpp
new file mode 100644
index 0000000..de1db50
--- /dev/null
+++ b/media/bufferpool/aidl/default/ClientManager.cpp
@@ -0,0 +1,515 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AidlBufferPoolMgr"
+//#define LOG_NDEBUG 0
+
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <sys/types.h>
+#include <utils/SystemClock.h>
+#include <unistd.h>
+#include <utils/Log.h>
+
+#include <chrono>
+
+#include "BufferPoolClient.h"
+#include "Observer.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using namespace std::chrono_literals;
+
+using Registration = aidl::android::hardware::media::bufferpool2::IClientManager::Registration;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+static constexpr int64_t kRegisterTimeoutMs = 500; // 0.5 sec
+static constexpr int64_t kCleanUpDurationMs = 1000; // TODO: 1 sec tune
+static constexpr int64_t kClientTimeoutMs = 5000; // TODO: 5 secs tune
+
+class ClientManager::Impl {
+public:
+ Impl();
+
+ // BnRegisterSender
+ BufferPoolStatus registerSender(const std::shared_ptr<IAccessor> &accessor,
+ Registration *pRegistration);
+
+ // BpRegisterSender
+ BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+ ConnectionId senderId,
+ ConnectionId *receiverId,
+ bool *isNew);
+
+ BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+ ConnectionId *pConnectionId);
+
+ BufferPoolStatus close(ConnectionId connectionId);
+
+ BufferPoolStatus flush(ConnectionId connectionId);
+
+ BufferPoolStatus allocate(ConnectionId connectionId,
+ const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ BufferPoolStatus receive(ConnectionId connectionId,
+ TransactionId transactionId,
+ BufferId bufferId,
+ int64_t timestampMs,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ BufferPoolStatus postSend(ConnectionId receiverId,
+ const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId,
+ int64_t *timestampMs);
+
+ BufferPoolStatus getAccessor(ConnectionId connectionId,
+ std::shared_ptr<IAccessor> *accessor);
+
+ void cleanUp(bool clearCache = false);
+
+private:
+ // In order to prevent deadlock between multiple locks,
+ // always lock ClientCache.lock before locking ActiveClients.lock.
+ struct ClientCache {
+ // This lock is held for brief duration.
+ // Blocking operation is not performed while holding the lock.
+ std::mutex mMutex;
+ std::list<std::pair<const std::weak_ptr<IAccessor>, const std::weak_ptr<BufferPoolClient>>>
+ mClients;
+ std::condition_variable mConnectCv;
+ bool mConnecting;
+ int64_t mLastCleanUpMs;
+
+ ClientCache() : mConnecting(false), mLastCleanUpMs(::android::elapsedRealtime()) {}
+ } mCache;
+
+ // Active clients which can be retrieved via ConnectionId
+ struct ActiveClients {
+ // This lock is held for brief duration.
+ // Blocking operation is not performed holding the lock.
+ std::mutex mMutex;
+ std::map<ConnectionId, const std::shared_ptr<BufferPoolClient>>
+ mClients;
+ } mActive;
+
+ std::shared_ptr<Observer> mObserver;
+};
+
+ClientManager::Impl::Impl()
+ : mObserver(::ndk::SharedRefBase::make<Observer>()) {}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+ const std::shared_ptr<IAccessor> &accessor, Registration *pRegistration) {
+ cleanUp();
+ int64_t timeoutMs = ::android::elapsedRealtime() + kRegisterTimeoutMs;
+ do {
+ std::unique_lock<std::mutex> lock(mCache.mMutex);
+ for (auto it = mCache.mClients.begin(); it != mCache.mClients.end(); ++it) {
+ std::shared_ptr<IAccessor> sAccessor = it->first.lock();
+ if (sAccessor && sAccessor.get() == accessor.get()) {
+ const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+ if (client) {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ pRegistration->connectionId = client->getConnectionId();
+ if (mActive.mClients.find(pRegistration->connectionId)
+ != mActive.mClients.end()) {
+ ALOGV("register existing connection %lld",
+ (long long)pRegistration->connectionId);
+ pRegistration->isNew = false;
+ return ResultStatus::OK;
+ }
+ }
+ mCache.mClients.erase(it);
+ break;
+ }
+ }
+ if (!mCache.mConnecting) {
+ mCache.mConnecting = true;
+ lock.unlock();
+ BufferPoolStatus result = ResultStatus::OK;
+ const std::shared_ptr<BufferPoolClient> client =
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
+ lock.lock();
+ if (!client) {
+ result = ResultStatus::NO_MEMORY;
+ } else if (!client->isValid()) {
+ result = ResultStatus::CRITICAL_ERROR;
+ }
+ if (result == ResultStatus::OK) {
+ // TODO: handle insert fail. (malloc fail)
+ const std::weak_ptr<BufferPoolClient> wclient = client;
+ mCache.mClients.push_back(std::make_pair(accessor, wclient));
+ ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ mActive.mClients.insert(std::make_pair(conId, client));
+ }
+ pRegistration->connectionId = conId;
+ pRegistration->isNew = true;
+ ALOGV("register new connection %lld", (long long)conId);
+ }
+ mCache.mConnecting = false;
+ lock.unlock();
+ mCache.mConnectCv.notify_all();
+ return result;
+ }
+ mCache.mConnectCv.wait_for(lock, kRegisterTimeoutMs*1ms);
+ } while (::android::elapsedRealtime() < timeoutMs);
+ // TODO: return timeout error
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::registerSender(
+ const std::shared_ptr<IClientManager> &receiver,
+ ConnectionId senderId,
+ ConnectionId *receiverId,
+ bool *isNew) {
+ std::shared_ptr<IAccessor> accessor;
+ bool local = false;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(senderId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ it->second->getAccessor(&accessor);
+ local = it->second->isLocal();
+ }
+ if (accessor) {
+ Registration registration;
+ ::ndk::ScopedAStatus status = receiver->registerSender(accessor, ®istration);
+ if (!status.isOk()) {
+ return ResultStatus::CRITICAL_ERROR;
+ } else if (local) {
+ std::shared_ptr<ConnectionDeathRecipient> recipient =
+ Accessor::getConnectionDeathRecipient();
+ if (recipient) {
+ ALOGV("client death recipient registered %lld", (long long)*receiverId);
+ recipient->addCookieToConnection(receiver->asBinder().get(), *receiverId);
+ AIBinder_linkToDeath(receiver->asBinder().get(), recipient->getRecipient(),
+ receiver->asBinder().get());
+ }
+ }
+ *receiverId = registration.connectionId;
+ *isNew = registration.isNew;
+ return ResultStatus::OK;
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::Impl::create(
+ const std::shared_ptr<BufferPoolAllocator> &allocator,
+ ConnectionId *pConnectionId) {
+ std::shared_ptr<Accessor> accessor = ::ndk::SharedRefBase::make<Accessor>(allocator);
+ if (!accessor || !accessor->isValid()) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ // TODO: observer is local. use direct call instead of hidl call.
+ std::shared_ptr<BufferPoolClient> client =
+ std::make_shared<BufferPoolClient>(accessor, mObserver);
+ if (!client || !client->isValid()) {
+ return ResultStatus::CRITICAL_ERROR;
+ }
+ // Since a new bufferpool is created, evict memories which are used by
+ // existing bufferpools and clients.
+ cleanUp(true);
+ {
+ // TODO: handle insert fail. (malloc fail)
+ std::lock_guard<std::mutex> lock(mCache.mMutex);
+ const std::weak_ptr<BufferPoolClient> wclient = client;
+ mCache.mClients.push_back(std::make_pair(accessor, wclient));
+ ConnectionId conId = client->getConnectionId();
+ mObserver->addClient(conId, wclient);
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ mActive.mClients.insert(std::make_pair(conId, client));
+ }
+ *pConnectionId = conId;
+ ALOGV("create new connection %lld", (long long)*pConnectionId);
+ }
+ return ResultStatus::OK;
+}
+
+BufferPoolStatus ClientManager::Impl::close(ConnectionId connectionId) {
+ std::unique_lock<std::mutex> lock1(mCache.mMutex);
+ std::unique_lock<std::mutex> lock2(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it != mActive.mClients.end()) {
+ std::shared_ptr<IAccessor> accessor;
+ it->second->getAccessor(&accessor);
+ std::shared_ptr<BufferPoolClient> closing = it->second;
+ mActive.mClients.erase(connectionId);
+ for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+ // clean up dead client caches
+ std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+ if (!cAccessor || (accessor && cAccessor.get() == accessor.get())) {
+ cit = mCache.mClients.erase(cit);
+ } else {
+ cit++;
+ }
+ }
+ lock2.unlock();
+ lock1.unlock();
+ closing->flush();
+ return ResultStatus::OK;
+ }
+ return ResultStatus::NOT_FOUND;
+}
+
+BufferPoolStatus ClientManager::Impl::flush(ConnectionId connectionId) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+ return client->flush();
+}
+
+BufferPoolStatus ClientManager::Impl::allocate(
+ ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+ native_handle_t *origHandle;
+ BufferPoolStatus res = client->allocate(params, &origHandle, buffer);
+ if (res != ResultStatus::OK) {
+ return res;
+ }
+ *handle = native_handle_clone(origHandle);
+ if (handle == NULL) {
+ buffer->reset();
+ return ResultStatus::NO_MEMORY;
+ }
+ return ResultStatus::OK;
+#else
+ return client->allocate(params, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::receive(
+ ConnectionId connectionId, TransactionId transactionId,
+ BufferId bufferId, int64_t timestampMs,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+#ifdef BUFFERPOOL_CLONE_HANDLES
+ native_handle_t *origHandle;
+ BufferPoolStatus res = client->receive(
+ transactionId, bufferId, timestampMs, &origHandle, buffer);
+ if (res != ResultStatus::OK) {
+ return res;
+ }
+ *handle = native_handle_clone(origHandle);
+ if (handle == NULL) {
+ buffer->reset();
+ return ResultStatus::NO_MEMORY;
+ }
+ return ResultStatus::OK;
+#else
+ return client->receive(transactionId, bufferId, timestampMs, handle, buffer);
+#endif
+}
+
+BufferPoolStatus ClientManager::Impl::postSend(
+ ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId, int64_t *timestampMs) {
+ ConnectionId connectionId = buffer->mConnectionId;
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+ return client->postSend(receiverId, buffer, transactionId, timestampMs);
+}
+
+BufferPoolStatus ClientManager::Impl::getAccessor(
+ ConnectionId connectionId, std::shared_ptr<IAccessor> *accessor) {
+ std::shared_ptr<BufferPoolClient> client;
+ {
+ std::lock_guard<std::mutex> lock(mActive.mMutex);
+ auto it = mActive.mClients.find(connectionId);
+ if (it == mActive.mClients.end()) {
+ return ResultStatus::NOT_FOUND;
+ }
+ client = it->second;
+ }
+ return client->getAccessor(accessor);
+}
+
+void ClientManager::Impl::cleanUp(bool clearCache) {
+ int64_t now = ::android::elapsedRealtime();
+ int64_t lastTransactionMs;
+ std::lock_guard<std::mutex> lock1(mCache.mMutex);
+ if (clearCache || mCache.mLastCleanUpMs + kCleanUpDurationMs < now) {
+ std::lock_guard<std::mutex> lock2(mActive.mMutex);
+ int cleaned = 0;
+ for (auto it = mActive.mClients.begin(); it != mActive.mClients.end();) {
+ if (!it->second->isActive(&lastTransactionMs, clearCache)) {
+ if (lastTransactionMs + kClientTimeoutMs < now) {
+ std::shared_ptr<IAccessor> accessor;
+ it->second->getAccessor(&accessor);
+ it = mActive.mClients.erase(it);
+ ++cleaned;
+ continue;
+ }
+ }
+ ++it;
+ }
+ for (auto cit = mCache.mClients.begin(); cit != mCache.mClients.end();) {
+ // clean up dead client caches
+ std::shared_ptr<IAccessor> cAccessor = cit->first.lock();
+ if (!cAccessor) {
+ cit = mCache.mClients.erase(cit);
+ } else {
+ ++cit;
+ }
+ }
+ ALOGV("# of cleaned connections: %d", cleaned);
+ mCache.mLastCleanUpMs = now;
+ }
+}
+
+::ndk::ScopedAStatus ClientManager::registerSender(
+ const std::shared_ptr<IAccessor>& in_bufferPool, Registration* _aidl_return) {
+ BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+ if (mImpl) {
+ status = mImpl->registerSender(in_bufferPool, _aidl_return);
+ }
+ if (status != ResultStatus::OK) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(status);
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+// Methods for local use.
+std::shared_ptr<ClientManager> ClientManager::sInstance;
+std::mutex ClientManager::sInstanceLock;
+
+std::shared_ptr<ClientManager> ClientManager::getInstance() {
+ std::lock_guard<std::mutex> lock(sInstanceLock);
+ if (!sInstance) {
+ sInstance = ::ndk::SharedRefBase::make<ClientManager>();
+ // TODO: configure thread count for threadpool properly
+ // after b/261652496 is resolved.
+ }
+ Accessor::createInvalidator();
+ Accessor::createEvictor();
+ return sInstance;
+}
+
+ClientManager::ClientManager() : mImpl(new Impl()) {}
+
+ClientManager::~ClientManager() {
+}
+
+BufferPoolStatus ClientManager::create(
+ const std::shared_ptr<BufferPoolAllocator> &allocator,
+ ConnectionId *pConnectionId) {
+ if (mImpl) {
+ return mImpl->create(allocator, pConnectionId);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::registerSender(
+ const std::shared_ptr<IClientManager> &receiver,
+ ConnectionId senderId,
+ ConnectionId *receiverId,
+ bool *isNew) {
+ if (mImpl) {
+ return mImpl->registerSender(receiver, senderId, receiverId, isNew);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::close(ConnectionId connectionId) {
+ if (mImpl) {
+ return mImpl->close(connectionId);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::flush(ConnectionId connectionId) {
+ if (mImpl) {
+ return mImpl->flush(connectionId);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::allocate(
+ ConnectionId connectionId, const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+ if (mImpl) {
+ return mImpl->allocate(connectionId, params, handle, buffer);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::receive(
+ ConnectionId connectionId, TransactionId transactionId,
+ BufferId bufferId, int64_t timestampMs,
+ native_handle_t **handle, std::shared_ptr<BufferPoolData> *buffer) {
+ if (mImpl) {
+ return mImpl->receive(connectionId, transactionId, bufferId,
+ timestampMs, handle, buffer);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus ClientManager::postSend(
+ ConnectionId receiverId, const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId, int64_t* timestampMs) {
+ if (mImpl && buffer) {
+ return mImpl->postSend(receiverId, buffer, transactionId, timestampMs);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+void ClientManager::cleanUp() {
+ if (mImpl) {
+ mImpl->cleanUp(true);
+ }
+}
+
+} // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.cpp b/media/bufferpool/aidl/default/Connection.cpp
new file mode 100644
index 0000000..53d350d
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "AidlBufferPoolCon"
+//#define LOG_NDEBUG 0
+
+#include <aidlcommonsupport/NativeHandle.h>
+
+#include "Connection.h"
+#include "Accessor.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using Buffer = aidl::android::hardware::media::bufferpool2::Buffer;
+using FetchInfo = aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo;
+using FetchResult = aidl::android::hardware::media::bufferpool2::IConnection::FetchResult;
+
+::ndk::ScopedAStatus Connection::fetch(const std::vector<FetchInfo>& in_fetchInfos,
+ std::vector<FetchResult>* _aidl_return) {
+ int success = 0;
+ int failure = 0;
+ if (mInitialized && mAccessor) {
+ for (auto it = in_fetchInfos.begin(); it != in_fetchInfos.end(); ++it) {
+ if (fetch(it->transactionId, it->bufferId, _aidl_return)) {
+ success++;
+ } else {
+ failure++;
+ }
+ }
+ if (failure > 0) {
+ ALOGD("total fetch %d, failure %d", success + failure, failure);
+ }
+ return ::ndk::ScopedAStatus::ok();
+ }
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(ResultStatus::CRITICAL_ERROR);
+}
+
+::ndk::ScopedAStatus Connection::sync() {
+ if (mInitialized && mAccessor) {
+ mAccessor->cleanUp(false);
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+
+bool Connection::fetch(TransactionId transactionId, BufferId bufferId,
+ std::vector<FetchResult> *result) {
+ BufferPoolStatus status = ResultStatus::CRITICAL_ERROR;
+ const native_handle_t *handle = nullptr;
+ status = mAccessor->fetch(
+ mConnectionId, transactionId, bufferId, &handle);
+ if (status == ResultStatus::OK) {
+ result->emplace_back(FetchResult::make<FetchResult::buffer>());
+ result->back().get<FetchResult::buffer>().id = bufferId;
+ result->back().get<FetchResult::buffer>().buffer = ::android::dupToAidl(handle);
+ return true;
+ }
+ result->emplace_back(FetchResult::make<FetchResult::failure>(status));
+ return false;
+}
+
+Connection::Connection() : mInitialized(false), mConnectionId(-1LL) {}
+
+Connection::~Connection() {
+ if (mInitialized && mAccessor) {
+ mAccessor->close(mConnectionId);
+ }
+}
+
+void Connection::initialize(
+ const std::shared_ptr<Accessor>& accessor, ConnectionId connectionId) {
+ if (!mInitialized) {
+ mAccessor = accessor;
+ mConnectionId = connectionId;
+ mInitialized = true;
+ }
+}
+
+BufferPoolStatus Connection::flush() {
+ if (mInitialized && mAccessor) {
+ return mAccessor->flush();
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+BufferPoolStatus Connection::allocate(
+ const std::vector<uint8_t> ¶ms, BufferId *bufferId,
+ const native_handle_t **handle) {
+ if (mInitialized && mAccessor) {
+ return mAccessor->allocate(mConnectionId, params, bufferId, handle);
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+void Connection::cleanUp(bool clearCache) {
+ if (mInitialized && mAccessor) {
+ mAccessor->cleanUp(clearCache);
+ }
+}
+
+} // namespace ::aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Connection.h b/media/bufferpool/aidl/default/Connection.h
new file mode 100644
index 0000000..d8298af
--- /dev/null
+++ b/media/bufferpool/aidl/default/Connection.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <aidl/android/hardware/media/bufferpool2/BnConnection.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+struct Accessor;
+
+struct Connection : public BnConnection {
+ // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+ ::ndk::ScopedAStatus fetch(const std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchInfo>& in_fetchInfos, std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>* _aidl_return) override;
+
+ // Methods from ::aidl::android::hardware::media::bufferpool2::IConnection.
+ ::ndk::ScopedAStatus sync() override;
+
+ /**
+ * Invalidates all buffers which are active and/or are ready to be recycled.
+ */
+ BufferPoolStatus flush();
+
+ /**
+ * Allocates a buffer using the specified parameters. Recycles a buffer if
+ * it is possible. The returned buffer can be transferred to other remote
+ * clients(Connection).
+ *
+ * @param params allocation parameters.
+ * @param bufferId Id of the allocated buffer.
+ * @param handle native handle of the allocated buffer.
+ *
+ * @return OK if a buffer is successfully allocated.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus allocate(const std::vector<uint8_t> ¶ms,
+ BufferId *bufferId, const native_handle_t **handle);
+
+ /**
+ * Processes pending buffer status messages and performs periodic cache cleaning
+ * from bufferpool.
+ *
+ * @param clearCache if clearCache is true, bufferpool frees all buffers
+ * waiting to be recycled.
+ */
+ void cleanUp(bool clearCache);
+
+ /** Destructs a connection. */
+ ~Connection();
+
+ /** Creates a connection. */
+ Connection();
+
+ /**
+ * Initializes with the specified buffer pool and the connection id.
+ * The connection id should be unique in the whole system.
+ *
+ * @param accessor the specified buffer pool.
+ * @param connectionId Id.
+ */
+ void initialize(const std::shared_ptr<Accessor> &accessor, ConnectionId connectionId);
+
+ enum : uint32_t {
+ SYNC_BUFFERID = UINT32_MAX,
+ };
+
+private:
+ bool mInitialized;
+ std::shared_ptr<Accessor> mAccessor;
+ ConnectionId mConnectionId;
+
+ bool fetch(
+ uint64_t transactionId,
+ uint32_t bufferId,
+ std::vector<::aidl::android::hardware::media::bufferpool2::IConnection::FetchResult>
+ *result);
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/DataHelper.h b/media/bufferpool/aidl/default/DataHelper.h
new file mode 100644
index 0000000..a90b3c7
--- /dev/null
+++ b/media/bufferpool/aidl/default/DataHelper.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+#include <map>
+#include <set>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool insert(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+ auto iter = mapOfSet->find(key);
+ if (iter == mapOfSet->end()) {
+ std::set<U> valueSet{value};
+ mapOfSet->insert(std::make_pair(key, valueSet));
+ return true;
+ } else if (iter->second.find(value) == iter->second.end()) {
+ iter->second.insert(value);
+ return true;
+ }
+ return false;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool erase(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+ bool ret = false;
+ auto iter = mapOfSet->find(key);
+ if (iter != mapOfSet->end()) {
+ if (iter->second.erase(value) > 0) {
+ ret = true;
+ }
+ if (iter->second.size() == 0) {
+ mapOfSet->erase(iter);
+ }
+ }
+ return ret;
+}
+
+// Helper template methods for handling map of set.
+template<class T, class U>
+bool contains(std::map<T, std::set<U>> *mapOfSet, T key, U value) {
+ auto iter = mapOfSet->find(key);
+ if (iter != mapOfSet->end()) {
+ auto setIter = iter->second.find(value);
+ return setIter != iter->second.end();
+ }
+ return false;
+}
+
+// Buffer data structure for internal BufferPool use.(storage/fetching)
+struct InternalBuffer {
+ BufferId mId;
+ size_t mOwnerCount;
+ size_t mTransactionCount;
+ const std::shared_ptr<BufferPoolAllocation> mAllocation;
+ const size_t mAllocSize;
+ const std::vector<uint8_t> mConfig;
+ bool mInvalidated;
+
+ InternalBuffer(
+ BufferId id,
+ const std::shared_ptr<BufferPoolAllocation> &alloc,
+ const size_t allocSize,
+ const std::vector<uint8_t> &allocConfig)
+ : mId(id), mOwnerCount(0), mTransactionCount(0),
+ mAllocation(alloc), mAllocSize(allocSize), mConfig(allocConfig),
+ mInvalidated(false) {}
+
+ const native_handle_t *handle() {
+ return mAllocation->handle();
+ }
+
+ void invalidate() {
+ mInvalidated = true;
+ }
+};
+
+// Buffer transacion status/message data structure for internal BufferPool use.
+struct TransactionStatus {
+ TransactionId mId;
+ BufferId mBufferId;
+ ConnectionId mSender;
+ ConnectionId mReceiver;
+ BufferStatus mStatus;
+ int64_t mTimestampMs;
+ bool mSenderValidated;
+
+ TransactionStatus(const BufferStatusMessage &message, int64_t timestampMs) {
+ mId = message.transactionId;
+ mBufferId = message.bufferId;
+ mStatus = message.status;
+ mTimestampMs = timestampMs;
+ if (mStatus == BufferStatus::TRANSFER_TO) {
+ mSender = message.connectionId;
+ mReceiver = message.targetConnectionId;
+ mSenderValidated = true;
+ } else {
+ mSender = -1LL;
+ mReceiver = message.connectionId;
+ mSenderValidated = false;
+ }
+ }
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.cpp b/media/bufferpool/aidl/default/Observer.cpp
new file mode 100644
index 0000000..a22e825
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Observer.h"
+#include "BufferPoolClient.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+Observer::Observer() {
+}
+
+Observer::~Observer() {
+}
+
+::ndk::ScopedAStatus Observer::onMessage(int64_t in_connectionId, int32_t in_msgId) {
+ std::unique_lock<std::mutex> lock(mLock);
+ auto it = mClients.find(in_connectionId);
+ if (it != mClients.end()) {
+ const std::shared_ptr<BufferPoolClient> client = it->second.lock();
+ if (!client) {
+ mClients.erase(it);
+ } else {
+ lock.unlock();
+ client->receiveInvalidation(in_msgId);
+ }
+ }
+ return ::ndk::ScopedAStatus::ok();
+}
+
+void Observer::addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient) {
+ std::lock_guard<std::mutex> lock(mLock);
+ for (auto it = mClients.begin(); it != mClients.end();) {
+ if (!it->second.lock() || it->first == connectionId) {
+ it = mClients.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ mClients.insert(std::make_pair(connectionId, wclient));
+
+}
+
+void Observer::delClient(ConnectionId connectionId) {
+ std::lock_guard<std::mutex> lock(mLock);
+ mClients.erase(connectionId);
+}
+
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
diff --git a/media/bufferpool/aidl/default/Observer.h b/media/bufferpool/aidl/default/Observer.h
new file mode 100644
index 0000000..febb21b
--- /dev/null
+++ b/media/bufferpool/aidl/default/Observer.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <aidl/android/hardware/media/bufferpool2/BnObserver.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+class BufferPoolClient;
+
+struct Observer : public BnObserver {
+ ::ndk::ScopedAStatus onMessage(int64_t in_connectionId, int32_t in_msgId) override;
+
+ ~Observer();
+
+ void addClient(ConnectionId connectionId,
+ const std::weak_ptr<BufferPoolClient> &wclient);
+
+ void delClient(ConnectionId connectionId);
+
+private:
+ Observer();
+
+ friend class ::ndk::SharedRefBase;
+
+ std::mutex mLock;
+ std::map<ConnectionId, const std::weak_ptr<BufferPoolClient>> mClients;
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
new file mode 100644
index 0000000..b833362
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/BufferPoolTypes.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cutils/native_handle.h>
+#include <fmq/AidlMessageQueue.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferStatusMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/BufferInvalidationMessage.h>
+#include <aidl/android/hardware/media/bufferpool2/ResultStatus.h>
+
+namespace aidl::android::hardware::media::bufferpool2 {
+
+struct BufferPoolData {
+ // For local use, to specify a bufferpool (client connection) for buffers.
+ // Retrieved from returned info of IAccessor#connect(android.hardware.media.bufferpool@2.0).
+ int64_t mConnectionId;
+ // BufferId
+ uint32_t mId;
+
+ BufferPoolData() : mConnectionId(0), mId(0) {}
+
+ BufferPoolData(
+ int64_t connectionId, uint32_t id)
+ : mConnectionId(connectionId), mId(id) {}
+
+ ~BufferPoolData() {}
+};
+
+namespace implementation {
+
+using aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using aidl::android::hardware::common::fmq::UnsynchronizedWrite;
+
+using aidl::android::hardware::media::bufferpool2::BufferStatusMessage;
+using aidl::android::hardware::media::bufferpool2::BufferInvalidationMessage;
+
+typedef uint32_t BufferId;
+typedef uint64_t TransactionId;
+typedef int64_t ConnectionId;
+typedef int32_t BufferPoolStatus;
+
+// AIDL hal description language does not support unsigned.
+int32_t static inline ToAidl(BufferId id) {return static_cast<int32_t>(id);}
+int64_t static inline ToAidl(TransactionId id) {return static_cast<int64_t>(id);}
+
+BufferId static inline FromAidl(int32_t id) {return static_cast<BufferId>(id);}
+TransactionId static inline FromAidl(int64_t id) {return static_cast<TransactionId>(id);}
+
+enum : ConnectionId {
+ INVALID_CONNECTIONID = 0,
+};
+
+typedef ::android::AidlMessageQueue<BufferStatusMessage, SynchronizedReadWrite> BufferStatusQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferStatusMessage, SynchronizedReadWrite>
+ StatusDescriptor;
+
+typedef ::android::AidlMessageQueue<BufferInvalidationMessage, UnsynchronizedWrite>
+ BufferInvalidationQueue;
+typedef aidl::android::hardware::common::fmq::MQDescriptor<BufferInvalidationMessage, UnsynchronizedWrite>
+ InvalidationDescriptor;
+
+/**
+ * Allocation wrapper class for buffer pool.
+ */
+struct BufferPoolAllocation {
+ const native_handle_t *mHandle;
+
+ const native_handle_t *handle() {
+ return mHandle;
+ }
+
+ BufferPoolAllocation(const native_handle_t *handle) : mHandle(handle) {}
+
+ ~BufferPoolAllocation() {};
+};
+
+/**
+ * Allocator wrapper class for buffer pool.
+ */
+class BufferPoolAllocator {
+public:
+
+ /**
+ * Allocate an allocation(buffer) for buffer pool.
+ *
+ * @param params allocation parameters
+ * @param alloc created allocation
+ * @param allocSize size of created allocation
+ *
+ * @return OK when an allocation is created successfully.
+ */
+ virtual BufferPoolStatus allocate(
+ const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<BufferPoolAllocation> *alloc,
+ size_t *allocSize) = 0;
+
+ /**
+ * Returns whether allocation parameters of an old allocation are
+ * compatible with new allocation parameters.
+ */
+ virtual bool compatible(const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) = 0;
+
+protected:
+ BufferPoolAllocator() = default;
+
+ virtual ~BufferPoolAllocator() = default;
+};
+
+} // namespace implementation
+} // namespace aidl::android::hareware::media::bufferpool2
+
diff --git a/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
new file mode 100644
index 0000000..bff75ba
--- /dev/null
+++ b/media/bufferpool/aidl/default/include/bufferpool2/ClientManager.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/media/bufferpool2/IAccessor.h>
+#include <aidl/android/hardware/media/bufferpool2/BnClientManager.h>
+#include <memory>
+#include "BufferPoolTypes.h"
+
+namespace aidl::android::hardware::media::bufferpool2::implementation {
+
+using aidl::android::hardware::media::bufferpool2::BnClientManager;
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::IAccessor;
+
+struct ClientManager : public BnClientManager {
+ // Methods from ::aidl::android::hardware::media::bufferpool2::IClientManager follow.
+ ::ndk::ScopedAStatus registerSender(
+ const std::shared_ptr<IAccessor>& in_bufferPool,
+ ::aidl::android::hardware::media::bufferpool2::IClientManager::Registration* _aidl_return)
+ override;
+
+ /** Gets an instance. */
+ static std::shared_ptr<ClientManager> getInstance();
+
+ /**
+ * Creates a local connection with a newly created buffer pool.
+ *
+ * @param allocator for new buffer allocation.
+ * @param pConnectionId Id of the created connection. This is
+ * system-wide unique.
+ *
+ * @return OK when a buffer pool and a local connection is successfully
+ * created.
+ * ResultStatus::NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus create(const std::shared_ptr<BufferPoolAllocator> &allocator,
+ ConnectionId *pConnectionId);
+
+ /**
+ * Register a created connection as sender for remote process.
+ *
+ * @param receiver The remote receiving process.
+ * @param senderId A local connection which will send buffers to.
+ * @param receiverId Id of the created receiving connection on the receiver
+ * process.
+ * @param isNew @true when the receiving connection is newly created.
+ *
+ * @return OK when the receiving connection is successfully created on the
+ * receiver process.
+ * NOT_FOUND when the sender connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus registerSender(const std::shared_ptr<IClientManager> &receiver,
+ ConnectionId senderId,
+ ConnectionId *receiverId,
+ bool *isNew);
+
+ /**
+ * Closes the specified connection.
+ *
+ * @param connectionId The id of the connection.
+ *
+ * @return OK when the connection is closed.
+ * NOT_FOUND when the specified connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus close(ConnectionId connectionId);
+
+ /**
+ * Evicts cached allocations. If it's local connection, release the
+ * previous allocations and do not recycle current active allocations.
+ *
+ * @param connectionId The id of the connection.
+ *
+ * @return OK when the connection is resetted.
+ * NOT_FOUND when the specified connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus flush(ConnectionId connectionId);
+
+ /**
+ * Allocates a buffer from the specified connection. The output parameter
+ * handle is cloned from the internal handle. So it is safe to use directly,
+ * and it should be deleted and destroyed after use.
+ *
+ * @param connectionId The id of the connection.
+ * @param params The allocation parameters.
+ * @param handle The native handle to the allocated buffer. handle
+ * should be cloned before use.
+ * @param buffer The allocated buffer.
+ *
+ * @return OK when a buffer was allocated successfully.
+ * NOT_FOUND when the specified connection was not found.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus allocate(ConnectionId connectionId,
+ const std::vector<uint8_t> ¶ms,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ /**
+ * Receives a buffer for the transaction. The output parameter handle is
+ * cloned from the internal handle. So it is safe to use directly, and it
+ * should be deleted and destoyed after use.
+ *
+ * @param connectionId The id of the receiving connection.
+ * @param transactionId The id for the transaction.
+ * @param bufferId The id for the buffer.
+ * @param timestampMs The timestamp of the buffer is being sent.
+ * @param handle The native handle to the allocated buffer. handle
+ * should be cloned before use.
+ * @param buffer The received buffer.
+ *
+ * @return OK when a buffer was received successfully.
+ * NOT_FOUND when the specified connection was not found.
+ * NO_MEMORY when there is no memory.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus receive(ConnectionId connectionId,
+ TransactionId transactionId,
+ BufferId bufferId,
+ int64_t timestampMs,
+ native_handle_t **handle,
+ std::shared_ptr<BufferPoolData> *buffer);
+
+ /**
+ * Posts a buffer transfer transaction to the buffer pool. Sends a buffer
+ * to other remote clients(connection) after this call has been succeeded.
+ *
+ * @param receiverId The id of the receiving connection.
+ * @param buffer to transfer
+ * @param transactionId Id of the transfer transaction.
+ * @param timestampMs The timestamp of the buffer transaction is being
+ * posted.
+ *
+ * @return OK when a buffer transaction was posted successfully.
+ * NOT_FOUND when the sending connection was not found.
+ * CRITICAL_ERROR otherwise.
+ */
+ BufferPoolStatus postSend(ConnectionId receiverId,
+ const std::shared_ptr<BufferPoolData> &buffer,
+ TransactionId *transactionId,
+ int64_t *timestampMs);
+
+ /**
+ * Time out inactive lingering connections and close.
+ */
+ void cleanUp();
+
+ /** Destructs the manager of buffer pool clients. */
+ ~ClientManager();
+private:
+ static std::shared_ptr<ClientManager> sInstance;
+ static std::mutex sInstanceLock;
+
+ class Impl;
+ const std::unique_ptr<Impl> mImpl;
+
+ friend class ::ndk::SharedRefBase;
+
+ ClientManager();
+};
+
+} // namespace aidl::android::hardware::media::bufferpool2::implementation
+
diff --git a/media/bufferpool/aidl/default/tests/Android.bp b/media/bufferpool/aidl/default/tests/Android.bp
new file mode 100644
index 0000000..549af57
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/Android.bp
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["hardware_interfaces_license"],
+}
+
+cc_test {
+ name: "VtsVndkAidlBufferpool2V1_0TargetSingleTest",
+ test_suites: ["device-tests"],
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "allocator.cpp",
+ "single.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "android.hardware.media.bufferpool2-V1-ndk",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libstagefright_aidl_bufferpool2"
+ ],
+ compile_multilib: "both",
+}
+
+cc_test {
+ name: "VtsVndkAidlBufferpool2V1_0TargetMultiTest",
+ test_suites: ["device-tests"],
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "allocator.cpp",
+ "multi.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "android.hardware.media.bufferpool2-V1-ndk",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libstagefright_aidl_bufferpool2"
+ ],
+ compile_multilib: "both",
+}
+
+cc_test {
+ name: "VtsVndkAidlBufferpool2V1_0TargetCondTest",
+ test_suites: ["device-tests"],
+ defaults: ["VtsHalTargetTestDefaults"],
+ srcs: [
+ "allocator.cpp",
+ "cond.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcutils",
+ "libfmq",
+ "liblog",
+ "libutils",
+ "android.hardware.media.bufferpool2-V1-ndk",
+ ],
+ static_libs: [
+ "libaidlcommonsupport",
+ "libstagefright_aidl_bufferpool2"
+ ],
+ compile_multilib: "both",
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.cpp b/media/bufferpool/aidl/default/tests/allocator.cpp
new file mode 100644
index 0000000..16b33a6
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.cpp
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/ashmem.h>
+#include <sys/mman.h>
+#include "allocator.h"
+
+union Params {
+ struct {
+ uint32_t capacity;
+ } data;
+ uint8_t array[0];
+ Params() : data{0} {}
+ Params(uint32_t size)
+ : data{size} {}
+};
+
+
+namespace {
+
+struct HandleAshmem : public native_handle_t {
+ HandleAshmem(int ashmemFd, size_t size)
+ : native_handle_t(cHeader),
+ mFds{ ashmemFd },
+ mInts{ int (size & 0xFFFFFFFF), int((uint64_t(size) >> 32) & 0xFFFFFFFF), kMagic } {}
+
+ int ashmemFd() const { return mFds.mAshmem; }
+ size_t size() const {
+ return size_t(unsigned(mInts.mSizeLo))
+ | size_t(uint64_t(unsigned(mInts.mSizeHi)) << 32);
+ }
+
+ static bool isValid(const native_handle_t * const o);
+
+protected:
+ struct {
+ int mAshmem;
+ } mFds;
+ struct {
+ int mSizeLo;
+ int mSizeHi;
+ int mMagic;
+ } mInts;
+
+private:
+ enum {
+ kMagic = 'ahm\x00',
+ numFds = sizeof(mFds) / sizeof(int),
+ numInts = sizeof(mInts) / sizeof(int),
+ version = sizeof(native_handle_t)
+ };
+ const static native_handle_t cHeader;
+};
+
+const native_handle_t HandleAshmem::cHeader = {
+ HandleAshmem::version,
+ HandleAshmem::numFds,
+ HandleAshmem::numInts,
+ {}
+};
+
+bool HandleAshmem::isValid(const native_handle_t * const o) {
+ if (!o || memcmp(o, &cHeader, sizeof(cHeader))) {
+ return false;
+ }
+ const HandleAshmem *other = static_cast<const HandleAshmem*>(o);
+ return other->mInts.mMagic == kMagic;
+}
+
+class AllocationAshmem {
+private:
+ AllocationAshmem(int ashmemFd, size_t capacity, bool res)
+ : mHandle(ashmemFd, capacity),
+ mInit(res) {}
+
+public:
+ static AllocationAshmem *Alloc(size_t size) {
+ constexpr static const char *kAllocationTag = "bufferpool_test";
+ int ashmemFd = ashmem_create_region(kAllocationTag, size);
+ return new AllocationAshmem(ashmemFd, size, ashmemFd >= 0);
+ }
+
+ ~AllocationAshmem() {
+ if (mInit) {
+ native_handle_close(&mHandle);
+ }
+ }
+
+ const HandleAshmem *handle() {
+ return &mHandle;
+ }
+
+private:
+ HandleAshmem mHandle;
+ bool mInit;
+ // TODO: mapping and map fd
+};
+
+struct AllocationDtor {
+ AllocationDtor(const std::shared_ptr<AllocationAshmem> &alloc)
+ : mAlloc(alloc) {}
+
+ void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+ const std::shared_ptr<AllocationAshmem> mAlloc;
+};
+
+}
+
+void IpcMutex::init() {
+ pthread_mutexattr_t mattr;
+ pthread_mutexattr_init(&mattr);
+ pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
+ pthread_mutex_init(&lock, &mattr);
+ pthread_mutexattr_destroy(&mattr);
+
+ pthread_condattr_t cattr;
+ pthread_condattr_init(&cattr);
+ pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
+ pthread_cond_init(&cond, &cattr);
+ pthread_condattr_destroy(&cattr);
+}
+
+IpcMutex *IpcMutex::Import(void *pMutex) {
+ return reinterpret_cast<IpcMutex *>(pMutex);
+}
+
+
+BufferPoolStatus TestBufferPoolAllocator::allocate(
+ const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<BufferPoolAllocation> *alloc,
+ size_t *allocSize) {
+ Params ashmemParams;
+ memcpy(&ashmemParams, params.data(), std::min(sizeof(Params), params.size()));
+
+ std::shared_ptr<AllocationAshmem> ashmemAlloc =
+ std::shared_ptr<AllocationAshmem>(
+ AllocationAshmem::Alloc(ashmemParams.data.capacity));
+ if (ashmemAlloc) {
+ BufferPoolAllocation *ptr = new BufferPoolAllocation(ashmemAlloc->handle());
+ if (ptr) {
+ *alloc = std::shared_ptr<BufferPoolAllocation>(ptr, AllocationDtor(ashmemAlloc));
+ if (*alloc) {
+ *allocSize = ashmemParams.data.capacity;
+ return ResultStatus::OK;
+ }
+ delete ptr;
+ return ResultStatus::NO_MEMORY;
+ }
+ }
+ return ResultStatus::CRITICAL_ERROR;
+}
+
+bool TestBufferPoolAllocator::compatible(const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) {
+ size_t newSize = newParams.size();
+ size_t oldSize = oldParams.size();
+ if (newSize == oldSize) {
+ for (size_t i = 0; i < newSize; ++i) {
+ if (newParams[i] != oldParams[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+bool TestBufferPoolAllocator::Fill(const native_handle_t *handle, const unsigned char val) {
+ if (!HandleAshmem::isValid(handle)) {
+ return false;
+ }
+ const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+ unsigned char *ptr = (unsigned char *)mmap(
+ NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+
+ if (ptr != MAP_FAILED) {
+ for (size_t i = 0; i < o->size(); ++i) {
+ ptr[i] = val;
+ }
+ munmap(ptr, o->size());
+ return true;
+ }
+ return false;
+}
+
+bool TestBufferPoolAllocator::Verify(const native_handle_t *handle, const unsigned char val) {
+ if (!HandleAshmem::isValid(handle)) {
+ return false;
+ }
+ const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+ unsigned char *ptr = (unsigned char *)mmap(
+ NULL, o->size(), PROT_READ, MAP_SHARED, o->ashmemFd(), 0);
+
+ if (ptr != MAP_FAILED) {
+ bool res = true;
+ for (size_t i = 0; i < o->size(); ++i) {
+ if (ptr[i] != val) {
+ res = false;
+ break;
+ }
+ }
+ munmap(ptr, o->size());
+ return res;
+ }
+ return false;
+}
+
+bool TestBufferPoolAllocator::MapMemoryForMutex(const native_handle_t *handle, void **mem) {
+ if (!HandleAshmem::isValid(handle)) {
+ return false;
+ }
+ const HandleAshmem *o = static_cast<const HandleAshmem*>(handle);
+ *mem = mmap(
+ NULL, o->size(), PROT_READ|PROT_WRITE, MAP_SHARED, o->ashmemFd(), 0);
+ if (*mem == MAP_FAILED || *mem == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+bool TestBufferPoolAllocator::UnmapMemoryForMutex(void *mem) {
+ munmap(mem, sizeof(IpcMutex));
+ return true;
+}
+
+void getTestAllocatorParams(std::vector<uint8_t> *params) {
+ constexpr static int kAllocationSize = 1024 * 10;
+ Params ashmemParams(kAllocationSize);
+
+ params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
+
+void getIpcMutexParams(std::vector<uint8_t> *params) {
+ Params ashmemParams(sizeof(IpcMutex));
+
+ params->assign(ashmemParams.array, ashmemParams.array + sizeof(ashmemParams));
+}
diff --git a/media/bufferpool/aidl/default/tests/allocator.h b/media/bufferpool/aidl/default/tests/allocator.h
new file mode 100644
index 0000000..7e7203f
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/allocator.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <pthread.h>
+#include <bufferpool2/BufferPoolTypes.h>
+
+using aidl::android::hardware::media::bufferpool2::implementation::
+ BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::
+ BufferPoolAllocation;
+using aidl::android::hardware::media::bufferpool2::implementation::
+ BufferPoolAllocator;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+
+struct IpcMutex {
+ pthread_mutex_t lock;
+ pthread_cond_t cond;
+ int counter = 0;
+ bool signalled = false;
+
+ void init();
+
+ static IpcMutex *Import(void *mem);
+};
+
+// buffer allocator for the tests
+class TestBufferPoolAllocator : public BufferPoolAllocator {
+ public:
+ TestBufferPoolAllocator() {}
+
+ ~TestBufferPoolAllocator() override {}
+
+ BufferPoolStatus allocate(const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<BufferPoolAllocation> *alloc,
+ size_t *allocSize) override;
+
+ bool compatible(const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) override;
+
+ static bool Fill(const native_handle_t *handle, const unsigned char val);
+
+ static bool Verify(const native_handle_t *handle, const unsigned char val);
+
+ static bool MapMemoryForMutex(const native_handle_t *handle, void **mem);
+
+ static bool UnmapMemoryForMutex(void *mem);
+};
+
+// retrieve buffer allocator parameters
+void getTestAllocatorParams(std::vector<uint8_t> *params);
+
+void getIpcMutexParams(std::vector<uint8_t> *params);
diff --git a/media/bufferpool/aidl/default/tests/cond.cpp b/media/bufferpool/aidl/default/tests/cond.cpp
new file mode 100644
index 0000000..6d469ce
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/cond.cpp
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance = std::string() + ClientManager::descriptor + "/condtest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+ INIT_OK = 0,
+ INIT_ERROR,
+ SEND,
+ RECEIVE_OK,
+ RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+ struct {
+ int32_t command;
+ BufferId bufferId;
+ ConnectionId connectionId;
+ TransactionId transactionId;
+ int64_t timestampUs;
+ } data;
+ char array[0];
+};
+
+constexpr int kSignalInt = 200;
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ BufferPoolStatus status;
+ mReceiverPid = -1;
+ mConnectionValid = false;
+
+ ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+ ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+ mReceiverPid = fork();
+ ASSERT_TRUE(mReceiverPid >= 0);
+
+ if (mReceiverPid == 0) {
+ doReceiver();
+ // In order to ignore gtest behaviour, wait for being killed from
+ // tearDown
+ pause();
+ }
+
+ mManager = ClientManager::getInstance();
+ ASSERT_NE(mManager, nullptr);
+
+ mAllocator = std::make_shared<TestBufferPoolAllocator>();
+ ASSERT_TRUE((bool)mAllocator);
+
+ status = mManager->create(mAllocator, &mConnectionId);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ mConnectionValid = true;
+ }
+
+ virtual void TearDown() override {
+ if (mReceiverPid > 0) {
+ kill(mReceiverPid, SIGKILL);
+ int wstatus;
+ wait(&wstatus);
+ }
+
+ if (mConnectionValid) {
+ mManager->close(mConnectionId);
+ }
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ std::shared_ptr<ClientManager> mManager;
+ std::shared_ptr<BufferPoolAllocator> mAllocator;
+ bool mConnectionValid;
+ ConnectionId mConnectionId;
+ pid_t mReceiverPid;
+ int mCommandPipeFds[2];
+ int mResultPipeFds[2];
+
+ bool sendMessage(int *pipes, const PipeMessage &message) {
+ int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+ return ret == sizeof(PipeMessage);
+ }
+
+ bool receiveMessage(int *pipes, PipeMessage *message) {
+ int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+ return ret == sizeof(PipeMessage);
+ }
+
+ void doReceiver() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ PipeMessage message;
+ mManager = ClientManager::getInstance();
+ if (!mManager) {
+ message.data.command = PipeCommand::INIT_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ auto binder = mManager->asBinder();
+ AIBinder_forceDowngradeToSystemStability(binder.get());
+ binder_status_t status =
+ AServiceManager_addService(binder.get(), testInstance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+ if (status != android::OK) {
+ message.data.command = PipeCommand::INIT_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ message.data.command = PipeCommand::INIT_OK;
+ sendMessage(mResultPipeFds, message);
+
+ int val = 0;
+ receiveMessage(mCommandPipeFds, &message);
+ {
+ native_handle_t *rhandle = nullptr;
+ std::shared_ptr<BufferPoolData> rbuffer;
+ void *mem = nullptr;
+ IpcMutex *mutex = nullptr;
+ BufferPoolStatus status = mManager->receive(
+ message.data.connectionId, message.data.transactionId,
+ message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+ mManager->close(message.data.connectionId);
+ if (status != ResultStatus::OK) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (!TestBufferPoolAllocator::MapMemoryForMutex(rhandle, &mem)) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ mutex = IpcMutex::Import(mem);
+ pthread_mutex_lock(&(mutex->lock));
+ while (mutex->signalled != true) {
+ pthread_cond_wait(&(mutex->cond), &(mutex->lock));
+ }
+ val = mutex->counter;
+ pthread_mutex_unlock(&(mutex->lock));
+
+ (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+ if (rhandle) {
+ native_handle_close(rhandle);
+ native_handle_delete(rhandle);
+ }
+ }
+ if (val == kSignalInt) {
+ message.data.command = PipeCommand::RECEIVE_OK;
+ } else {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ }
+ sendMessage(mResultPipeFds, message);
+ }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+ BufferPoolStatus status;
+ PipeMessage message;
+
+ ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+
+ std::shared_ptr<IClientManager> receiver =
+ IClientManager::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(testInstance.c_str())));
+ ASSERT_NE(receiver, nullptr);
+ ConnectionId receiverId;
+
+ bool isNew = true;
+ status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ {
+ native_handle_t *shandle = nullptr;
+ std::shared_ptr<BufferPoolData> sbuffer;
+ TransactionId transactionId;
+ int64_t postUs;
+ std::vector<uint8_t> vecParams;
+ void *mem = nullptr;
+ IpcMutex *mutex = nullptr;
+
+ getIpcMutexParams(&vecParams);
+ status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ ASSERT_TRUE(TestBufferPoolAllocator::MapMemoryForMutex(shandle, &mem));
+
+ mutex = new(mem) IpcMutex();
+ mutex->init();
+
+ status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ message.data.command = PipeCommand::SEND;
+ message.data.bufferId = sbuffer->mId;
+ message.data.connectionId = receiverId;
+ message.data.transactionId = transactionId;
+ message.data.timestampUs = postUs;
+ sendMessage(mCommandPipeFds, message);
+ for (int i=0; i < 200000000; ++i) {
+ // no-op in order to ensure
+ // pthread_cond_wait is called before pthread_cond_signal
+ }
+ pthread_mutex_lock(&(mutex->lock));
+ mutex->counter = kSignalInt;
+ mutex->signalled = true;
+ pthread_cond_signal(&(mutex->cond));
+ pthread_mutex_unlock(&(mutex->lock));
+ (void)TestBufferPoolAllocator::UnmapMemoryForMutex(mem);
+ if (shandle) {
+ native_handle_close(shandle);
+ native_handle_delete(shandle);
+ }
+ }
+ EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+ EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/multi.cpp b/media/bufferpool/aidl/default/tests/multi.cpp
new file mode 100644
index 0000000..8806eb0
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/multi.cpp
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <android/binder_stability.h>
+#include <android-base/logging.h>
+#include <bufferpool2/ClientManager.h>
+
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <iostream>
+#include <memory>
+#include <vector>
+
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::IClientManager;
+using aidl::android::hardware::media::bufferpool2::ResultStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+const std::string testInstance = std::string() + ClientManager::descriptor + "/multitest";
+
+// communication message types between processes.
+enum PipeCommand : int32_t {
+ INIT_OK = 0,
+ INIT_ERROR,
+ SEND,
+ RECEIVE_OK,
+ RECEIVE_ERROR,
+};
+
+// communication message between processes.
+union PipeMessage {
+ struct {
+ int32_t command;
+ BufferId bufferId;
+ ConnectionId connectionId;
+ TransactionId transactionId;
+ int64_t timestampUs;
+ } data;
+ char array[0];
+};
+
+// media.bufferpool test setup
+class BufferpoolMultiTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ BufferPoolStatus status;
+ mReceiverPid = -1;
+ mConnectionValid = false;
+
+ ASSERT_TRUE(pipe(mCommandPipeFds) == 0);
+ ASSERT_TRUE(pipe(mResultPipeFds) == 0);
+
+ mReceiverPid = fork();
+ ASSERT_TRUE(mReceiverPid >= 0);
+
+ if (mReceiverPid == 0) {
+ doReceiver();
+ // In order to ignore gtest behaviour, wait for being killed from
+ // tearDown
+ pause();
+ }
+ mManager = ClientManager::getInstance();
+ ASSERT_NE(mManager, nullptr);
+
+ mAllocator = std::make_shared<TestBufferPoolAllocator>();
+ ASSERT_TRUE((bool)mAllocator);
+
+ status = mManager->create(mAllocator, &mConnectionId);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ mConnectionValid = true;
+ }
+
+ virtual void TearDown() override {
+ if (mReceiverPid > 0) {
+ kill(mReceiverPid, SIGKILL);
+ int wstatus;
+ wait(&wstatus);
+ }
+
+ if (mConnectionValid) {
+ mManager->close(mConnectionId);
+ }
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ std::shared_ptr<ClientManager> mManager;
+ std::shared_ptr<BufferPoolAllocator> mAllocator;
+ bool mConnectionValid;
+ ConnectionId mConnectionId;
+ pid_t mReceiverPid;
+ int mCommandPipeFds[2];
+ int mResultPipeFds[2];
+
+ bool sendMessage(int *pipes, const PipeMessage &message) {
+ int ret = write(pipes[1], message.array, sizeof(PipeMessage));
+ return ret == sizeof(PipeMessage);
+ }
+
+ bool receiveMessage(int *pipes, PipeMessage *message) {
+ int ret = read(pipes[0], message->array, sizeof(PipeMessage));
+ return ret == sizeof(PipeMessage);
+ }
+
+ void doReceiver() {
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+ PipeMessage message;
+ mManager = ClientManager::getInstance();
+ if (!mManager) {
+ message.data.command = PipeCommand::INIT_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ auto binder = mManager->asBinder();
+ AIBinder_forceDowngradeToSystemStability(binder.get());
+ binder_status_t status =
+ AServiceManager_addService(binder.get(), testInstance.c_str());
+ CHECK_EQ(status, STATUS_OK);
+ if (status != android::OK) {
+ message.data.command = PipeCommand::INIT_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ message.data.command = PipeCommand::INIT_OK;
+ sendMessage(mResultPipeFds, message);
+
+ receiveMessage(mCommandPipeFds, &message);
+ {
+ native_handle_t *rhandle = nullptr;
+ std::shared_ptr<BufferPoolData> rbuffer;
+ BufferPoolStatus status = mManager->receive(
+ message.data.connectionId, message.data.transactionId,
+ message.data.bufferId, message.data.timestampUs, &rhandle, &rbuffer);
+ mManager->close(message.data.connectionId);
+ if (status != ResultStatus::OK) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (!TestBufferPoolAllocator::Verify(rhandle, 0x77)) {
+ message.data.command = PipeCommand::RECEIVE_ERROR;
+ sendMessage(mResultPipeFds, message);
+ return;
+ }
+ if (rhandle) {
+ native_handle_close(rhandle);
+ native_handle_delete(rhandle);
+ }
+ }
+ message.data.command = PipeCommand::RECEIVE_OK;
+ sendMessage(mResultPipeFds, message);
+ }
+};
+
+// Buffer transfer test between processes.
+TEST_F(BufferpoolMultiTest, TransferBuffer) {
+ BufferPoolStatus status;
+ PipeMessage message;
+
+ ASSERT_TRUE(receiveMessage(mResultPipeFds, &message));
+ ABinderProcess_setThreadPoolMaxThreadCount(1);
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<IClientManager> receiver = IClientManager::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(testInstance.c_str())));
+ ASSERT_NE(receiver, nullptr);
+ ConnectionId receiverId;
+
+ bool isNew = true;
+ status = mManager->registerSender(receiver, mConnectionId, &receiverId, &isNew);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ {
+ native_handle_t *shandle = nullptr;
+ std::shared_ptr<BufferPoolData> sbuffer;
+ TransactionId transactionId;
+ int64_t postUs;
+ std::vector<uint8_t> vecParams;
+
+ getTestAllocatorParams(&vecParams);
+ status = mManager->allocate(mConnectionId, vecParams, &shandle, &sbuffer);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ ASSERT_TRUE(TestBufferPoolAllocator::Fill(shandle, 0x77));
+ if (shandle) {
+ native_handle_close(shandle);
+ native_handle_delete(shandle);
+ }
+
+ status = mManager->postSend(receiverId, sbuffer, &transactionId, &postUs);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ message.data.command = PipeCommand::SEND;
+ message.data.bufferId = sbuffer->mId;
+ message.data.connectionId = receiverId;
+ message.data.transactionId = transactionId;
+ message.data.timestampUs = postUs;
+ sendMessage(mCommandPipeFds, message);
+ }
+ EXPECT_TRUE(receiveMessage(mResultPipeFds, &message));
+ EXPECT_TRUE(message.data.command == PipeCommand::RECEIVE_OK);
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/media/bufferpool/aidl/default/tests/single.cpp b/media/bufferpool/aidl/default/tests/single.cpp
new file mode 100644
index 0000000..66aa5e9
--- /dev/null
+++ b/media/bufferpool/aidl/default/tests/single.cpp
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "buffferpool_unit_test"
+
+#include <gtest/gtest.h>
+
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
+#include <bufferpool2/ClientManager.h>
+#include <unistd.h>
+#include <iostream>
+#include <memory>
+#include <vector>
+#include "allocator.h"
+
+using aidl::android::hardware::media::bufferpool2::implementation::BufferId;
+using aidl::android::hardware::media::bufferpool2::implementation::BufferPoolStatus;
+using aidl::android::hardware::media::bufferpool2::implementation::ClientManager;
+using aidl::android::hardware::media::bufferpool2::implementation::ConnectionId;
+using aidl::android::hardware::media::bufferpool2::implementation::TransactionId;
+using aidl::android::hardware::media::bufferpool2::BufferPoolData;
+
+namespace {
+
+// Number of iteration for buffer allocation test.
+constexpr static int kNumAllocationTest = 3;
+
+// Number of iteration for buffer recycling test.
+constexpr static int kNumRecycleTest = 3;
+
+// media.bufferpool test setup
+class BufferpoolSingleTest : public ::testing::Test {
+ public:
+ virtual void SetUp() override {
+ BufferPoolStatus status;
+ mConnectionValid = false;
+
+ mManager = ClientManager::getInstance();
+ ASSERT_NE(mManager, nullptr);
+
+ mAllocator = std::make_shared<TestBufferPoolAllocator>();
+ ASSERT_TRUE((bool)mAllocator);
+
+ status = mManager->create(mAllocator, &mConnectionId);
+ ASSERT_TRUE(status == ResultStatus::OK);
+
+ mConnectionValid = true;
+
+ bool isNew = true;
+ status = mManager->registerSender(mManager, mConnectionId, &mReceiverId, &isNew);
+ ASSERT_TRUE(status == ResultStatus::OK && isNew == false &&
+ mReceiverId == mConnectionId);
+ }
+
+ virtual void TearDown() override {
+ if (mConnectionValid) {
+ mManager->close(mConnectionId);
+ }
+ }
+
+ protected:
+ static void description(const std::string& description) {
+ RecordProperty("description", description);
+ }
+
+ std::shared_ptr<ClientManager> mManager;
+ std::shared_ptr<BufferPoolAllocator> mAllocator;
+ bool mConnectionValid;
+ ConnectionId mConnectionId;
+ ConnectionId mReceiverId;
+
+};
+
+// Buffer allocation test.
+// Check whether each buffer allocation is done successfully with
+// unique buffer id.
+TEST_F(BufferpoolSingleTest, AllocateBuffer) {
+ BufferPoolStatus status;
+ std::vector<uint8_t> vecParams;
+ getTestAllocatorParams(&vecParams);
+
+ std::shared_ptr<BufferPoolData> buffer[kNumAllocationTest];
+ native_handle_t *allocHandle = nullptr;
+ for (int i = 0; i < kNumAllocationTest; ++i) {
+ status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer[i]);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
+ }
+ for (int i = 0; i < kNumAllocationTest; ++i) {
+ for (int j = i + 1; j < kNumAllocationTest; ++j) {
+ ASSERT_TRUE(buffer[i]->mId != buffer[j]->mId);
+ }
+ }
+ EXPECT_TRUE(kNumAllocationTest > 1);
+}
+
+// Buffer recycle test.
+// Check whether de-allocated buffers are recycled.
+TEST_F(BufferpoolSingleTest, RecycleBuffer) {
+ BufferPoolStatus status;
+ std::vector<uint8_t> vecParams;
+ getTestAllocatorParams(&vecParams);
+
+ BufferId bid[kNumRecycleTest];
+ for (int i = 0; i < kNumRecycleTest; ++i) {
+ std::shared_ptr<BufferPoolData> buffer;
+ native_handle_t *allocHandle = nullptr;
+ status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &buffer);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ bid[i] = buffer->mId;
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
+ }
+ for (int i = 1; i < kNumRecycleTest; ++i) {
+ ASSERT_TRUE(bid[i - 1] == bid[i]);
+ }
+ EXPECT_TRUE(kNumRecycleTest > 1);
+}
+
+// Buffer transfer test.
+// Check whether buffer is transferred to another client successfully.
+TEST_F(BufferpoolSingleTest, TransferBuffer) {
+ BufferPoolStatus status;
+ std::vector<uint8_t> vecParams;
+ getTestAllocatorParams(&vecParams);
+ std::shared_ptr<BufferPoolData> sbuffer, rbuffer;
+ native_handle_t *allocHandle = nullptr;
+ native_handle_t *recvHandle = nullptr;
+
+ TransactionId transactionId;
+ int64_t postMs;
+
+ status = mManager->allocate(mConnectionId, vecParams, &allocHandle, &sbuffer);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ ASSERT_TRUE(TestBufferPoolAllocator::Fill(allocHandle, 0x77));
+ status = mManager->postSend(mReceiverId, sbuffer, &transactionId, &postMs);
+ ASSERT_TRUE(status == ResultStatus::OK);
+ status = mManager->receive(mReceiverId, transactionId, sbuffer->mId, postMs,
+ &recvHandle, &rbuffer);
+ EXPECT_TRUE(status == ResultStatus::OK);
+ ASSERT_TRUE(TestBufferPoolAllocator::Verify(recvHandle, 0x77));
+
+ if (allocHandle) {
+ native_handle_close(allocHandle);
+ native_handle_delete(allocHandle);
+ }
+ if (recvHandle) {
+ native_handle_close(recvHandle);
+ native_handle_delete(recvHandle);
+ }
+}
+
+} // anonymous namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ int status = RUN_ALL_TESTS();
+ LOG(INFO) << "Test result = " << status;
+ return status;
+}
diff --git a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
index 399dbb7..f186df7 100644
--- a/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
+++ b/radio/aidl/android/hardware/radio/network/IRadioNetworkResponse.aidl
@@ -633,6 +633,7 @@
* RadioError:NONE
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:MODEM_ERR
+ * RadioError:REQUEST_NOT_SUPPORTED
*/
void isNullCipherAndIntegrityEnabledResponse(in RadioResponseInfo info, in boolean isEnabled);
diff --git a/radio/aidl/vts/radio_network_test.cpp b/radio/aidl/vts/radio_network_test.cpp
index 03127cd..658fcf7 100644
--- a/radio/aidl/vts/radio_network_test.cpp
+++ b/radio/aidl/vts/radio_network_test.cpp
@@ -2001,9 +2001,9 @@
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_network->rspInfo.type);
EXPECT_EQ(serial, radioRsp_network->rspInfo.serial);
- ASSERT_TRUE(CheckAnyOfErrors(
- radioRsp_network->rspInfo.error,
- {RadioError::NONE, RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
+ ASSERT_TRUE(CheckAnyOfErrors(radioRsp_network->rspInfo.error,
+ {RadioError::NONE, RadioError::REQUEST_NOT_SUPPORTED,
+ RadioError::RADIO_NOT_AVAILABLE, RadioError::MODEM_ERR}));
LOG(DEBUG) << "setNullCipherAndIntegrityEnabled finished";
}
diff --git a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index 36b40ea..1dc593a 100644
--- a/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/aidl_api/android.hardware.tv.tuner/current/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -39,4 +39,5 @@
LOW_WATER = 2,
HIGH_WATER = 4,
OVERFLOW = 8,
+ NO_DATA = 16,
}
diff --git a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
index e6f3b63..45a473e 100644
--- a/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
+++ b/tv/tuner/aidl/android/hardware/tv/tuner/DemuxFilterStatus.aidl
@@ -46,4 +46,9 @@
* discarded.
*/
OVERFLOW = 1 << 3,
+
+ /**
+ * Indicating there is no data coming to the filter.
+ */
+ NO_DATA = 1 << 4,
}
diff --git a/tv/tuner/aidl/default/Filter.cpp b/tv/tuner/aidl/default/Filter.cpp
index ade265c..59e301d 100644
--- a/tv/tuner/aidl/default/Filter.cpp
+++ b/tv/tuner/aidl/default/Filter.cpp
@@ -691,6 +691,8 @@
return DemuxFilterStatus::OVERFLOW;
} else if (availableToRead > highThreshold) {
return DemuxFilterStatus::HIGH_WATER;
+ } else if (availableToRead == 0) {
+ return DemuxFilterStatus::NO_DATA;
} else if (availableToRead < lowThreshold) {
return DemuxFilterStatus::LOW_WATER;
}
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index f50a5e7..c88cb59 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -602,10 +602,11 @@
EXPECT_EQ(Status::EX_NONE, vibrator->compose(composite, callback).exceptionCode())
<< toString(primitive);
- //TODO(b/187207798): revert back to conservative timeout values once
- //latencies have been fixed
- EXPECT_EQ(completionFuture.wait_for(duration * 4), std::future_status::ready)
- << toString(primitive);
+ // TODO(b/261130361): Investigate why latency from driver and hardware will cause test
+ // to fail when wait duration is ~40ms or less.
+ EXPECT_EQ(completionFuture.wait_for(duration + std::chrono::milliseconds(50)),
+ std::future_status::ready)
+ << toString(primitive);
end = high_resolution_clock::now();
elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(end - start);
diff --git a/wifi/aidl/default/aidl_struct_util.cpp b/wifi/aidl/default/aidl_struct_util.cpp
index 22319ae..5e80ff9 100644
--- a/wifi/aidl/default/aidl_struct_util.cpp
+++ b/wifi/aidl/default/aidl_struct_util.cpp
@@ -1718,7 +1718,7 @@
}
*legacy_request = {};
- legacy_request->publish_id = aidl_request.baseConfigs.sessionId;
+ legacy_request->publish_id = static_cast<uint8_t>(aidl_request.baseConfigs.sessionId);
legacy_request->ttl = aidl_request.baseConfigs.ttlSec;
legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod;
legacy_request->publish_count = aidl_request.baseConfigs.discoveryCount;
@@ -1860,7 +1860,7 @@
}
*legacy_request = {};
- legacy_request->subscribe_id = aidl_request.baseConfigs.sessionId;
+ legacy_request->subscribe_id = static_cast<uint8_t>(aidl_request.baseConfigs.sessionId);
legacy_request->ttl = aidl_request.baseConfigs.ttlSec;
legacy_request->period = aidl_request.baseConfigs.discoveryWindowPeriod;
legacy_request->subscribe_count = aidl_request.baseConfigs.discoveryCount;
@@ -2007,7 +2007,7 @@
}
*legacy_request = {};
- legacy_request->publish_subscribe_id = aidl_request.discoverySessionId;
+ legacy_request->publish_subscribe_id = static_cast<uint8_t>(aidl_request.discoverySessionId);
legacy_request->requestor_instance_id = aidl_request.peerId;
memcpy(legacy_request->addr, aidl_request.addr.data(), 6);
legacy_request->priority = aidl_request.isHighPriority ? legacy_hal::NAN_TX_PRIORITY_HIGH
diff --git a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
similarity index 69%
copy from audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
copy to wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
index bc010ca..28c1028 100644
--- a/audio/aidl/aidl_api/android.hardware.audio.core.sounddose/current/android/hardware/audio/core/ISoundDose.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
@@ -31,22 +31,8 @@
// with such a backward incompatible change, it has a high risk of breaking
// later when a module using the interface is updated, e.g., Mainline modules.
-package android.hardware.audio.core;
+package android.hardware.wifi.supplicant;
@VintfStability
-interface ISoundDose {
- void setOutputRs2(float rs2ValueDbA);
- float getOutputRs2();
- void registerSoundDoseCallback(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback callback);
- const int DEFAULT_MAX_RS2 = 100;
- const int MIN_RS2 = 80;
- @VintfStability
- interface IHalSoundDoseCallback {
- oneway void onMomentaryExposureWarning(float currentDbA, in android.media.audio.common.AudioDevice audioDevice);
- oneway void onNewMelValues(in android.hardware.audio.core.ISoundDose.IHalSoundDoseCallback.MelRecord melRecord, in android.media.audio.common.AudioDevice audioDevice);
- @VintfStability
- parcelable MelRecord {
- float[] melValues;
- long timestamp;
- }
- }
+interface INonStandardCertCallback {
+ byte[] getBlob(in String alias);
}
diff --git a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
index 4b26ac3..dd62167 100644
--- a/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/aidl_api/android.hardware.wifi.supplicant/current/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -47,5 +47,6 @@
void setConcurrencyPriority(in android.hardware.wifi.supplicant.IfaceType type);
void setDebugParams(in android.hardware.wifi.supplicant.DebugLevel level, in boolean showTimestamp, in boolean showKeys);
oneway void terminate();
+ void registerNonStandardCertCallback(in android.hardware.wifi.supplicant.INonStandardCertCallback callback);
const int EXT_RADIO_WORK_TIMEOUT_IN_SECS = 10;
}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
new file mode 100644
index 0000000..3259585
--- /dev/null
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/INonStandardCertCallback.aidl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.wifi.supplicant;
+
+/**
+ * Callback to allow supplicant to retrieve non-standard certificate types
+ * from the client.
+ *
+ * Must be registered by the client at initialization, so that
+ * supplicant can call into the client to retrieve any values.
+ */
+@VintfStability
+interface INonStandardCertCallback {
+ /**
+ * Requests a binary blob from the certificate key-value store.
+ *
+ * @param alias Key into the key-value mapping.
+ * @return Value associated with |alias| in the certificate store.
+ * @throws ServiceSpecificException with one of the following values:
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ byte[] getBlob(in String alias);
+}
diff --git a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
index c17289d..b187c2f 100644
--- a/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
+++ b/wifi/supplicant/aidl/android/hardware/wifi/supplicant/ISupplicant.aidl
@@ -17,6 +17,7 @@
package android.hardware.wifi.supplicant;
import android.hardware.wifi.supplicant.DebugLevel;
+import android.hardware.wifi.supplicant.INonStandardCertCallback;
import android.hardware.wifi.supplicant.ISupplicantCallback;
import android.hardware.wifi.supplicant.ISupplicantP2pIface;
import android.hardware.wifi.supplicant.ISupplicantStaIface;
@@ -158,4 +159,14 @@
* wait to be restarted.
*/
oneway void terminate();
+
+ /**
+ * Register a Non-Standard Certificate callback with supplicant.
+ *
+ * @param callback An instance of the |INonStandardCertCallback| AIDL interface
+ * object.
+ * @throws ServiceSpecificException with one of the following values:
+ * |SupplicantStatusCode.FAILURE_UNKNOWN|
+ */
+ void registerNonStandardCertCallback(in INonStandardCertCallback callback);
}
diff --git a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
index 0aebe6d..0e2b72c 100644
--- a/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
+++ b/wifi/supplicant/aidl/vts/functional/supplicant_sta_network_aidl_test.cpp
@@ -806,7 +806,15 @@
* SetMinimumTlsVersionEapPhase1Param
*/
TEST_P(SupplicantStaNetworkAidlTest, SetMinimumTlsVersionEapPhase1Param) {
- EXPECT_TRUE(sta_network_->setMinimumTlsVersionEapPhase1Param(TlsVersion::TLS_V1_3).isOk());
+ WpaDriverCapabilitiesMask caps;
+ EXPECT_TRUE(sta_iface_->getWpaDriverCapabilities(&caps).isOk());
+ const bool tlsV13Supported = !!(static_cast<uint32_t>(caps) &
+ static_cast<uint32_t>(WpaDriverCapabilitiesMask::TLS_V1_3));
+ LOG(INFO) << "TLS_V1_3 Supported: " << tlsV13Supported;
+
+ // Operation will succeed if TLS_V1_3 is supported, or fail otherwise.
+ EXPECT_EQ(sta_network_->setMinimumTlsVersionEapPhase1Param(TlsVersion::TLS_V1_3).isOk(),
+ tlsV13Supported);
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(SupplicantStaNetworkAidlTest);