Merge "[AIDL CTS] pass Equalizer implementation cts"
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 0d156a5..9174adf 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -9215,24 +9215,25 @@
* camera's crop region is set to maximum size, the FOV of the physical streams for the
* ultrawide lens will be the same as the logical stream, by making the crop region
* smaller than its active array size to compensate for the smaller focal length.</p>
- * <p>There are two ways for the application to capture RAW images from a logical camera
- * with RAW capability:</p>
+ * <p>For a logical camera, typically the underlying physical cameras have different RAW
+ * capabilities (such as resolution or CFA pattern). There are two ways for the
+ * application to capture RAW images from the logical camera:</p>
* <ul>
- * <li>Because the underlying physical cameras may have different RAW capabilities (such
- * as resolution or CFA pattern), to maintain backward compatibility, when a RAW stream
- * is configured, the camera device makes sure the default active physical camera remains
- * active and does not switch to other physical cameras. (One exception is that, if the
- * logical camera consists of identical image sensors and advertises multiple focalLength
- * due to different lenses, the camera device may generate RAW images from different
- * physical cameras based on the focalLength being set by the application.) This
- * backward-compatible approach usually results in loss of optical zoom, to telephoto
- * lens or to ultrawide lens.</li>
- * <li>Alternatively, to take advantage of the full zoomRatio range of the logical camera,
- * the application should use <a href="https://developer.android.com/reference/android/hardware/camera2/MultiResolutionImageReader.html">MultiResolutionImageReader</a>
- * to capture RAW images from the currently active physical camera. Because different
- * physical camera may have different RAW characteristics, the application needs to use
- * the characteristics and result metadata of the active physical camera for the
- * relevant RAW metadata.</li>
+ * <li>If the logical camera has RAW capability, the application can create and use RAW
+ * streams in the same way as before. In case a RAW stream is configured, to maintain
+ * backward compatibility, the camera device makes sure the default active physical
+ * camera remains active and does not switch to other physical cameras. (One exception
+ * is that, if the logical camera consists of identical image sensors and advertises
+ * multiple focalLength due to different lenses, the camera device may generate RAW
+ * images from different physical cameras based on the focalLength being set by the
+ * application.) This backward-compatible approach usually results in loss of optical
+ * zoom, to telephoto lens or to ultrawide lens.</li>
+ * <li>Alternatively, if supported by the device,
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/MultiResolutionImageReader.html">MultiResolutionImageReader</a>
+ * can be used to capture RAW images from one of the underlying physical cameras (
+ * depending on current zoom level). Because different physical cameras may have
+ * different RAW characteristics, the application needs to use the characteristics
+ * and result metadata of the active physical camera for the relevant RAW metadata.</li>
* </ul>
* <p>The capture request and result metadata tags required for backward compatible camera
* functionalities will be solely based on the logical camera capability. On the other
diff --git a/drm/libmediadrm/DrmMetricsLogger.cpp b/drm/libmediadrm/DrmMetricsLogger.cpp
index 89b1dcc..de6d097 100644
--- a/drm/libmediadrm/DrmMetricsLogger.cpp
+++ b/drm/libmediadrm/DrmMetricsLogger.cpp
@@ -63,6 +63,8 @@
DrmStatus DrmMetricsLogger::createPlugin(const uint8_t uuid[IDRM_UUID_SIZE],
const String8& appPackageName) {
std::memcpy(mUuid.data(), uuid, IDRM_UUID_SIZE);
+ mUuid[0] = betoh64(mUuid[0]);
+ mUuid[1] = betoh64(mUuid[1]);
if (kUuidSchemeMap.count(mUuid)) {
mScheme = kUuidSchemeMap.at(mUuid);
} else {
@@ -460,8 +462,8 @@
void DrmMetricsLogger::reportMediaDrmCreated() const {
mediametrics_handle_t handle(mediametrics_create("mediadrm.created"));
mediametrics_setCString(handle, "scheme", mScheme.c_str());
- mediametrics_setInt64(handle, "uuid_msb", be64toh(mUuid[0]));
- mediametrics_setInt64(handle, "uuid_lsb", be64toh(mUuid[1]));
+ mediametrics_setInt64(handle, "uuid_msb", mUuid[0]);
+ mediametrics_setInt64(handle, "uuid_lsb", mUuid[1]);
mediametrics_setInt32(handle, "frontend", mFrontend);
mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
mediametrics_selfRecord(handle);
@@ -471,8 +473,8 @@
void DrmMetricsLogger::reportMediaDrmSessionOpened(const std::vector<uint8_t>& sessionId) const {
mediametrics_handle_t handle(mediametrics_create("mediadrm.session_opened"));
mediametrics_setCString(handle, "scheme", mScheme.c_str());
- mediametrics_setInt64(handle, "uuid_msb", be64toh(mUuid[0]));
- mediametrics_setInt64(handle, "uuid_lsb", be64toh(mUuid[1]));
+ mediametrics_setInt64(handle, "uuid_msb", mUuid[0]);
+ mediametrics_setInt64(handle, "uuid_lsb", mUuid[1]);
mediametrics_setInt32(handle, "frontend", mFrontend);
mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
const std::lock_guard<std::mutex> lock(mSessionMapMutex);
@@ -490,8 +492,8 @@
const std::vector<uint8_t>& sessionId) const {
mediametrics_handle_t handle(mediametrics_create("mediadrm.errored"));
mediametrics_setCString(handle, "scheme", mScheme.c_str());
- mediametrics_setInt64(handle, "uuid_msb", be64toh(mUuid[0]));
- mediametrics_setInt64(handle, "uuid_lsb", be64toh(mUuid[1]));
+ mediametrics_setInt64(handle, "uuid_msb", mUuid[0]);
+ mediametrics_setInt64(handle, "uuid_lsb", mUuid[1]);
mediametrics_setInt32(handle, "frontend", mFrontend);
mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
if (!sessionId.empty()) {
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 757215d..39c3f4a 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -21,12 +21,14 @@
#include <cstdint>
#include <audio_utils/clock.h>
+#include <media/AidlConversionUtil.h>
#include <mediautils/TimeCheck.h>
#include <utils/Log.h>
#include "DeviceHalAidl.h"
#include "StreamHalAidl.h"
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
using ::aidl::android::hardware::audio::core::IStreamCommon;
using ::aidl::android::hardware::audio::core::IStreamIn;
using ::aidl::android::hardware::audio::core::IStreamOut;
@@ -334,7 +336,8 @@
return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
- StreamDescriptor::DrainMode::DRAIN_ALL), reply);
+ StreamDescriptor::DrainMode::DRAIN_ALL), reply,
+ true /*safeFromNonWorkerThread*/);
}
status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
@@ -472,11 +475,10 @@
return StreamHalAidl::getLatency(latency);
}
-status_t StreamOutHalAidl::setVolume(float left __unused, float right __unused) {
+status_t StreamOutHalAidl::setVolume(float left, float right) {
TIME_CHECK();
if (!mStream) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
- return OK;
+ return statusTFromBinderStatus(mStream->setHwVolume({left, right}));
}
status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
@@ -617,7 +619,7 @@
TIME_CHECK();
if (!mStream) return NO_INIT;
ALOGE("%s not implemented yet", __func__);
- return OK;
+ return BAD_VALUE;
}
status_t StreamOutHalAidl::setPlaybackRateParameters(
@@ -625,7 +627,7 @@
TIME_CHECK();
if (!mStream) return NO_INIT;
ALOGE("%s not implemented yet", __func__);
- return OK;
+ return BAD_VALUE;
}
status_t StreamOutHalAidl::setEventCallback(
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index c6e036a..d018c47 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -58,3 +58,39 @@
"libwebrtc_absl_headers",
],
}
+
+cc_library_shared {
+ name: "libpreprocessingaidl",
+ srcs: [
+ "aidl/PreProcessingContext.cpp",
+ "aidl/EffectPreProcessing.cpp",
+ ":effectCommonFile",
+ ],
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+ local_include_dirs: ["aidl"],
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libaudioutils",
+ ],
+ static_libs: [
+ "webrtc_audio_processing",
+ ],
+ header_libs: [
+ "libwebrtc_absl_headers",
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+ cflags: [
+ "-Wthread-safety",
+ "-Wno-unused-parameter",
+ ],
+ relative_install_path: "soundfx",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
new file mode 100644
index 0000000..b9df915
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectPreProcessing"
+#include <algorithm>
+#include <unordered_set>
+
+#include <Utils.h>
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+
+#include "EffectPreProcessing.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EffectPreProcessing;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAcousticEchoCancelerSwImplUUID;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlV1SwImplUUID;
+using aidl::android::hardware::audio::effect::kAutomaticGainControlV2SwImplUUID;
+using aidl::android::hardware::audio::effect::kNoiseSuppressionSwImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+bool isPreProcessingUuidSupported(const AudioUuid& uuid) {
+ return (uuid == kAcousticEchoCancelerSwImplUUID || uuid == kAutomaticGainControlV1SwImplUUID ||
+ uuid == kAutomaticGainControlV2SwImplUUID || uuid == kNoiseSuppressionSwImplUUID);
+}
+
+extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!uuid || !isPreProcessingUuidSupported(*uuid)) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<EffectPreProcessing>(*uuid);
+ 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 || !isPreProcessingUuidSupported(*in_impl_uuid)) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (*in_impl_uuid == kAcousticEchoCancelerSwImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::kAcousticEchoCancelerDesc;
+ } else if (*in_impl_uuid == kAutomaticGainControlV1SwImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV1Desc;
+ } else if (*in_impl_uuid == kAutomaticGainControlV2SwImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::kAutomaticGainControlV2Desc;
+ } else if (*in_impl_uuid == kNoiseSuppressionSwImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::kNoiseSuppressionDesc;
+ }
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectPreProcessing::EffectPreProcessing(const AudioUuid& uuid) {
+ LOG(DEBUG) << __func__ << uuid.toString();
+ if (uuid == kAcousticEchoCancelerSwImplUUID) {
+ mType = PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION;
+ mDescriptor = &kAcousticEchoCancelerDesc;
+ mEffectName = &kAcousticEchoCancelerEffectName;
+ } else if (uuid == kAutomaticGainControlV1SwImplUUID) {
+ mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1;
+ mDescriptor = &kAutomaticGainControlV1Desc;
+ mEffectName = &kAutomaticGainControlV1EffectName;
+ } else if (uuid == kAutomaticGainControlV2SwImplUUID) {
+ mType = PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2;
+ mDescriptor = &kAutomaticGainControlV2Desc;
+ mEffectName = &kAutomaticGainControlV2EffectName;
+ } else if (uuid == kNoiseSuppressionSwImplUUID) {
+ mType = PreProcessingEffectType::NOISE_SUPPRESSION;
+ mDescriptor = &kNoiseSuppressionDesc;
+ mEffectName = &kNoiseSuppressionEffectName;
+ } else {
+ LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
+ }
+}
+
+EffectPreProcessing::~EffectPreProcessing() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << _aidl_return->toString();
+ *_aidl_return = *mDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterSpecific(const Parameter::Specific& specific) {
+ LOG(DEBUG) << __func__ << " specific " << specific.toString();
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto tag = specific.getTag();
+ switch (tag) {
+ case Parameter::Specific::acousticEchoCanceler:
+ return setParameterAcousticEchoCanceler(specific);
+ case Parameter::Specific::automaticGainControlV1:
+ return setParameterAutomaticGainControlV1(specific);
+ case Parameter::Specific::automaticGainControlV2:
+ return setParameterAutomaticGainControlV2(specific);
+ case Parameter::Specific::noiseSuppression:
+ return setParameterNoiseSuppression(specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "specificParamNotSupported");
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAcousticEchoCanceler(
+ const Parameter::Specific& specific) {
+ auto& param = specific.get<Parameter::Specific::acousticEchoCanceler>();
+ RETURN_IF(!inRange(param, kAcousticEchoCancelerRanges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+ auto tag = param.getTag();
+
+ switch (tag) {
+ case AcousticEchoCanceler::echoDelayUs: {
+ RETURN_IF(mContext->setAcousticEchoCancelerEchoDelay(
+ param.get<AcousticEchoCanceler::echoDelayUs>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "echoDelayNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case AcousticEchoCanceler::mobileMode: {
+ RETURN_IF(mContext->setAcousticEchoCancelerMobileMode(
+ param.get<AcousticEchoCanceler::mobileMode>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "SettingMobileModeNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "AcousticEchoCancelerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV1(
+ const Parameter::Specific& specific) {
+ auto& param = specific.get<Parameter::Specific::automaticGainControlV1>();
+ RETURN_IF(!inRange(param, kAutomaticGainControlV1Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+ auto tag = param.getTag();
+
+ switch (tag) {
+ case AutomaticGainControlV1::targetPeakLevelDbFs: {
+ RETURN_IF(mContext->setAutomaticGainControlV1TargetPeakLevel(
+ param.get<AutomaticGainControlV1::targetPeakLevelDbFs>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "targetPeakLevelNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case AutomaticGainControlV1::maxCompressionGainDb: {
+ RETURN_IF(mContext->setAutomaticGainControlV1MaxCompressionGain(
+ param.get<AutomaticGainControlV1::maxCompressionGainDb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "maxCompressionGainNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case AutomaticGainControlV1::enableLimiter: {
+ RETURN_IF(
+ mContext->setAutomaticGainControlV1EnableLimiter(
+ param.get<AutomaticGainControlV1::enableLimiter>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "enableLimiterNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterAutomaticGainControlV2(
+ const Parameter::Specific& specific) {
+ auto& param = specific.get<Parameter::Specific::automaticGainControlV2>();
+ RETURN_IF(!inRange(param, kAutomaticGainControlV2Ranges), EX_ILLEGAL_ARGUMENT, "outOfRange");
+ auto tag = param.getTag();
+
+ switch (tag) {
+ case AutomaticGainControlV2::fixedDigitalGainMb: {
+ RETURN_IF(mContext->setAutomaticGainControlV2DigitalGain(
+ param.get<AutomaticGainControlV2::fixedDigitalGainMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "digitalGainNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case AutomaticGainControlV2::levelEstimator: {
+ RETURN_IF(mContext->setAutomaticGainControlV2LevelEstimator(
+ param.get<AutomaticGainControlV2::levelEstimator>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "levelEstimatorNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ case AutomaticGainControlV2::saturationMarginMb: {
+ RETURN_IF(mContext->setAutomaticGainControlV2SaturationMargin(
+ param.get<AutomaticGainControlV2::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, "AutomaticGainControlV2TagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::setParameterNoiseSuppression(
+ const Parameter::Specific& specific) {
+ auto& param = specific.get<Parameter::Specific::noiseSuppression>();
+ auto tag = param.getTag();
+
+ switch (tag) {
+ case NoiseSuppression::level: {
+ RETURN_IF(mContext->setNoiseSuppressionLevel(param.get<NoiseSuppression::level>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "levelNotSupported");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "NoiseSuppressionTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+
+ switch (tag) {
+ case Parameter::Id::acousticEchoCancelerTag:
+ return getParameterAcousticEchoCanceler(
+ id.get<Parameter::Id::acousticEchoCancelerTag>(), specific);
+ case Parameter::Id::automaticGainControlV1Tag:
+ return getParameterAutomaticGainControlV1(
+ id.get<Parameter::Id::automaticGainControlV1Tag>(), specific);
+ case Parameter::Id::automaticGainControlV2Tag:
+ return getParameterAutomaticGainControlV2(
+ id.get<Parameter::Id::automaticGainControlV2Tag>(), specific);
+ case Parameter::Id::noiseSuppressionTag:
+ return getParameterNoiseSuppression(id.get<Parameter::Id::noiseSuppressionTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "wrongIdTag");
+ }
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAcousticEchoCanceler(
+ const AcousticEchoCanceler::Id& id, Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != AcousticEchoCanceler::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "AcousticEchoCancelerTagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ AcousticEchoCanceler param;
+ auto tag = id.get<AcousticEchoCanceler::Id::commonTag>();
+ switch (tag) {
+ case AcousticEchoCanceler::echoDelayUs: {
+ param.set<AcousticEchoCanceler::echoDelayUs>(
+ mContext->getAcousticEchoCancelerEchoDelay());
+ break;
+ }
+ case AcousticEchoCanceler::mobileMode: {
+ param.set<AcousticEchoCanceler::mobileMode>(
+ mContext->getAcousticEchoCancelerMobileMode());
+ 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();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV1(
+ const AutomaticGainControlV1::Id& id, Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != AutomaticGainControlV1::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "AutomaticGainControlV1TagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ AutomaticGainControlV1 param;
+
+ auto tag = id.get<AutomaticGainControlV1::Id::commonTag>();
+ switch (tag) {
+ case AutomaticGainControlV1::targetPeakLevelDbFs: {
+ param.set<AutomaticGainControlV1::targetPeakLevelDbFs>(
+ mContext->getAutomaticGainControlV1TargetPeakLevel());
+ break;
+ }
+ case AutomaticGainControlV1::maxCompressionGainDb: {
+ param.set<AutomaticGainControlV1::maxCompressionGainDb>(
+ mContext->getAutomaticGainControlV1MaxCompressionGain());
+ break;
+ }
+ case AutomaticGainControlV1::enableLimiter: {
+ param.set<AutomaticGainControlV1::enableLimiter>(
+ mContext->getAutomaticGainControlV1EnableLimiter());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV1TagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::automaticGainControlV1>(param);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterAutomaticGainControlV2(
+ const AutomaticGainControlV2::Id& id, Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != AutomaticGainControlV2::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "AutomaticGainControlV2TagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ AutomaticGainControlV2 param;
+
+ auto tag = id.get<AutomaticGainControlV2::Id::commonTag>();
+ switch (tag) {
+ case AutomaticGainControlV2::fixedDigitalGainMb: {
+ param.set<AutomaticGainControlV2::fixedDigitalGainMb>(
+ mContext->getAutomaticGainControlV2DigitalGain());
+ break;
+ }
+ case AutomaticGainControlV2::levelEstimator: {
+ param.set<AutomaticGainControlV2::levelEstimator>(
+ mContext->getAutomaticGainControlV2LevelEstimator());
+ break;
+ }
+ case AutomaticGainControlV2::saturationMarginMb: {
+ param.set<AutomaticGainControlV2::saturationMarginMb>(
+ mContext->getAutomaticGainControlV2SaturationMargin());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "AutomaticGainControlV2TagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::automaticGainControlV2>(param);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectPreProcessing::getParameterNoiseSuppression(
+ const NoiseSuppression::Id& id, Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != NoiseSuppression::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "NoiseSuppressionTagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ NoiseSuppression param;
+
+ auto tag = id.get<NoiseSuppression::Id::commonTag>();
+ switch (tag) {
+ case NoiseSuppression::level: {
+ param.set<NoiseSuppression::level>(mContext->getNoiseSuppressionLevel());
+ 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> EffectPreProcessing::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ } else {
+ // PreProcessingSession is a singleton
+ mContext = PreProcessingSession::getPreProcessingSession().createSession(
+ mType, 1 /* statusFmqDepth */, common);
+ }
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
+ return mContext;
+}
+
+RetCode EffectPreProcessing::releaseContext() {
+ if (mContext) {
+ PreProcessingSession::getPreProcessingSession().releaseSession(mType,
+ mContext->getSessionId());
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+ndk::ScopedAStatus EffectPreProcessing::commandImpl(CommandId command) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ switch (command) {
+ case CommandId::START:
+ mContext->enable();
+ break;
+ case CommandId::STOP:
+ mContext->disable();
+ break;
+ case CommandId::RESET:
+ mContext->disable();
+ mContext->resetBuffer();
+ break;
+ default:
+ LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commandIdNotSupported");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status EffectPreProcessing::effectProcessImpl(float* in, float* out, int sampleToProcess) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ return mContext->lvmProcess(in, out, sampleToProcess);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
new file mode 100644
index 0000000..fad848a
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include "PreProcessingContext.h"
+#include "PreProcessingSession.h"
+#include "effect-impl/EffectImpl.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectPreProcessing final : public EffectImpl {
+ public:
+ explicit EffectPreProcessing(const AudioUuid& uuid);
+ ~EffectPreProcessing() override;
+
+ 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;
+
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+
+ ndk::ScopedAStatus commandImpl(CommandId command) override;
+
+ std::string getEffectName() override { return *mEffectName; }
+
+ private:
+ std::shared_ptr<PreProcessingContext> mContext;
+ const Descriptor* mDescriptor;
+ const std::string* mEffectName;
+ PreProcessingEffectType mType;
+
+ ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id& id,
+ Parameter::Specific* specific);
+
+ ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id& id,
+ Parameter::Specific* specific);
+
+ ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id& id,
+ Parameter::Specific* specific);
+
+ ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Id& id,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
new file mode 100644
index 0000000..104277e
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cstddef>
+#define LOG_TAG "PreProcessingContext"
+#include <Utils.h>
+
+#include "PreProcessingContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+
+RetCode PreProcessingContext::init(const Parameter::Common& common) {
+ std::lock_guard lg(mMutex);
+ webrtc::AudioProcessingBuilder apBuilder;
+ mAudioProcessingModule = apBuilder.Create();
+ if (mAudioProcessingModule == nullptr) {
+ LOG(ERROR) << "init could not get apm engine";
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+
+ updateConfigs(common);
+
+ mEnabledMsk = 0;
+ mProcessedMsk = 0;
+ mRevEnabledMsk = 0;
+ mRevProcessedMsk = 0;
+
+ auto config = mAudioProcessingModule->GetConfig();
+ switch (mType) {
+ case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+ config.echo_canceller.mobile_mode = true;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+ config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
+ config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
+ config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+ config.gain_controller2.fixed_digital.gain_db = 0.f;
+ break;
+ case PreProcessingEffectType::NOISE_SUPPRESSION:
+ config.noise_suppression.level = kNsDefaultLevel;
+ break;
+ }
+ mAudioProcessingModule->ApplyConfig(config);
+ mState = PRE_PROC_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::deInit() {
+ std::lock_guard lg(mMutex);
+ mAudioProcessingModule = nullptr;
+ mState = PRE_PROC_STATE_UNINITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::enable() {
+ if (mState != PRE_PROC_STATE_INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ int typeMsk = (1 << int(mType));
+ std::lock_guard lg(mMutex);
+ // Check if effect is already enabled.
+ if ((mEnabledMsk & typeMsk) == typeMsk) {
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mEnabledMsk |= typeMsk;
+ auto config = mAudioProcessingModule->GetConfig();
+ switch (mType) {
+ case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+ config.echo_canceller.enabled = true;
+ // AEC has reverse stream
+ mRevEnabledMsk |= typeMsk;
+ mRevProcessedMsk = 0;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+ config.gain_controller1.enabled = true;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+ config.gain_controller2.enabled = true;
+ break;
+ case PreProcessingEffectType::NOISE_SUPPRESSION:
+ config.noise_suppression.enabled = true;
+ break;
+ }
+ mProcessedMsk = 0;
+ mAudioProcessingModule->ApplyConfig(config);
+ mState = PRE_PROC_STATE_ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::disable() {
+ if (mState != PRE_PROC_STATE_ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ int typeMsk = (1 << int(mType));
+ std::lock_guard lg(mMutex);
+ // Check if effect is already disabled.
+ if ((mEnabledMsk & typeMsk) != typeMsk) {
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mEnabledMsk &= ~typeMsk;
+ auto config = mAudioProcessingModule->GetConfig();
+ switch (mType) {
+ case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+ config.echo_canceller.enabled = false;
+ // AEC has reverse stream
+ mRevEnabledMsk &= ~typeMsk;
+ mRevProcessedMsk = 0;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+ config.gain_controller1.enabled = false;
+ break;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+ config.gain_controller2.enabled = false;
+ break;
+ case PreProcessingEffectType::NOISE_SUPPRESSION:
+ config.noise_suppression.enabled = false;
+ break;
+ }
+ mProcessedMsk = 0;
+ mAudioProcessingModule->ApplyConfig(config);
+ mState = PRE_PROC_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ updateConfigs(common);
+ return RetCode::SUCCESS;
+}
+
+void PreProcessingContext::updateConfigs(const Parameter::Common& common) {
+ mInputConfig.set_sample_rate_hz(common.input.base.sampleRate);
+ mInputConfig.set_num_channels(
+ ::android::hardware::audio::common::getChannelCount(common.input.base.channelMask));
+ mOutputConfig.set_sample_rate_hz(common.input.base.sampleRate);
+ mOutputConfig.set_num_channels(
+ ::android::hardware::audio::common::getChannelCount(common.output.base.channelMask));
+}
+
+RetCode PreProcessingContext::setAcousticEchoCancelerEchoDelay(int echoDelayUs) {
+ mEchoDelayUs = echoDelayUs;
+ std::lock_guard lg(mMutex);
+ mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
+ return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAcousticEchoCancelerEchoDelay() const {
+ return mEchoDelayUs;
+}
+
+RetCode PreProcessingContext::setAcousticEchoCancelerMobileMode(bool mobileMode) {
+ mMobileMode = mobileMode;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.echo_canceller.mobile_mode = mobileMode;
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+bool PreProcessingContext::getAcousticEchoCancelerMobileMode() const {
+ return mMobileMode;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1TargetPeakLevel(int targetPeakLevel) {
+ mTargetPeakLevel = targetPeakLevel;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.gain_controller1.target_level_dbfs = -(mTargetPeakLevel / 100);
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV1TargetPeakLevel() const {
+ return mTargetPeakLevel;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1MaxCompressionGain(int maxCompressionGain) {
+ mMaxCompressionGain = maxCompressionGain;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.gain_controller1.compression_gain_db = mMaxCompressionGain / 100;
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV1MaxCompressionGain() const {
+ return mMaxCompressionGain;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV1EnableLimiter(bool enableLimiter) {
+ mEnableLimiter = enableLimiter;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.gain_controller1.enable_limiter = mEnableLimiter;
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+bool PreProcessingContext::getAutomaticGainControlV1EnableLimiter() const {
+ return mEnableLimiter;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2DigitalGain(int gain) {
+ mDigitalGain = gain;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.gain_controller2.fixed_digital.gain_db = mDigitalGain;
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV2DigitalGain() const {
+ return mDigitalGain;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2LevelEstimator(
+ AutomaticGainControlV2::LevelEstimator levelEstimator) {
+ mLevelEstimator = levelEstimator;
+ return RetCode::SUCCESS;
+}
+
+AutomaticGainControlV2::LevelEstimator
+PreProcessingContext::getAutomaticGainControlV2LevelEstimator() const {
+ return mLevelEstimator;
+}
+
+RetCode PreProcessingContext::setAutomaticGainControlV2SaturationMargin(int saturationMargin) {
+ mSaturationMargin = saturationMargin;
+ return RetCode::SUCCESS;
+}
+
+int PreProcessingContext::getAutomaticGainControlV2SaturationMargin() const {
+ return mSaturationMargin;
+}
+
+RetCode PreProcessingContext::setNoiseSuppressionLevel(NoiseSuppression::Level level) {
+ mLevel = level;
+ std::lock_guard lg(mMutex);
+ auto config = mAudioProcessingModule->GetConfig();
+ config.noise_suppression.level =
+ (webrtc::AudioProcessing::Config::NoiseSuppression::Level)level;
+ mAudioProcessingModule->ApplyConfig(config);
+ return RetCode::SUCCESS;
+}
+
+NoiseSuppression::Level PreProcessingContext::getNoiseSuppressionLevel() const {
+ return mLevel;
+}
+
+IEffect::Status PreProcessingContext::lvmProcess(float* in, float* out, int samples) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!in, status, "nullInput");
+ RETURN_VALUE_IF(!out, status, "nullOutput");
+ status = {EX_ILLEGAL_STATE, 0, 0};
+ int64_t inputFrameCount = getCommon().input.frameCount;
+ int64_t outputFrameCount = getCommon().output.frameCount;
+ RETURN_VALUE_IF(inputFrameCount != outputFrameCount, status, "FrameCountMismatch");
+ RETURN_VALUE_IF(0 == getInputFrameSize(), status, "zeroFrameSize");
+
+ LOG(DEBUG) << __func__ << " start processing";
+ std::lock_guard lg(mMutex);
+
+ mProcessedMsk |= (1 << int(mType));
+
+ // webrtc implementation clear out was_stream_delay_set every time after ProcessStream() call
+ mAudioProcessingModule->set_stream_delay_ms(mEchoDelayUs / 1000);
+
+ if ((mProcessedMsk & mEnabledMsk) == mEnabledMsk) {
+ mProcessedMsk = 0;
+ int processStatus = mAudioProcessingModule->ProcessStream(
+ (const int16_t* const)in, mInputConfig, mOutputConfig, (int16_t* const)out);
+ if (processStatus != 0) {
+ LOG(ERROR) << "Process stream failed with error " << processStatus;
+ return status;
+ }
+ }
+
+ mRevProcessedMsk |= (1 << int(mType));
+
+ if ((mRevProcessedMsk & mRevEnabledMsk) == mRevEnabledMsk) {
+ mRevProcessedMsk = 0;
+ int revProcessStatus = mAudioProcessingModule->ProcessReverseStream(
+ (const int16_t* const)in, mInputConfig, mInputConfig, (int16_t* const)out);
+ if (revProcessStatus != 0) {
+ LOG(ERROR) << "Process reverse stream failed with error " << revProcessStatus;
+ return status;
+ }
+ }
+
+ return {STATUS_OK, samples, samples};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.h b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
new file mode 100644
index 0000000..9ba1bbe
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+#include <audio_processing.h>
+#include <unordered_map>
+
+#include "PreProcessingTypes.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum PreProcEffectState {
+ PRE_PROC_STATE_UNINITIALIZED,
+ PRE_PROC_STATE_INITIALIZED,
+ PRE_PROC_STATE_ACTIVE,
+};
+
+class PreProcessingContext final : public EffectContext {
+ public:
+ PreProcessingContext(int statusDepth, const Parameter::Common& common,
+ const PreProcessingEffectType& type)
+ : EffectContext(statusDepth, common), mType(type) {
+ LOG(DEBUG) << __func__ << type;
+ mState = PRE_PROC_STATE_UNINITIALIZED;
+ }
+ ~PreProcessingContext() override { LOG(DEBUG) << __func__; }
+
+ RetCode init(const Parameter::Common& common);
+ RetCode deInit();
+
+ PreProcessingEffectType getPreProcessingType() const { return mType; }
+
+ RetCode enable();
+ RetCode disable();
+
+ RetCode setCommon(const Parameter::Common& common) override;
+ void updateConfigs(const Parameter::Common& common);
+
+ RetCode setAcousticEchoCancelerEchoDelay(int echoDelayUs);
+ int getAcousticEchoCancelerEchoDelay() const;
+ RetCode setAcousticEchoCancelerMobileMode(bool mobileMode);
+ bool getAcousticEchoCancelerMobileMode() const;
+
+ RetCode setAutomaticGainControlV1TargetPeakLevel(int targetPeakLevel);
+ int getAutomaticGainControlV1TargetPeakLevel() const;
+ RetCode setAutomaticGainControlV1MaxCompressionGain(int maxCompressionGain);
+ int getAutomaticGainControlV1MaxCompressionGain() const;
+ RetCode setAutomaticGainControlV1EnableLimiter(bool enableLimiter);
+ bool getAutomaticGainControlV1EnableLimiter() const;
+
+ RetCode setAutomaticGainControlV2DigitalGain(int gain);
+ int getAutomaticGainControlV2DigitalGain() const;
+ RetCode setAutomaticGainControlV2LevelEstimator(
+ AutomaticGainControlV2::LevelEstimator levelEstimator);
+ AutomaticGainControlV2::LevelEstimator getAutomaticGainControlV2LevelEstimator() const;
+ RetCode setAutomaticGainControlV2SaturationMargin(int saturationMargin);
+ int getAutomaticGainControlV2SaturationMargin() const;
+
+ RetCode setNoiseSuppressionLevel(NoiseSuppression::Level level);
+ NoiseSuppression::Level getNoiseSuppressionLevel() const;
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ static constexpr inline int kAgcDefaultTargetLevel = 3;
+ static constexpr inline int kAgcDefaultCompGain = 9;
+ static constexpr inline bool kAgcDefaultLimiter = true;
+ static constexpr inline webrtc::AudioProcessing::Config::NoiseSuppression::Level
+ kNsDefaultLevel = webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
+
+ std::mutex mMutex;
+ const PreProcessingEffectType mType;
+ PreProcEffectState mState; // current state
+
+ // handle on webRTC audio processing module (APM)
+ rtc::scoped_refptr<webrtc::AudioProcessing> mAudioProcessingModule GUARDED_BY(mMutex);
+
+ int mEnabledMsk GUARDED_BY(mMutex); // bit field containing IDs of enabled pre processors
+ int mProcessedMsk GUARDED_BY(mMutex); // bit field containing IDs of pre processors already
+ // processed in current round
+ int mRevEnabledMsk GUARDED_BY(mMutex); // bit field containing IDs of enabled pre processors
+ // with reverse channel
+ int mRevProcessedMsk GUARDED_BY(mMutex); // bit field containing IDs of pre processors with
+ // reverse channel already processed in current round
+
+ webrtc::StreamConfig mInputConfig; // input stream configuration
+ webrtc::StreamConfig mOutputConfig; // output stream configuration
+
+ // Acoustic Echo Canceler
+ int mEchoDelayUs = 0;
+ bool mMobileMode = false;
+
+ // Automatic Gain Control V1
+ int mTargetPeakLevel = 0;
+ int mMaxCompressionGain = 0;
+ bool mEnableLimiter = false;
+
+ // Automatic Gain Control V2
+ int mDigitalGain = 0;
+ AutomaticGainControlV2::LevelEstimator mLevelEstimator =
+ AutomaticGainControlV2::LevelEstimator::RMS;
+ int mSaturationMargin = 2;
+
+ // NoiseSuppression
+ NoiseSuppression::Level mLevel = NoiseSuppression::Level::LOW;
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingSession.h b/media/libeffects/preprocessing/aidl/PreProcessingSession.h
new file mode 100644
index 0000000..877292f
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingSession.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <memory>
+#include <unordered_map>
+
+#include <android-base/logging.h>
+#include <android-base/thread_annotations.h>
+
+#include "PreProcessingContext.h"
+#include "PreProcessingTypes.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+/**
+ * @brief Maintain all effect pre-processing sessions.
+ *
+ * Sessions are identified with the session ID, maximum of MAX_BUNDLE_SESSIONS is supported by the
+ * pre-processing implementation.
+ */
+class PreProcessingSession {
+ public:
+ static PreProcessingSession& getPreProcessingSession() {
+ static PreProcessingSession instance;
+ return instance;
+ }
+
+ static bool findPreProcessingTypeInList(
+ std::vector<std::shared_ptr<PreProcessingContext>>& list,
+ const PreProcessingEffectType& type, bool remove = false) {
+ auto itor = std::find_if(list.begin(), list.end(),
+ [type](const std::shared_ptr<PreProcessingContext>& bundle) {
+ return bundle->getPreProcessingType() == type;
+ });
+ if (itor == list.end()) {
+ return false;
+ }
+ if (remove) {
+ (*itor)->deInit();
+ list.erase(itor);
+ }
+ return true;
+ }
+
+ /**
+ * Create a certain type of PreProcessingContext in shared_ptr container, each session must not
+ * have more than one session for each type.
+ */
+ std::shared_ptr<PreProcessingContext> createSession(const PreProcessingEffectType& type,
+ int statusDepth,
+ const Parameter::Common& common) {
+ int sessionId = common.session;
+ LOG(DEBUG) << __func__ << type << " with sessionId " << sessionId;
+ std::lock_guard lg(mMutex);
+ if (mSessionMap.count(sessionId) == 0 && mSessionMap.size() >= MAX_PRE_PROC_SESSIONS) {
+ LOG(ERROR) << __func__ << " exceed max bundle session";
+ return nullptr;
+ }
+
+ if (mSessionMap.count(sessionId)) {
+ if (findPreProcessingTypeInList(mSessionMap[sessionId], type)) {
+ LOG(ERROR) << __func__ << type << " already exist in session " << sessionId;
+ return nullptr;
+ }
+ }
+
+ auto& list = mSessionMap[sessionId];
+ auto context = std::make_shared<PreProcessingContext>(statusDepth, common, type);
+ RETURN_VALUE_IF(!context, nullptr, "failedToCreateContext");
+
+ RetCode ret = context->init(common);
+ if (RetCode::SUCCESS != ret) {
+ LOG(ERROR) << __func__ << " context init ret " << ret;
+ return nullptr;
+ }
+ list.push_back(context);
+ return context;
+ }
+
+ void releaseSession(const PreProcessingEffectType& type, int sessionId) {
+ LOG(DEBUG) << __func__ << type << " sessionId " << sessionId;
+ std::lock_guard lg(mMutex);
+ if (mSessionMap.count(sessionId)) {
+ auto& list = mSessionMap[sessionId];
+ if (!findPreProcessingTypeInList(list, type, true /* remove */)) {
+ LOG(ERROR) << __func__ << " can't find " << type << "in session " << sessionId;
+ return;
+ }
+ if (list.empty()) {
+ mSessionMap.erase(sessionId);
+ }
+ }
+ }
+
+ private:
+ // Lock for mSessionMap access.
+ std::mutex mMutex;
+ // Max session number supported.
+ static constexpr int MAX_PRE_PROC_SESSIONS = 8;
+ std::unordered_map<int /* session ID */, std::vector<std::shared_ptr<PreProcessingContext>>>
+ mSessionMap GUARDED_BY(mMutex);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingTypes.h b/media/libeffects/preprocessing/aidl/PreProcessingTypes.h
new file mode 100644
index 0000000..2c880d4
--- /dev/null
+++ b/media/libeffects/preprocessing/aidl/PreProcessingTypes.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+
+#include <audio_effects/effect_aec.h>
+#include <audio_effects/effect_agc.h>
+#include <audio_effects/effect_agc2.h>
+#include <audio_effects/effect_ns.h>
+
+#include "effect-impl/EffectTypes.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+// Acoustic Echo Cancellation
+static const std::string kAcousticEchoCancelerEffectName = "Acoustic Echo Canceler";
+static const std::vector<Range::AcousticEchoCancelerRange> kAcousticEchoCancelerRanges = {
+ MAKE_RANGE(AcousticEchoCanceler, AcousticEchoCanceler::echoDelayUs, 0, 500)};
+static const Capability kAcousticEchoCancelerCap = {.range = kAcousticEchoCancelerRanges};
+static const Descriptor kAcousticEchoCancelerDesc = {
+ .common = {.id = {.type = kAcousticEchoCancelerTypeUUID,
+ .uuid = kAcousticEchoCancelerSwImplUUID,
+ .proxy = kEffectNullUuid},
+ .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+ .name = kAcousticEchoCancelerEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = kAcousticEchoCancelerCap};
+
+// Automatic Gain Control 1
+static const std::string kAutomaticGainControlV1EffectName = "Automatic Gain Control V1";
+static const std::vector<Range::AutomaticGainControlV1Range> kAutomaticGainControlV1Ranges = {
+ MAKE_RANGE(AutomaticGainControlV1, AutomaticGainControlV1::targetPeakLevelDbFs, -3100, 0),
+ MAKE_RANGE(AutomaticGainControlV1, AutomaticGainControlV1::maxCompressionGainDb, 0, 9000)};
+static const Capability kAutomaticGainControlV1Cap = {.range = kAutomaticGainControlV1Ranges};
+static const Descriptor kAutomaticGainControlV1Desc = {
+ .common = {.id = {.type = kAutomaticGainControlV1TypeUUID,
+ .uuid = kAutomaticGainControlV1SwImplUUID,
+ .proxy = kEffectNullUuid},
+ .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+ .name = kAutomaticGainControlV1EffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = kAutomaticGainControlV1Cap};
+
+// Automatic Gain Control 2
+static const std::string kAutomaticGainControlV2EffectName = "Automatic Gain Control V2";
+const std::vector<Range::AutomaticGainControlV2Range> kAutomaticGainControlV2Ranges = {
+ MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::fixedDigitalGainMb, 0, 90),
+ // extra_staturation_margin_db is no longer configurable in webrtc
+ MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::saturationMarginMb, 2, 2),
+ // WebRTC only supports RMS level estimator now
+ MAKE_RANGE(AutomaticGainControlV2, AutomaticGainControlV2::levelEstimator,
+ AutomaticGainControlV2::LevelEstimator::RMS,
+ AutomaticGainControlV2::LevelEstimator::RMS)};
+static const Capability kAutomaticGainControlV2Cap = {.range = kAutomaticGainControlV2Ranges};
+static const Descriptor kAutomaticGainControlV2Desc = {
+ .common = {.id = {.type = kAutomaticGainControlV2TypeUUID,
+ .uuid = kAutomaticGainControlV2SwImplUUID,
+ .proxy = kEffectNullUuid},
+ .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+ .name = kAutomaticGainControlV2EffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = kAutomaticGainControlV2Cap};
+
+// Noise suppression
+static const std::string kNoiseSuppressionEffectName = "Noise Suppression";
+static const Descriptor kNoiseSuppressionDesc = {
+ .common = {.id = {.type = kNoiseSuppressionTypeUUID,
+ .uuid = kNoiseSuppressionSwImplUUID,
+ .proxy = kEffectNullUuid},
+ .flags = {.type = Flags::Type::PRE_PROC, .deviceIndication = true},
+ .name = kNoiseSuppressionEffectName,
+ .implementor = "The Android Open Source Project"}};
+
+enum class PreProcessingEffectType {
+ ACOUSTIC_ECHO_CANCELLATION,
+ AUTOMATIC_GAIN_CONTROL_V1,
+ AUTOMATIC_GAIN_CONTROL_V2,
+ NOISE_SUPPRESSION,
+};
+
+inline std::ostream& operator<<(std::ostream& out, const PreProcessingEffectType& type) {
+ switch (type) {
+ case PreProcessingEffectType::ACOUSTIC_ECHO_CANCELLATION:
+ return out << kAcousticEchoCancelerEffectName;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V1:
+ return out << kAutomaticGainControlV1EffectName;
+ case PreProcessingEffectType::AUTOMATIC_GAIN_CONTROL_V2:
+ return out << kAutomaticGainControlV2EffectName;
+ case PreProcessingEffectType::NOISE_SUPPRESSION:
+ return out << kNoiseSuppressionEffectName;
+ }
+ return out << "EnumPreProcessingEffectTypeError";
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/module/extractors/ogg/OggExtractor.cpp b/media/module/extractors/ogg/OggExtractor.cpp
index 23ad1b1..4c106b2 100644
--- a/media/module/extractors/ogg/OggExtractor.cpp
+++ b/media/module/extractors/ogg/OggExtractor.cpp
@@ -1048,16 +1048,21 @@
size_t numerator = mTableOfContents.size();
if (numerator > kMaxNumTOCEntries) {
- size_t denom = numerator - kMaxNumTOCEntries;
+ Vector<TOCEntry> maxTOC;
+ maxTOC.setCapacity(kMaxNumTOCEntries);
+ size_t denom = numerator - kMaxNumTOCEntries;
size_t accum = 0;
- for (ssize_t i = mTableOfContents.size(); i > 0; --i) {
+ for (ssize_t i = 0; i < mTableOfContents.size(); i++) {
accum += denom;
if (accum >= numerator) {
- mTableOfContents.removeAt(i);
accum -= numerator;
+ } else {
+ maxTOC.push(mTableOfContents.itemAt(i));
}
}
+
+ mTableOfContents = maxTOC;
}
}
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 5005365..0df7636 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -758,6 +758,9 @@
EXPORT
media_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
const char *propertyName, const uint8_t *value, size_t valueSize) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return AMEDIA_ERROR_INVALID_OBJECT;
+ }
Vector<uint8_t> byteArray;
byteArray.appendArray(value, valueSize);
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 0de7e7d..00b612f 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -2140,9 +2140,19 @@
if (!isStreamInitialized()) {
ALOGE("The stream is not open yet"); // This should not happen.
} else {
- // setEventCallback will need a strong pointer as a parameter. Calling it
- // here instead of constructor of PlaybackThread so that the onFirstRef
- // callback would not be made on an incompletely constructed object.
+ // Callbacks take strong or weak pointers as a parameter.
+ // Since PlaybackThread passes itself as a callback handler, it can only
+ // be done outside of the constructor. Creating weak and especially strong
+ // pointers to a refcounted object in its own constructor is strongly
+ // discouraged, see comments in system/core/libutils/include/utils/RefBase.h.
+ // Even if a function takes a weak pointer, it is possible that it will
+ // need to convert it to a strong pointer down the line.
+ if (mOutput->flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING &&
+ mOutput->stream->setCallback(this) == OK) {
+ mUseAsyncWrite = true;
+ mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
+ }
+
if (mOutput->stream->setEventCallback(this) != OK) {
ALOGD("Failed to add event callback");
}
@@ -3007,13 +3017,6 @@
mFrameCount);
}
- if (mOutput->flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING) {
- if (mOutput->stream->setCallback(this) == OK) {
- mUseAsyncWrite = true;
- mCallbackThread = new AudioFlinger::AsyncCallbackThread(this);
- }
- }
-
mHwSupportsPause = false;
if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) {
bool supportsPause = false, supportsResume = false;
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 863fdbe..9f08eca 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -248,10 +248,10 @@
if (!item->getInt32("frontend", &frontend)) return false;
// Optional to be included
- int64_t apex_version = -1;
- item->getInt64("apex_version", &apex_version);
+ std::string version = "";
+ item->getString("version", &version);
const int result = stats_write(stats::media_metrics::MEDIA_DRM_CREATED,
- scheme, uuid_lsb, uuid_msb, uid, frontend, apex_version);
+ scheme, uuid_lsb, uuid_msb, uid, frontend, version.c_str());
std::stringstream log;
log << "result:" << result << " {"
@@ -262,7 +262,7 @@
<< " uuid_msb:" << uuid_msb
<< " uid:" << uid
<< " frontend:" << frontend
- << " apex_version:" << apex_version
+ << " version:" << version
<< " }";
statsdLog->log(stats::media_metrics::MEDIA_DRM_CREATED, log.str());
return true;
@@ -287,10 +287,10 @@
if (!item->getInt32("opened_security_level", &opened_security_level)) return false;
// Optional to be included
- int64_t apex_version = -1;
- item->getInt64("apex_version", &apex_version);
+ std::string version = "";
+ item->getString("version", &version);
const int result = stats_write(stats::media_metrics::MEDIA_DRM_SESSION_OPENED,
- scheme, uuid_lsb, uuid_msb, uid, frontend, apex_version,
+ scheme, uuid_lsb, uuid_msb, uid, frontend, version.c_str(),
object_nonce.c_str(), requested_security_level,
opened_security_level);
@@ -303,7 +303,7 @@
<< " uuid_msb:" << uuid_msb
<< " uid:" << uid
<< " frontend:" << frontend
- << " apex_version:" << apex_version
+ << " version:" << version
<< " object_nonce:" << object_nonce
<< " requested_security_level:" << requested_security_level
<< " opened_security_level:" << opened_security_level
@@ -334,8 +334,8 @@
if (!item->getInt32("error_code", &error_code)) return false;
// Optional to be included
- int64_t apex_version = -1;
- item->getInt64("apex_version", &apex_version);
+ std::string version = "";
+ item->getString("version", &version);
std::string session_nonce = "";
item->getString("session_nonce", &session_nonce);
@@ -347,7 +347,7 @@
item->getInt32("error_context", &error_context);
const int result = stats_write(stats::media_metrics::MEDIA_DRM_ERRORED, scheme, uuid_lsb,
- uuid_msb, uid, frontend, apex_version, object_nonce.c_str(),
+ uuid_msb, uid, frontend, version.c_str(), object_nonce.c_str(),
session_nonce.c_str(), security_level, api, error_code, cdm_err,
oem_err, error_context);
@@ -360,7 +360,7 @@
<< " uuid_msb:" << uuid_msb
<< " uid:" << uid
<< " frontend:" << frontend
- << " apex_version:" << apex_version
+ << " version:" << version
<< " object_nonce:" << object_nonce
<< " session_nonce:" << session_nonce
<< " security_level:" << security_level