Merge changes from topic "processing_effects"

* changes:
  Effect AIDL: Add AEC, AGC and NS AIDL vts
  Effect AIDL: Add AEC, AGC and NS AIDL and placeholder implmentation
  Effect AIDL: Add AEC, AGC and NS AIDL interface definition
This commit is contained in:
Shunkai Yao
2022-12-20 21:45:13 +00:00
committed by Gerrit Code Review
30 changed files with 2085 additions and 4 deletions

View File

@@ -223,6 +223,8 @@ aidl_interface {
"android.hardware.audio_defaults",
],
srcs: [
"android/hardware/audio/effect/AcousticEchoCanceler.aidl",
"android/hardware/audio/effect/AutomaticGainControl.aidl",
"android/hardware/audio/effect/BassBoost.aidl",
"android/hardware/audio/effect/Capability.aidl",
"android/hardware/audio/effect/CommandId.aidl",
@@ -236,6 +238,7 @@ aidl_interface {
"android/hardware/audio/effect/IEffect.aidl",
"android/hardware/audio/effect/IFactory.aidl",
"android/hardware/audio/effect/LoudnessEnhancer.aidl",
"android/hardware/audio/effect/NoiseSuppression.aidl",
"android/hardware/audio/effect/Parameter.aidl",
"android/hardware/audio/effect/PresetReverb.aidl",
"android/hardware/audio/effect/Processing.aidl",

View File

@@ -23,6 +23,15 @@
},
{
"name": "VtsHalVisualizerTargetTest"
},
{
"name": "VtsHalAECTargetTest"
},
{
"name": "VtsHalAGCTargetTest"
},
{
"name": "VtsHalNSTargetTest"
}
]
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
///////////////////////////////////////////////////////////////////////////////
// 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.effect;
@VintfStability
union AcousticEchoCanceler {
android.hardware.audio.effect.VendorExtension vendor;
int echoDelayUs;
boolean mobileMode;
@VintfStability
union Id {
int vendorExtensionTag;
android.hardware.audio.effect.AcousticEchoCanceler.Tag commonTag;
}
@VintfStability
parcelable Capability {
ParcelableHolder extension;
int maxEchoDelayUs;
boolean supportMobileMode;
}
}

View File

@@ -0,0 +1,57 @@
/*
* 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.effect;
@VintfStability
union AutomaticGainControl {
android.hardware.audio.effect.VendorExtension vendor;
int fixedDigitalGainMb;
android.hardware.audio.effect.AutomaticGainControl.LevelEstimator levelEstimator;
int saturationMarginMb;
@VintfStability
union Id {
int vendorExtensionTag;
android.hardware.audio.effect.AutomaticGainControl.Tag commonTag;
}
@VintfStability
parcelable Capability {
ParcelableHolder extension;
int maxFixedDigitalGainMb;
int maxSaturationMarginMb;
}
@Backing(type="int") @VintfStability
enum LevelEstimator {
RMS = 0,
PEAK = 1,
}
}

View File

@@ -35,6 +35,8 @@ package android.hardware.audio.effect;
@VintfStability
union Capability {
android.hardware.audio.effect.VendorExtension vendorExtension;
android.hardware.audio.effect.AcousticEchoCanceler.Capability acousticEchoCanceler;
android.hardware.audio.effect.AutomaticGainControl.Capability automaticGainControl;
android.hardware.audio.effect.BassBoost.Capability bassBoost;
android.hardware.audio.effect.Downmix.Capability downmix;
android.hardware.audio.effect.DynamicsProcessing.Capability dynamicsProcessing;
@@ -42,6 +44,7 @@ union Capability {
android.hardware.audio.effect.Equalizer.Capability equalizer;
android.hardware.audio.effect.HapticGenerator.Capability hapticGenerator;
android.hardware.audio.effect.LoudnessEnhancer.Capability loudnessEnhancer;
android.hardware.audio.effect.NoiseSuppression.Capability noiseSuppression;
android.hardware.audio.effect.PresetReverb.Capability presetReverb;
android.hardware.audio.effect.Virtualizer.Capability virtualizer;
android.hardware.audio.effect.Visualizer.Capability visualizer;

View File

@@ -0,0 +1,54 @@
/*
* 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.effect;
@VintfStability
union NoiseSuppression {
android.hardware.audio.effect.VendorExtension vendor;
android.hardware.audio.effect.NoiseSuppression.Level level;
@VintfStability
union Id {
int vendorExtensionTag;
android.hardware.audio.effect.NoiseSuppression.Tag commonTag;
}
@VintfStability
parcelable Capability {
ParcelableHolder extension;
}
@Backing(type="int") @VintfStability
enum Level {
LOW = 0,
MEDIUM = 1,
HIGH = 2,
}
}

View File

@@ -43,6 +43,8 @@ union Parameter {
@VintfStability
union Id {
int vendorEffectTag;
android.hardware.audio.effect.AcousticEchoCanceler.Id acousticEchoCancelerTag;
android.hardware.audio.effect.AutomaticGainControl.Id automaticGainControlTag;
android.hardware.audio.effect.BassBoost.Id bassBoostTag;
android.hardware.audio.effect.Downmix.Id downmixTag;
android.hardware.audio.effect.DynamicsProcessing.Id dynamicsProcessingTag;
@@ -50,6 +52,7 @@ union Parameter {
android.hardware.audio.effect.Equalizer.Id equalizerTag;
android.hardware.audio.effect.HapticGenerator.Id hapticGeneratorTag;
android.hardware.audio.effect.LoudnessEnhancer.Id loudnessEnhancerTag;
android.hardware.audio.effect.NoiseSuppression.Id noiseSuppressionTag;
android.hardware.audio.effect.PresetReverb.Id presetReverbTag;
android.hardware.audio.effect.Virtualizer.Id virtualizerTag;
android.hardware.audio.effect.Visualizer.Id visualizerTag;
@@ -71,6 +74,8 @@ union Parameter {
@VintfStability
union Specific {
android.hardware.audio.effect.VendorExtension vendorEffect;
android.hardware.audio.effect.AcousticEchoCanceler acousticEchoCanceler;
android.hardware.audio.effect.AutomaticGainControl automaticGainControl;
android.hardware.audio.effect.BassBoost bassBoost;
android.hardware.audio.effect.Downmix downmix;
android.hardware.audio.effect.DynamicsProcessing dynamicsProcessing;
@@ -78,6 +83,7 @@ union Parameter {
android.hardware.audio.effect.Equalizer equalizer;
android.hardware.audio.effect.HapticGenerator hapticGenerator;
android.hardware.audio.effect.LoudnessEnhancer loudnessEnhancer;
android.hardware.audio.effect.NoiseSuppression noiseSuppression;
android.hardware.audio.effect.PresetReverb presetReverb;
android.hardware.audio.effect.Virtualizer virtualizer;
android.hardware.audio.effect.Visualizer visualizer;

View File

@@ -35,7 +35,7 @@ package android.hardware.audio.effect;
@VintfStability
parcelable Processing {
android.hardware.audio.effect.Processing.Type type;
android.hardware.audio.effect.Descriptor.Identity[] ids;
android.hardware.audio.effect.Descriptor[] ids;
@VintfStability
union Type {
android.media.audio.common.AudioStreamType streamType = android.media.audio.common.AudioStreamType.INVALID;

View File

@@ -0,0 +1,77 @@
/*
* 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.effect;
import android.hardware.audio.effect.VendorExtension;
/**
* Acoustic Echo Canceler (AEC) is an audio pre-processor which removes the contribution of the
* signal received from the remote party from the captured audio signal.
*
* All parameters defined in union AcousticEchoCanceler must be gettable and settable. The
* capabilities defined in AcousticEchoCanceler.Capability can only acquired with
* IEffect.getDescriptor() and not settable.
*/
@VintfStability
union AcousticEchoCanceler {
/**
* Effect parameter tag to identify the parameters for getParameter().
*/
@VintfStability
union Id {
int vendorExtensionTag;
AcousticEchoCanceler.Tag commonTag;
}
/**
* Vendor AEC implementation definition for additional parameters.
*/
VendorExtension vendor;
/**
* Capability supported by AEC implementation.
*/
@VintfStability
parcelable Capability {
/**
* AEC capability extension, vendor can use this extension in case existing capability
* definition not enough.
*/
ParcelableHolder extension;
/**
* Maximum AEC echo delay in microseconds supported.
*/
int maxEchoDelayUs;
/**
* If AEC mobile mode was supported by the AEC implementation.
*/
boolean supportMobileMode;
}
/**
* The AEC echo delay in microseconds.
* Must never be negative, and not larger than maxEchoDelayUs in capability.
*/
int echoDelayUs;
/**
* If AEC mobile mode enabled.
* Can only be false if AEC implementation indicate not support mobile mode by set
* supportMobileMode to false in capability.
*/
boolean mobileMode;
}

View File

@@ -0,0 +1,90 @@
/*
* 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.effect;
import android.hardware.audio.effect.VendorExtension;
/**
* Automatic Gain Control (AGC) is an audio pre-processor which automatically normalizes the output
* of the captured signal by boosting or lowering input from the microphone to match a preset level
* so that the output signal level is virtually constant. AGC can be used by applications where the
* input signal dynamic range is not important but where a constant strong capture level is desired.
*
* All parameters defined in union AutomaticGainControl must be gettable and settable. The
* capabilities defined in AutomaticGainControl.Capability can only acquired with
* IEffect.getDescriptor() and not settable.
*/
@VintfStability
union AutomaticGainControl {
/**
* Effect parameter tag to identify the parameters for getParameter().
*/
@VintfStability
union Id {
int vendorExtensionTag;
AutomaticGainControl.Tag commonTag;
}
/**
* Vendor AutomaticGainControl implementation definition for additional parameters.
*/
VendorExtension vendor;
/**
* Capability supported by AutomaticGainControl implementation.
*/
@VintfStability
parcelable Capability {
/**
* AutomaticGainControl capability extension, vendor can use this extension in case existing
* capability definition not enough.
*/
ParcelableHolder extension;
/**
* Max fixed digital gain supported by AGC implementation in millibel.
*/
int maxFixedDigitalGainMb;
/**
* Max fixed saturation margin supported by AGC implementation in millibel.
*/
int maxSaturationMarginMb;
}
@VintfStability
@Backing(type="int")
enum LevelEstimator {
/* Use Root Mean Square level estimator*/
RMS = 0,
/* Use Peak level estimator*/
PEAK = 1,
}
/**
* The AGC fixed digital gain in millibel.
* Must never be negative, and not larger than maxFixedDigitalGainMb in capability.
*/
int fixedDigitalGainMb;
/*
* Adaptive digital level estimator.
*/
LevelEstimator levelEstimator;
/**
* The AGC saturation margin in millibel.
* Must never be negative, and not larger than maxSaturationMarginMb in capability.
*/
int saturationMarginMb;
}

View File

@@ -16,6 +16,8 @@
package android.hardware.audio.effect;
import android.hardware.audio.effect.AcousticEchoCanceler;
import android.hardware.audio.effect.AutomaticGainControl;
import android.hardware.audio.effect.BassBoost;
import android.hardware.audio.effect.Downmix;
import android.hardware.audio.effect.DynamicsProcessing;
@@ -23,6 +25,7 @@ import android.hardware.audio.effect.EnvironmentalReverb;
import android.hardware.audio.effect.Equalizer;
import android.hardware.audio.effect.HapticGenerator;
import android.hardware.audio.effect.LoudnessEnhancer;
import android.hardware.audio.effect.NoiseSuppression;
import android.hardware.audio.effect.PresetReverb;
import android.hardware.audio.effect.VendorExtension;
import android.hardware.audio.effect.Virtualizer;
@@ -49,6 +52,8 @@ union Capability {
/**
* Effect capabilities.
*/
AcousticEchoCanceler.Capability acousticEchoCanceler;
AutomaticGainControl.Capability automaticGainControl;
BassBoost.Capability bassBoost;
Downmix.Capability downmix;
DynamicsProcessing.Capability dynamicsProcessing;
@@ -56,6 +61,7 @@ union Capability {
Equalizer.Capability equalizer;
HapticGenerator.Capability hapticGenerator;
LoudnessEnhancer.Capability loudnessEnhancer;
NoiseSuppression.Capability noiseSuppression;
PresetReverb.Capability presetReverb;
Virtualizer.Capability virtualizer;
Visualizer.Capability visualizer;

View File

@@ -0,0 +1,71 @@
/*
* 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.effect;
import android.hardware.audio.effect.VendorExtension;
/**
* Noise suppression (NS) is an audio pre-processor which removes background noise from the captured
* signal. The component of the signal considered as noise can be either stationary (car/airplane
* engine, AC system) or non-stationary (other peoples conversations, car horn) for more advanced
* implementations.
*
* All parameters defined in union NoiseSuppression must be gettable and settable. The capabilities
* defined in NoiseSuppression.Capability can only acquired with IEffect.getDescriptor() and not
* settable.
*/
@VintfStability
union NoiseSuppression {
/**
* Effect parameter tag to identify the parameters for getParameter().
*/
@VintfStability
union Id {
int vendorExtensionTag;
NoiseSuppression.Tag commonTag;
}
/**
* Vendor NoiseSuppression implementation definition for additional parameters.
*/
VendorExtension vendor;
/**
* Capability supported by NoiseSuppression implementation.
*/
@VintfStability
parcelable Capability {
/**
* NoiseSuppression capability extension, vendor can use this extension in case existing
* capability definition not enough.
*/
ParcelableHolder extension;
}
/**
* Different level of Noise Suppression to set.
* As an example, webrtc have NsConfig::SuppressionLevel::k6dB applied for LOW level noise
* suppression, NsConfig::SuppressionLevel::k12dB for MEDIUM, and
* NsConfig::SuppressionLevel::k18dB for HIGH.
*/
@VintfStability @Backing(type="int") enum Level { LOW, MEDIUM, HIGH }
/**
* The NS level.
*/
Level level;
}

View File

@@ -16,6 +16,8 @@
package android.hardware.audio.effect;
import android.hardware.audio.effect.AcousticEchoCanceler;
import android.hardware.audio.effect.AutomaticGainControl;
import android.hardware.audio.effect.BassBoost;
import android.hardware.audio.effect.Downmix;
import android.hardware.audio.effect.DynamicsProcessing;
@@ -23,6 +25,7 @@ import android.hardware.audio.effect.EnvironmentalReverb;
import android.hardware.audio.effect.Equalizer;
import android.hardware.audio.effect.HapticGenerator;
import android.hardware.audio.effect.LoudnessEnhancer;
import android.hardware.audio.effect.NoiseSuppression;
import android.hardware.audio.effect.PresetReverb;
import android.hardware.audio.effect.VendorExtension;
import android.hardware.audio.effect.Virtualizer;
@@ -71,6 +74,8 @@ union Parameter {
* effectInstance.getParameter(id, &param);
*
*/
AcousticEchoCanceler.Id acousticEchoCancelerTag;
AutomaticGainControl.Id automaticGainControlTag;
BassBoost.Id bassBoostTag;
Downmix.Id downmixTag;
DynamicsProcessing.Id dynamicsProcessingTag;
@@ -78,6 +83,7 @@ union Parameter {
Equalizer.Id equalizerTag;
HapticGenerator.Id hapticGeneratorTag;
LoudnessEnhancer.Id loudnessEnhancerTag;
NoiseSuppression.Id noiseSuppressionTag;
PresetReverb.Id presetReverbTag;
Virtualizer.Id virtualizerTag;
Visualizer.Id visualizerTag;
@@ -149,6 +155,8 @@ union Parameter {
@VintfStability
union Specific {
VendorExtension vendorEffect;
AcousticEchoCanceler acousticEchoCanceler;
AutomaticGainControl automaticGainControl;
BassBoost bassBoost;
Downmix downmix;
DynamicsProcessing dynamicsProcessing;
@@ -156,6 +164,7 @@ union Parameter {
Equalizer equalizer;
HapticGenerator hapticGenerator;
LoudnessEnhancer loudnessEnhancer;
NoiseSuppression noiseSuppression;
PresetReverb presetReverb;
Virtualizer virtualizer;
Visualizer visualizer;

View File

@@ -38,7 +38,7 @@ parcelable Processing {
*/
Type type;
/**
* List of effect identities for this processing.
* List of effect descriptors for this processing.
*/
Descriptor.Identity[] ids;
Descriptor[] ids;
}

View File

@@ -0,0 +1,194 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <cstddef>
#include <memory>
#define LOG_TAG "AHAL_AcousticEchoCancelerSw"
#include <Utils.h>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "AcousticEchoCancelerSw.h"
using aidl::android::hardware::audio::effect::AcousticEchoCancelerSw;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kAcousticEchoCancelerSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<AcousticEchoCancelerSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
if (!in_impl_uuid || *in_impl_uuid != kAcousticEchoCancelerSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = AcousticEchoCancelerSw::kDescriptor;
LOG(ERROR) << __func__ << "xxx " << _aidl_return->toString();
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
const std::string AcousticEchoCancelerSw::kEffectName = "AcousticEchoCancelerSw";
const AcousticEchoCanceler::Capability AcousticEchoCancelerSw::kCapability = {
.maxEchoDelayUs = 500, .supportMobileMode = false};
const Descriptor AcousticEchoCancelerSw::kDescriptor = {
.common = {.id = {.type = kAcousticEchoCancelerTypeUUID,
.uuid = kAcousticEchoCancelerSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = AcousticEchoCancelerSw::kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::acousticEchoCanceler>(
AcousticEchoCancelerSw::kCapability)};
ndk::ScopedAStatus AcousticEchoCancelerSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus AcousticEchoCancelerSw::setParameterSpecific(
const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::acousticEchoCanceler != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
auto tag = param.getTag();
switch (tag) {
case AcousticEchoCanceler::echoDelayUs: {
RETURN_IF(mContext->setEchoDelay(param.get<AcousticEchoCanceler::echoDelayUs>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
return ndk::ScopedAStatus::ok();
}
case AcousticEchoCanceler::mobileMode: {
RETURN_IF(true == param.get<AcousticEchoCanceler::mobileMode>(), EX_ILLEGAL_ARGUMENT,
"SettingmobileModeSupported");
return ndk::ScopedAStatus::ok();
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
}
}
}
ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::acousticEchoCancelerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
auto specificId = id.get<Parameter::Id::acousticEchoCancelerTag>();
auto specificIdTag = specificId.getTag();
switch (specificIdTag) {
case AcousticEchoCanceler::Id::commonTag:
return getParameterAcousticEchoCanceler(
specificId.get<AcousticEchoCanceler::Id::commonTag>(), specific);
default:
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
}
}
ndk::ScopedAStatus AcousticEchoCancelerSw::getParameterAcousticEchoCanceler(
const AcousticEchoCanceler::Tag& tag, Parameter::Specific* specific) {
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
AcousticEchoCanceler param;
switch (tag) {
case AcousticEchoCanceler::echoDelayUs: {
param.set<AcousticEchoCanceler::echoDelayUs>(mContext->getEchoDelay());
break;
}
case AcousticEchoCanceler::mobileMode: {
param.set<AcousticEchoCanceler::mobileMode>(false);
break;
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
}
}
specific->set<Parameter::Specific::acousticEchoCanceler>(param);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> AcousticEchoCancelerSw::createContext(
const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
} else {
mContext = std::make_shared<AcousticEchoCancelerSwContext>(1 /* statusFmqDepth */, common);
}
return mContext;
}
std::shared_ptr<EffectContext> AcousticEchoCancelerSw::getContext() {
return mContext;
}
RetCode AcousticEchoCancelerSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status AcousticEchoCancelerSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
return {STATUS_OK, samples, samples};
}
RetCode AcousticEchoCancelerSwContext::setEchoDelay(int echoDelayUs) {
if (echoDelayUs < 0 || echoDelayUs > AcousticEchoCancelerSw::kCapability.maxEchoDelayUs) {
LOG(DEBUG) << __func__ << " illegal delay " << echoDelayUs;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
mEchoDelayUs = echoDelayUs;
return RetCode::SUCCESS;
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class AcousticEchoCancelerSwContext final : public EffectContext {
public:
AcousticEchoCancelerSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
RetCode setEchoDelay(int echoDelayUs);
int getEchoDelay() const { return mEchoDelayUs; }
private:
int mEchoDelayUs;
};
class AcousticEchoCancelerSw final : public EffectImpl {
public:
static const std::string kEffectName;
static const bool kStrengthSupported;
static const AcousticEchoCanceler::Capability kCapability;
static const Descriptor kDescriptor;
AcousticEchoCancelerSw() { LOG(DEBUG) << __func__; }
~AcousticEchoCancelerSw() {
cleanUp();
LOG(DEBUG) << __func__;
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
std::string getEffectName() override { return kEffectName; };
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
private:
std::shared_ptr<AcousticEchoCancelerSwContext> mContext;
ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Tag& tag,
Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libaecsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"AcousticEchoCancelerSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -28,6 +28,8 @@
name of a library .so file on the target device.
-->
<libraries>
<library name="aecsw" path="libaecsw.so"/>
<library name="agcsw" path="libagcsw.so"/>
<library name="bassboostsw" path="libbassboostsw.so"/>
<library name="bundle" path="libbundleaidl.so"/>
<library name="downmix" path="libdownmixaidl.so"/>
@@ -35,6 +37,7 @@
<library name="equalizersw" path="libequalizersw.so"/>
<library name="haptic_generatorsw" path="libhapticgeneratorsw.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"/>
@@ -62,6 +65,8 @@
-->
<effects>
<effect name="acoustic_echo_canceler" library="aecsw" uuid="bb392ec0-8d4d-11e0-a896-0002a5d5c51b"/>
<effect name="automatic_gain_control" library="agcsw" uuid="89f38e65-d4d2-4d64-ad0e-2b3e799ea886"/>
<effectProxy name="bassboost" uuid="14804144-a5ee-4d24-aa88-0002a5d5c51b">
<libsw library="bassboostsw" uuid="fa8181f2-588b-11ed-9b6a-0242ac120002"/>
<libsw library="bundle" uuid="8631f300-72e2-11df-b57e-0002a5d5c51b"/>
@@ -71,6 +76,7 @@
<effect name="haptic_generator" library="haptic_generatorsw" uuid="fa819110-588b-11ed-9b6a-0242ac120002"/>
<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"/>
<effect name="preset_reverb" library="preset_reverbsw" uuid="fa8199c6-588b-11ed-9b6a-0242ac120002"/>
<effect name="virtualizer" library="virtualizersw" uuid="fa819d86-588b-11ed-9b6a-0242ac120002"/>
<effect name="visualizer" library="visualizersw" uuid="fa81a0f6-588b-11ed-9b6a-0242ac120002"/>

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libagcsw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"AutomaticGainControlSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <cstddef>
#include <memory>
#define LOG_TAG "AHAL_AutomaticGainControlSw"
#include <Utils.h>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "AutomaticGainControlSw.h"
using aidl::android::hardware::audio::effect::AutomaticGainControlSw;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kAutomaticGainControlSwImplUUID;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<AutomaticGainControlSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
if (!in_impl_uuid || *in_impl_uuid != kAutomaticGainControlSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = AutomaticGainControlSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
const std::string AutomaticGainControlSw::kEffectName = "AutomaticGainControlSw";
const AutomaticGainControl::Capability AutomaticGainControlSw::kCapability = {
.maxFixedDigitalGainMb = 50000, .maxSaturationMarginMb = 10000};
const Descriptor AutomaticGainControlSw::kDescriptor = {
.common = {.id = {.type = kAutomaticGainControlTypeUUID,
.uuid = kAutomaticGainControlSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = AutomaticGainControlSw::kEffectName,
.implementor = "The Android Open Source Project"},
.capability = Capability::make<Capability::automaticGainControl>(
AutomaticGainControlSw::kCapability)};
ndk::ScopedAStatus AutomaticGainControlSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus AutomaticGainControlSw::setParameterSpecific(
const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::automaticGainControl != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& param = specific.get<Parameter::Specific::automaticGainControl>();
auto tag = param.getTag();
switch (tag) {
case AutomaticGainControl::fixedDigitalGainMb: {
RETURN_IF(mContext->setDigitalGain(
param.get<AutomaticGainControl::fixedDigitalGainMb>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
return ndk::ScopedAStatus::ok();
}
case AutomaticGainControl::levelEstimator: {
RETURN_IF(
mContext->setLevelEstimator(
param.get<AutomaticGainControl::levelEstimator>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
return ndk::ScopedAStatus::ok();
}
case AutomaticGainControl::saturationMarginMb: {
RETURN_IF(mContext->setSaturationMargin(
param.get<AutomaticGainControl::saturationMarginMb>()) !=
RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "saturationMarginNotSupported");
return ndk::ScopedAStatus::ok();
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
}
}
}
ndk::ScopedAStatus AutomaticGainControlSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::automaticGainControlTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
auto specificId = id.get<Parameter::Id::automaticGainControlTag>();
auto specificIdTag = specificId.getTag();
switch (specificIdTag) {
case AutomaticGainControl::Id::commonTag:
return getParameterAutomaticGainControl(
specificId.get<AutomaticGainControl::Id::commonTag>(), specific);
default:
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
}
}
ndk::ScopedAStatus AutomaticGainControlSw::getParameterAutomaticGainControl(
const AutomaticGainControl::Tag& tag, Parameter::Specific* specific) {
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
AutomaticGainControl param;
switch (tag) {
case AutomaticGainControl::fixedDigitalGainMb: {
param.set<AutomaticGainControl::fixedDigitalGainMb>(mContext->getDigitalGain());
break;
}
case AutomaticGainControl::levelEstimator: {
param.set<AutomaticGainControl::levelEstimator>(mContext->getLevelEstimator());
break;
}
case AutomaticGainControl::saturationMarginMb: {
param.set<AutomaticGainControl::saturationMarginMb>(mContext->getSaturationMargin());
break;
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "AutomaticGainControlTagNotSupported");
}
}
specific->set<Parameter::Specific::automaticGainControl>(param);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> AutomaticGainControlSw::createContext(
const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
} else {
mContext = std::make_shared<AutomaticGainControlSwContext>(1 /* statusFmqDepth */, common);
}
return mContext;
}
std::shared_ptr<EffectContext> AutomaticGainControlSw::getContext() {
return mContext;
}
RetCode AutomaticGainControlSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status AutomaticGainControlSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
return {STATUS_OK, samples, samples};
}
RetCode AutomaticGainControlSwContext::setDigitalGain(int gain) {
if (gain < 0 || gain > AutomaticGainControlSw::kCapability.maxFixedDigitalGainMb) {
LOG(DEBUG) << __func__ << " illegal digital gain " << gain;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
mDigitalGain = gain;
return RetCode::SUCCESS;
}
int AutomaticGainControlSwContext::getDigitalGain() {
return mDigitalGain;
}
RetCode AutomaticGainControlSwContext::setLevelEstimator(
AutomaticGainControl::LevelEstimator levelEstimator) {
mLevelEstimator = levelEstimator;
return RetCode::SUCCESS;
}
AutomaticGainControl::LevelEstimator AutomaticGainControlSwContext::getLevelEstimator() {
return mLevelEstimator;
}
RetCode AutomaticGainControlSwContext::setSaturationMargin(int margin) {
if (margin < 0 || margin > AutomaticGainControlSw::kCapability.maxSaturationMarginMb) {
LOG(DEBUG) << __func__ << " illegal saturationMargin " << margin;
return RetCode::ERROR_ILLEGAL_PARAMETER;
}
mSaturationMargin = margin;
return RetCode::SUCCESS;
}
int AutomaticGainControlSwContext::getSaturationMargin() {
return mSaturationMargin;
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class AutomaticGainControlSwContext final : public EffectContext {
public:
AutomaticGainControlSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
RetCode setDigitalGain(int gain);
int getDigitalGain();
RetCode setLevelEstimator(AutomaticGainControl::LevelEstimator levelEstimator);
AutomaticGainControl::LevelEstimator getLevelEstimator();
RetCode setSaturationMargin(int margin);
int getSaturationMargin();
private:
int mDigitalGain;
AutomaticGainControl::LevelEstimator mLevelEstimator;
int mSaturationMargin;
};
class AutomaticGainControlSw final : public EffectImpl {
public:
static const std::string kEffectName;
static const bool kStrengthSupported;
static const AutomaticGainControl::Capability kCapability;
static const Descriptor kDescriptor;
AutomaticGainControlSw() { LOG(DEBUG) << __func__; }
~AutomaticGainControlSw() {
cleanUp();
LOG(DEBUG) << __func__;
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
std::string getEffectName() override { return kEffectName; };
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
private:
std::shared_ptr<AutomaticGainControlSwContext> mContext;
ndk::ScopedAStatus getParameterAutomaticGainControl(const AutomaticGainControl::Tag& tag,
Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -33,6 +33,30 @@ static const AudioUuid kEffectNullUuid = {static_cast<int32_t>(0xec7178ec),
static const AudioUuid kEffectZeroUuid = {
static_cast<int32_t>(0x0), 0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
// 7b491460-8d4d-11e0-bd61-0002a5d5c51b.
static const AudioUuid kAcousticEchoCancelerTypeUUID = {static_cast<int32_t>(0x7b491460),
0x8d4d,
0x11e0,
0xbd61,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// bb392ec0-8d4d-11e0-a896-0002a5d5c51b
static const AudioUuid kAcousticEchoCancelerSwImplUUID = {static_cast<int32_t>(0xbb392ec0),
0x8d4d,
0x11e0,
0xa896,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// 0xae3c653b-be18-4ab8-8938-418f0a7f06ac
static const AudioUuid kAutomaticGainControlTypeUUID = {static_cast<int32_t>(0xae3c653b),
0xbe18,
0x4ab8,
0x8938,
{0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac}};
// 89f38e65-d4d2-4d64-ad0e-2b3e799ea886
static const AudioUuid kAutomaticGainControlSwImplUUID = {static_cast<int32_t>(0x89f38e65),
0xd4d2,
0x4d64,
0xad0e,
{0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}};
// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
0xddd4,
@@ -153,6 +177,18 @@ static const AudioUuid kEnvReverbSwImplUUID = {static_cast<int32_t>(0xfa819886),
0x11ed,
0x9b6a,
{0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
// 58b4b260-8e06-11e0-aa8e-0002a5d5c51b
static const AudioUuid kNoiseSuppressionTypeUUID = {static_cast<int32_t>(0x58b4b260),
0x8e06,
0x11e0,
0xaa8e,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// c06c8400-8e06-11e0-9cb6-0002a5d5c51b
static const AudioUuid kNoiseSuppressionSwImplUUID = {static_cast<int32_t>(0xc06c8400),
0x8e06,
0x11e0,
0x9cb6,
{0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
0xddd8,
@@ -208,6 +244,8 @@ static const AudioUuid kVolumeSwImplUUID = {static_cast<int32_t>(0xfa81a718),
* We need this map is because existing audio_effects.xml don't have a type UUID defined.
*/
static const std::map<const std::string /* effect type */, const AudioUuid&> kUuidNameTypeMap = {
{"acoustic_echo_canceler", kAcousticEchoCancelerTypeUUID},
{"automatic_gain_control", kAutomaticGainControlTypeUUID},
{"bassboost", kBassBoostTypeUUID},
{"downmix", kDownmixTypeUUID},
{"dynamics_processing", kDynamicsProcessingTypeUUID},
@@ -215,6 +253,7 @@ static const std::map<const std::string /* effect type */, const AudioUuid&> kUu
{"haptic_generator", kHapticGeneratorTypeUUID},
{"loudness_enhancer", kLoudnessEnhancerTypeUUID},
{"env_reverb", kEnvReverbTypeUUID},
{"noise_suppression", kNoiseSuppressionTypeUUID},
{"preset_reverb", kPresetReverbTypeUUID},
{"reverb_env_aux", kEnvReverbTypeUUID},
{"reverb_env_ins", kEnvReverbTypeUUID},

View File

@@ -0,0 +1,40 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package {
// See: http://go/android-license-faq
// A large-scale-change added 'default_applicable_licenses' to import
// all of the 'license_kinds' from "hardware_interfaces_license"
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_library_shared {
name: "libnssw",
defaults: [
"aidlaudioeffectservice_defaults",
"latest_android_media_audio_common_types_ndk_shared",
"latest_android_hardware_audio_effect_ndk_shared",
],
srcs: [
"NoiseSuppressionSw.cpp",
":effectCommonFile",
],
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
}

View File

@@ -0,0 +1,180 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <algorithm>
#include <cstddef>
#include <memory>
#define LOG_TAG "AHAL_NoiseSuppressionSw"
#include <Utils.h>
#include <unordered_set>
#include <android-base/logging.h>
#include <fmq/AidlMessageQueue.h>
#include "NoiseSuppressionSw.h"
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::kNoiseSuppressionSwImplUUID;
using aidl::android::hardware::audio::effect::NoiseSuppressionSw;
using aidl::android::media::audio::common::AudioUuid;
extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
std::shared_ptr<IEffect>* instanceSpp) {
if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
if (instanceSpp) {
*instanceSpp = ndk::SharedRefBase::make<NoiseSuppressionSw>();
LOG(DEBUG) << __func__ << " instance " << instanceSpp->get() << " created";
return EX_NONE;
} else {
LOG(ERROR) << __func__ << " invalid input parameter!";
return EX_ILLEGAL_ARGUMENT;
}
}
extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
if (!in_impl_uuid || *in_impl_uuid != kNoiseSuppressionSwImplUUID) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
*_aidl_return = NoiseSuppressionSw::kDescriptor;
return EX_NONE;
}
namespace aidl::android::hardware::audio::effect {
const std::string NoiseSuppressionSw::kEffectName = "NoiseSuppressionSw";
const NoiseSuppression::Capability NoiseSuppressionSw::kCapability;
const Descriptor NoiseSuppressionSw::kDescriptor = {
.common = {.id = {.type = kNoiseSuppressionTypeUUID,
.uuid = kNoiseSuppressionSwImplUUID,
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT,
.insert = Flags::Insert::FIRST,
.volume = Flags::Volume::CTRL},
.name = NoiseSuppressionSw::kEffectName,
.implementor = "The Android Open Source Project"},
.capability =
Capability::make<Capability::noiseSuppression>(NoiseSuppressionSw::kCapability)};
ndk::ScopedAStatus NoiseSuppressionSw::getDescriptor(Descriptor* _aidl_return) {
LOG(DEBUG) << __func__ << kDescriptor.toString();
*_aidl_return = kDescriptor;
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus NoiseSuppressionSw::setParameterSpecific(const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::noiseSuppression != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& param = specific.get<Parameter::Specific::noiseSuppression>();
auto tag = param.getTag();
switch (tag) {
case NoiseSuppression::level: {
RETURN_IF(mContext->setLevel(param.get<NoiseSuppression::level>()) != RetCode::SUCCESS,
EX_ILLEGAL_ARGUMENT, "levelSupported");
return ndk::ScopedAStatus::ok();
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
}
}
}
ndk::ScopedAStatus NoiseSuppressionSw::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
auto tag = id.getTag();
RETURN_IF(Parameter::Id::noiseSuppressionTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
auto specificId = id.get<Parameter::Id::noiseSuppressionTag>();
auto specificIdTag = specificId.getTag();
switch (specificIdTag) {
case NoiseSuppression::Id::commonTag:
return getParameterNoiseSuppression(specificId.get<NoiseSuppression::Id::commonTag>(),
specific);
default:
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
}
}
ndk::ScopedAStatus NoiseSuppressionSw::getParameterNoiseSuppression(
const NoiseSuppression::Tag& tag, Parameter::Specific* specific) {
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
NoiseSuppression param;
switch (tag) {
case NoiseSuppression::level: {
param.set<NoiseSuppression::level>(mContext->getLevel());
break;
}
default: {
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
}
}
specific->set<Parameter::Specific::noiseSuppression>(param);
return ndk::ScopedAStatus::ok();
}
std::shared_ptr<EffectContext> NoiseSuppressionSw::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
} else {
mContext = std::make_shared<NoiseSuppressionSwContext>(1 /* statusFmqDepth */, common);
}
return mContext;
}
std::shared_ptr<EffectContext> NoiseSuppressionSw::getContext() {
return mContext;
}
RetCode NoiseSuppressionSw::releaseContext() {
if (mContext) {
mContext.reset();
}
return RetCode::SUCCESS;
}
// Processing method running in EffectWorker thread.
IEffect::Status NoiseSuppressionSw::effectProcessImpl(float* in, float* out, int samples) {
// TODO: get data buffer and process.
LOG(DEBUG) << __func__ << " in " << in << " out " << out << " samples " << samples;
for (int i = 0; i < samples; i++) {
*out++ = *in++;
}
return {STATUS_OK, samples, samples};
}
RetCode NoiseSuppressionSwContext::setLevel(NoiseSuppression::Level level) {
mLevel = level;
return RetCode::SUCCESS;
}
NoiseSuppression::Level NoiseSuppressionSwContext::getLevel() {
return mLevel;
}
} // namespace aidl::android::hardware::audio::effect

View File

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#pragma once
#include <aidl/android/hardware/audio/effect/BnEffect.h>
#include <fmq/AidlMessageQueue.h>
#include <cstdlib>
#include <memory>
#include "effect-impl/EffectImpl.h"
#include "effect-impl/EffectUUID.h"
namespace aidl::android::hardware::audio::effect {
class NoiseSuppressionSwContext final : public EffectContext {
public:
NoiseSuppressionSwContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
}
RetCode setLevel(NoiseSuppression::Level level);
NoiseSuppression::Level getLevel();
private:
NoiseSuppression::Level mLevel;
};
class NoiseSuppressionSw final : public EffectImpl {
public:
static const std::string kEffectName;
static const bool kStrengthSupported;
static const NoiseSuppression::Capability kCapability;
static const Descriptor kDescriptor;
NoiseSuppressionSw() { LOG(DEBUG) << __func__; }
~NoiseSuppressionSw() {
cleanUp();
LOG(DEBUG) << __func__;
}
ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) override;
std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
std::shared_ptr<EffectContext> getContext() override;
RetCode releaseContext() override;
std::string getEffectName() override { return kEffectName; };
IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
private:
std::shared_ptr<NoiseSuppressionSwContext> mContext;
ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Tag& tag,
Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect

View File

@@ -102,3 +102,21 @@ cc_test {
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalVisualizerTargetTest.cpp"],
}
cc_test {
name: "VtsHalAECTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalAECTargetTest.cpp"],
}
cc_test {
name: "VtsHalAGCTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalAGCTargetTest.cpp"],
}
cc_test {
name: "VtsHalNSTargetTest",
defaults: ["VtsHalAudioTargetTestDefaults"],
srcs: ["VtsHalNSTargetTest.cpp"],
}

View File

@@ -70,7 +70,6 @@ class EffectFactoryHelper {
}
}
}
return result;
}

View File

@@ -0,0 +1,219 @@
/*
* 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 <aidl/Vintf.h>
#include <algorithm>
#define LOG_TAG "VtsHalAECParamTest"
#include <Utils.h>
#include "EffectHelper.h"
using namespace android;
using aidl::android::hardware::audio::effect::AcousticEchoCanceler;
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::kAcousticEchoCancelerTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;
enum ParamName { PARAM_INSTANCE_NAME, PARAM_ECHO_DELAY, PARAM_MOBILE_MODE };
using AECParamTestParam = std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>,
int /* echoDelayUs */, bool /* mobileMode */>;
class AECParamTest : public ::testing::TestWithParam<AECParamTestParam>, public EffectHelper {
public:
AECParamTest()
: mEchoDelay(std::get<PARAM_ECHO_DELAY>(GetParam())),
mMobileMode(std::get<PARAM_MOBILE_MODE>(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() {
AcousticEchoCanceler aec = AcousticEchoCanceler::make<AcousticEchoCanceler::echoDelayUs>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::acousticEchoCanceler>(aec);
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;
Descriptor mDescriptor;
int mEchoDelay;
bool mMobileMode;
void SetAndGetParameters() {
for (auto& it : mTags) {
auto& tag = it.first;
auto& aec = it.second;
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
const bool valid = isTagInRange(tag, aec, desc);
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set parameter
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::acousticEchoCanceler>(aec);
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;
AcousticEchoCanceler::Id specificId;
specificId.set<AcousticEchoCanceler::Id::commonTag>(tag);
id.set<Parameter::Id::acousticEchoCancelerTag>(specificId);
EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
<< "\ngetParam:" << getParam.toString();
}
}
}
void addEchoDelayParam(int delay) {
AcousticEchoCanceler aec;
aec.set<AcousticEchoCanceler::echoDelayUs>(delay);
mTags.push_back({AcousticEchoCanceler::echoDelayUs, aec});
}
void addMobileModeParam(bool mode) {
AcousticEchoCanceler aec;
aec.set<AcousticEchoCanceler::mobileMode>(mode);
mTags.push_back({AcousticEchoCanceler::mobileMode, aec});
}
bool isTagInRange(const AcousticEchoCanceler::Tag& tag, const AcousticEchoCanceler& aec,
const Descriptor& desc) const {
const AcousticEchoCanceler::Capability& aecCap =
desc.capability.get<Capability::acousticEchoCanceler>();
switch (tag) {
case AcousticEchoCanceler::echoDelayUs: {
return isEchoDelayInRange(aecCap, aec.get<AcousticEchoCanceler::echoDelayUs>());
}
case AcousticEchoCanceler::mobileMode: {
bool mode = aec.get<AcousticEchoCanceler::mobileMode>();
return isMobileModeValid(aecCap, mode);
}
default:
return false;
}
}
bool isEchoDelayInRange(const AcousticEchoCanceler::Capability& cap, int delay) const {
return (delay >= 0 && delay <= cap.maxEchoDelayUs);
}
bool isMobileModeValid(const AcousticEchoCanceler::Capability& cap, bool mode) const {
if (cap.supportMobileMode) {
return true;
} else {
return mode == false;
}
}
static std::vector<int> getEchoDelayTestValues() {
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::acousticEchoCanceler>()
.maxEchoDelayUs <
b.second.capability.get<Capability::acousticEchoCanceler>()
.maxEchoDelayUs;
});
if (max == kFactoryDescList.end()) {
return {0};
}
int maxDelay =
max->second.capability.get<Capability::acousticEchoCanceler>().maxEchoDelayUs;
return {-1, 0, maxDelay - 1, maxDelay, maxDelay + 1};
}
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();
}
TEST_P(AECParamTest, SetAndGetMobileMode) {
EXPECT_NO_FATAL_FAILURE(addMobileModeParam(mMobileMode));
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;
});
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AECParamTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,256 @@
/*
* 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 <aidl/Vintf.h>
#define LOG_TAG "VtsHalAGCParamTest"
#include <Utils.h>
#include "EffectHelper.h"
using namespace android;
using aidl::android::hardware::audio::effect::AutomaticGainControl;
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::kAutomaticGainControlTypeUUID;
using aidl::android::hardware::audio::effect::Parameter;
enum ParamName {
PARAM_INSTANCE_NAME,
PARAM_DIGITAL_GAIN,
PARAM_SATURATION_MARGIN,
PARAM_LEVEL_ESTIMATOR
};
using AGCParamTestParam =
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, int /* gain */,
int /* margin */, AutomaticGainControl::LevelEstimator>;
class AGCParamTest : public ::testing::TestWithParam<AGCParamTestParam>, public EffectHelper {
public:
AGCParamTest()
: mGain(std::get<PARAM_DIGITAL_GAIN>(GetParam())),
mMargin(std::get<PARAM_SATURATION_MARGIN>(GetParam())),
mLevelEstimator(std::get<PARAM_LEVEL_ESTIMATOR>(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() {
AutomaticGainControl AGC =
AutomaticGainControl::make<AutomaticGainControl::fixedDigitalGainMb>(0);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::automaticGainControl>(AGC);
return specific;
}
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;
int mGain;
int mMargin;
AutomaticGainControl::LevelEstimator mLevelEstimator;
void SetAndGetParameters() {
for (auto& it : mTags) {
auto& tag = it.first;
auto& AGC = it.second;
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
const bool valid = isTagInRange(tag, AGC, desc);
const binder_exception_t expected = valid ? EX_NONE : EX_ILLEGAL_ARGUMENT;
// set parameter
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::automaticGainControl>(AGC);
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;
AutomaticGainControl::Id specificId;
specificId.set<AutomaticGainControl::Id::commonTag>(tag);
id.set<Parameter::Id::automaticGainControlTag>(specificId);
EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
<< "\ngetParam:" << getParam.toString();
}
}
}
void addDigitalGainParam(int gain) {
AutomaticGainControl AGC;
AGC.set<AutomaticGainControl::fixedDigitalGainMb>(gain);
mTags.push_back({AutomaticGainControl::fixedDigitalGainMb, AGC});
}
void addSaturationMarginParam(int margin) {
AutomaticGainControl AGC;
AGC.set<AutomaticGainControl::saturationMarginMb>(margin);
mTags.push_back({AutomaticGainControl::saturationMarginMb, AGC});
}
void addLevelEstimatorParam(AutomaticGainControl::LevelEstimator levelEstimator) {
AutomaticGainControl AGC;
AGC.set<AutomaticGainControl::levelEstimator>(levelEstimator);
mTags.push_back({AutomaticGainControl::levelEstimator, AGC});
}
bool isTagInRange(const AutomaticGainControl::Tag& tag, const AutomaticGainControl& AGC,
const Descriptor& desc) const {
const AutomaticGainControl::Capability& AGCCap =
desc.capability.get<Capability::automaticGainControl>();
switch (tag) {
case AutomaticGainControl::fixedDigitalGainMb: {
auto gain = AGC.get<AutomaticGainControl::fixedDigitalGainMb>();
return gain >= 0 && gain <= AGCCap.maxFixedDigitalGainMb;
}
case AutomaticGainControl::levelEstimator: {
return true;
}
case AutomaticGainControl::saturationMarginMb: {
auto margin = AGC.get<AutomaticGainControl::saturationMarginMb>();
return margin >= 0 && margin <= AGCCap.maxSaturationMarginMb;
}
default:
return false;
}
}
static std::vector<int> getDigitalGainValues() {
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::automaticGainControl>()
.maxFixedDigitalGainMb <
b.second.capability.get<Capability::automaticGainControl>()
.maxFixedDigitalGainMb;
});
if (max == kFactoryDescList.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() {
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::automaticGainControl>()
.maxSaturationMarginMb <
b.second.capability.get<Capability::automaticGainControl>()
.maxSaturationMarginMb;
});
if (max == kFactoryDescList.end()) {
return {0};
}
int maxMargin = max->second.capability.get<Capability::automaticGainControl>()
.maxSaturationMarginMb;
return {-1, 0, maxMargin - 1, maxMargin, maxMargin + 1};
}
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();
}
TEST_P(AGCParamTest, SetAndGetSaturationMargin) {
EXPECT_NO_FATAL_FAILURE(addSaturationMarginParam(mMargin));
SetAndGetParameters();
}
TEST_P(AGCParamTest, SetAndGetLevelEstimator) {
EXPECT_NO_FATAL_FAILURE(addLevelEstimatorParam(mLevelEstimator));
SetAndGetParameters();
}
INSTANTIATE_TEST_SUITE_P(
AGCParamTest, AGCParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kAutomaticGainControlTypeUUID)),
testing::ValuesIn(AGCParamTest::kDigitalGainValues),
testing::ValuesIn(AGCParamTest::kSaturationMarginValues),
testing::ValuesIn(AGCParamTest::kLevelEstimatorValues)),
[](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));
std::string estimator = aidl::android::hardware::audio::effect::toString(
std::get<PARAM_LEVEL_ESTIMATOR>(info.param));
std::string margin =
std::to_string(static_cast<int>(std::get<PARAM_SATURATION_MARGIN>(info.param)));
std::string name = "Implementor_" + descriptor.common.implementor + "_name_" +
descriptor.common.name + "_UUID_" +
descriptor.common.id.uuid.toString() + "_digital_gain_" + gain +
"_level_estimator_" + estimator + "_margin_" + margin;
std::replace_if(
name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
return name;
});
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(AGCParamTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,158 @@
/*
* 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 <aidl/Vintf.h>
#define LOG_TAG "VtsHalNSParamTest"
#include <Utils.h>
#include "EffectHelper.h"
using namespace android;
using aidl::android::hardware::audio::effect::Capability;
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::hardware::audio::effect::kNoiseSuppressionTypeUUID;
using aidl::android::hardware::audio::effect::NoiseSuppression;
using aidl::android::hardware::audio::effect::Parameter;
enum ParamName { PARAM_INSTANCE_NAME, PARAM_LEVEL };
using NSParamTestParam =
std::tuple<std::pair<std::shared_ptr<IFactory>, Descriptor>, NoiseSuppression::Level>;
class NSParamTest : public ::testing::TestWithParam<NSParamTestParam>, public EffectHelper {
public:
NSParamTest() : mLevel(std::get<PARAM_LEVEL>(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() {
NoiseSuppression ns =
NoiseSuppression::make<NoiseSuppression::level>(NoiseSuppression::Level::MEDIUM);
Parameter::Specific specific =
Parameter::Specific::make<Parameter::Specific::noiseSuppression>(ns);
return specific;
}
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;
NoiseSuppression::Level mLevel;
void SetAndGetParameters() {
for (auto& it : mTags) {
auto& tag = it.first;
auto& ns = it.second;
// validate parameter
Descriptor desc;
ASSERT_STATUS(EX_NONE, mEffect->getDescriptor(&desc));
const binder_exception_t expected = EX_NONE;
// set parameter
Parameter expectParam;
Parameter::Specific specific;
specific.set<Parameter::Specific::noiseSuppression>(ns);
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;
NoiseSuppression::Id specificId;
specificId.set<NoiseSuppression::Id::commonTag>(tag);
id.set<Parameter::Id::noiseSuppressionTag>(specificId);
EXPECT_STATUS(EX_NONE, mEffect->getParameter(id, &getParam));
EXPECT_EQ(expectParam, getParam) << "\nexpect:" << expectParam.toString()
<< "\ngetParam:" << getParam.toString();
}
}
}
void addLevelParam(NoiseSuppression::Level level) {
NoiseSuppression ns;
ns.set<NoiseSuppression::level>(level);
mTags.push_back({NoiseSuppression::level, ns});
}
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();
}
INSTANTIATE_TEST_SUITE_P(
NSParamTest, NSParamTest,
::testing::Combine(testing::ValuesIn(EffectFactoryHelper::getAllEffectDescriptors(
IFactory::descriptor, kNoiseSuppressionTypeUUID)),
testing::ValuesIn(NSParamTest::kLevelValues)),
[](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(
std::get<PARAM_LEVEL>(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(NSParamTest);
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_setThreadPoolMaxThreadCount(1);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}