Merge "Enable decode looping for specified duration"
diff --git a/apex/ld.config.txt b/apex/ld.config.txt
index 713f0b7..4dc5fb1 100644
--- a/apex/ld.config.txt
+++ b/apex/ld.config.txt
@@ -33,7 +33,7 @@
# TODO: replace the following when apex has a way to auto-generate this list
# namespace.default.link.platform.shared_libs = %LLNDK_LIBRARIES%
# namespace.default.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so:libbinder_ndk.so
+namespace.default.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libdl_android.so:libvulkan.so:libbinder_ndk.so
###############################################################################
# "platform" namespace
@@ -138,7 +138,7 @@
# TODO: replace the following when apex has a way to auto-generate this list
# namespace.sphal.link.platform.shared_libs = %LLNDK_LIBRARIES%
# namespace.sphal.link.platform.shared_libs += %SANITIZER_RUNTIME_LIBRARIES%
-namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libRS.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so:libbinder_ndk.so
+namespace.sphal.link.platform.shared_libs = libEGL.so:libGLESv1_CM.so:libGLESv2.so:libGLESv3.so:libandroid_net.so:libc.so:libcgrouprc.so:libclang_rt.asan-aarch64-android.so:libclang_rt.asan-arm-android.so:libclang_rt.hwasan-aarch64-android.so:libclang_rt.asan-i686-android.so:libclang_rt.asan-x86_64-android.so:libdl.so:libft2.so:liblog.so:libm.so:libmediandk.so:libnativewindow.so:libneuralnetworks.so:libsync.so:libvndksupport.so:libvulkan.so:libbinder_ndk.so
# Add a link for libz.so which is llndk on devices where VNDK is not enforced.
namespace.sphal.link.platform.shared_libs += libz.so
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index d50566d..da4484a 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -97,6 +97,10 @@
return mMirrorMode;
}
+bool OutputConfiguration::useReadoutTimestamp() const {
+ return mUseReadoutTimestamp;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
mSurfaceSetID(INVALID_SET_ID),
@@ -110,7 +114,8 @@
mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
- mMirrorMode(MIRROR_MODE_AUTO) {
+ mMirrorMode(MIRROR_MODE_AUTO),
+ mUseReadoutTimestamp(false) {
}
OutputConfiguration::OutputConfiguration(const android::Parcel& parcel) :
@@ -220,6 +225,12 @@
return err;
}
+ int useReadoutTimestamp = 0;
+ if ((err = parcel->readInt32(&useReadoutTimestamp)) != OK) {
+ ALOGE("%s: Failed to read useReadoutTimestamp flag from parcel", __FUNCTION__);
+ return err;
+ }
+
mRotation = rotation;
mSurfaceSetID = setID;
mSurfaceType = surfaceType;
@@ -231,6 +242,7 @@
mStreamUseCase = streamUseCase;
mTimestampBase = timestampBase;
mMirrorMode = mirrorMode;
+ mUseReadoutTimestamp = useReadoutTimestamp != 0;
for (auto& surface : surfaceShims) {
ALOGV("%s: OutputConfiguration: %p, name %s", __FUNCTION__,
surface.graphicBufferProducer.get(),
@@ -244,10 +256,10 @@
ALOGV("%s: OutputConfiguration: rotation = %d, setId = %d, surfaceType = %d,"
" physicalCameraId = %s, isMultiResolution = %d, streamUseCase = %" PRId64
- ", timestampBase = %d, mirrorMode = %d",
+ ", timestampBase = %d, mirrorMode = %d, useReadoutTimestamp = %d",
__FUNCTION__, mRotation, mSurfaceSetID, mSurfaceType,
String8(mPhysicalCameraId).string(), mIsMultiResolution, mStreamUseCase, timestampBase,
- mMirrorMode);
+ mMirrorMode, mUseReadoutTimestamp);
return err;
}
@@ -267,6 +279,7 @@
mStreamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
mTimestampBase = TIMESTAMP_BASE_DEFAULT;
mMirrorMode = MIRROR_MODE_AUTO;
+ mUseReadoutTimestamp = false;
}
OutputConfiguration::OutputConfiguration(
@@ -280,7 +293,7 @@
mColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
mStreamUseCase(ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT),
mTimestampBase(TIMESTAMP_BASE_DEFAULT),
- mMirrorMode(MIRROR_MODE_AUTO) { }
+ mMirrorMode(MIRROR_MODE_AUTO), mUseReadoutTimestamp(false) { }
status_t OutputConfiguration::writeToParcel(android::Parcel* parcel) const {
@@ -342,6 +355,9 @@
err = parcel->writeInt32(mMirrorMode);
if (err != OK) return err;
+ err = parcel->writeInt32(mUseReadoutTimestamp ? 1 : 0);
+ if (err != OK) return err;
+
return OK;
}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 27ebb7a..8472562 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -37,6 +37,7 @@
"libui",
"libgui",
"libbinder",
+ "libbinder_ndk",
"libhidlbase",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
@@ -59,6 +60,6 @@
init_rc: ["cameraserver.rc"],
vintf_fragments: [
- "manifest_android.frameworks.cameraservice.service@2.2.xml",
+ "manifest_android.frameworks.cameraservice.service.xml",
],
}
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index 6a311f2..e307653 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -6,3 +6,4 @@
task_profiles CameraServiceCapacity MaxPerformance
rlimit rtprio 10 10
onrestart class_restart cameraWatchdog
+ interface aidl android.frameworks.cameraservice.service.ICameraService/default
diff --git a/camera/cameraserver/main_cameraserver.cpp b/camera/cameraserver/main_cameraserver.cpp
index cef8ef5..c494732 100644
--- a/camera/cameraserver/main_cameraserver.cpp
+++ b/camera/cameraserver/main_cameraserver.cpp
@@ -18,6 +18,7 @@
//#define LOG_NDEBUG 0
#include "CameraService.h"
+#include <android/binder_process.h>
#include <hidl/HidlTransportSupport.h>
using namespace android;
@@ -26,15 +27,21 @@
{
signal(SIGPIPE, SIG_IGN);
- // Set 5 threads for HIDL calls. Now cameraserver will serve HIDL calls in
- // addition to consuming them from the Camera HAL as well.
+ // Set 5 threads for HIDL calls. Now cameraserver will serve HIDL calls.
hardware::configureRpcThreadpool(5, /*willjoin*/ false);
+ // Set 5 threads for VNDK AIDL calls. Now cameraserver will serve
+ // VNDK AIDL calls in addition to consuming them from the Camera HAL as well.
+ ABinderProcess_setThreadPoolMaxThreadCount(5);
+
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
CameraService::instantiate();
ALOGI("ServiceManager: %p done instantiate", sm.get());
ProcessState::self()->startThreadPool();
+ ABinderProcess_startThreadPool();
+
IPCThreadState::self()->joinThreadPool();
+ ABinderProcess_joinThreadPool();
}
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
new file mode 100644
index 0000000..f7e455f
--- /dev/null
+++ b/camera/cameraserver/manifest_android.frameworks.cameraservice.service.xml
@@ -0,0 +1,20 @@
+<manifest version="1.0" type="framework">
+ <hal format="hidl" max-level="7">
+ <name>android.frameworks.cameraservice.service</name>
+ <transport>hwbinder</transport>
+ <version>2.2</version>
+ <interface>
+ <name>ICameraService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+
+ <hal format="aidl">
+ <name>android.frameworks.cameraservice.service</name>
+ <version>1</version>
+ <interface>
+ <name>ICameraService</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml b/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml
deleted file mode 100644
index eeafc91..0000000
--- a/camera/cameraserver/manifest_android.frameworks.cameraservice.service@2.2.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<manifest version="1.0" type="framework">
- <hal>
- <name>android.frameworks.cameraservice.service</name>
- <transport>hwbinder</transport>
- <version>2.2</version>
- <interface>
- <name>ICameraService</name>
- <instance>default</instance>
- </interface>
- </hal>
-</manifest>
diff --git a/camera/include/camera/camera2/OutputConfiguration.h b/camera/include/camera/camera2/OutputConfiguration.h
index a713b40..16fddb5 100644
--- a/camera/include/camera/camera2/OutputConfiguration.h
+++ b/camera/include/camera/camera2/OutputConfiguration.h
@@ -44,8 +44,7 @@
TIMESTAMP_BASE_MONOTONIC = 2,
TIMESTAMP_BASE_REALTIME = 3,
TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED = 4,
- TIMESTAMP_BASE_READOUT_SENSOR = 5,
- TIMESTAMP_BASE_MAX = TIMESTAMP_BASE_READOUT_SENSOR,
+ TIMESTAMP_BASE_MAX = TIMESTAMP_BASE_CHOREOGRAPHER_SYNCED,
};
enum MirrorModeType {
MIRROR_MODE_AUTO = 0,
@@ -69,6 +68,7 @@
int64_t getStreamUseCase() const;
int getTimestampBase() const;
int getMirrorMode() const;
+ bool useReadoutTimestamp() const;
// set of sensor pixel mode resolutions allowed {MAX_RESOLUTION, DEFAULT_MODE};
const std::vector<int32_t>& getSensorPixelModesUsed() const;
@@ -115,7 +115,8 @@
mColorSpace == other.mColorSpace &&
mStreamUseCase == other.mStreamUseCase &&
mTimestampBase == other.mTimestampBase &&
- mMirrorMode == other.mMirrorMode);
+ mMirrorMode == other.mMirrorMode &&
+ mUseReadoutTimestamp == other.mUseReadoutTimestamp);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -167,6 +168,9 @@
if (mMirrorMode != other.mMirrorMode) {
return mMirrorMode < other.mMirrorMode;
}
+ if (mUseReadoutTimestamp != other.mUseReadoutTimestamp) {
+ return mUseReadoutTimestamp < other.mUseReadoutTimestamp;
+ }
return gbpsLessThan(other);
}
@@ -196,6 +200,7 @@
int64_t mStreamUseCase;
int mTimestampBase;
int mMirrorMode;
+ bool mUseReadoutTimestamp;
};
} // namespace params
} // namespace camera2
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index fef873b..bfd02b3 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -141,6 +141,7 @@
],
shared_libs: [
+ "libbinder_ndk",
"libfmq",
"libhidlbase",
"libhardware",
@@ -151,15 +152,13 @@
"libcutils",
"libcamera_metadata",
"libmediandk",
- "android.frameworks.cameraservice.device@2.0",
- "android.frameworks.cameraservice.device@2.1",
- "android.frameworks.cameraservice.common@2.0",
- "android.frameworks.cameraservice.service@2.0",
- "android.frameworks.cameraservice.service@2.1",
- "android.frameworks.cameraservice.service@2.2",
+ "android.frameworks.cameraservice.common-V1-ndk",
+ "android.frameworks.cameraservice.device-V1-ndk",
+ "android.frameworks.cameraservice.service-V1-ndk",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
+ "libaidlcommonsupport",
"libarect",
],
// TODO: jchowdhary@, use header_libs instead b/131165718
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 9c98778..65b8837 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -29,6 +29,7 @@
#include "impl/ACameraCaptureSession.h"
#include "impl/ACameraCaptureSession.inc"
+
#include "NdkCameraCaptureSession.inc"
using namespace android;
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 691996b..8211671 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -22,18 +22,11 @@
#include <utils/Trace.h>
#include <camera/NdkCameraDevice.h>
+
#include "impl/ACameraCaptureSession.h"
using namespace android::acam;
-bool areWindowTypesEqual(ACameraWindowType *a, ACameraWindowType *b) {
-#ifdef __ANDROID_VNDK__
- return utils::isWindowNativeHandleEqual(a, b);
-#else
- return a == b;
-#endif
-}
-
EXPORT
camera_status_t ACameraDevice_close(ACameraDevice* device) {
ATRACE_CALL();
@@ -183,14 +176,15 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (areWindowTypesEqual(out->mWindow, window)) {
+ if (out->isWindowEqual(window)) {
ALOGE("%s: Error trying to add the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- auto insert = out->mSharedWindows.insert(window);
- camera_status_t ret = (insert.second) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
+
+ bool insert = out->addSharedWindow(window);
+ camera_status_t ret = (insert) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
return ret;
}
@@ -208,13 +202,13 @@
__FUNCTION__);
return ACAMERA_ERROR_INVALID_OPERATION;
}
- if (areWindowTypesEqual(out->mWindow, window)) {
+ if (out->isWindowEqual(window)) {
ALOGE("%s: Error trying to remove the same window associated with the output configuration",
__FUNCTION__);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- auto remove = out->mSharedWindows.erase(window);
+ auto remove = out->removeSharedWindow(window);
camera_status_t ret = (remove) ? ACAMERA_OK : ACAMERA_ERROR_INVALID_PARAMETER;
return ret;
}
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 3d231a8..2de4a50 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -81,7 +81,7 @@
callback->onCameraAvailable, callback->onCameraUnavailable);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance().registerAvailabilityCallback(callback);
+ CameraManagerGlobal::getInstance()->registerAvailabilityCallback(callback);
return ACAMERA_OK;
}
@@ -100,7 +100,7 @@
callback->onCameraAvailable, callback->onCameraUnavailable);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance().unregisterAvailabilityCallback(callback);
+ CameraManagerGlobal::getInstance()->unregisterAvailabilityCallback(callback);
return ACAMERA_OK;
}
@@ -131,7 +131,7 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
}
- CameraManagerGlobal::getInstance().registerExtendedAvailabilityCallback(callback);
+ CameraManagerGlobal::getInstance()->registerExtendedAvailabilityCallback(callback);
return ACAMERA_OK;
}
@@ -154,7 +154,7 @@
callback->onCameraAccessPrioritiesChanged);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- CameraManagerGlobal::getInstance().unregisterExtendedAvailabilityCallback(callback);
+ CameraManagerGlobal::getInstance()->unregisterExtendedAvailabilityCallback(callback);
return ACAMERA_OK;
}
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index 68db233..110d47a 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -23,7 +23,11 @@
ACameraCaptureSession::~ACameraCaptureSession() {
ALOGV("~ACameraCaptureSession: %p notify device end of life", this);
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev != nullptr && !dev->isClosed()) {
dev->lockDeviceForSessionOps();
{
@@ -50,7 +54,11 @@
mClosedByApp = true;
}
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev != nullptr) {
dev->lockDeviceForSessionOps();
}
@@ -75,7 +83,11 @@
camera_status_t
ACameraCaptureSession::stopRepeating() {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -93,7 +105,11 @@
camera_status_t
ACameraCaptureSession::abortCaptures() {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -110,7 +126,11 @@
}
camera_status_t ACameraCaptureSession::updateOutputConfiguration(ACaptureSessionOutput *output) {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -129,7 +149,11 @@
ACameraDevice*
ACameraCaptureSession::getDevice() {
Mutex::Autolock _l(mSessionLock);
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return nullptr;
@@ -143,6 +167,17 @@
mIsClosed = true;
}
+#ifdef __ANDROID_VNDK__
+std::shared_ptr<acam::CameraDevice>
+ACameraCaptureSession::getDevicePtr() {
+ std::shared_ptr<acam::CameraDevice> device = mDevice.lock();
+ if (device == nullptr || device->isClosed()) {
+ ALOGW("Device is closed but session %d is not notified", mId);
+ return nullptr;
+ }
+ return device;
+}
+#else
sp<acam::CameraDevice>
ACameraCaptureSession::getDeviceSp() {
sp<acam::CameraDevice> device = mDevice.promote();
@@ -152,5 +187,4 @@
}
return device;
}
-
-
+#endif
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 08a9226..cd65e8c 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -47,6 +47,21 @@
return mWindow > other.mWindow;
}
+ inline bool isWindowEqual(ACameraWindowType* window) const {
+ return mWindow == window;
+ }
+
+ // returns true if the window was successfully added, false otherwise.
+ inline bool addSharedWindow(ACameraWindowType* window) {
+ auto ret = mSharedWindows.insert(window);
+ return ret.second;
+ }
+
+ // returns the number of elements removed.
+ inline size_t removeSharedWindow(ACameraWindowType* window) {
+ return mSharedWindows.erase(window);
+ }
+
ACameraWindowType* mWindow;
std::set<ACameraWindowType *> mSharedWindows;
bool mIsShared;
@@ -65,6 +80,15 @@
*/
struct ACameraCaptureSession : public RefBase {
public:
+#ifdef __ANDROID_VNDK__
+ ACameraCaptureSession(
+ int id,
+ const ACaptureSessionOutputContainer* outputs,
+ const ACameraCaptureSession_stateCallbacks* cb,
+ std::weak_ptr<android::acam::CameraDevice> device) :
+ mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
+ mDevice(std::move(device)) {}
+#else
ACameraCaptureSession(
int id,
const ACaptureSessionOutputContainer* outputs,
@@ -72,6 +96,7 @@
android::acam::CameraDevice* device) :
mId(id), mOutput(*outputs), mUserSessionCallback(*cb),
mDevice(device) {}
+#endif
// This can be called in app calling close() or after some app callback is finished
// Make sure the caller does not hold device or session lock!
@@ -114,12 +139,21 @@
// or a new session is replacing this session.
void closeByDevice();
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<android::acam::CameraDevice> getDevicePtr();
+#else
sp<android::acam::CameraDevice> getDeviceSp();
+#endif
const int mId;
const ACaptureSessionOutputContainer mOutput;
const ACameraCaptureSession_stateCallbacks mUserSessionCallback;
+#ifdef __ANDROID_VNDK__
+ const std::weak_ptr<android::acam::CameraDevice> mDevice;
+#else
const wp<android::acam::CameraDevice> mDevice;
+#endif
+
bool mIsClosed = false;
bool mClosedByApp = false;
Mutex mSessionLock;
diff --git a/camera/ndk/impl/ACameraCaptureSession.inc b/camera/ndk/impl/ACameraCaptureSession.inc
index 86bf8a5..da535f8 100644
--- a/camera/ndk/impl/ACameraCaptureSession.inc
+++ b/camera/ndk/impl/ACameraCaptureSession.inc
@@ -15,9 +15,8 @@
*/
#include "ACameraCaptureSession.h"
-
#ifdef __ANDROID_VNDK__
-#include "ndk_vendor/impl/ACameraDeviceVendor.inc"
+#include <ndk_vendor/impl/ACameraDeviceVendor.inc>
#else
#include "ACameraDevice.inc"
#endif
@@ -30,7 +29,11 @@
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
@@ -52,7 +55,11 @@
/*optional*/T* cbs,
int numRequests, ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
+#ifdef __ANDROID_VNDK__
+ std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
if (dev == nullptr) {
ALOGE("Error: Device associated with session %p has been closed!", this);
return ACAMERA_ERROR_SESSION_CLOSED;
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 7997768..536055b 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -1412,7 +1412,6 @@
while (it != mSequenceLastFrameNumberMap.end()) {
int sequenceId = it->first;
int64_t lastFrameNumber = it->second.lastFrameNumber;
- bool hasCallback = true;
if (mRemote == nullptr) {
ALOGW("Camera %s closed while checking sequence complete", getId());
@@ -1425,7 +1424,6 @@
// This should not happen because we always register callback (with nullptr inside)
if (mSequenceCallbackMap.count(sequenceId) == 0) {
ALOGW("No callback found for sequenceId %d", sequenceId);
- hasCallback = false;
}
if (lastFrameNumber <= completedFrameNumber) {
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 23d90cc..837b5be 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -38,17 +38,16 @@
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
const nsecs_t CameraManagerGlobal::kCallbackDrainTimeout = 5000000; // 5 ms
Mutex CameraManagerGlobal::sLock;
-CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+wp<CameraManagerGlobal> CameraManagerGlobal::sInstance = nullptr;
-CameraManagerGlobal&
-CameraManagerGlobal::getInstance() {
+sp<CameraManagerGlobal> CameraManagerGlobal::getInstance() {
Mutex::Autolock _l(sLock);
- CameraManagerGlobal* instance = sInstance;
+ sp<CameraManagerGlobal> instance = sInstance.promote();
if (instance == nullptr) {
instance = new CameraManagerGlobal();
sInstance = instance;
}
- return *instance;
+ return instance;
}
CameraManagerGlobal::~CameraManagerGlobal() {
@@ -637,7 +636,7 @@
Mutex::Autolock _l(mLock);
std::vector<String8> idList;
- CameraManagerGlobal::getInstance().getCameraIdList(&idList);
+ CameraManagerGlobal::getInstance()->getCameraIdList(&idList);
int numCameras = idList.size();
ACameraIdList *out = new ACameraIdList;
@@ -687,7 +686,7 @@
const char* cameraIdStr, sp<ACameraMetadata>* characteristics) {
Mutex::Autolock _l(mLock);
- sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
@@ -696,7 +695,7 @@
CameraMetadata rawMetadata;
int targetSdkVersion = android_get_application_target_sdk_version();
binder::Status serviceRet = cs->getCameraCharacteristics(String16(cameraIdStr),
- targetSdkVersion, /*overrideToPortrait*/true, &rawMetadata);
+ targetSdkVersion, /*overrideToPortrait*/false, &rawMetadata);
if (!serviceRet.isOk()) {
switch(serviceRet.serviceSpecificErrorCode()) {
case hardware::ICameraService::ERROR_DISCONNECTED:
@@ -733,7 +732,7 @@
ACameraDevice* device = new ACameraDevice(cameraId, callback, chars);
- sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ sp<hardware::ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
delete device;
@@ -748,7 +747,7 @@
binder::Status serviceRet = cs->connectDevice(
callbacks, String16(cameraId), String16(""), {},
hardware::ICameraService::USE_CALLING_UID, /*oomScoreOffset*/0,
- targetSdkVersion, /*overrideToPortrait*/true, /*out*/&deviceRemote);
+ targetSdkVersion, /*overrideToPortrait*/false, /*out*/&deviceRemote);
if (!serviceRet.isOk()) {
ALOGE("%s: connect camera device failed: %s", __FUNCTION__, serviceRet.toString8().string());
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index d53d809..0dd79da 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -46,7 +46,7 @@
*/
class CameraManagerGlobal final : public RefBase {
public:
- static CameraManagerGlobal& getInstance();
+ static sp<CameraManagerGlobal> getInstance();
sp<hardware::ICameraService> getCameraService();
void registerAvailabilityCallback(
@@ -257,7 +257,7 @@
// For the singleton instance
static Mutex sLock;
- static CameraManagerGlobal* sInstance;
+ static wp<CameraManagerGlobal> sInstance;
CameraManagerGlobal() {};
~CameraManagerGlobal();
};
@@ -271,7 +271,7 @@
*/
struct ACameraManager {
ACameraManager() :
- mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
+ mGlobalManager(android::acam::CameraManagerGlobal::getInstance()) {}
~ACameraManager();
camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
static void deleteCameraIdList(ACameraIdList* cameraIdList);
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index 7be4bd3..239cb31 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -470,18 +470,6 @@
* <a href="http://developer.android.com/reference/android/media/CamcorderProfile.html">
* CamcorderProfiles</a>.</li>
*
- * <li>For efficient YUV processing with <a href=
- * "http://developer.android.com/reference/android/renderscript/package-summary.html">
- * RenderScript</a>:
- * Create a RenderScript
- * <a href="http://developer.android.com/reference/android/renderscript/Allocation.html">
- * Allocation</a> with a supported YUV
- * type, the IO_INPUT flag, and one of the YUV output sizes returned by
- * {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS},
- * Then obtain the Surface with
- * <a href="http://developer.android.com/reference/android/renderscript/Allocation.html#getSurface()">
- * Allocation#getSurface}</a>.</li>
- *
* <li>For access to RAW, uncompressed YUV, or compressed JPEG data in the application: Create an
* {@link AImageReader} object using the {@link AImageReader_new} method with one of the supported
* output formats given by {@link ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS}. Then obtain a
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 2869669..6f97770 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -75,6 +75,7 @@
ACAMERA_AUTOMOTIVE,
ACAMERA_AUTOMOTIVE_LENS,
ACAMERA_EXTENSION,
+ ACAMERA_JPEGR,
ACAMERA_SECTION_COUNT,
ACAMERA_VENDOR = 0x8000
@@ -121,6 +122,7 @@
ACAMERA_AUTOMOTIVE_START = ACAMERA_AUTOMOTIVE << 16,
ACAMERA_AUTOMOTIVE_LENS_START = ACAMERA_AUTOMOTIVE_LENS << 16,
ACAMERA_EXTENSION_START = ACAMERA_EXTENSION << 16,
+ ACAMERA_JPEGR_START = ACAMERA_JPEGR << 16,
ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
} acamera_metadata_section_start_t;
@@ -3738,9 +3740,9 @@
* <p>Output streams use this rectangle to produce their output, cropping to a smaller region
* if necessary to maintain the stream's aspect ratio, then scaling the sensor input to
* match the output's configured resolution.</p>
- * <p>The crop region is applied after the RAW to other color space (e.g. YUV)
- * conversion. Since raw streams (e.g. RAW16) don't have the conversion stage, they are not
- * croppable. The crop region will be ignored by raw streams.</p>
+ * <p>The crop region is usually applied after the RAW to other color space (e.g. YUV)
+ * conversion. As a result RAW streams are not croppable unless supported by the
+ * camera device. See ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES#CROPPED_RAW for details.</p>
* <p>For non-raw streams, any additional per-stream cropping will be done to maximize the
* final pixel area of the stream.</p>
* <p>For example, if the crop region is set to a 4:3 aspect ratio, then 4:3 streams will use
@@ -3831,6 +3833,7 @@
* @see ACAMERA_CONTROL_ZOOM_RATIO
* @see ACAMERA_DISTORTION_CORRECTION_MODE
* @see ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM
+ * @see ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES
* @see ACAMERA_SCALER_CROPPING_TYPE
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE_MAXIMUM_RESOLUTION
@@ -4486,6 +4489,59 @@
*/
ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES = // int64[n] (acamera_metadata_enum_android_scaler_available_stream_use_cases_t)
ACAMERA_SCALER_START + 25,
+ /**
+ * <p>The region of the sensor that corresponds to the RAW read out for this
+ * capture when the stream use case of a RAW stream is set to CROPPED_RAW.</p>
+ *
+ * <p>Type: int32[4]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * </ul></p>
+ *
+ * <p>The coordinate system follows that of ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE.</p>
+ * <p>This CaptureResult key will be set when the corresponding CaptureRequest has a RAW target
+ * with stream use case set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW">CameraMetadata#SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW</a>,
+ * otherwise it will be {@code null}.
+ * The value of this key specifies the region of the sensor used for the RAW capture and can
+ * be used to calculate the corresponding field of view of RAW streams.
+ * This field of view will always be >= field of view for (processed) non-RAW streams for the
+ * capture. Note: The region specified may not necessarily be centered.</p>
+ * <p>For example: Assume a camera device has a pre correction active array size of
+ * {@code {0, 0, 1500, 2000}}. If the RAW_CROP_REGION is {@code {500, 375, 1500, 1125}}, that
+ * corresponds to a centered crop of 1/4th of the full field of view RAW stream.</p>
+ * <p>The metadata keys which describe properties of RAW frames:</p>
+ * <ul>
+ * <li>ACAMERA_STATISTICS_HOT_PIXEL_MAP</li>
+ * <li>android.statistics.lensShadingCorrectionMap</li>
+ * <li>ACAMERA_LENS_DISTORTION</li>
+ * <li>ACAMERA_LENS_POSE_TRANSLATION</li>
+ * <li>ACAMERA_LENS_POSE_ROTATION</li>
+ * <li>ACAMERA_LENS_DISTORTION</li>
+ * <li>ACAMERA_LENS_INTRINSIC_CALIBRATION</li>
+ * </ul>
+ * <p>should be interpreted in the effective after raw crop field-of-view coordinate system.
+ * In this coordinate system,
+ * {preCorrectionActiveArraySize.left, preCorrectionActiveArraySize.top} corresponds to the
+ * the top left corner of the cropped RAW frame and
+ * {preCorrectionActiveArraySize.right, preCorrectionActiveArraySize.bottom} corresponds to
+ * the bottom right corner. Client applications must use the values of the keys
+ * in the CaptureResult metadata if present.</p>
+ * <p>Crop regions (android.scaler.CropRegion), AE/AWB/AF regions and face coordinates still
+ * use the ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE coordinate system as usual.</p>
+ *
+ * @see ACAMERA_LENS_DISTORTION
+ * @see ACAMERA_LENS_INTRINSIC_CALIBRATION
+ * @see ACAMERA_LENS_POSE_ROTATION
+ * @see ACAMERA_LENS_POSE_TRANSLATION
+ * @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
+ * @see ACAMERA_STATISTICS_HOT_PIXEL_MAP
+ */
+ ACAMERA_SCALER_RAW_CROP_REGION = // int32[4]
+ ACAMERA_SCALER_START + 26,
ACAMERA_SCALER_END,
/**
@@ -7513,6 +7569,145 @@
ACAMERA_AUTOMOTIVE_LENS_START,
ACAMERA_AUTOMOTIVE_LENS_END,
+ /**
+ * <p>The available Jpeg/R stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>The configurations are listed as <code>(format, width, height, input?)</code> tuples.</p>
+ * <p>If the camera device supports Jpeg/R, it will support the same stream combinations with
+ * Jpeg/R as it does with P010. The stream combinations with Jpeg/R (or P010) supported
+ * by the device is determined by the device's hardware level and capabilities.</p>
+ * <p>All the static, control, and dynamic metadata tags related to JPEG apply to Jpeg/R formats.
+ * Configuring JPEG and Jpeg/R streams at the same time is not supported.</p>
+ * <p>All the configuration tuples <code>(format, width, height, input?)</code> will contain
+ * AIMAGE_FORMAT_JPEGR format as OUTPUT only.</p>
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS = // int32[n*4] (acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_t)
+ ACAMERA_JPEGR_START,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for Jpeg/R output formats.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>This should correspond to the frame duration when only that
+ * stream is active, with all processing (typically in android.*.mode)
+ * set to either OFF or FAST.</p>
+ * <p>When multiple streams are used in a request, the minimum frame
+ * duration will be max(individual stream min durations).</p>
+ * <p>See ACAMERA_SENSOR_FRAME_DURATION and
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for more details about
+ * calculating the max frame rate.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+ * @see ACAMERA_SENSOR_FRAME_DURATION
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS = // int64[4*n]
+ ACAMERA_JPEGR_START + 1,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for Jpeg/R streams.</p>
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>A stall duration is how much extra time would get added
+ * to the normal minimum frame duration for a repeating request
+ * that has streams with non-zero stall.</p>
+ * <p>This functions similarly to
+ * ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS for Jpeg/R
+ * streams.</p>
+ * <p>All Jpeg/R output stream formats may have a nonzero stall
+ * duration.</p>
+ *
+ * @see ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS = // int64[4*n]
+ ACAMERA_JPEGR_START + 2,
+ /**
+ * <p>The available Jpeg/R stream
+ * configurations that this camera device supports
+ * (i.e. format, width, height, output/input stream).</p>
+ *
+ * <p>Type: int32[n*4] (acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_maximum_resolution_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS for details.</p>
+ * <p>All the configuration tuples <code>(format, width, height, input?)</code> will contain
+ * AIMAGE_FORMAT_JPEG_R format as OUTPUT only.</p>
+ *
+ * @see ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION =
+ // int32[n*4] (acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_maximum_resolution_t)
+ ACAMERA_JPEGR_START + 3,
+ /**
+ * <p>This lists the minimum frame duration for each
+ * format/size combination for Jpeg/R output formats for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS for details.</p>
+ *
+ * @see ACAMERA_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_JPEGR_START + 4,
+ /**
+ * <p>This lists the maximum stall duration for each
+ * output format/size combination for Jpeg/R streams for CaptureRequests where
+ * ACAMERA_SENSOR_PIXEL_MODE is set to
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraMetadata.html#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION">CameraMetadata#SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION</a>.</p>
+ *
+ * @see ACAMERA_SENSOR_PIXEL_MODE
+ *
+ * <p>Type: int64[4*n]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ * <p>Refer to ACAMERA_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS for details.</p>
+ *
+ * @see ACAMERA_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS
+ */
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION =
+ // int64[4*n]
+ ACAMERA_JPEGR_START + 5,
+ ACAMERA_JPEGR_END,
+
} acamera_metadata_tag_t;
/**
@@ -10066,6 +10261,30 @@
*/
ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5,
+ /**
+ * <p>Cropped RAW stream when the client chooses to crop the field of view.</p>
+ * <p>Certain types of image sensors can run in binned modes in order to improve signal to
+ * noise ratio while capturing frames. However, at certain zoom levels and / or when
+ * other scene conditions are deemed fit, the camera sub-system may choose to un-bin and
+ * remosaic the sensor's output. This results in a RAW frame which is cropped in field
+ * of view and yet has the same number of pixels as full field of view RAW, thereby
+ * improving image detail.</p>
+ * <p>The resultant field of view of the RAW stream will be greater than or equal to
+ * croppable non-RAW streams. The effective crop region for this RAW stream will be
+ * reflected in the CaptureResult key ACAMERA_SCALER_RAW_CROP_REGION.</p>
+ * <p>If this stream use case is set on a non-RAW stream, i.e. not one of :</p>
+ * <ul>
+ * <li>{@link AIMAGE_FORMAT_RAW16 RAW_SENSOR}</li>
+ * <li>{@link AIMAGE_FORMAT_RAW10 RAW10}</li>
+ * <li>{@link AIMAGE_FORMAT_RAW12 RAW12}</li>
+ * </ul>
+ * <p>session configuration is not guaranteed to succeed.</p>
+ * <p>This stream use case may not be supported on some devices.</p>
+ *
+ * @see ACAMERA_SCALER_RAW_CROP_REGION
+ */
+ ACAMERA_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 0x6,
+
} acamera_metadata_enum_android_scaler_available_stream_use_cases_t;
@@ -10991,6 +11210,25 @@
+// ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS
+typedef enum acamera_metadata_enum_acamera_jpegr_available_jpeg_r_stream_configurations {
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT = 0,
+
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_INPUT = 1,
+
+} acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_t;
+
+// ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION
+typedef enum acamera_metadata_enum_acamera_jpegr_available_jpeg_r_stream_configurations_maximum_resolution {
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_OUTPUT
+ = 0,
+
+ ACAMERA_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION_INPUT
+ = 1,
+
+} acamera_metadata_enum_android_jpegr_available_jpeg_r_stream_configurations_maximum_resolution_t;
+
+
__END_DECLS
diff --git a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
index 5a1af79..45098c3 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
@@ -14,9 +14,14 @@
* limitations under the License.
*/
-#include <string>
#include "utils.h"
+#include <android/binder_auto_utils.h>
+#include <string>
+#include <set>
+
+using ::android::acam::utils::native_handle_ptr_wrapper;
+
struct ACaptureSessionOutput {
explicit ACaptureSessionOutput(const native_handle_t* window, bool isShared = false,
const char* physicalCameraId = "") :
@@ -38,8 +43,23 @@
return mWindow > other.mWindow;
}
- android::acam::utils::native_handle_ptr_wrapper mWindow;
- std::set<android::acam::utils::native_handle_ptr_wrapper> mSharedWindows;
+ inline bool isWindowEqual(ACameraWindowType* window) const {
+ return mWindow == native_handle_ptr_wrapper(window);
+ }
+
+ // returns true if the window was successfully added, false otherwise.
+ inline bool addSharedWindow(ACameraWindowType* window) {
+ auto ret = mSharedWindows.insert(window);
+ return ret.second;
+ }
+
+ // returns the number of elements removed.
+ inline size_t removeSharedWindow(ACameraWindowType* window) {
+ return mSharedWindows.erase(window);
+ }
+
+ native_handle_ptr_wrapper mWindow;
+ std::set<native_handle_ptr_wrapper> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
std::string mPhysicalCameraId;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index 0a57590..96df7db 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -17,27 +17,34 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ACameraDeviceVendor"
-#include <vector>
-#include <inttypes.h>
-#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
-#include <android/frameworks/cameraservice/device/2.0/types.h>
-#include <CameraMetadata.h>
-
-#include "ndk_vendor/impl/ACameraDevice.h"
#include "ACameraCaptureSession.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
+#include "ndk_vendor/impl/ACameraDevice.h"
#include "utils.h"
+#include <CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/device/CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/device/OutputConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/SessionConfiguration.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <inttypes.h>
+#include <map>
+#include <utility>
+#include <vector>
-#define CHECK_TRANSACTION_AND_RET(remoteRet, status, callName) \
- if (!remoteRet.isOk()) { \
- ALOGE("%s: Transaction error during %s call %s", __FUNCTION__, callName, \
- remoteRet.description().c_str()); \
- return ACAMERA_ERROR_UNKNOWN; \
- } \
- if (status != Status::NO_ERROR) { \
- ALOGE("%s: %s call failed", __FUNCTION__, callName); \
- return utils::convertFromHidl(status); \
+#define CHECK_TRANSACTION_AND_RET(ret, callName) \
+ if (!remoteRet.isOk()) { \
+ if (remoteRet.getExceptionCode() != EX_SERVICE_SPECIFIC) { \
+ ALOGE("%s: Transaction error during %s call %d", __FUNCTION__, callName, \
+ ret.getExceptionCode()); \
+ return ACAMERA_ERROR_UNKNOWN; \
+ } else { \
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError()); \
+ std::string errorMsg = \
+ aidl::android::frameworks::cameraservice::common::toString(errStatus); \
+ ALOGE("%s: %s call failed: %s", __FUNCTION__, callName, errorMsg.c_str()); \
+ return utils::convertFromAidl(errStatus); \
+ } \
}
using namespace android;
@@ -49,10 +56,10 @@
namespace android {
namespace acam {
-using HCameraMetadata = frameworks::cameraservice::device::V2_0::CameraMetadata;
-using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
-using SessionConfiguration = frameworks::cameraservice::device::V2_0::SessionConfiguration;
-using hardware::Void;
+using AidlCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
+using ::aidl::android::frameworks::cameraservice::device::SessionConfiguration;
+using ::ndk::ScopedAStatus;
// Static member definitions
const char* CameraDevice::kContextKey = "Context";
@@ -81,7 +88,6 @@
mCameraId(id),
mAppCallbacks(*cb),
mChars(std::move(chars)),
- mServiceCallback(new ServiceCallback(this)),
mWrapper(wrapper),
mInError(false),
mError(ACAMERA_OK),
@@ -125,8 +131,11 @@
CameraDevice::~CameraDevice() { }
-void
-CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
+void CameraDevice::init() {
+ mServiceCallback = ndk::SharedRefBase::make<ServiceCallback>(weak_from_this());
+}
+
+void CameraDevice::postSessionMsgAndCleanup(sp<AMessage>& msg) {
msg->post();
msg.clear();
sp<AMessage> cleanupMsg = new AMessage(kWhatCleanUpSessions, mHandler);
@@ -134,8 +143,7 @@
}
// TODO: cached created request?
-camera_status_t
-CameraDevice::createCaptureRequest(
+camera_status_t CameraDevice::createCaptureRequest(
ACameraDevice_request_template templateId,
const ACameraIdList* physicalCameraIdList,
ACaptureRequest** request) const {
@@ -147,20 +155,16 @@
if (mRemote == nullptr) {
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
- CameraMetadata rawRequest;
- Status status = Status::UNKNOWN_ERROR;
- auto remoteRet = mRemote->createDefaultRequest(
- utils::convertToHidl(templateId),
- [&status, &rawRequest](auto s, const hidl_vec<uint8_t> &metadata) {
- status = s;
- if (status == Status::NO_ERROR && utils::convertFromHidlCloned(metadata, &rawRequest)) {
- } else {
- ALOGE("%s: Couldn't create default request", __FUNCTION__);
- }
- });
- CHECK_TRANSACTION_AND_RET(remoteRet, status, "createDefaultRequest()")
+
+ AidlCameraMetadata aidlMetadata;
+ ScopedAStatus remoteRet = mRemote->createDefaultRequest(
+ utils::convertToAidl(templateId), &aidlMetadata);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "createDefaultRequest()")
+
+ camera_metadata_t* rawRequest;
+ utils::cloneFromAidl(aidlMetadata, &rawRequest);
ACaptureRequest* outReq = new ACaptureRequest();
- outReq->settings = new ACameraMetadata(rawRequest.release(), ACameraMetadata::ACM_REQUEST);
+ outReq->settings = new ACameraMetadata(rawRequest, ACameraMetadata::ACM_REQUEST);
if (physicalCameraIdList != nullptr) {
for (auto i = 0; i < physicalCameraIdList->numCameras; i++) {
outReq->physicalSettings.emplace(physicalCameraIdList->cameraIds[i],
@@ -172,9 +176,8 @@
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::createCaptureSession(
- const ACaptureSessionOutputContainer* outputs,
+camera_status_t CameraDevice::createCaptureSession(
+ const ACaptureSessionOutputContainer* outputs,
const ACaptureRequest* sessionParameters,
const ACameraCaptureSession_stateCallbacks* callbacks,
/*out*/ACameraCaptureSession** session) {
@@ -199,7 +202,7 @@
}
ACameraCaptureSession* newSession = new ACameraCaptureSession(
- mNextSessionId++, outputs, callbacks, this);
+ mNextSessionId++, outputs, callbacks, weak_from_this());
// set new session as current session
newSession->incStrong((void *) ACameraDevice_createCaptureSession);
@@ -225,41 +228,39 @@
sessionConfig.outputStreams.resize(sessionOutputContainer->mOutputs.size());
size_t index = 0;
for (const auto& output : sessionOutputContainer->mOutputs) {
- sessionConfig.outputStreams[index].rotation = utils::convertToHidl(output.mRotation);
- sessionConfig.outputStreams[index].windowGroupId = -1;
- sessionConfig.outputStreams[index].windowHandles.resize(output.mSharedWindows.size() + 1);
- sessionConfig.outputStreams[index].windowHandles[0] = output.mWindow;
- sessionConfig.outputStreams[index].physicalCameraId = output.mPhysicalCameraId;
+ OutputConfiguration& outputStream = sessionConfig.outputStreams[index];
+ outputStream.rotation = utils::convertToAidl(output.mRotation);
+ outputStream.windowGroupId = -1;
+ outputStream.windowHandles.resize(output.mSharedWindows.size() + 1);
+ outputStream.windowHandles[0] = std::move(dupToAidl(output.mWindow));
+ outputStream.physicalCameraId = output.mPhysicalCameraId;
index++;
}
bool configSupported = false;
- Status status = Status::UNKNOWN_ERROR;
- auto remoteRet = mRemote->isSessionConfigurationSupported(sessionConfig,
- [&status, &configSupported](auto s, auto supported) {
- status = s;
- configSupported = supported;
- });
-
- CHECK_TRANSACTION_AND_RET(remoteRet, status, "isSessionConfigurationSupported()");
+ ScopedAStatus remoteRet = mRemote->isSessionConfigurationSupported(
+ sessionConfig, &configSupported);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "isSessionConfigurationSupported()")
return configSupported ? ACAMERA_OK : ACAMERA_ERROR_STREAM_CONFIGURE_FAIL;
}
static void addMetadataToPhysicalCameraSettings(const CameraMetadata *metadata,
const std::string &cameraId, PhysicalCameraSettings *physicalCameraSettings) {
- CameraMetadata metadataCopy = *metadata;
- camera_metadata_t *camera_metadata = metadataCopy.release();
- HCameraMetadata hCameraMetadata;
- utils::convertToHidl(camera_metadata, &hCameraMetadata, /*shouldOwn*/ true);
- physicalCameraSettings->settings.metadata(std::move(hCameraMetadata));
+ const camera_metadata_t* cameraMetadata = metadata->getAndLock();
+ AidlCameraMetadata aidlCameraMetadata;
+ utils::convertToAidl(cameraMetadata, &aidlCameraMetadata);
+ metadata->unlock(cameraMetadata);
+ physicalCameraSettings->settings.set<CaptureMetadataInfo::metadata>(
+ std::move(aidlCameraMetadata));
physicalCameraSettings->id = cameraId;
}
void CameraDevice::addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest,
sp<CaptureRequest> &req) {
req->mPhysicalCameraSettings.resize(1 + aCaptureRequest->physicalSettings.size());
- addMetadataToPhysicalCameraSettings(&(aCaptureRequest->settings->getInternalData()), getId(),
- &(req->mPhysicalCameraSettings[0]));
+ addMetadataToPhysicalCameraSettings(
+ &(aCaptureRequest->settings->getInternalData()),
+ getId(),&(req->mPhysicalCameraSettings[0]));
size_t i = 1;
for (auto &physicalSetting : aCaptureRequest->physicalSettings) {
addMetadataToPhysicalCameraSettings(&(physicalSetting.second->getInternalData()),
@@ -285,7 +286,7 @@
int32_t streamId = -1;
for (auto& kvPair : mConfiguredOutputs) {
- if (utils::isWindowNativeHandleEqual(kvPair.second.first, output->mWindow)) {
+ if (kvPair.second.first == output->mWindow) {
streamId = kvPair.first;
break;
}
@@ -295,56 +296,59 @@
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- OutputConfigurationWrapper outConfigW;
- OutputConfiguration &outConfig = outConfigW.mOutputConfiguration;
- outConfig.rotation = utils::convertToHidl(output->mRotation);
+ OutputConfiguration outConfig;
+ outConfig.rotation = utils::convertToAidl(output->mRotation);
outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
- outConfig.windowHandles[0] = output->mWindow;
+ outConfig.windowHandles[0] = std::move(dupToAidl(output->mWindow));
outConfig.physicalCameraId = output->mPhysicalCameraId;
int i = 1;
for (auto& anw : output->mSharedWindows) {
- outConfig.windowHandles[i++] = anw;
+ outConfig.windowHandles[i++] = std::move(dupToAidl(anw));
}
- auto remoteRet = mRemote->updateOutputConfiguration(streamId, outConfig);
+ auto remoteRet = mRemote->updateOutputConfiguration(streamId,
+ outConfig);
+
if (!remoteRet.isOk()) {
- ALOGE("%s: Transaction error in updating OutputConfiguration: %s", __FUNCTION__,
- remoteRet.description().c_str());
- return ACAMERA_ERROR_UNKNOWN;
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status st = static_cast<Status>(remoteRet.getServiceSpecificError());
+ switch (st) {
+ case Status::NO_ERROR:
+ break;
+ case Status::INVALID_OPERATION:
+ ALOGE("Camera device %s invalid operation", getId());
+ return ACAMERA_ERROR_INVALID_OPERATION;
+ case Status::ALREADY_EXISTS:
+ ALOGE("Camera device %s output surface already exists", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ case Status::ILLEGAL_ARGUMENT:
+ ALOGE("Camera device %s invalid input argument", getId());
+ return ACAMERA_ERROR_INVALID_PARAMETER;
+ default:
+ ALOGE("Camera device %s failed to add shared output", getId());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
+ } else {
+ ALOGE("%s: Transaction error in updating OutputConfiguration: %d", __FUNCTION__,
+ remoteRet.getExceptionCode());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
}
- switch (remoteRet) {
- case Status::NO_ERROR:
- break;
- case Status::INVALID_OPERATION:
- ALOGE("Camera device %s invalid operation", getId());
- return ACAMERA_ERROR_INVALID_OPERATION;
- case Status::ALREADY_EXISTS:
- ALOGE("Camera device %s output surface already exists", getId());
- return ACAMERA_ERROR_INVALID_PARAMETER;
- case Status::ILLEGAL_ARGUMENT:
- ALOGE("Camera device %s invalid input argument", getId());
- return ACAMERA_ERROR_INVALID_PARAMETER;
- default:
- ALOGE("Camera device %s failed to add shared output", getId());
- return ACAMERA_ERROR_UNKNOWN;
- }
-
- mConfiguredOutputs[streamId] =
- std::move(std::make_pair(std::move(output->mWindow), std::move(outConfigW)));
-
+ mConfiguredOutputs[streamId] = std::make_pair(output->mWindow,
+ std::move(outConfig));
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::allocateCaptureRequestLocked(
+camera_status_t CameraDevice::allocateCaptureRequestLocked(
const ACaptureRequest* request, /*out*/sp<CaptureRequest> &outReq) {
sp<CaptureRequest> req(new CaptureRequest());
req->mCaptureRequest.physicalCameraSettings.resize(1 + request->physicalSettings.size());
size_t index = 0;
allocateOneCaptureRequestMetadata(
- req->mCaptureRequest.physicalCameraSettings[index++], mCameraId, request->settings);
+ req->mCaptureRequest.physicalCameraSettings[index++],
+ mCameraId, request->settings);
for (auto& physicalEntry : request->physicalSettings) {
allocateOneCaptureRequestMetadata(
@@ -354,19 +358,20 @@
std::vector<int32_t> requestStreamIdxList;
std::vector<int32_t> requestSurfaceIdxList;
- for (auto outputTarget : request->targets->mOutputs) {
- const native_handle_t* anw = outputTarget.mWindow;
+
+ for (auto& outputTarget : request->targets->mOutputs) {
+ native_handle_ptr_wrapper anw = outputTarget.mWindow;
bool found = false;
req->mSurfaceList.push_back(anw);
// lookup stream/surface ID
for (const auto& kvPair : mConfiguredOutputs) {
int streamId = kvPair.first;
- const OutputConfigurationWrapper& outConfig = kvPair.second.second;
- const auto& windowHandles = outConfig.mOutputConfiguration.windowHandles;
+ const OutputConfiguration& outConfig = kvPair.second.second;
+ const auto& windowHandles = outConfig.windowHandles;
for (int surfaceId = 0; surfaceId < (int) windowHandles.size(); surfaceId++) {
- // If two native handles are equivalent, so are their surfaces.
- if (utils::isWindowNativeHandleEqual(windowHandles[surfaceId].getNativeHandle(),
- anw)) {
+ // If two window handles point to the same native window,
+ // they have the same surfaces.
+ if (utils::isWindowNativeHandleEqual(anw, windowHandles[surfaceId])) {
found = true;
requestStreamIdxList.push_back(streamId);
requestSurfaceIdxList.push_back(surfaceId);
@@ -378,7 +383,7 @@
}
}
if (!found) {
- ALOGE("Unconfigured output target %p in capture request!", anw);
+ ALOGE("Unconfigured output target %p in capture request!", anw.mWindow);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
}
@@ -395,54 +400,57 @@
PhysicalCameraSettings& cameraSettings,
const std::string& id, const sp<ACameraMetadata>& metadata) {
cameraSettings.id = id;
- // TODO: Do we really need to copy the metadata here ?
- CameraMetadata metadataCopy = metadata->getInternalData();
- camera_metadata_t *cameraMetadata = metadataCopy.release();
- HCameraMetadata hCameraMetadata;
- utils::convertToHidl(cameraMetadata, &hCameraMetadata, true);
- if (metadata != nullptr) {
- if (hCameraMetadata.data() != nullptr &&
- mCaptureRequestMetadataQueue != nullptr &&
- mCaptureRequestMetadataQueue->write(
- reinterpret_cast<const uint8_t *>(hCameraMetadata.data()),
- hCameraMetadata.size())) {
- // The metadata field of the union would've been destructued, so no need
- // to re-size it.
- cameraSettings.settings.fmqMetadataSize(hCameraMetadata.size());
- } else {
- ALOGE("Fmq write capture result failed, falling back to hwbinder");
- cameraSettings.settings.metadata(std::move(hCameraMetadata));
- }
+
+ if (metadata == nullptr) {
+ return;
+ }
+
+ const camera_metadata_t* cameraMetadata = metadata->getInternalData().getAndLock();
+ AidlCameraMetadata aidlCameraMetadata;
+ utils::convertToAidl(cameraMetadata, &aidlCameraMetadata);
+ metadata->getInternalData().unlock(cameraMetadata);
+
+ if (aidlCameraMetadata.metadata.data() != nullptr &&
+ mCaptureRequestMetadataQueue != nullptr &&
+ mCaptureRequestMetadataQueue->write(
+ reinterpret_cast<const int8_t*>(aidlCameraMetadata.metadata.data()),
+ aidlCameraMetadata.metadata.size())) {
+ cameraSettings.settings.set<CaptureMetadataInfo::fmqMetadataSize>(
+ aidlCameraMetadata.metadata.size());
+ } else {
+ ALOGE("Fmq write capture result failed, falling back to hwbinder");
+ cameraSettings.settings.set<CaptureMetadataInfo::metadata>(std::move(aidlCameraMetadata));
}
}
-ACaptureRequest*
-CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req, const char* deviceId) {
+ACaptureRequest* CameraDevice::allocateACaptureRequest(sp<CaptureRequest>& req,
+ const char* deviceId) {
ACaptureRequest* pRequest = new ACaptureRequest();
for (size_t i = 0; i < req->mPhysicalCameraSettings.size(); i++) {
const std::string& id = req->mPhysicalCameraSettings[i].id;
- CameraMetadata clone;
- utils::convertFromHidlCloned(req->mPhysicalCameraSettings[i].settings.metadata(), &clone);
- camera_metadata_t *clonep = clone.release();
+ camera_metadata_t* clone;
+ AidlCameraMetadata& aidlCameraMetadata = req->mPhysicalCameraSettings[i].settings
+ .get<CaptureMetadataInfo::metadata>();
+ utils::cloneFromAidl(aidlCameraMetadata, &clone);
+
if (id == deviceId) {
- pRequest->settings = new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
+ pRequest->settings = new ACameraMetadata(clone, ACameraMetadata::ACM_REQUEST);
} else {
pRequest->physicalSettings[req->mPhysicalCameraSettings[i].id] =
- new ACameraMetadata(clonep, ACameraMetadata::ACM_REQUEST);
+ new ACameraMetadata(clone, ACameraMetadata::ACM_REQUEST);
}
}
pRequest->targets = new ACameraOutputTargets();
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
- const native_handle_t* anw = req->mSurfaceList[i];
+ native_handle_ptr_wrapper anw = req->mSurfaceList[i];
ACameraOutputTarget outputTarget(anw);
- pRequest->targets->mOutputs.insert(outputTarget);
+ pRequest->targets->mOutputs.insert(std::move(outputTarget));
}
return pRequest;
}
-void
-CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
+void CameraDevice::freeACaptureRequest(ACaptureRequest* req) {
if (req == nullptr) {
return;
}
@@ -459,7 +467,7 @@
}
if (mCurrentSession != session) {
- // Session has been replaced by other seesion or device is closed
+ // Session has been replaced by other session or device is closed
return;
}
mCurrentSession = nullptr;
@@ -471,8 +479,8 @@
return;
}
- // No new session, unconfigure now
- // Note: The unconfiguration of session won't be accounted for session
+ // No new session, un-configure now
+ // Note: The un-configuration of session won't be accounted for session
// latency because a stream configuration with 0 streams won't ever become
// active.
nsecs_t startTimeNs = systemTime();
@@ -494,8 +502,8 @@
ALOGD("%s: binder disconnect reached", __FUNCTION__);
auto ret = mRemote->disconnect();
if (!ret.isOk()) {
- ALOGE("%s: Transaction error while disconnecting device %s", __FUNCTION__,
- ret.description().c_str());
+ ALOGE("%s: Transaction error while disconnecting device %d", __FUNCTION__,
+ ret.getExceptionCode());
}
}
mRemote = nullptr;
@@ -505,8 +513,7 @@
}
}
-camera_status_t
-CameraDevice::stopRepeatingLocked() {
+camera_status_t CameraDevice::stopRepeatingLocked() {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
@@ -517,20 +524,14 @@
mRepeatingSequenceId = REQUEST_ID_NONE;
int64_t lastFrameNumber;
- Status status = Status::UNKNOWN_ERROR;
- auto remoteRet = mRemote->cancelRepeatingRequest(
- [&status, &lastFrameNumber](Status s, auto frameNumber) {
- status = s;
- lastFrameNumber = frameNumber;
- });
- CHECK_TRANSACTION_AND_RET(remoteRet, status, "cancelRepeatingRequest()");
+ ScopedAStatus remoteRet = mRemote->cancelRepeatingRequest(&lastFrameNumber);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "cancelRepeatingRequest()");
checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
}
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::flushLocked(ACameraCaptureSession* session) {
+camera_status_t CameraDevice::flushLocked(ACameraCaptureSession* session) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s abort captures failed! ret %d", getId(), ret);
@@ -571,20 +572,15 @@
}
int64_t lastFrameNumber;
- Status status = Status::UNKNOWN_ERROR;
- auto remoteRet = mRemote->flush([&status, &lastFrameNumber](auto s, auto frameNumber) {
- status = s;
- lastFrameNumber = frameNumber;
- });
- CHECK_TRANSACTION_AND_RET(remoteRet, status, "flush()")
+ ScopedAStatus remoteRet = mRemote->flush(&lastFrameNumber);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "flush()")
if (mRepeatingSequenceId != REQUEST_ID_NONE) {
checkRepeatingSequenceCompleteLocked(mRepeatingSequenceId, lastFrameNumber);
}
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::waitUntilIdleLocked() {
+camera_status_t CameraDevice::waitUntilIdleLocked() {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Wait until camera %s idle failed! ret %d", getId(), ret);
@@ -597,13 +593,13 @@
}
auto remoteRet = mRemote->waitUntilIdle();
- CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "waitUntilIdle()")
+ CHECK_TRANSACTION_AND_RET(remoteRet, "waitUntilIdle()")
return ACAMERA_OK;
}
-camera_status_t
-CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
- const ACaptureRequest* sessionParameters, nsecs_t startTimeNs) {
+camera_status_t CameraDevice::configureStreamsLocked(const ACaptureSessionOutputContainer* outputs,
+ const ACaptureRequest* sessionParameters,
+ nsecs_t startTimeNs) {
ACaptureSessionOutputContainer emptyOutput;
if (outputs == nullptr) {
outputs = &emptyOutput;
@@ -614,31 +610,37 @@
return ret;
}
- std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> outputSet;
- for (auto outConfig : outputs->mOutputs) {
- const native_handle_t* anw = outConfig.mWindow;
- OutputConfigurationWrapper outConfigInsertW;
- OutputConfiguration &outConfigInsert = outConfigInsertW.mOutputConfiguration;
- outConfigInsert.rotation = utils::convertToHidl(outConfig.mRotation);
+ std::map<native_handle_ptr_wrapper, OutputConfiguration> handleToConfig;
+ for (const auto& outConfig : outputs->mOutputs) {
+ native_handle_ptr_wrapper anw = outConfig.mWindow;
+ OutputConfiguration outConfigInsert;
+ outConfigInsert.rotation = utils::convertToAidl(outConfig.mRotation);
outConfigInsert.windowGroupId = -1;
outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
- outConfigInsert.windowHandles[0] = anw;
+ outConfigInsert.windowHandles[0] = std::move(dupToAidl(anw));
outConfigInsert.physicalCameraId = outConfig.mPhysicalCameraId;
- native_handle_ptr_wrapper wrap(anw);
-
- outputSet.emplace(std::make_pair(std::move(anw), std::move(outConfigInsertW)));
+ handleToConfig.insert({anw, std::move(outConfigInsert)});
}
- std::set<std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> addSet = outputSet;
+
+ std::set<native_handle_ptr_wrapper> addSet;
+ for (auto& kvPair : handleToConfig) {
+ addSet.insert(kvPair.first);
+ }
+
std::vector<int32_t> deleteList;
// Determine which streams need to be created, which to be deleted
for (auto& kvPair : mConfiguredOutputs) {
int32_t streamId = kvPair.first;
auto& outputPair = kvPair.second;
- if (outputSet.count(outputPair)) {
- deleteList.push_back(streamId); // Need to delete a no longer needed stream
+ auto& anw = outputPair.first;
+ auto& configuredOutput = outputPair.second;
+
+ auto itr = handleToConfig.find(anw);
+ if (itr != handleToConfig.end() && (itr->second) == configuredOutput) {
+ deleteList.push_back(streamId);
} else {
- addSet.erase(outputPair); // No need to add already existing stream
+ addSet.erase(anw);
}
}
@@ -673,106 +675,96 @@
mIdle = true;
auto remoteRet = mRemote->beginConfigure();
- CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "beginConfigure()")
+ CHECK_TRANSACTION_AND_RET(remoteRet, "beginConfigure()")
// delete to-be-deleted streams
for (auto streamId : deleteList) {
remoteRet = mRemote->deleteStream(streamId);
- CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "deleteStream()")
+ CHECK_TRANSACTION_AND_RET(remoteRet, "deleteStream()")
mConfiguredOutputs.erase(streamId);
}
// add new streams
- for (const auto &outputPair : addSet) {
- int streamId;
- Status status = Status::UNKNOWN_ERROR;
- auto ret = mRemote->createStream(outputPair.second,
- [&status, &streamId](Status s, auto stream_id) {
- status = s;
- streamId = stream_id;
- });
- CHECK_TRANSACTION_AND_RET(ret, status, "createStream()")
- mConfiguredOutputs.insert(std::make_pair(streamId, outputPair));
+ for (const auto &anw : addSet) {
+ int32_t streamId;
+ auto itr = handleToConfig.find(anw);
+ remoteRet = mRemote->createStream(itr->second, &streamId);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "createStream()")
+ mConfiguredOutputs.insert(std::make_pair(streamId,
+ std::make_pair(anw,
+ std::move(itr->second))));
+ handleToConfig.erase(itr);
}
- CameraMetadata params;
- HCameraMetadata hidlParams;
+ AidlCameraMetadata aidlParams;
if ((sessionParameters != nullptr) && (sessionParameters->settings != nullptr)) {
- params.append(sessionParameters->settings->getInternalData());
- const camera_metadata_t *params_metadata = params.getAndLock();
- utils::convertToHidl(params_metadata, &hidlParams);
- params.unlock(params_metadata);
+ const CameraMetadata ¶ms = sessionParameters->settings->getInternalData();
+ const camera_metadata_t* paramsMetadata = params.getAndLock();
+ utils::convertToAidl(paramsMetadata, &aidlParams);
+ params.unlock(paramsMetadata);
}
- remoteRet = mRemote->endConfigure_2_1(StreamConfigurationMode::NORMAL_MODE,
- hidlParams, startTimeNs);
- CHECK_TRANSACTION_AND_RET(remoteRet, remoteRet, "endConfigure()")
+ remoteRet = mRemote->endConfigure(StreamConfigurationMode::NORMAL_MODE,
+ aidlParams, startTimeNs);
+ CHECK_TRANSACTION_AND_RET(remoteRet, "endConfigure()")
return ACAMERA_OK;
}
-void
-CameraDevice::setRemoteDevice(sp<ICameraDeviceUser> remote) {
+void CameraDevice::setRemoteDevice(std::shared_ptr<ICameraDeviceUser> remote) {
Mutex::Autolock _l(mDeviceLock);
- mRemote = remote;
+ mRemote = std::move(remote);
}
-bool
-CameraDevice::setDeviceMetadataQueues() {
+bool CameraDevice::setDeviceMetadataQueues() {
if (mRemote == nullptr) {
ALOGE("mRemote must not be null while trying to fetch metadata queues");
return false;
}
std::shared_ptr<RequestMetadataQueue> &reqQueue = mCaptureRequestMetadataQueue;
- auto ret =
- mRemote->getCaptureRequestMetadataQueue(
- [&reqQueue](const auto &mqDescriptor) {
- reqQueue = std::make_shared<RequestMetadataQueue>(mqDescriptor);
- if (!reqQueue->isValid() || reqQueue->availableToWrite() <=0) {
- ALOGE("Empty fmq from cameraserver");
- reqQueue = nullptr;
- }
- });
+ MQDescriptor<int8_t, SynchronizedReadWrite> reqMqDescriptor;
+ ScopedAStatus ret = mRemote->getCaptureRequestMetadataQueue(&reqMqDescriptor);
if (!ret.isOk()) {
ALOGE("Transaction error trying to get capture request metadata queue");
return false;
}
+ reqQueue = std::make_shared<RequestMetadataQueue>(reqMqDescriptor);
+ if (!reqQueue->isValid() || reqQueue->availableToWrite() <= 0) {
+ ALOGE("Empty fmq from cameraserver");
+ reqQueue = nullptr;
+ }
+
+ MQDescriptor<int8_t, SynchronizedReadWrite> resMqDescriptor;
std::shared_ptr<ResultMetadataQueue> &resQueue = mCaptureResultMetadataQueue;
- ret =
- mRemote->getCaptureResultMetadataQueue(
- [&resQueue](const auto &mqDescriptor) {
- resQueue = std::make_shared<ResultMetadataQueue>(mqDescriptor);
- if (!resQueue->isValid() || resQueue->availableToWrite() <=0) {
- ALOGE("Empty fmq from cameraserver");
- }
- });
+ ret = mRemote->getCaptureResultMetadataQueue(&resMqDescriptor);
if (!ret.isOk()) {
ALOGE("Transaction error trying to get capture result metadata queue");
return false;
}
+ resQueue = std::make_shared<ResultMetadataQueue>(resMqDescriptor);
+ if (!resQueue->isValid() || resQueue->availableToWrite() <= 0) {
+ ALOGE("Empty fmq from cameraserver");
+ }
+
return true;
}
-camera_status_t
-CameraDevice::checkCameraClosedOrErrorLocked() const {
+camera_status_t CameraDevice::checkCameraClosedOrErrorLocked() const {
if (mRemote == nullptr) {
ALOGE("%s: camera device already closed", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
- if (mInError) {// triggered by onDeviceError
- ALOGE("%s: camera device has encountered a serious error", __FUNCTION__);
+ if (mInError) { // triggered by onDeviceError
+ ALOGE("%s: camera device has encountered a serious error: %d", __FUNCTION__, mError);
return mError;
}
return ACAMERA_OK;
}
-void
-CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
+void CameraDevice::setCameraDeviceErrorLocked(camera_status_t error) {
mInError = true;
mError = error;
- return;
}
-void
-CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
+void CameraDevice::FrameNumberTracker::updateTracker(int64_t frameNumber, bool isError) {
ALOGV("updateTracker frame %" PRId64 " isError %d", frameNumber, isError);
if (isError) {
mFutureErrorSet.insert(frameNumber);
@@ -791,8 +783,7 @@
update();
}
-void
-CameraDevice::FrameNumberTracker::update() {
+void CameraDevice::FrameNumberTracker::update() {
for (auto it = mFutureErrorSet.begin(); it != mFutureErrorSet.end();) {
int64_t errorFrameNumber = *it;
if (errorFrameNumber == mCompletedFrameNumber + 1) {
@@ -811,10 +802,8 @@
ALOGV("Update complete frame %" PRId64, mCompletedFrameNumber);
}
-void
-CameraDevice::onCaptureErrorLocked(
- ErrorCode errorCode,
- const CaptureResultExtras& resultExtras) {
+void CameraDevice::onCaptureErrorLocked(ErrorCode errorCode,
+ const CaptureResultExtras& resultExtras) {
int sequenceId = resultExtras.requestId;
int64_t frameNumber = resultExtras.frameNumber;
int32_t burstId = resultExtras.burstId;
@@ -826,7 +815,7 @@
return;
}
- CallbackHolder cbh = (*it).second;
+ CallbackHolder cbh = it->second;
sp<ACameraCaptureSession> session = cbh.mSession;
if ((size_t) burstId >= cbh.mRequests.size()) {
ALOGE("%s: Error: request index %d out of bound (size %zu)",
@@ -852,7 +841,7 @@
// them and try to match the surfaces in the corresponding
// CaptureRequest.
const auto& errorWindowHandles =
- outputPairIt->second.second.mOutputConfiguration.windowHandles;
+ outputPairIt->second.second.windowHandles;
for (const auto& errorWindowHandle : errorWindowHandles) {
for (const auto &requestStreamAndWindowId :
request->mCaptureRequest.streamAndWindowIds) {
@@ -869,11 +858,11 @@
}
const auto &requestWindowHandles =
- requestSurfacePairIt->second.second.mOutputConfiguration.windowHandles;
- if (utils::isWindowNativeHandleEqual(
- requestWindowHandles[requestWindowId], errorWindowHandle)) {
- const native_handle_t* anw =
- requestWindowHandles[requestWindowId].getNativeHandle();
+ requestSurfacePairIt->second.second.windowHandles;
+
+ if (requestWindowHandles[requestWindowId] == errorWindowHandle) {
+ const native_handle_t* anw = makeFromAidl(
+ requestWindowHandles[requestWindowId]);
ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
getId(), anw, frameNumber);
@@ -898,14 +887,16 @@
failure->sequenceId = sequenceId;
failure->wasImageCaptured = (errorCode == ErrorCode::CAMERA_RESULT);
- sp<AMessage> msg = new AMessage(cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureFail :
- kWhatCaptureFail, mHandler);
+ sp<AMessage> msg = new AMessage(cbh.mIsLogicalCameraCallback ? kWhatLogicalCaptureFail
+ : kWhatCaptureFail,
+ mHandler);
msg->setPointer(kContextKey, cbh.mContext);
msg->setObject(kSessionSpKey, session);
if (cbh.mIsLogicalCameraCallback) {
- if (resultExtras.errorPhysicalCameraId.size() > 0) {
- msg->setString(kFailingPhysicalCameraId, resultExtras.errorPhysicalCameraId.c_str(),
- resultExtras.errorPhysicalCameraId.size());
+ if (!resultExtras.errorPhysicalCameraId.empty()) {
+ msg->setString(kFailingPhysicalCameraId,
+ resultExtras.errorPhysicalCameraId.c_str(),
+ resultExtras.errorPhysicalCameraId.size());
}
msg->setPointer(kCallbackFpKey, (void*) cbh.mOnLogicalCameraCaptureFailed);
} else {
@@ -919,7 +910,6 @@
mFrameNumberTracker.updateTracker(frameNumber, /*isError*/true);
checkAndFireSequenceCompleteLocked();
}
- return;
}
CameraDevice::CallbackHandler::CallbackHandler(const char *id) : mId(id) { }
@@ -1020,7 +1010,7 @@
return;
}
sp<ACameraCaptureSession> session(static_cast<ACameraCaptureSession*>(obj.get()));
- mCachedSessions.push(session);
+ mCachedSessions.push_back(session);
sp<CaptureRequest> requestSp = nullptr;
const char *id_cstr = mId.c_str();
switch (msg->what()) {
@@ -1167,7 +1157,8 @@
clone.update(ANDROID_SYNC_FRAME_NUMBER,
&physicalResult->mFrameNumber, /*data_count*/1);
sp<ACameraMetadata> metadata =
- new ACameraMetadata(clone.release(), ACameraMetadata::ACM_RESULT);
+ new ACameraMetadata(clone.release(),
+ ACameraMetadata::ACM_RESULT);
physicalMetadataCopy.push_back(metadata);
}
std::vector<const char*> physicalCameraIdPtrs;
@@ -1302,7 +1293,7 @@
return;
}
- const native_handle_t* anw;
+ native_handle_t* anw;
found = msg->findPointer(kAnwKey, (void**) &anw);
if (!found) {
ALOGE("%s: Cannot find native_handle_t!", __FUNCTION__);
@@ -1319,6 +1310,7 @@
ACaptureRequest* request = allocateACaptureRequest(requestSp, id_cstr);
(*onBufferLost)(context, session.get(), request, anw, frameNumber);
freeACaptureRequest(request);
+ native_handle_delete(anw); // clean up anw as it was copied from AIDL
break;
}
}
@@ -1329,10 +1321,10 @@
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs) :
- mSession(session), mRequests(requests),
+ mSession(std::move(session)), mRequests(std::move(requests)),
mIsRepeating(isRepeating),
mIs2Callback(false),
mIsLogicalCameraCallback(false) {
@@ -1346,10 +1338,10 @@
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs) :
- mSession(session), mRequests(requests),
+ mSession(std::move(session)), mRequests(std::move(requests)),
mIsRepeating(isRepeating),
mIs2Callback(false),
mIsLogicalCameraCallback(true) {
@@ -1363,10 +1355,10 @@
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacksV2* cbs) :
- mSession(session), mRequests(requests),
+ mSession(std::move(session)), mRequests(std::move(requests)),
mIsRepeating(isRepeating),
mIs2Callback(true),
mIsLogicalCameraCallback(false) {
@@ -1380,10 +1372,10 @@
CameraDevice::CallbackHolder::CallbackHolder(
sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs) :
- mSession(session), mRequests(requests),
+ mSession(std::move(session)), mRequests(std::move(requests)),
mIsRepeating(isRepeating),
mIs2Callback(true),
mIsLogicalCameraCallback(true) {
@@ -1501,23 +1493,21 @@
/**
* Camera service callback implementation
*/
-android::hardware::Return<void>
-CameraDevice::ServiceCallback::onDeviceError(
- ErrorCode errorCode,
- const CaptureResultExtras& resultExtras) {
+ScopedAStatus CameraDevice::ServiceCallback::onDeviceError(
+ ErrorCode errorCode, const CaptureResultExtras& resultExtras) {
ALOGD("Device error received, code %d, frame number %" PRId64 ", request ID %d, subseq ID %d"
" physical camera ID %s", errorCode, resultExtras.frameNumber, resultExtras.requestId,
resultExtras.burstId, resultExtras.errorPhysicalCameraId.c_str());
- auto ret = Void();
- sp<CameraDevice> dev = mDevice.promote();
+
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
if (dev == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
sp<ACameraCaptureSession> session = dev->mCurrentSession.promote();
Mutex::Autolock _l(dev->mDeviceLock);
if (dev->mRemote == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
switch (errorCode) {
case ErrorCode::CAMERA_DISCONNECTED:
@@ -1570,26 +1560,25 @@
dev->onCaptureErrorLocked(errorCode, resultExtras);
break;
}
- return ret;
+ return ScopedAStatus::ok();
}
-android::hardware::Return<void>
-CameraDevice::ServiceCallback::onDeviceIdle() {
+ScopedAStatus CameraDevice::ServiceCallback::onDeviceIdle() {
ALOGV("Camera is now idle");
- auto ret = Void();
- sp<CameraDevice> dev = mDevice.promote();
+
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
if (dev == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
Mutex::Autolock _l(dev->mDeviceLock);
if (dev->isClosed() || dev->mRemote == nullptr) {
- return ret;
+ return ScopedAStatus::ok();
}
if (dev->mIdle) {
// Already in idle state. Possibly other thread did waitUntilIdle
- return ret;
+ return ScopedAStatus::ok();
}
if (dev->mCurrentSession != nullptr) {
@@ -1597,13 +1586,14 @@
if (dev->mBusySession != dev->mCurrentSession) {
ALOGE("Current session != busy session");
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
- return ret;
+ return ScopedAStatus::ok();
}
sp<AMessage> msg = new AMessage(kWhatSessionStateCb, dev->mHandler);
msg->setPointer(kContextKey, dev->mBusySession->mUserSessionCallback.context);
msg->setObject(kSessionSpKey, dev->mBusySession);
- msg->setPointer(kCallbackFpKey, (void*) dev->mBusySession->mUserSessionCallback.onReady);
+ msg->setPointer(kCallbackFpKey,
+ (void*) dev->mBusySession->mUserSessionCallback.onReady);
// Make sure we clear the sp first so the session destructor can
// only happen on handler thread (where we don't hold device/session lock)
dev->mBusySession.clear();
@@ -1611,22 +1601,20 @@
}
dev->mIdle = true;
dev->mFlushing = false;
- return ret;
+ return ScopedAStatus::ok();
}
-android::hardware::Return<void>
-CameraDevice::ServiceCallback::onCaptureStarted(
- const CaptureResultExtras& resultExtras,
- uint64_t timestamp) {
- auto ret = Void();
- sp<CameraDevice> dev = mDevice.promote();
+
+ndk::ScopedAStatus CameraDevice::ServiceCallback::onCaptureStarted(
+ const CaptureResultExtras& resultExtras, int64_t timestamp) {
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
if (dev == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
Mutex::Autolock _l(dev->mDeviceLock);
if (dev->isClosed() || dev->mRemote == nullptr) {
- return ret;
+ return ScopedAStatus::ok();
}
int32_t sequenceId = resultExtras.requestId;
@@ -1635,7 +1623,7 @@
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
- CallbackHolder cbh = (*it).second;
+ CallbackHolder &cbh = it->second;
ACameraCaptureSession_captureCallback_start onStart = cbh.mOnCaptureStarted;
ACameraCaptureSession_captureCallback_startV2 onStart2 = cbh.mOnCaptureStarted2;
bool v2Callback = cbh.mIs2Callback;
@@ -1646,6 +1634,7 @@
dev->setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_SERVICE);
}
sp<CaptureRequest> request = cbh.mRequests[burstId];
+ ALOGE("%s: request = %p", __FUNCTION__, request.get());
sp<AMessage> msg = nullptr;
if (v2Callback) {
msg = new AMessage(kWhatCaptureStart2, dev->mHandler);
@@ -1661,24 +1650,22 @@
msg->setInt64(kFrameNumberKey, frameNumber);
dev->postSessionMsgAndCleanup(msg);
}
- return ret;
+ return ScopedAStatus::ok();
}
-android::hardware::Return<void>
-CameraDevice::ServiceCallback::onResultReceived(
- const FmqSizeOrMetadata& resultMetadata,
+ScopedAStatus CameraDevice::ServiceCallback::onResultReceived(
+ const CaptureMetadataInfo& resultMetadata,
const CaptureResultExtras& resultExtras,
- const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) {
- auto ret = Void();
+ const std::vector<PhysicalCaptureResultInfo>& physicalResultInfos) {
- sp<CameraDevice> dev = mDevice.promote();
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
if (dev == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
int32_t sequenceId = resultExtras.requestId;
int64_t frameNumber = resultExtras.frameNumber;
int32_t burstId = resultExtras.burstId;
- bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
+ bool isPartialResult = (resultExtras.partialResultCount < dev->mPartialResultCount);
if (!isPartialResult) {
ALOGV("SeqId %d frame %" PRId64 " result arrive.", sequenceId, frameNumber);
@@ -1686,7 +1673,7 @@
Mutex::Autolock _l(dev->mDeviceLock);
if (dev->mRemote == nullptr) {
- return ret; // device has been disconnected
+ return ScopedAStatus::ok(); // device has been disconnected
}
if (dev->isClosed()) {
@@ -1694,7 +1681,7 @@
dev->mFrameNumberTracker.updateTracker(frameNumber, /*isError*/false);
}
// early return to avoid callback sent to closed devices
- return ret;
+ return ScopedAStatus::ok();
}
CameraMetadata metadataCopy;
@@ -1702,11 +1689,12 @@
dev->mCaptureResultMetadataQueue.get(), &metadataCopy);
if (status != ACAMERA_OK) {
ALOGE("%s: result metadata couldn't be converted", __FUNCTION__);
- return ret;
+ return ScopedAStatus::ok();
}
- metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize, /*data_count*/2);
- metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /*data_count*/1);
+ metadataCopy.update(ANDROID_LENS_INFO_SHADING_MAP_SIZE, dev->mShadingMapSize,
+ /* data_count= */ 2);
+ metadataCopy.update(ANDROID_SYNC_FRAME_NUMBER, &frameNumber, /* data_count= */1);
auto it = dev->mSequenceCallbackMap.find(sequenceId);
if (it != dev->mSequenceCallbackMap.end()) {
@@ -1730,7 +1718,7 @@
&localPhysicalResult[i].physicalMetadata);
if (status != ACAMERA_OK) {
ALOGE("%s: physical camera result metadata couldn't be converted", __FUNCTION__);
- return ret;
+ return ScopedAStatus::ok();
}
}
sp<ACameraPhysicalCaptureResultInfo> physicalResult(
@@ -1762,17 +1750,14 @@
dev->checkAndFireSequenceCompleteLocked();
}
- return ret;
+ return ScopedAStatus::ok();
}
-android::hardware::Return<void>
-CameraDevice::ServiceCallback::onRepeatingRequestError(
- uint64_t lastFrameNumber, int32_t stoppedSequenceId) {
- auto ret = Void();
-
- sp<CameraDevice> dev = mDevice.promote();
+ScopedAStatus CameraDevice::ServiceCallback::onRepeatingRequestError(int64_t lastFrameNumber,
+ int32_t stoppedSequenceId) {
+ std::shared_ptr<CameraDevice> dev = mDevice.lock();
if (dev == nullptr) {
- return ret; // device has been closed
+ return ScopedAStatus::ok(); // device has been closed
}
Mutex::Autolock _l(dev->mDeviceLock);
@@ -1784,33 +1769,41 @@
dev->checkRepeatingSequenceCompleteLocked(repeatingSequenceId, lastFrameNumber);
- return ret;
+ return ScopedAStatus::ok();
}
camera_status_t CameraDevice::ServiceCallback::readOneResultMetadata(
- const FmqSizeOrMetadata& fmqSizeOrMetadata, ResultMetadataQueue* metadataQueue,
+ const CaptureMetadataInfo& captureMetadataInfo, ResultMetadataQueue* metadataQueue,
CameraMetadata* metadata) {
if (metadataQueue == nullptr || metadata == nullptr) {
return ACAMERA_ERROR_INVALID_PARAMETER;
}
bool converted;
- HCameraMetadata hCameraMetadata;
- if (fmqSizeOrMetadata.getDiscriminator() ==
- FmqSizeOrMetadata::hidl_discriminator::fmqMetadataSize) {
- hCameraMetadata.resize(fmqSizeOrMetadata.fmqMetadataSize());
- bool read = metadataQueue->read(
- hCameraMetadata.data(), fmqSizeOrMetadata.fmqMetadataSize());
+ AidlCameraMetadata aidlCameraMetadata;
+ std::vector<uint8_t>& metadataVec = aidlCameraMetadata.metadata;
+ camera_metadata_t* clonedMetadata;
+ if (captureMetadataInfo.getTag() == CaptureMetadataInfo::fmqMetadataSize) {
+ int64_t size = captureMetadataInfo.get<CaptureMetadataInfo::fmqMetadataSize>();
+ metadataVec.resize(size);
+ bool read = metadataQueue->read(reinterpret_cast<int8_t*>(metadataVec.data()), size);
if (!read) {
ALOGE("%s capture request settings could't be read from fmq", __FUNCTION__);
return ACAMERA_ERROR_UNKNOWN;
}
// TODO: Do we actually need to clone here ?
- converted = utils::convertFromHidlCloned(hCameraMetadata, metadata);
+ converted = utils::cloneFromAidl(aidlCameraMetadata, &clonedMetadata);
} else {
- converted = utils::convertFromHidlCloned(fmqSizeOrMetadata.metadata(), metadata);
+ const AidlCameraMetadata &embeddedMetadata =
+ captureMetadataInfo.get<CaptureMetadataInfo::metadata>();
+ converted = utils::cloneFromAidl(embeddedMetadata, &clonedMetadata);
}
- return converted ? ACAMERA_OK : ACAMERA_ERROR_UNKNOWN;
+ if (converted) {
+ *metadata = CameraMetadata(clonedMetadata);
+ return ACAMERA_OK;
+ }
+
+ return ACAMERA_ERROR_UNKNOWN;
}
} // namespace acam
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index c306206..cad23aa 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -16,54 +16,63 @@
#ifndef _ACAMERA_DEVICE_H
#define _ACAMERA_DEVICE_H
-#include <memory>
-#include <map>
-#include <set>
-#include <atomic>
-#include <utility>
-#include <vector>
-#include <utils/StrongPointer.h>
-#include <utils/Mutex.h>
-#include <utils/List.h>
-#include <utils/Vector.h>
-#include <android/frameworks/cameraservice/device/2.1/ICameraDeviceUser.h>
-#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceCallback.h>
-#include <android/frameworks/cameraservice/device/2.0/types.h>
-#include <fmq/MessageQueue.h>
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <camera/NdkCameraManager.h>
-#include <camera/NdkCameraCaptureSession.h>
-
#include "ACameraMetadata.h"
#include "utils.h"
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/device/BnCameraDeviceCallback.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureResultExtras.h>
+#include <aidl/android/frameworks/cameraservice/device/ErrorCode.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/ICameraDeviceUser.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCameraSettings.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCaptureResultInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/StreamConfigurationMode.h>
+#include <aidl/android/frameworks/cameraservice/device/SubmitInfo.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraStatusAndId.h>
+#include <atomic>
+#include <camera/NdkCameraCaptureSession.h>
+#include <camera/NdkCameraManager.h>
+#include <fmq/AidlMessageQueue.h>
+#include <fmq/MessageQueue.h>
+#include <map>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <memory>
+#include <set>
+#include <utility>
+#include <utils/List.h>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
+#include <utils/Vector.h>
+#include <vector>
+
namespace android {
namespace acam {
-using ICameraDeviceCallback = frameworks::cameraservice::device::V2_0::ICameraDeviceCallback;
-using ICameraDeviceUser_2_0 = frameworks::cameraservice::device::V2_0::ICameraDeviceUser;
-using ICameraDeviceUser = frameworks::cameraservice::device::V2_1::ICameraDeviceUser;
-using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
-using PhysicalCaptureResultInfo = frameworks::cameraservice::device::V2_0::PhysicalCaptureResultInfo;
-using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
-using SubmitInfo = frameworks::cameraservice::device::V2_0::SubmitInfo;
-using CaptureResultExtras = frameworks::cameraservice::device::V2_0::CaptureResultExtras;
-using ErrorCode = frameworks::cameraservice::device::V2_0::ErrorCode;
-using FmqSizeOrMetadata = frameworks::cameraservice::device::V2_0::FmqSizeOrMetadata;
-using StreamConfigurationMode = frameworks::cameraservice::device::V2_0::StreamConfigurationMode;
-using Status = frameworks::cameraservice::common::V2_0::Status;
-using ResultMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-using RequestMetadataQueue = hardware::MessageQueue<uint8_t, hardware::kSynchronizedReadWrite>;
-using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
+using ::aidl::android::frameworks::cameraservice::common::Status;
+using ::aidl::android::frameworks::cameraservice::device::BnCameraDeviceCallback;
+using ::aidl::android::frameworks::cameraservice::device::CaptureResultExtras;
+using ::aidl::android::frameworks::cameraservice::device::ErrorCode;
+using ::aidl::android::frameworks::cameraservice::device::CaptureMetadataInfo;
+using ::aidl::android::frameworks::cameraservice::device::ICameraDeviceCallback;
+using ::aidl::android::frameworks::cameraservice::device::ICameraDeviceUser;
+using ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
+using ::aidl::android::frameworks::cameraservice::device::PhysicalCameraSettings;
+using ::aidl::android::frameworks::cameraservice::device::PhysicalCaptureResultInfo;
+using ::aidl::android::frameworks::cameraservice::device::StreamConfigurationMode;
+using ::aidl::android::frameworks::cameraservice::device::SubmitInfo;
+using ::aidl::android::frameworks::cameraservice::service::CameraStatusAndId;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::acam::utils::native_handle_ptr_wrapper;
-using hardware::hidl_vec;
-using hardware::hidl_string;
-using utils::native_handle_ptr_wrapper;
+
+using ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using RequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
using utils::CaptureRequest;
-using utils::OutputConfigurationWrapper;
// Wrap ACameraCaptureFailure so it can be ref-counted
struct CameraCaptureFailure : public RefBase, public ACameraCaptureFailure { };
@@ -83,13 +92,16 @@
int64_t mFrameNumber;
};
-class CameraDevice final : public RefBase {
+class CameraDevice final : public std::enable_shared_from_this<CameraDevice> {
public:
CameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars,
ACameraDevice* wrapper);
~CameraDevice();
+ // Called to initialize fields that require shared_ptr to `this`
+ void init();
+
inline const char* getId() const { return mCameraId.c_str(); }
camera_status_t createCaptureRequest(
@@ -107,30 +119,35 @@
const ACaptureSessionOutputContainer* sessionOutputContainer) const;
// Callbacks from camera service
- class ServiceCallback : public ICameraDeviceCallback {
+ class ServiceCallback : public BnCameraDeviceCallback {
public:
- explicit ServiceCallback(CameraDevice* device) : mDevice(device) {}
- android::hardware::Return<void> onDeviceError(ErrorCode errorCode,
- const CaptureResultExtras& resultExtras) override;
- android::hardware::Return<void> onDeviceIdle() override;
- android::hardware::Return<void> onCaptureStarted(const CaptureResultExtras& resultExtras,
- uint64_t timestamp) override;
- android::hardware::Return<void> onResultReceived(const FmqSizeOrMetadata& result,
- const CaptureResultExtras& resultExtras,
- const hidl_vec<PhysicalCaptureResultInfo>& physicalResultInfos) override;
- android::hardware::Return<void> onRepeatingRequestError(uint64_t lastFrameNumber,
- int32_t stoppedSequenceId) override;
+ explicit ServiceCallback(std::weak_ptr<CameraDevice> device) :
+ mDevice(std::move(device)) {}
+
+ ndk::ScopedAStatus onDeviceError(ErrorCode in_errorCode,
+ const CaptureResultExtras& in_resultExtras) override;
+ ndk::ScopedAStatus onDeviceIdle() override;
+
+ ndk::ScopedAStatus onCaptureStarted(const CaptureResultExtras& in_resultExtras,
+ int64_t in_timestamp) override;
+ ndk::ScopedAStatus onRepeatingRequestError(int64_t in_lastFrameNumber,
+ int32_t in_repeatingRequestId) override;
+ ndk::ScopedAStatus onResultReceived(const CaptureMetadataInfo& in_result,
+ const CaptureResultExtras& in_resultExtras,
+ const std::vector<PhysicalCaptureResultInfo>&
+ in_physicalCaptureResultInfos) override;
+
private:
- camera_status_t readOneResultMetadata(const FmqSizeOrMetadata& fmqSizeOrMetadata,
+ camera_status_t readOneResultMetadata(const CaptureMetadataInfo& captureMetadataInfo,
ResultMetadataQueue* metadataQueue, CameraMetadata* metadata);
- const wp<CameraDevice> mDevice;
+ const std::weak_ptr<CameraDevice> mDevice;
};
- inline sp<ICameraDeviceCallback> getServiceCallback() {
+ inline std::shared_ptr<BnCameraDeviceCallback> getServiceCallback() {
return mServiceCallback;
};
// Camera device is only functional after remote being set
- void setRemoteDevice(sp<ICameraDeviceUser> remote);
+ void setRemoteDevice(std::shared_ptr<ICameraDeviceUser> remote);
bool setDeviceMetadataQueues();
inline ACameraDevice* getWrapper() const { return mWrapper; };
@@ -208,15 +225,15 @@
void postSessionMsgAndCleanup(sp<AMessage>& msg);
mutable Mutex mDeviceLock;
- const hidl_string mCameraId; // Camera ID
+ const std::string mCameraId; // Camera ID
const ACameraDevice_StateCallbacks mAppCallbacks; // Callback to app
const sp<ACameraMetadata> mChars; // Camera characteristics
- const sp<ServiceCallback> mServiceCallback;
+ std::shared_ptr<ServiceCallback> mServiceCallback;
ACameraDevice* mWrapper;
// stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
// camera service)
- std::map<int, std::pair<native_handle_ptr_wrapper, OutputConfigurationWrapper>> mConfiguredOutputs;
+ std::map<int, std::pair<native_handle_ptr_wrapper, OutputConfiguration>> mConfiguredOutputs;
// TODO: maybe a bool will suffice for synchronous implementation?
std::atomic_bool mClosing;
@@ -232,7 +249,7 @@
// This will avoid a busy session being deleted before it's back to idle state
sp<ACameraCaptureSession> mBusySession;
- sp<ICameraDeviceUser> mRemote;
+ std::shared_ptr<ICameraDeviceUser> mRemote;
// Looper thread to handle callback to app
sp<ALooper> mCbLooper;
@@ -281,7 +298,7 @@
// This handler will cache all capture session sp until kWhatCleanUpSessions
// is processed. This is used to guarantee the last session reference is always
// being removed in callback thread without holding camera device lock
- Vector<sp<ACameraCaptureSession>> mCachedSessions;
+ std::vector<sp<ACameraCaptureSession>> mCachedSessions;
};
sp<CallbackHandler> mHandler;
@@ -303,19 +320,19 @@
struct CallbackHolder {
CallbackHolder(sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest>>& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacks* cbs);
CallbackHolder(sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest>>& requests,
+ std::vector<sp<CaptureRequest>> requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacks* lcbs);
CallbackHolder(sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest> > requests,
bool isRepeating,
ACameraCaptureSession_captureCallbacksV2* cbs);
CallbackHolder(sp<ACameraCaptureSession> session,
- const Vector<sp<CaptureRequest> >& requests,
+ std::vector<sp<CaptureRequest> > requests,
bool isRepeating,
ACameraCaptureSession_logicalCamera_captureCallbacksV2* lcbs);
void clearCallbacks() {
@@ -359,7 +376,7 @@
}
sp<ACameraCaptureSession> mSession;
- Vector<sp<CaptureRequest>> mRequests;
+ std::vector<sp<CaptureRequest>> mRequests;
const bool mIsRepeating;
const bool mIs2Callback;
const bool mIsLogicalCameraCallback;
@@ -401,7 +418,7 @@
// Misc variables
int32_t mShadingMapSize[2]; // const after constructor
int32_t mPartialResultCount; // const after constructor
- std::shared_ptr<ResultMetadataQueue> mCaptureRequestMetadataQueue = nullptr;
+ std::shared_ptr<RequestMetadataQueue> mCaptureRequestMetadataQueue = nullptr;
std::shared_ptr<ResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
};
@@ -415,7 +432,10 @@
struct ACameraDevice {
ACameraDevice(const char* id, ACameraDevice_StateCallbacks* cb,
sp<ACameraMetadata> chars) :
- mDevice(new android::acam::CameraDevice(id, cb, std::move(chars), this)) {}
+ mDevice(std::make_shared<android::acam::CameraDevice>(id, cb,
+ std::move(chars), this)) {
+ mDevice->init();
+ }
~ACameraDevice();
/*******************
@@ -446,19 +466,20 @@
/***********************
* Device interal APIs *
***********************/
- inline android::sp<android::acam::ICameraDeviceCallback> getServiceCallback() {
+ inline std::shared_ptr<android::acam::BnCameraDeviceCallback> getServiceCallback() {
return mDevice->getServiceCallback();
};
// Camera device is only functional after remote being set
- inline void setRemoteDevice(android::sp<android::acam::ICameraDeviceUser> remote) {
+ inline void setRemoteDevice(std::shared_ptr<
+ ::aidl::android::frameworks::cameraservice::device::ICameraDeviceUser> remote) {
mDevice->setRemoteDevice(remote);
}
inline bool setDeviceMetadataQueues() {
return mDevice->setDeviceMetadataQueues();
}
private:
- android::sp<android::acam::CameraDevice> mDevice;
+ std::shared_ptr<android::acam::CameraDevice> mDevice;
};
#endif // _ACAMERA_DEVICE_H
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
index 8bd5a52..1e724eb 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
+++ b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
@@ -14,17 +14,14 @@
* limitations under the License.
*/
-#include <vector>
-#include <inttypes.h>
-#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
-#include <android/frameworks/cameraservice/device/2.0/types.h>
-#include <CameraMetadata.h>
-
-#include "ndk_vendor/impl/ACameraDevice.h"
#include "ACameraCaptureSession.h"
#include "ACameraMetadata.h"
#include "ACaptureRequest.h"
#include "utils.h"
+#include <CameraMetadata.h>
+#include <inttypes.h>
+#include <ndk_vendor/impl/ACameraDevice.h>
+#include <vector>
using namespace android;
@@ -32,22 +29,22 @@
namespace acam {
template<class T>
-camera_status_t
-CameraDevice::captureLocked(
+camera_status_t CameraDevice::captureLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
- int numRequests, ACaptureRequest** requests,
+ int numRequests,
+ ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/false);
}
template<class T>
-camera_status_t
-CameraDevice::setRepeatingRequestsLocked(
+camera_status_t CameraDevice::setRepeatingRequestsLocked(
sp<ACameraCaptureSession> session,
/*optional*/T* cbs,
- int numRequests, ACaptureRequest** requests,
+ int numRequests,
+ ACaptureRequest** requests,
/*optional*/int* captureSequenceId) {
return submitRequestsLocked(
session, cbs, numRequests, requests, captureSequenceId, /*isRepeating*/true);
@@ -56,11 +53,10 @@
template<class T>
camera_status_t CameraDevice::submitRequestsLocked(
sp<ACameraCaptureSession> session,
- /*optional*/T* cbs,
- int numRequests, ACaptureRequest** requests,
+ /*optional*/T* cbs, int numRequests,
+ ACaptureRequest** requests,
/*out*/int* captureSequenceId,
- bool isRepeating)
-{
+ bool isRepeating) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
ALOGE("Camera %s submit capture request failed! ret %d", getId(), ret);
@@ -68,9 +64,10 @@
}
// Form two vectors of capture request, one for internal tracking
- std::vector<frameworks::cameraservice::device::V2_0::CaptureRequest> requestList;
- Vector<sp<CaptureRequest>> requestsV;
- requestsV.setCapacity(numRequests);
+
+ std::vector<::aidl::android::frameworks::cameraservice::device::CaptureRequest> requestList;
+ std::vector<sp<CaptureRequest>> requestsV;
+ requestsV.reserve(numRequests);
for (int i = 0; i < numRequests; i++) {
sp<CaptureRequest> req;
ret = allocateCaptureRequestLocked(requests[i], req);
@@ -87,7 +84,7 @@
ALOGE("Capture request without output target cannot be submitted!");
return ACAMERA_ERROR_INVALID_PARAMETER;
}
- requestList.push_back(utils::convertToHidl(req.get()));
+ requestList.push_back(utils::convertToAidl(req.get()));
requestsV.push_back(req);
}
if (isRepeating) {
@@ -100,18 +97,20 @@
SubmitInfo info;
Status status;
- auto remoteRet = mRemote->submitRequestList(requestList, isRepeating,
- [&status, &info](auto s, auto &submitInfo) {
- status = s;
- info = submitInfo;
- });
- if (!remoteRet.isOk()) {
- ALOGE("%s: Transaction error for submitRequestList call: %s", __FUNCTION__,
- remoteRet.description().c_str());
+ ndk::ScopedAStatus remoteRet = mRemote->submitRequestList(requestList, isRepeating, &info);
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: submitRequestList call failed: %s",
+ __FUNCTION__, toString(errStatus).c_str());
+ return utils::convertFromAidl(errStatus);
+ } else {
+ ALOGE("%s: Transaction error for submitRequestList call: %d", __FUNCTION__,
+ remoteRet.getExceptionCode());
+ return ACAMERA_ERROR_UNKNOWN;
+ }
}
- if (status != Status::NO_ERROR) {
- return utils::convertFromHidl(status);
- }
+
int32_t sequenceId = info.requestId;
int64_t lastFrameNumber = info.lastFrameNumber;
if (sequenceId < 0) {
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index bb4ef56..3aa7817 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -17,28 +17,29 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ACameraManagerVendor"
-#include <memory>
-#include "ndk_vendor/impl/ACameraManager.h"
#include "ACameraMetadata.h"
#include "ndk_vendor/impl/ACameraDevice.h"
+#include "ndk_vendor/impl/ACameraManager.h"
#include "utils.h"
+
#include <CameraMetadata.h>
-#include <camera_metadata_hidden.h>
-
-#include <utils/Vector.h>
-#include <cutils/properties.h>
-#include <stdlib.h>
-
#include <VendorTagDescriptor.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+#include <camera_metadata_hidden.h>
+#include <cutils/properties.h>
+#include <memory>
+#include <utils/Vector.h>
using namespace android::acam;
namespace android {
namespace acam {
-using frameworks::cameraservice::common::V2_0::ProviderIdAndVendorTagSections;
-using android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
-using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+using ::aidl::android::frameworks::cameraservice::common::ProviderIdAndVendorTagSections;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptor;
+using ::android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
+using ::ndk::ScopedAStatus;
// Static member definitions
const char* CameraManagerGlobal::kCameraIdKey = "CameraId";
@@ -47,52 +48,55 @@
const char* CameraManagerGlobal::kContextKey = "CallbackContext";
const nsecs_t CameraManagerGlobal::kCallbackDrainTimeout = 5000000; // 5 ms
Mutex CameraManagerGlobal::sLock;
-CameraManagerGlobal* CameraManagerGlobal::sInstance = nullptr;
+std::weak_ptr<CameraManagerGlobal> CameraManagerGlobal::sInstance =
+ std::weak_ptr<CameraManagerGlobal>();
/**
- * The vendor tag descriptor class that takes HIDL vendor tag information as
+ * The vendor tag descriptor class that takes AIDL vendor tag information as
* input. Not part of vendor available VendorTagDescriptor class because that class is used by
* default HAL implementation code as well.
+ *
+ * This is a class instead of a free-standing function because VendorTagDescriptor has some
+ * protected fields that need to be initialized during conversion.
*/
-class HidlVendorTagDescriptor : public VendorTagDescriptor {
+class AidlVendorTagDescriptor : public VendorTagDescriptor {
public:
/**
- * Create a VendorTagDescriptor object from the HIDL VendorTagSection
+ * Create a VendorTagDescriptor object from the AIDL VendorTagSection
* vector.
*
* Returns OK on success, or a negative error code.
*/
- static status_t createDescriptorFromHidl(const hidl_vec<VendorTagSection>& vts,
+ static status_t createDescriptorFromAidl(const std::vector<VendorTagSection>& vts,
/*out*/ sp<VendorTagDescriptor> *descriptor);
};
-status_t HidlVendorTagDescriptor::createDescriptorFromHidl(const hidl_vec<VendorTagSection> &vts,
- sp<VendorTagDescriptor> *descriptor) {
- int tagCount = 0;
+status_t AidlVendorTagDescriptor::createDescriptorFromAidl(const std::vector<VendorTagSection>& vts,
+ sp<VendorTagDescriptor>* descriptor){
+ size_t tagCount = 0;
for (size_t s = 0; s < vts.size(); s++) {
tagCount += vts[s].tags.size();
}
if (tagCount < 0 || tagCount > INT32_MAX) {
- ALOGE("%s: tag count %d from vendor tag sections is invalid.", __FUNCTION__, tagCount);
+ ALOGE("%s: tag count %zu from vendor tag sections is invalid.", __FUNCTION__, tagCount);
return BAD_VALUE;
}
- Vector<uint32_t> tagArray;
- LOG_ALWAYS_FATAL_IF(tagArray.resize(tagCount) != tagCount,
- "%s: too many (%u) vendor tags defined.", __FUNCTION__, tagCount);
+ std::vector<int64_t> tagArray;
+ tagArray.resize(tagCount);
- sp<HidlVendorTagDescriptor> desc = new HidlVendorTagDescriptor();
+ sp<AidlVendorTagDescriptor> desc = new AidlVendorTagDescriptor();
desc->mTagCount = tagCount;
- KeyedVector<uint32_t, String8> tagToSectionMap;
+ std::map<int64_t, std::string> tagToSectionMap;
int idx = 0;
for (size_t s = 0; s < vts.size(); s++) {
const VendorTagSection& section = vts[s];
const char *sectionName = section.sectionName.c_str();
- if (sectionName == NULL) {
+ if (sectionName == nullptr) {
ALOGE("%s: no section name defined for vendor tag section %zu.", __FUNCTION__, s);
return BAD_VALUE;
}
@@ -106,15 +110,15 @@
return BAD_VALUE;
}
- tagArray.editItemAt(idx++) = section.tags[j].tagId;
+ tagArray[idx++] = section.tags[j].tagId;
const char *tagName = section.tags[j].tagName.c_str();
- if (tagName == NULL) {
+ if (tagName == nullptr) {
ALOGE("%s: no tag name defined for vendor tag %d.", __FUNCTION__, tag);
return BAD_VALUE;
}
desc->mTagToNameMap.add(tag, String8(tagName));
- tagToSectionMap.add(tag, sectionString);
+ tagToSectionMap.insert({tag, section.sectionName});
int tagType = (int) section.tags[j].tagType;
if (tagType < 0 || tagType >= NUM_TYPES) {
@@ -127,8 +131,12 @@
for (size_t i = 0; i < tagArray.size(); ++i) {
uint32_t tag = tagArray[i];
- String8 sectionString = tagToSectionMap.valueFor(tag);
-
+ auto itr = tagToSectionMap.find(tag);
+ if (itr == tagToSectionMap.end()) {
+ ALOGE("%s: Couldn't find previously added tag in map.", __FUNCTION__);
+ return UNKNOWN_ERROR;
+ }
+ String8 sectionString = String8(itr->second.c_str());
// Set up tag to section index map
ssize_t index = desc->mSections.indexOf(sectionString);
LOG_ALWAYS_FATAL_IF(index < 0, "index %zd must be non-negative", index);
@@ -147,38 +155,37 @@
return OK;
}
-CameraManagerGlobal&
-CameraManagerGlobal::getInstance() {
+std::shared_ptr<CameraManagerGlobal> CameraManagerGlobal::getInstance() {
Mutex::Autolock _l(sLock);
- CameraManagerGlobal* instance = sInstance;
+ std::shared_ptr<CameraManagerGlobal> instance = sInstance.lock();
if (instance == nullptr) {
- instance = new CameraManagerGlobal();
+ instance = std::make_shared<CameraManagerGlobal>();
sInstance = instance;
}
- return *instance;
+ return instance;
}
CameraManagerGlobal::~CameraManagerGlobal() {
- // clear sInstance so next getInstance call knows to create a new one
Mutex::Autolock _sl(sLock);
- sInstance = nullptr;
Mutex::Autolock _l(mLock);
if (mCameraService != nullptr) {
- mCameraService->unlinkToDeath(mDeathNotifier);
+ AIBinder_unlinkToDeath(mCameraService->asBinder().get(),
+ mDeathRecipient.get(), this);
auto stat = mCameraService->removeListener(mCameraServiceListener);
if (!stat.isOk()) {
- ALOGE("Failed to remove listener to camera service %s", stat.description().c_str());
+ ALOGE("Failed to remove listener to camera service %d:%d", stat.getExceptionCode(),
+ stat.getServiceSpecificError());
}
}
- mDeathNotifier.clear();
+
if (mCbLooper != nullptr) {
mCbLooper->unregisterHandler(mHandler->id());
mCbLooper->stop();
}
mCbLooper.clear();
mHandler.clear();
- mCameraServiceListener.clear();
- mCameraService.clear();
+ mCameraServiceListener.reset();
+ mCameraService.reset();
}
static bool isCameraServiceDisabled() {
@@ -191,23 +198,28 @@
sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
Status status = Status::NO_ERROR;
std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
- auto remoteRet = mCameraService->getCameraVendorTagSections([&status, &providerIdsAndVts]
- (Status s,
- auto &IdsAndVts) {
- status = s;
- providerIdsAndVts = IdsAndVts; });
+ ScopedAStatus remoteRet = mCameraService->getCameraVendorTagSections(&providerIdsAndVts);
- if (!remoteRet.isOk() || status != Status::NO_ERROR) {
- ALOGE("Failed to retrieve VendorTagSections %s", remoteRet.description().c_str());
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: Failed to retrieve VendorTagSections %s",
+ __FUNCTION__, toString(status).c_str());
+ } else {
+ ALOGE("%s: Binder error when retrieving VendorTagSections: %d", __FUNCTION__,
+ remoteRet.getExceptionCode());
+ }
return false;
}
+
// Convert each providers VendorTagSections into a VendorTagDescriptor and
// add it to the cache
for (auto &providerIdAndVts : providerIdsAndVts) {
sp<VendorTagDescriptor> vendorTagDescriptor;
- if (HidlVendorTagDescriptor::createDescriptorFromHidl(providerIdAndVts.vendorTagSections,
- &vendorTagDescriptor) != OK) {
- ALOGE("Failed to convert from Hidl: VendorTagDescriptor");
+ status_t ret = AidlVendorTagDescriptor::createDescriptorFromAidl(
+ providerIdAndVts.vendorTagSections, &vendorTagDescriptor);
+ if (ret != OK) {
+ ALOGE("Failed to convert from Aidl: VendorTagDescriptor: %d", ret);
return false;
}
tagCache->addVendorDescriptor(providerIdAndVts.providerId, vendorTagDescriptor);
@@ -216,101 +228,125 @@
return true;
}
-sp<ICameraService> CameraManagerGlobal::getCameraService() {
+std::shared_ptr<ICameraService> CameraManagerGlobal::getCameraService() {
Mutex::Autolock _l(mLock);
- if (mCameraService.get() == nullptr) {
- if (isCameraServiceDisabled()) {
- return mCameraService;
- }
- sp<ICameraService> cameraServiceBinder;
- do {
- cameraServiceBinder = ICameraService::getService();
- if (cameraServiceBinder != nullptr) {
- break;
- }
- ALOGW("CameraService not published, waiting...");
- usleep(kCameraServicePollDelay);
- } while(true);
- if (mDeathNotifier == nullptr) {
- mDeathNotifier = new DeathNotifier(this);
- }
- cameraServiceBinder->linkToDeath(mDeathNotifier, 0);
- mCameraService = cameraServiceBinder;
+ if (mCameraService != nullptr) {
+ // Camera service already set up. Return existing value.
+ return mCameraService;
+ }
- // Setup looper thread to perfrom availiability callbacks
- if (mCbLooper == nullptr) {
- mCbLooper = new ALooper;
- mCbLooper->setName("C2N-mgr-looper");
- status_t err = mCbLooper->start(
- /*runOnCallingThread*/false,
- /*canCallJava*/ true,
- PRIORITY_DEFAULT);
- if (err != OK) {
- ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- mCbLooper.clear();
- return nullptr;
- }
- if (mHandler == nullptr) {
- mHandler = new CallbackHandler(this);
- }
- mCbLooper->registerHandler(mHandler);
- }
+ if (isCameraServiceDisabled()) {
+ // Camera service is disabled. return nullptr.
+ return mCameraService;
+ }
- // register ICameraServiceListener
- if (mCameraServiceListener == nullptr) {
- mCameraServiceListener = new CameraServiceListener(this);
- }
- hidl_vec<frameworks::cameraservice::service::V2_1::CameraStatusAndId> cameraStatuses{};
- Status status = Status::NO_ERROR;
- auto remoteRet = mCameraService->addListener_2_1(mCameraServiceListener,
- [&status, &cameraStatuses](Status s,
- auto &retStatuses) {
- status = s;
- cameraStatuses = retStatuses;
- });
- if (!remoteRet.isOk() || status != Status::NO_ERROR) {
- ALOGE("Failed to add listener to camera service %s", remoteRet.description().c_str());
- }
+ std::string serviceName = ICameraService::descriptor;
+ serviceName += "/default";
- // Setup vendor tags
- if (!setupVendorTags()) {
- ALOGE("Unable to set up vendor tags");
+ bool isDeclared = AServiceManager_isDeclared(serviceName.c_str());
+ if (!isDeclared) {
+ ALOGE("%s: No ICameraService instance declared: %s", __FUNCTION__, serviceName.c_str());
+ return nullptr;
+ }
+
+ // Before doing any more make sure there is a binder threadpool alive
+ // This is a no-op if the binder threadpool was already started by this process.
+ ABinderProcess_startThreadPool();
+
+ std::shared_ptr<ICameraService> cameraService =
+ ICameraService::fromBinder(ndk::SpAIBinder(
+ AServiceManager_waitForService(serviceName.c_str())));
+ if (cameraService == nullptr) {
+ ALOGE("%s: Could not get ICameraService instance.", __FUNCTION__);
+ return nullptr;
+ }
+
+ if (mDeathRecipient.get() == nullptr) {
+ mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(CameraManagerGlobal::binderDeathCallback));
+ }
+ AIBinder_linkToDeath(cameraService->asBinder().get(),
+ mDeathRecipient.get(), /*cookie=*/ this);
+
+ mCameraService = cameraService;
+
+ // Setup looper thread to perform availability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ mCbLooper.clear();
return nullptr;
}
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler(weak_from_this());
+ }
+ mCbLooper->registerHandler(mHandler);
+ }
- for (auto& c : cameraStatuses) {
- onStatusChangedLocked(c.v2_0);
+ // register ICameraServiceListener
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = ndk::SharedRefBase::make<CameraServiceListener>(weak_from_this());
+ }
- for (auto& unavailablePhysicalId : c.unavailPhysicalCameraIds) {
- PhysicalCameraStatusAndId statusAndId;
- statusAndId.deviceStatus = CameraDeviceStatus::STATUS_NOT_PRESENT;
- statusAndId.cameraId = c.v2_0.cameraId;
- statusAndId.physicalCameraId = unavailablePhysicalId;
- onStatusChangedLocked(statusAndId);
- }
+ std::vector<CameraStatusAndId> cameraStatuses;
+ Status status = Status::NO_ERROR;
+ ScopedAStatus remoteRet = mCameraService->addListener(mCameraServiceListener,
+ &cameraStatuses);
+
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: Failed to add listener to camera service: %s", __FUNCTION__,
+ toString(errStatus).c_str());
+ } else {
+ ALOGE("%s: Transaction failed when adding listener to camera service: %d",
+ __FUNCTION__, remoteRet.getExceptionCode());
+ }
+ }
+
+ // Setup vendor tags
+ if (!setupVendorTags()) {
+ ALOGE("Unable to set up vendor tags");
+ return nullptr;
+ }
+
+ for (auto& csi: cameraStatuses){
+ onStatusChangedLocked(csi.deviceStatus, csi.cameraId);
+
+ for (auto& unavailablePhysicalId : csi.unavailPhysicalCameraIds) {
+ onStatusChangedLocked(CameraDeviceStatus::STATUS_NOT_PRESENT,
+ csi.cameraId, unavailablePhysicalId);
}
}
return mCameraService;
}
-void CameraManagerGlobal::DeathNotifier::serviceDied(uint64_t cookie, const wp<IBase> &who) {
- (void) cookie;
- (void) who;
+void CameraManagerGlobal::binderDeathCallback(void* /*cookie*/) {
+ AutoMutex _l(sLock);
+
ALOGE("Camera service binderDied!");
- sp<CameraManagerGlobal> cm = mCameraManager.promote();
- if (cm != nullptr) {
- AutoMutex lock(cm->mLock);
- for (auto& pair : cm->mDeviceStatusMap) {
- CameraStatusAndId cameraStatusAndId;
- cameraStatusAndId.cameraId = pair.first;
- cameraStatusAndId.deviceStatus = pair.second.getStatus();
- cm->onStatusChangedLocked(cameraStatusAndId);
- }
- cm->mCameraService.clear();
- // TODO: consider adding re-connect call here?
+ std::shared_ptr<CameraManagerGlobal> instance = sInstance.lock();
+ if (instance == nullptr) {
+ return;
}
+
+ // Remove cameraService from the static instance
+ AutoMutex lock(instance->mLock);
+ for (auto& pair : instance->mDeviceStatusMap) {
+ const auto &cameraId = pair.first;
+ const auto &deviceStatus = pair.second.getStatus();
+ instance->onStatusChangedLocked(deviceStatus, cameraId);
+ }
+ instance->mCameraService.reset();
+ // TODO: consider adding re-connect call here?
}
void CameraManagerGlobal::registerAvailabilityCallback(
@@ -362,41 +398,45 @@
void CameraManagerGlobal::registerAvailCallback(const T *callback) {
Mutex::Autolock _l(mLock);
Callback cb(callback);
- auto pair = mCallbacks.insert(cb);
+ auto res = mCallbacks.insert(cb);
+ if (!res.second) {
+ ALOGE("%s: Failed to register callback. Couldn't insert in map.", __FUNCTION__);
+ return;
+ }
// Send initial callbacks if callback is newly registered
- if (pair.second) {
- for (auto& pair : mDeviceStatusMap) {
- const hidl_string& cameraId = pair.first;
- CameraDeviceStatus status = pair.second.getStatus();
+ for (auto& pair : mDeviceStatusMap) {
+ const std::string& cameraId = pair.first;
+ CameraDeviceStatus status = pair.second.getStatus();
+ {
// Camera available/unavailable callback
sp<AMessage> msg = new AMessage(kWhatSendSingleCallback, mHandler);
ACameraManager_AvailabilityCallback cbFunc = isStatusAvailable(status) ?
- cb.mAvailable : cb.mUnavailable;
+ cb.mAvailable : cb.mUnavailable;
msg->setPointer(kCallbackFpKey, (void *) cbFunc);
msg->setPointer(kContextKey, cb.mContext);
msg->setString(kCameraIdKey, AString(cameraId.c_str()));
mPendingCallbackCnt++;
msg->post();
+ }
- // Physical camera unavailable callback
- std::set<hidl_string> unavailPhysicalIds = pair.second.getUnavailablePhysicalIds();
- for (const auto& physicalCameraId : unavailPhysicalIds) {
- sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
- ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
- cb.mPhysicalCamUnavailable;
- msg->setPointer(kCallbackFpKey, (void *) cbFunc);
- msg->setPointer(kContextKey, cb.mContext);
- msg->setString(kCameraIdKey, AString(cameraId.c_str()));
- msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
- mPendingCallbackCnt++;
- msg->post();
- }
+ // Physical camera unavailable callback
+ std::set<std::string> unavailPhysicalIds = pair.second.getUnavailablePhysicalIds();
+ for (const auto& physicalCameraId : unavailPhysicalIds) {
+ sp<AMessage> msg = new AMessage(kWhatSendSinglePhysicalCameraCallback, mHandler);
+ ACameraManager_PhysicalCameraAvailabilityCallback cbFunc =
+ cb.mPhysicalCamUnavailable;
+ msg->setPointer(kCallbackFpKey, (void *) cbFunc);
+ msg->setPointer(kContextKey, cb.mContext);
+ msg->setString(kCameraIdKey, AString(cameraId.c_str()));
+ msg->setString(kPhysicalCameraIdKey, AString(physicalCameraId.c_str()));
+ mPendingCallbackCnt++;
+ msg->post();
}
}
}
-void CameraManagerGlobal::getCameraIdList(std::vector<hidl_string>* cameraIds) {
+void CameraManagerGlobal::getCameraIdList(std::vector<std::string>* cameraIds) {
// Ensure that we have initialized/refreshed the list of available devices
auto cs = getCameraService();
Mutex::Autolock _l(mLock);
@@ -507,33 +547,31 @@
}
void CameraManagerGlobal::CallbackHandler::notifyParent() {
- sp<CameraManagerGlobal> parent = mParent.promote();
+ std::shared_ptr<CameraManagerGlobal> parent = mParent.lock();
if (parent != nullptr) {
parent->onCallbackCalled();
}
}
-hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onStatusChanged(
- const CameraStatusAndId &statusAndId) {
- sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ScopedAStatus CameraManagerGlobal::CameraServiceListener::onStatusChanged(
+ CameraDeviceStatus status, const std::string &cameraId) {
+ std::shared_ptr<CameraManagerGlobal> cm = mCameraManager.lock();
if (cm != nullptr) {
- cm->onStatusChanged(statusAndId);
+ cm->onStatusChanged(status, cameraId);
} else {
ALOGE("Cannot deliver status change. Global camera manager died");
}
- return Void();
+ return ScopedAStatus::ok();
}
void CameraManagerGlobal::onStatusChanged(
- const CameraStatusAndId &statusAndId) {
+ const CameraDeviceStatus &status, const std::string &cameraId) {
Mutex::Autolock _l(mLock);
- onStatusChangedLocked(statusAndId);
+ onStatusChangedLocked(status, cameraId);
}
void CameraManagerGlobal::onStatusChangedLocked(
- const CameraStatusAndId &statusAndId) {
- hidl_string cameraId = statusAndId.cameraId;
- CameraDeviceStatus status = statusAndId.deviceStatus;
+ const CameraDeviceStatus &status, const std::string &cameraId) {
if (!validStatus(status)) {
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
return;
@@ -567,28 +605,28 @@
}
}
-hardware::Return<void> CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
- const PhysicalCameraStatusAndId &statusAndId) {
- sp<CameraManagerGlobal> cm = mCameraManager.promote();
+ScopedAStatus CameraManagerGlobal::CameraServiceListener::onPhysicalCameraStatusChanged(
+ CameraDeviceStatus in_status, const std::string& in_cameraId,
+ const std::string& in_physicalCameraId) {
+ std::shared_ptr<CameraManagerGlobal> cm = mCameraManager.lock();
if (cm != nullptr) {
- cm->onStatusChanged(statusAndId);
+ cm->onStatusChanged(in_status, in_cameraId, in_physicalCameraId);
} else {
ALOGE("Cannot deliver status change. Global camera manager died");
}
- return Void();
+ return ScopedAStatus::ok();
}
void CameraManagerGlobal::onStatusChanged(
- const PhysicalCameraStatusAndId &statusAndId) {
+ const CameraDeviceStatus &status, const std::string& cameraId,
+ const std::string& physicalCameraId) {
Mutex::Autolock _l(mLock);
- onStatusChangedLocked(statusAndId);
+ onStatusChangedLocked(status, cameraId, physicalCameraId);
}
void CameraManagerGlobal::onStatusChangedLocked(
- const PhysicalCameraStatusAndId &statusAndId) {
- hidl_string cameraId = statusAndId.cameraId;
- hidl_string physicalCameraId = statusAndId.physicalCameraId;
- CameraDeviceStatus status = statusAndId.deviceStatus;
+ const CameraDeviceStatus &status, const std::string& cameraId,
+ const std::string& physicalCameraId) {
if (!validStatus(status)) {
ALOGE("%s: Invalid status %d", __FUNCTION__, status);
return;
@@ -642,20 +680,20 @@
}
bool CameraManagerGlobal::CameraStatus::addUnavailablePhysicalId(
- const hidl_string& physicalCameraId) {
+ const std::string& physicalCameraId) {
std::lock_guard<std::mutex> lock(mLock);
auto result = unavailablePhysicalIds.insert(physicalCameraId);
return result.second;
}
bool CameraManagerGlobal::CameraStatus::removeUnavailablePhysicalId(
- const hidl_string& physicalCameraId) {
+ const std::string& physicalCameraId) {
std::lock_guard<std::mutex> lock(mLock);
auto count = unavailablePhysicalIds.erase(physicalCameraId);
return count > 0;
}
-std::set<hidl_string> CameraManagerGlobal::CameraStatus::getUnavailablePhysicalIds() {
+std::set<std::string> CameraManagerGlobal::CameraStatus::getUnavailablePhysicalIds() {
std::lock_guard<std::mutex> lock(mLock);
return unavailablePhysicalIds;
}
@@ -666,16 +704,15 @@
/**
* ACameraManger Implementation
*/
-camera_status_t
-ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
+camera_status_t ACameraManager::getCameraIdList(ACameraIdList** cameraIdList) {
Mutex::Autolock _l(mLock);
- std::vector<hidl_string> idList;
- CameraManagerGlobal::getInstance().getCameraIdList(&idList);
+ std::vector<std::string> idList;
+ CameraManagerGlobal::getInstance()->getCameraIdList(&idList);
int numCameras = idList.size();
ACameraIdList *out = new ACameraIdList;
- if (!out) {
+ if (out == nullptr) {
ALOGE("Allocate memory for ACameraIdList failed!");
return ACAMERA_ERROR_NOT_ENOUGH_MEMORY;
}
@@ -717,33 +754,37 @@
}
}
-camera_status_t ACameraManager::getCameraCharacteristics(
- const char *cameraIdStr, sp<ACameraMetadata> *characteristics) {
+camera_status_t ACameraManager::getCameraCharacteristics(const char *cameraIdStr,
+ sp<ACameraMetadata> *characteristics) {
+ using AidlCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
Mutex::Autolock _l(mLock);
- sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ std::shared_ptr<ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
- CameraMetadata rawMetadata;
- Status status = Status::NO_ERROR;
- auto serviceRet =
- cs->getCameraCharacteristics(cameraIdStr,
- [&status, &rawMetadata] (auto s ,
- const hidl_vec<uint8_t> &metadata) {
- status = s;
- if (status == Status::NO_ERROR) {
- utils::convertFromHidlCloned(metadata, &rawMetadata);
- }
- });
- if (!serviceRet.isOk() || status != Status::NO_ERROR) {
- ALOGE("Get camera characteristics from camera service failed");
+ AidlCameraMetadata rawMetadata;
+ ScopedAStatus serviceRet = cs->getCameraCharacteristics(cameraIdStr, &rawMetadata);
+
+ if (!serviceRet.isOk()) {
+ if (serviceRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(serviceRet.getServiceSpecificError());
+ ALOGE("%s: Get camera characteristics from camera service failed: %s",
+ __FUNCTION__, toString(errStatus).c_str());
+ } else {
+ ALOGE("%s: Transaction error when getting camera "
+ "characteristics from camera service: %d",
+ __FUNCTION__, serviceRet.getExceptionCode());
+ }
return ACAMERA_ERROR_UNKNOWN; // should not reach here
}
- *characteristics = new ACameraMetadata(
- rawMetadata.release(), ACameraMetadata::ACM_CHARACTERISTICS);
+ camera_metadata_t* metadataBuffer;
+ ::android::acam::utils::cloneFromAidl(rawMetadata, &metadataBuffer);
+
+ *characteristics = new ACameraMetadata(metadataBuffer,
+ ACameraMetadata::ACM_CHARACTERISTICS);
return ACAMERA_OK;
}
@@ -763,42 +804,41 @@
ACameraDevice* device = new ACameraDevice(cameraId, callback, std::move(rawChars));
- sp<ICameraService> cs = CameraManagerGlobal::getInstance().getCameraService();
+ std::shared_ptr<ICameraService> cs = CameraManagerGlobal::getInstance()->getCameraService();
if (cs == nullptr) {
ALOGE("%s: Cannot reach camera service!", __FUNCTION__);
delete device;
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
- sp<ICameraDeviceCallback> callbacks = device->getServiceCallback();
- sp<ICameraDeviceUser_2_0> deviceRemote_2_0;
+ std::shared_ptr<BnCameraDeviceCallback> deviceCallback = device->getServiceCallback();
+ std::shared_ptr<ICameraDeviceUser> deviceRemote;
// No way to get package name from native.
// Send a zero length package name and let camera service figure it out from UID
- Status status = Status::NO_ERROR;
- auto serviceRet = cs->connectDevice(
- callbacks, cameraId, [&status, &deviceRemote_2_0](auto s, auto &device) {
- status = s;
- deviceRemote_2_0 = device;
- });
-
- if (!serviceRet.isOk() || status != Status::NO_ERROR) {
- ALOGE("%s: connect camera device failed", __FUNCTION__);
- delete device;
- return utils::convertFromHidl(status);
+ ScopedAStatus serviceRet = cs->connectDevice(deviceCallback,
+ std::string(cameraId), &deviceRemote);
+ if (!serviceRet.isOk()) {
+ if (serviceRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(serviceRet.getServiceSpecificError());
+ ALOGE("%s: connect camera device failed: %s",
+ __FUNCTION__, toString(errStatus).c_str());
+ delete device;
+ return utils::convertFromAidl(errStatus);
+ } else {
+ ALOGE("%s: Transaction failed when connecting camera device: %d",
+ __FUNCTION__, serviceRet.getExceptionCode());
+ delete device;
+ return ACAMERA_ERROR_UNKNOWN;
+ }
}
- if (deviceRemote_2_0 == nullptr) {
+
+ if (deviceRemote == nullptr) {
ALOGE("%s: connect camera device failed! remote device is null", __FUNCTION__);
delete device;
return ACAMERA_ERROR_CAMERA_DISCONNECTED;
}
- auto castResult = ICameraDeviceUser::castFrom(deviceRemote_2_0);
- if (!castResult.isOk()) {
- ALOGE("%s: failed to cast remote device to version 2.1", __FUNCTION__);
- delete device;
- return ACAMERA_ERROR_CAMERA_DISCONNECTED;
- }
- sp<ICameraDeviceUser> deviceRemote = castResult;
+
device->setRemoteDevice(deviceRemote);
device->setDeviceMetadataQueues();
*outDevice = device;
@@ -821,7 +861,7 @@
sp<VendorTagDescriptorCache> vtCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
sp<VendorTagDescriptor> vTags = nullptr;
vtCache->getVendorTagDescriptor(vendorTagId, &vTags);
- status_t status= metadata.getTagFromName(name, vTags.get(), tag);
+ status_t status = CameraMetadata::getTagFromName(name, vTags.get(), tag);
return status == OK ? ACAMERA_OK : ACAMERA_ERROR_METADATA_NOT_FOUND;
}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 4663529..85acee7 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -17,39 +17,35 @@
#ifndef _ACAMERA_MANAGER_H
#define _ACAMERA_MANAGER_H
-#include <camera/NdkCameraManager.h>
-
-#include <android-base/parseint.h>
-#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
-#include <android/frameworks/cameraservice/service/2.1/ICameraService.h>
-#include <android/frameworks/cameraservice/service/2.2/ICameraService.h>
-#include <android/frameworks/cameraservice/service/2.1/ICameraServiceListener.h>
-
#include <CameraMetadata.h>
-#include <utils/StrongPointer.h>
-#include <utils/Mutex.h>
-
-#include <media/stagefright/foundation/ALooper.h>
-#include <media/stagefright/foundation/AHandler.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <set>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTag.h>
+#include <aidl/android/frameworks/cameraservice/common/VendorTagSection.h>
+#include <aidl/android/frameworks/cameraservice/service/BnCameraServiceListener.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraDeviceStatus.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraStatusAndId.h>
+#include <aidl/android/frameworks/cameraservice/service/ICameraService.h>
+#include <android-base/parseint.h>
+#include <camera/NdkCameraManager.h>
#include <map>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <set>
+#include <utility>
+#include <utils/Mutex.h>
+#include <utils/StrongPointer.h>
namespace android {
namespace acam {
-using ICameraService = frameworks::cameraservice::service::V2_2::ICameraService;
-using CameraDeviceStatus = frameworks::cameraservice::service::V2_0::CameraDeviceStatus;
-using ICameraServiceListener = frameworks::cameraservice::service::V2_1::ICameraServiceListener;
-using PhysicalCameraStatusAndId = frameworks::cameraservice::service::V2_1::PhysicalCameraStatusAndId;
-using CameraStatusAndId = frameworks::cameraservice::service::V2_0::CameraStatusAndId;
-using Status = frameworks::cameraservice::common::V2_0::Status;
-using VendorTagSection = frameworks::cameraservice::common::V2_0::VendorTagSection;
-using VendorTag = frameworks::cameraservice::common::V2_0::VendorTag;
-using IBase = android::hidl::base::V1_0::IBase;
-using android::hardware::hidl_string;
-using hardware::Void;
+using ::aidl::android::frameworks::cameraservice::common::Status;
+using ::aidl::android::frameworks::cameraservice::common::VendorTag;
+using ::aidl::android::frameworks::cameraservice::common::VendorTagSection;
+using ::aidl::android::frameworks::cameraservice::service::BnCameraServiceListener;
+using ::aidl::android::frameworks::cameraservice::service::CameraDeviceStatus;
+using ::aidl::android::frameworks::cameraservice::service::CameraStatusAndId;
+using ::aidl::android::frameworks::cameraservice::service::ICameraService;
/**
* Per-process singleton instance of CameraManger. Shared by all ACameraManager
@@ -58,15 +54,18 @@
*
* TODO: maybe CameraManagerGlobal is better suited in libcameraclient?
*/
-class CameraManagerGlobal final : public RefBase {
+class CameraManagerGlobal final: public std::enable_shared_from_this<CameraManagerGlobal> {
public:
- static CameraManagerGlobal& getInstance();
- sp<ICameraService> getCameraService();
+ static std::shared_ptr<CameraManagerGlobal> getInstance();
+ static void binderDeathCallback(void* cookie);
- void registerAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback);
- void unregisterAvailabilityCallback(
- const ACameraManager_AvailabilityCallbacks *callback);
+ CameraManagerGlobal() {};
+ ~CameraManagerGlobal();
+
+ std::shared_ptr<ICameraService> getCameraService();
+
+ void registerAvailabilityCallback(const ACameraManager_AvailabilityCallbacks *callback);
+ void unregisterAvailabilityCallback(const ACameraManager_AvailabilityCallbacks *callback);
void registerExtendedAvailabilityCallback(
const ACameraManager_ExtendedAvailabilityCallbacks* callback);
@@ -76,35 +75,28 @@
/**
* Return camera IDs that support camera2
*/
- void getCameraIdList(std::vector<hidl_string> *cameraIds);
+ void getCameraIdList(std::vector<std::string> *cameraIds);
private:
- sp<ICameraService> mCameraService;
+ std::shared_ptr<ICameraService> mCameraService;
const int kCameraServicePollDelay = 500000; // 0.5s
Mutex mLock;
- class DeathNotifier : public android::hardware::hidl_death_recipient {
- public:
- explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
- protected:
- // IBinder::DeathRecipient implementation
- virtual void serviceDied(uint64_t cookie, const wp<IBase> &who);
- private:
- const wp<CameraManagerGlobal> mCameraManager;
- };
- sp<DeathNotifier> mDeathNotifier;
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
- class CameraServiceListener final : public ICameraServiceListener {
+ class CameraServiceListener final : public BnCameraServiceListener {
public:
- explicit CameraServiceListener(CameraManagerGlobal* cm) : mCameraManager(cm) {}
- android::hardware::Return<void> onStatusChanged(
- const CameraStatusAndId &statusAndId) override;
- android::hardware::Return<void> onPhysicalCameraStatusChanged(
- const PhysicalCameraStatusAndId &statusAndId) override;
+ explicit CameraServiceListener(std::weak_ptr<CameraManagerGlobal> cm) :
+ mCameraManager(std::move(cm)) {}
+ ndk::ScopedAStatus onPhysicalCameraStatusChanged(
+ CameraDeviceStatus in_status, const std::string& in_cameraId,
+ const std::string& in_physicalCameraId) override;
+ ndk::ScopedAStatus onStatusChanged(CameraDeviceStatus in_status,
+ const std::string& in_cameraId) override;
private:
- const wp<CameraManagerGlobal> mCameraManager;
+ const std::weak_ptr<CameraManagerGlobal> mCameraManager;
};
- sp<CameraServiceListener> mCameraServiceListener;
+ std::shared_ptr<CameraServiceListener> mCameraServiceListener;
// Wrapper of ACameraManager_AvailabilityCallbacks so we can store it in std::set
struct Callback {
@@ -180,20 +172,22 @@
static const nsecs_t kCallbackDrainTimeout;
class CallbackHandler : public AHandler {
public:
- CallbackHandler(wp<CameraManagerGlobal> parent) : mParent(parent) {}
+ CallbackHandler(std::weak_ptr<CameraManagerGlobal> parent) : mParent(std::move(parent)) {}
void onMessageReceived(const sp<AMessage> &msg) override;
private:
- wp<CameraManagerGlobal> mParent;
+ std::weak_ptr<CameraManagerGlobal> mParent;
void notifyParent();
void onMessageReceivedInternal(const sp<AMessage> &msg);
};
sp<CallbackHandler> mHandler;
sp<ALooper> mCbLooper; // Looper thread where callbacks actually happen on
- void onStatusChanged(const CameraStatusAndId &statusAndId);
- void onStatusChangedLocked(const CameraStatusAndId &statusAndId);
- void onStatusChanged(const PhysicalCameraStatusAndId &statusAndId);
- void onStatusChangedLocked(const PhysicalCameraStatusAndId &statusAndId);
+ void onStatusChanged(const CameraDeviceStatus &status, const std::string &cameraId);
+ void onStatusChangedLocked(const CameraDeviceStatus &status, const std::string &cameraId);
+ void onStatusChanged(const CameraDeviceStatus &status, const std::string &cameraId,
+ const std::string &physicalCameraId);
+ void onStatusChangedLocked(const CameraDeviceStatus &status, const std::string &cameraId,
+ const std::string &physicalCameraId);
bool setupVendorTags();
// Utils for status
@@ -203,7 +197,7 @@
// The sort logic must match the logic in
// libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
struct CameraIdComparator {
- bool operator()(const hidl_string& a, const hidl_string& b) const {
+ bool operator()(const std::string& a, const std::string& b) const {
uint32_t aUint = 0, bUint = 0;
bool aIsUint = base::ParseUint(a.c_str(), &aUint);
bool bIsUint = base::ParseUint(b.c_str(), &bUint);
@@ -225,29 +219,29 @@
private:
CameraDeviceStatus status = CameraDeviceStatus::STATUS_NOT_PRESENT;
mutable std::mutex mLock;
- std::set<hidl_string> unavailablePhysicalIds;
+ std::set<std::string> unavailablePhysicalIds;
public:
CameraStatus(CameraDeviceStatus st): status(st) { };
CameraStatus() = default;
- bool addUnavailablePhysicalId(const hidl_string& physicalCameraId);
- bool removeUnavailablePhysicalId(const hidl_string& physicalCameraId);
+ bool addUnavailablePhysicalId(const std::string& physicalCameraId);
+ bool removeUnavailablePhysicalId(const std::string& physicalCameraId);
CameraDeviceStatus getStatus();
void updateStatus(CameraDeviceStatus newStatus);
- std::set<hidl_string> getUnavailablePhysicalIds();
+ std::set<std::string> getUnavailablePhysicalIds();
};
template <class T>
void registerAvailCallback(const T *callback);
// Map camera_id -> status
- std::map<hidl_string, CameraStatus, CameraIdComparator> mDeviceStatusMap;
+ std::map<std::string, CameraStatus, CameraIdComparator> mDeviceStatusMap;
// For the singleton instance
static Mutex sLock;
- static CameraManagerGlobal* sInstance;
- CameraManagerGlobal() {};
- ~CameraManagerGlobal();
+ // Static instance is stored in a weak pointer, so will only exist if there is at least one
+ // active consumer of CameraManagerGlobal
+ static std::weak_ptr<CameraManagerGlobal> sInstance;
};
} // namespace acam;
@@ -259,7 +253,7 @@
*/
struct ACameraManager {
ACameraManager() :
- mGlobalManager(&(android::acam::CameraManagerGlobal::getInstance())) {}
+ mGlobalManager(android::acam::CameraManagerGlobal::getInstance()) {}
~ACameraManager();
camera_status_t getCameraIdList(ACameraIdList** cameraIdList);
static void deleteCameraIdList(ACameraIdList* cameraIdList);
@@ -277,7 +271,7 @@
kCameraIdListNotInit = -1
};
android::Mutex mLock;
- android::sp<android::acam::CameraManagerGlobal> mGlobalManager;
+ std::shared_ptr<android::acam::CameraManagerGlobal> mGlobalManager;
};
#endif //_ACAMERA_MANAGER_H
diff --git a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
index 5715d77..fcb7e34 100644
--- a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
+++ b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
@@ -16,6 +16,7 @@
#include "utils.h"
+using ::android::acam::utils::native_handle_ptr_wrapper;
struct ACameraOutputTarget {
explicit ACameraOutputTarget(const native_handle_t* window) : mWindow(window) {};
@@ -32,5 +33,5 @@
return mWindow > other.mWindow;
}
- android::acam::utils::native_handle_ptr_wrapper mWindow;
+ native_handle_ptr_wrapper mWindow;
};
diff --git a/camera/ndk/ndk_vendor/impl/utils.cpp b/camera/ndk/ndk_vendor/impl/utils.cpp
index e4fb204..73a527b 100644
--- a/camera/ndk/ndk_vendor/impl/utils.cpp
+++ b/camera/ndk/ndk_vendor/impl/utils.cpp
@@ -16,66 +16,75 @@
#define LOG_TAG "ACameraVendorUtils"
-#include <utils/Log.h>
-
#include "utils.h"
+#include <aidlcommonsupport/NativeHandle.h>
+#include <utils/Log.h>
+
namespace android {
namespace acam {
namespace utils {
-// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
-frameworks::cameraservice::device::V2_0::CaptureRequest
-convertToHidl(const CaptureRequest *captureRequest) {
- frameworks::cameraservice::device::V2_0::CaptureRequest hCaptureRequest;
- hCaptureRequest.physicalCameraSettings = captureRequest->mCaptureRequest.physicalCameraSettings;
- hCaptureRequest.streamAndWindowIds = captureRequest->mCaptureRequest.streamAndWindowIds;
- return hCaptureRequest;
+// Convert CaptureRequest wrappable by sp<> to aidl CaptureRequest.
+AidlCaptureRequest convertToAidl(const CaptureRequest *captureRequest) {
+ AidlCaptureRequest aidlCaptureRequest;
+ aidlCaptureRequest.physicalCameraSettings =
+ captureRequest->mCaptureRequest.physicalCameraSettings;
+ aidlCaptureRequest.streamAndWindowIds = captureRequest->mCaptureRequest.streamAndWindowIds;
+ return aidlCaptureRequest;
}
-HRotation convertToHidl(int rotation) {
- HRotation hRotation = HRotation::R0;
+OutputConfiguration::Rotation convertToAidl(int rotation) {
+ using AidlRotation = OutputConfiguration::Rotation;
+
+ AidlRotation aRot = AidlRotation ::R0;
switch(rotation) {
case CAMERA3_STREAM_ROTATION_90:
- hRotation = HRotation::R90;
+ aRot = AidlRotation::R90;
break;
case CAMERA3_STREAM_ROTATION_180:
- hRotation = HRotation::R180;
+ aRot = AidlRotation::R180;
break;
case CAMERA3_STREAM_ROTATION_270:
- hRotation = HRotation::R270;
+ aRot = AidlRotation::R270;
break;
default:
break;
}
- return hRotation;
+ return aRot;
}
-bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata) {
- const camera_metadata *buffer = (camera_metadata_t*)(metadata.data());
- size_t expectedSize = metadata.size();
+bool cloneFromAidl(const AidlCameraMetadata& srcMetadata, camera_metadata_t** dst) {
+ const camera_metadata *buffer = (camera_metadata_t*)(srcMetadata.metadata.data());
+ size_t expectedSize = srcMetadata.metadata.size();
int ret = validate_camera_metadata_structure(buffer, &expectedSize);
- if (ret == OK || ret == CAMERA_METADATA_VALIDATION_SHIFTED) {
- *rawMetadata = buffer;
- } else {
- ALOGE("%s: Malformed camera metadata received from caller", __FUNCTION__);
+ if (ret != OK && ret != CAMERA_METADATA_VALIDATION_SHIFTED) {
+ ALOGE("%s: Malformed camera srcMetadata received from caller", __FUNCTION__);
return false;
}
- return true;
+
+ camera_metadata_t* clonedBuffer = clone_camera_metadata(buffer);
+ if (clonedBuffer != nullptr) {
+ *dst = clonedBuffer;
+ return true;
+ }
+
+ ALOGE("%s: Failed to clone srcMetadata buffer.", __FUNCTION__);
+ return false;
}
-// Note: existing data in dst will be gone. dst owns memory if shouldOwn is set
-// to true.
-void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst, bool shouldOwn) {
+// Note: existing data in dst will be gone.
+void convertToAidl(const camera_metadata_t *src, AidlCameraMetadata* dst) {
if (src == nullptr) {
return;
}
size_t size = get_camera_metadata_size(src);
- dst->setToExternal((uint8_t *) src, size, shouldOwn);
- return;
+ uint8_t* metadataStart = (uint8_t*)src;
+ uint8_t* metadataEnd = metadataStart + size;
+ dst->metadata.assign(metadataStart, metadataEnd);
}
-TemplateId convertToHidl(ACameraDevice_request_template templateId) {
+TemplateId convertToAidl(ACameraDevice_request_template templateId) {
switch(templateId) {
case TEMPLATE_STILL_CAPTURE:
return TemplateId::STILL_CAPTURE;
@@ -92,7 +101,7 @@
}
}
-camera_status_t convertFromHidl(Status status) {
+camera_status_t convertFromAidl(Status status) {
camera_status_t ret = ACAMERA_OK;
switch(status) {
case Status::NO_ERROR:
@@ -146,6 +155,14 @@
return true;
}
+bool isWindowNativeHandleEqual(const native_handle_t *nh1,
+ const aidl::android::hardware::common::NativeHandle& nh2) {
+ native_handle_t* tempNh = makeFromAidl(nh2);
+ bool equal = isWindowNativeHandleEqual(nh1, tempNh);
+ native_handle_delete(tempNh);
+ return equal;
+}
+
bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2) {
if (isWindowNativeHandleEqual(nh1, nh2)) {
return false;
@@ -166,32 +183,6 @@
return !isWindowNativeHandleLessThan(nh1, nh2) && !isWindowNativeHandleEqual(nh1, nh2);
}
-bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle> handles2) {
- if (handles1.size() != handles2.size()) {
- return false;
- }
- for (int i = 0; i < handles1.size(); i++) {
- if (!isWindowNativeHandleEqual(handles1[i], handles2[i])) {
- return false;
- }
- }
- return true;
-}
-
-bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2) {
- if (handles1.size() != handles2.size()) {
- return handles1.size() < handles2.size();
- }
- for (int i = 0; i < handles1.size(); i++) {
- const native_handle_t *handle1 = handles1[i].getNativeHandle();
- const native_handle_t *handle2 = handles2[i].getNativeHandle();
- if (!isWindowNativeHandleEqual(handle1, handle2)) {
- return isWindowNativeHandleLessThan(handle1, handle2);
- }
- }
- return false;
-}
-
} // namespace utils
} // namespace acam
} // namespace android
diff --git a/camera/ndk/ndk_vendor/impl/utils.h b/camera/ndk/ndk_vendor/impl/utils.h
index 62779a4..7ad74ad 100644
--- a/camera/ndk/ndk_vendor/impl/utils.h
+++ b/camera/ndk/ndk_vendor/impl/utils.h
@@ -14,46 +14,39 @@
* limitations under the License.
*/
-#include <android/frameworks/cameraservice/service/2.0/ICameraService.h>
-#include <android/frameworks/cameraservice/device/2.0/ICameraDeviceUser.h>
-#include <android/frameworks/cameraservice/device/2.0/types.h>
-#include <camera/NdkCameraDevice.h>
+#ifndef CAMERA_NDK_VENDOR_UTILS_H
+#define CAMERA_NDK_VENDOR_UTILS_H
+
#include <CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/device/CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureRequest.h>
+#include <aidl/android/frameworks/cameraservice/device/ICameraDeviceUser.h>
+#include <aidl/android/frameworks/cameraservice/device/OutputConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCameraSettings.h>
+#include <aidl/android/frameworks/cameraservice/device/TemplateId.h>
+#include <aidl/android/frameworks/cameraservice/service/ICameraService.h>
+#include <camera/NdkCameraDevice.h>
#include <hardware/camera3.h>
-
-#ifndef CAMERA_NDK_VENDOR_H
-#define CAMERA_NDK_VENDOR_H
-
-using android::hardware::hidl_vec;
-using android::hardware::hidl_handle;
+#include <utils/RefBase.h>
namespace android {
namespace acam {
namespace utils {
-using CameraMetadata = hardware::camera::common::V1_0::helper::CameraMetadata;
-using HCameraMetadata = frameworks::cameraservice::service::V2_0::CameraMetadata;
-using Status = frameworks::cameraservice::common::V2_0::Status;
-using TemplateId = frameworks::cameraservice::device::V2_0::TemplateId;
-using PhysicalCameraSettings = frameworks::cameraservice::device::V2_0::PhysicalCameraSettings;
-using HRotation = frameworks::cameraservice::device::V2_0::OutputConfiguration::Rotation;
-using OutputConfiguration = frameworks::cameraservice::device::V2_0::OutputConfiguration;
-
-// Utility class so that CaptureRequest can be stored by sp<>
-struct CaptureRequest : public RefBase {
- frameworks::cameraservice::device::V2_0::CaptureRequest mCaptureRequest;
- std::vector<const native_handle_t *> mSurfaceList;
- //Physical camera settings metadata is stored here, since the capture request
- //might not contain it. That's since, fmq might have consumed it.
- hidl_vec<PhysicalCameraSettings> mPhysicalCameraSettings;
-};
-
-bool areWindowNativeHandlesEqual(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
-
-bool areWindowNativeHandlesLessThan(hidl_vec<hidl_handle> handles1, hidl_vec<hidl_handle>handles2);
+using ::aidl::android::frameworks::cameraservice::common::Status;
+using ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
+using ::aidl::android::frameworks::cameraservice::device::PhysicalCameraSettings;
+using ::aidl::android::frameworks::cameraservice::device::TemplateId;
+using ::aidl::android::hardware::common::NativeHandle;
+using ::android::hardware::camera::common::V1_0::helper::CameraMetadata;
+using AidlCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using AidlCaptureRequest = ::aidl::android::frameworks::cameraservice::device::CaptureRequest;
bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2);
+bool isWindowNativeHandleEqual(const native_handle_t* nh1, const NativeHandle& nh2);
+
bool isWindowNativeHandleLessThan(const native_handle_t *nh1, const native_handle_t *nh2);
// Convenience wrapper over isWindowNativeHandleLessThan and isWindowNativeHandleEqual
@@ -88,117 +81,30 @@
};
-// Wrapper around OutputConfiguration. This is needed since HIDL
-// OutputConfiguration is auto-generated and marked final. Therefore, operator
-// overloads outside the class, will not get picked by clang while trying to
-// store OutputConfiguration in maps/sets.
-struct OutputConfigurationWrapper {
- OutputConfiguration mOutputConfiguration;
-
- operator const OutputConfiguration &() const {
- return mOutputConfiguration;
- }
-
- OutputConfigurationWrapper() {
- mOutputConfiguration.rotation = OutputConfiguration::Rotation::R0;
- // The ndk currently doesn't support deferred surfaces
- mOutputConfiguration.isDeferred = false;
- mOutputConfiguration.width = 0;
- mOutputConfiguration.height = 0;
- // ndk doesn't support inter OutputConfiguration buffer sharing.
- mOutputConfiguration.windowGroupId = -1;
- };
-
- OutputConfigurationWrapper(const OutputConfigurationWrapper &other) {
- *this = other;
- }
-
- // Needed to make sure that OutputConfiguration in
- // OutputConfigurationWrapper, when copied doesn't call hidl_handle's
- // assignment operator / copy constructor, which will lead to native handle
- // cloning, which is not what we want for app callbacks which have the native
- // handle as parameter.
- OutputConfigurationWrapper &operator=(const OutputConfigurationWrapper &other) {
- const OutputConfiguration &outputConfiguration = other.mOutputConfiguration;
- mOutputConfiguration.rotation = outputConfiguration.rotation;
- mOutputConfiguration.isDeferred = outputConfiguration.isDeferred;
- mOutputConfiguration.width = outputConfiguration.width;
- mOutputConfiguration.height = outputConfiguration.height;
- mOutputConfiguration.windowGroupId = outputConfiguration.windowGroupId;
- mOutputConfiguration.windowHandles.resize(outputConfiguration.windowHandles.size());
- mOutputConfiguration.physicalCameraId = outputConfiguration.physicalCameraId;
- size_t i = 0;
- for (const auto &handle : outputConfiguration.windowHandles) {
- mOutputConfiguration.windowHandles[i++] = handle.getNativeHandle();
- }
- return *this;
- }
-
- bool operator ==(const OutputConfiguration &other) const {
- const OutputConfiguration &self = mOutputConfiguration;
- return self.rotation == other.rotation && self.windowGroupId == other.windowGroupId &&
- self.physicalCameraId == other.physicalCameraId && self.width == other.width &&
- self.height == other.height && self.isDeferred == other.isDeferred &&
- areWindowNativeHandlesEqual(self.windowHandles, other.windowHandles);
- }
-
- bool operator < (const OutputConfiguration &other) const {
- if (*this == other) {
- return false;
- }
- const OutputConfiguration &self = mOutputConfiguration;
- if (self.windowGroupId != other.windowGroupId) {
- return self.windowGroupId < other.windowGroupId;
- }
-
- if (self.width != other.width) {
- return self.width < other.width;
- }
-
- if (self.height != other.height) {
- return self.height < other.height;
- }
-
- if (self.rotation != other.rotation) {
- return static_cast<uint32_t>(self.rotation) < static_cast<uint32_t>(other.rotation);
- }
-
- if (self.isDeferred != other.isDeferred) {
- return self.isDeferred < other.isDeferred;
- }
-
- if (self.physicalCameraId != other.physicalCameraId) {
- return self.physicalCameraId < other.physicalCameraId;
- }
- return areWindowNativeHandlesLessThan(self.windowHandles, other.windowHandles);
- }
-
- bool operator != (const OutputConfiguration &other) const {
- return !(*this == other);
- }
-
- bool operator > (const OutputConfiguration &other) const {
- return (*this != other) && !(*this < other);
- }
+// Utility class so that CaptureRequest can be stored by sp<>
+struct CaptureRequest: public RefBase {
+ AidlCaptureRequest mCaptureRequest;
+ std::vector<native_handle_ptr_wrapper> mSurfaceList;
+ // Physical camera settings metadata is stored here, as the capture request
+ // might not contain it. That's since, fmq might have consumed it.
+ std::vector<PhysicalCameraSettings> mPhysicalCameraSettings;
};
-// Convert CaptureRequest wrappable by sp<> to hidl CaptureRequest.
-frameworks::cameraservice::device::V2_0::CaptureRequest convertToHidl(
- const CaptureRequest *captureRequest);
+AidlCaptureRequest convertToAidl(const CaptureRequest *captureRequest);
-HRotation convertToHidl(int rotation);
+OutputConfiguration::Rotation convertToAidl(int rotation);
-bool convertFromHidlCloned(const HCameraMetadata &metadata, CameraMetadata *rawMetadata);
+bool cloneFromAidl(const AidlCameraMetadata & srcMetadata, camera_metadata_t** dst);
// Note: existing data in dst will be gone.
-void convertToHidl(const camera_metadata_t *src, HCameraMetadata* dst, bool shouldOwn = false);
+void convertToAidl(const camera_metadata_t *src, AidlCameraMetadata * dst);
-TemplateId convertToHidl(ACameraDevice_request_template templateId);
+TemplateId convertToAidl(ACameraDevice_request_template templateId);
-camera_status_t convertFromHidl(Status status);
+camera_status_t convertFromAidl(Status status);
} // namespace utils
} // namespace acam
} // namespace android
-#endif // CAMERA_NDK_VENDOR_H
+#endif // CAMERA_NDK_VENDOR_UTILS_H
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 63cdb76..3a13a73 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -254,20 +254,22 @@
&mLogicalCaptureCallbacksV2, 1, &mStillRequest, &seqId);
}
- bool checkCallbacks(int pictureCount) {
+ bool checkCallbacks(int pictureCount, bool printLog = false) {
std::lock_guard<std::mutex> lock(mMutex);
if (mCompletedCaptureCallbackCount != pictureCount) {
- ALOGE("Completed capture callback count not as expected. expected %d actual %d",
- pictureCount, mCompletedCaptureCallbackCount);
+ ALOGE_IF(printLog,
+ "Completed capture callback count not as expected. expected %d actual %d",
+ pictureCount, mCompletedCaptureCallbackCount);
return false;
}
return true;
}
- bool checkCallbacksV2(int pictureCount) {
+ bool checkCallbacksV2(int pictureCount, bool printLog = false) {
std::lock_guard<std::mutex> lock(mMutex);
if (mCaptureStartedCallbackCount != pictureCount) {
- ALOGE("Capture started callback count not as expected. expected %d actual %d",
- pictureCount, mCaptureStartedCallbackCount);
+ ALOGE_IF(printLog,
+ "Capture started callback count not as expected. expected %d actual %d",
+ pictureCount, mCaptureStartedCallbackCount);
return false;
}
return true;
@@ -670,15 +672,22 @@
// Sleep until all capture finished
for (int i = 0; i < kCaptureWaitRetry * pictureCount; i++) {
usleep(kCaptureWaitUs);
- if (testCase.getAcquiredImageCount() == pictureCount) {
+ bool receivedAllCallbacks = v2 ? cameraHelper.checkCallbacksV2(pictureCount)
+ : cameraHelper.checkCallbacks(pictureCount);
+
+ bool acquiredAllImages = testCase.getAcquiredImageCount() == pictureCount;
+ if (acquiredAllImages) {
ALOGI("Session take ~%d ms to capture %d images", i * kCaptureWaitUs / 1000,
pictureCount);
+ }
+ // Wait for all images to be acquired and all callbacks to be processed
+ if (acquiredAllImages && receivedAllCallbacks) {
break;
}
}
return testCase.getAcquiredImageCount() == pictureCount &&
- v2 ? cameraHelper.checkCallbacksV2(pictureCount) :
- cameraHelper.checkCallbacks(pictureCount);
+ v2 ? cameraHelper.checkCallbacksV2(pictureCount, /* printLog= */true) :
+ cameraHelper.checkCallbacks(pictureCount, /* printLog= */true);
}
bool testTakePicturesNative(const char* id) {
diff --git a/cmds/stagefright/Android.bp b/cmds/stagefright/Android.bp
index e1fe07e..445541e 100644
--- a/cmds/stagefright/Android.bp
+++ b/cmds/stagefright/Android.bp
@@ -211,46 +211,6 @@
}
cc_binary {
- name: "mediafilter",
-
- srcs: [
- "filters/argbtorgba.rscript",
- "filters/nightvision.rscript",
- "filters/saturation.rscript",
- "mediafilter.cpp",
- ],
-
- header_libs: [
- "libmediadrm_headers",
- "libmediametrics_headers",
- "libstagefright_headers",
- "rs-headers",
- ],
-
- shared_libs: [
- "libstagefright",
- "liblog",
- "libutils",
- "libbinder",
- "libstagefright_foundation",
- "libmedia_omx",
- "libui",
- "libgui",
- "libRScpp",
- ],
-
- static_libs: ["libstagefright_mediafilter"],
-
- cflags: [
- "-Wno-multichar",
- ],
-
- sanitize: {
- cfi: true,
- },
-}
-
-cc_binary {
name: "muxer",
srcs: ["muxer.cpp"],
diff --git a/cmds/stagefright/SineSource.cpp b/cmds/stagefright/SineSource.cpp
index 0ecc16c..0656030 100644
--- a/cmds/stagefright/SineSource.cpp
+++ b/cmds/stagefright/SineSource.cpp
@@ -63,12 +63,15 @@
MediaBufferBase **out, const ReadOptions * /* options */) {
*out = NULL;
- MediaBufferBase *buffer;
+ MediaBufferBase *buffer = nullptr;
status_t err = mGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
}
+ if (buffer == nullptr) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
size_t frameSize = mNumChannels * sizeof(int16_t);
size_t numFramesPerBuffer = buffer->size() / frameSize;
diff --git a/cmds/stagefright/filters/argbtorgba.rscript b/cmds/stagefright/filters/argbtorgba.rscript
deleted file mode 100644
index 229ff8c..0000000
--- a/cmds/stagefright/filters/argbtorgba.rscript
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2014 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 version(1)
-#pragma rs java_package_name(com.android.rs.cppbasic)
-#pragma rs_fp_relaxed
-
-void root(const uchar4 *v_in, uchar4 *v_out) {
- v_out->x = v_in->y;
- v_out->y = v_in->z;
- v_out->z = v_in->w;
- v_out->w = v_in->x;
-}
\ No newline at end of file
diff --git a/cmds/stagefright/filters/nightvision.rscript b/cmds/stagefright/filters/nightvision.rscript
deleted file mode 100644
index f61413c..0000000
--- a/cmds/stagefright/filters/nightvision.rscript
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2014 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 version(1)
-#pragma rs java_package_name(com.android.rs.cppbasic)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-const static float3 gNightVisionMult = {0.5f, 1.f, 0.5f};
-
-// calculates luminance of pixel, then biases color balance toward green
-void root(const uchar4 *v_in, uchar4 *v_out) {
- v_out->x = v_in->x; // don't modify A
-
- // get RGB, scale 0-255 uchar to 0-1.0 float
- float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
- v_in->w * 0.003921569f};
-
- // apply filter
- float3 result = dot(rgb, gMonoMult) * gNightVisionMult;
-
- v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
- v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
- v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
-}
diff --git a/cmds/stagefright/filters/saturation.rscript b/cmds/stagefright/filters/saturation.rscript
deleted file mode 100644
index 1de9dd8..0000000
--- a/cmds/stagefright/filters/saturation.rscript
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2014 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 version(1)
-#pragma rs java_package_name(com.android.rs.cppbasic)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-// global variables (parameters accessible to application code)
-float gSaturation = 1.0f;
-
-void root(const uchar4 *v_in, uchar4 *v_out) {
- v_out->x = v_in->x; // don't modify A
-
- // get RGB, scale 0-255 uchar to 0-1.0 float
- float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
- v_in->w * 0.003921569f};
-
- // apply saturation filter
- float3 result = dot(rgb, gMonoMult);
- result = mix(result, rgb, gSaturation);
-
- v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
- v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
- v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
-}
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
deleted file mode 100644
index f042d5e..0000000
--- a/cmds/stagefright/mediafilter.cpp
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "mediafilterTest"
-
-#include <inttypes.h>
-
-#include <binder/ProcessState.h>
-#include <filters/ColorConvert.h>
-#include <gui/ISurfaceComposer.h>
-#include <gui/SurfaceComposerClient.h>
-#include <gui/Surface.h>
-#include <media/IMediaHTTPService.h>
-#include <media/MediaCodecBuffer.h>
-#include <mediadrm/ICrypto.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaCodec.h>
-#include <media/stagefright/NuMediaExtractor.h>
-#include <media/stagefright/RenderScriptWrapper.h>
-#include <OMX_IVCommon.h>
-#include <ui/DisplayMode.h>
-
-#include "RenderScript.h"
-#include "ScriptC_argbtorgba.h"
-#include "ScriptC_nightvision.h"
-#include "ScriptC_saturation.h"
-
-// test parameters
-static const bool kTestFlush = true; // Note: true will drop 1 out of
-static const int kFlushAfterFrames = 25; // kFlushAfterFrames output frames
-static const int64_t kTimeout = 500ll;
-
-// built-in filter parameters
-static const int32_t kInvert = false; // ZeroFilter param
-static const float kBlurRadius = 15.0f; // IntrinsicBlurFilter param
-static const float kSaturation = 0.0f; // SaturationFilter param
-
-static void usage(const char *me) {
- fprintf(stderr, "usage: [flags] %s\n"
- "\t[-b] use IntrinsicBlurFilter\n"
- "\t[-c] use argb to rgba conversion RSFilter\n"
- "\t[-n] use night vision RSFilter\n"
- "\t[-r] use saturation RSFilter\n"
- "\t[-s] use SaturationFilter\n"
- "\t[-z] use ZeroFilter (copy filter)\n"
- "\t[-R] render output to surface (enables -S)\n"
- "\t[-S] allocate buffers from a surface\n"
- "\t[-T] use render timestamps (enables -R)\n",
- me);
- exit(1);
-}
-
-namespace android {
-
-struct SaturationRSFilter : RenderScriptWrapper::RSFilterCallback {
- void init(const RSC::sp<RSC::RS> &context) {
- mScript = new ScriptC_saturation(context);
- mScript->set_gSaturation(3.f);
- }
-
- virtual status_t processBuffers(
- RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
- mScript->forEach_root(inBuffer, outBuffer);
-
- return OK;
- }
-
- status_t handleSetParameters(const sp<AMessage> &msg __unused) {
- return OK;
- }
-
-private:
- RSC::sp<ScriptC_saturation> mScript;
-};
-
-struct NightVisionRSFilter : RenderScriptWrapper::RSFilterCallback {
- void init(const RSC::sp<RSC::RS> &context) {
- mScript = new ScriptC_nightvision(context);
- }
-
- virtual status_t processBuffers(
- RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
- mScript->forEach_root(inBuffer, outBuffer);
-
- return OK;
- }
-
- status_t handleSetParameters(const sp<AMessage> &msg __unused) {
- return OK;
- }
-
-private:
- RSC::sp<ScriptC_nightvision> mScript;
-};
-
-struct ARGBToRGBARSFilter : RenderScriptWrapper::RSFilterCallback {
- void init(const RSC::sp<RSC::RS> &context) {
- mScript = new ScriptC_argbtorgba(context);
- }
-
- virtual status_t processBuffers(
- RSC::Allocation *inBuffer, RSC::Allocation *outBuffer) {
- mScript->forEach_root(inBuffer, outBuffer);
-
- return OK;
- }
-
- status_t handleSetParameters(const sp<AMessage> &msg __unused) {
- return OK;
- }
-
-private:
- RSC::sp<ScriptC_argbtorgba> mScript;
-};
-
-struct CodecState {
- sp<MediaCodec> mCodec;
- Vector<sp<MediaCodecBuffer> > mInBuffers;
- Vector<sp<MediaCodecBuffer> > mOutBuffers;
- bool mSignalledInputEOS;
- bool mSawOutputEOS;
- int64_t mNumBuffersDecoded;
-};
-
-struct DecodedFrame {
- size_t index;
- size_t offset;
- size_t size;
- int64_t presentationTimeUs;
- uint32_t flags;
-};
-
-enum FilterType {
- FILTERTYPE_ZERO,
- FILTERTYPE_INTRINSIC_BLUR,
- FILTERTYPE_SATURATION,
- FILTERTYPE_RS_SATURATION,
- FILTERTYPE_RS_NIGHT_VISION,
- FILTERTYPE_RS_ARGB_TO_RGBA,
-};
-
-size_t inputFramesSinceFlush = 0;
-void tryCopyDecodedBuffer(
- List<DecodedFrame> *decodedFrameIndices,
- CodecState *filterState,
- CodecState *vidState) {
- if (decodedFrameIndices->empty()) {
- return;
- }
-
- size_t filterIndex;
- status_t err = filterState->mCodec->dequeueInputBuffer(
- &filterIndex, kTimeout);
- if (err != OK) {
- return;
- }
-
- ++inputFramesSinceFlush;
-
- DecodedFrame frame = *decodedFrameIndices->begin();
-
- // only consume a buffer if we are not going to flush, since we expect
- // the dequeue -> flush -> queue operation to cause an error and
- // not produce an output frame
- if (!kTestFlush || inputFramesSinceFlush < kFlushAfterFrames) {
- decodedFrameIndices->erase(decodedFrameIndices->begin());
- }
- size_t outIndex = frame.index;
-
- const sp<MediaCodecBuffer> &srcBuffer =
- vidState->mOutBuffers.itemAt(outIndex);
- const sp<MediaCodecBuffer> &destBuffer =
- filterState->mInBuffers.itemAt(filterIndex);
-
- sp<AMessage> srcFormat, destFormat;
- vidState->mCodec->getOutputFormat(&srcFormat);
- filterState->mCodec->getInputFormat(&destFormat);
-
- int32_t srcWidth, srcHeight, srcStride, srcSliceHeight;
- int32_t srcColorFormat, destColorFormat;
- int32_t destWidth, destHeight, destStride, destSliceHeight;
- CHECK(srcFormat->findInt32("stride", &srcStride)
- && srcFormat->findInt32("slice-height", &srcSliceHeight)
- && srcFormat->findInt32("width", &srcWidth)
- && srcFormat->findInt32("height", & srcHeight)
- && srcFormat->findInt32("color-format", &srcColorFormat));
- CHECK(destFormat->findInt32("stride", &destStride)
- && destFormat->findInt32("slice-height", &destSliceHeight)
- && destFormat->findInt32("width", &destWidth)
- && destFormat->findInt32("height", & destHeight)
- && destFormat->findInt32("color-format", &destColorFormat));
-
- CHECK(srcWidth <= destStride && srcHeight <= destSliceHeight);
-
- convertYUV420spToARGB(
- srcBuffer->data(),
- srcBuffer->data() + srcStride * srcSliceHeight,
- srcWidth,
- srcHeight,
- destBuffer->data());
-
- // copy timestamp
- int64_t timeUs;
- CHECK(srcBuffer->meta()->findInt64("timeUs", &timeUs));
- destBuffer->meta()->setInt64("timeUs", timeUs);
-
- if (kTestFlush && inputFramesSinceFlush >= kFlushAfterFrames) {
- inputFramesSinceFlush = 0;
-
- // check that queueing a buffer that was dequeued before flush
- // fails with expected error EACCES
- filterState->mCodec->flush();
-
- err = filterState->mCodec->queueInputBuffer(
- filterIndex, 0 /* offset */, destBuffer->size(),
- timeUs, frame.flags);
-
- if (err == OK) {
- ALOGE("FAIL: queue after flush returned OK");
- } else if (err != -EACCES) {
- ALOGE("queueInputBuffer after flush returned %d, "
- "expected -EACCES (-13)", err);
- }
- } else {
- err = filterState->mCodec->queueInputBuffer(
- filterIndex, 0 /* offset */, destBuffer->size(),
- timeUs, frame.flags);
- CHECK(err == OK);
-
- err = vidState->mCodec->releaseOutputBuffer(outIndex);
- CHECK(err == OK);
- }
-}
-
-size_t outputFramesSinceFlush = 0;
-void tryDrainOutputBuffer(
- CodecState *filterState,
- const sp<Surface> &surface, bool renderSurface,
- bool useTimestamp, int64_t *startTimeRender) {
- size_t index;
- size_t offset;
- size_t size;
- int64_t presentationTimeUs;
- uint32_t flags;
- status_t err = filterState->mCodec->dequeueOutputBuffer(
- &index, &offset, &size, &presentationTimeUs, &flags,
- kTimeout);
-
- if (err != OK) {
- return;
- }
-
- ++outputFramesSinceFlush;
-
- if (kTestFlush && outputFramesSinceFlush >= kFlushAfterFrames) {
- filterState->mCodec->flush();
- }
-
- if (surface == NULL || !renderSurface) {
- err = filterState->mCodec->releaseOutputBuffer(index);
- } else if (useTimestamp) {
- if (*startTimeRender == -1) {
- // begin rendering 2 vsyncs after first decode
- *startTimeRender = systemTime(SYSTEM_TIME_MONOTONIC)
- + 33000000 - (presentationTimeUs * 1000);
- }
- presentationTimeUs =
- (presentationTimeUs * 1000) + *startTimeRender;
- err = filterState->mCodec->renderOutputBufferAndRelease(
- index, presentationTimeUs);
- } else {
- err = filterState->mCodec->renderOutputBufferAndRelease(index);
- }
-
- if (kTestFlush && outputFramesSinceFlush >= kFlushAfterFrames) {
- outputFramesSinceFlush = 0;
-
- // releasing the buffer dequeued before flush should cause an error
- // if so, the frame will also be skipped in output stream
- if (err == OK) {
- ALOGE("FAIL: release after flush returned OK");
- } else if (err != -EACCES) {
- ALOGE("releaseOutputBuffer after flush returned %d, "
- "expected -EACCES (-13)", err);
- }
- } else {
- CHECK(err == OK);
- }
-
- if (flags & MediaCodec::BUFFER_FLAG_EOS) {
- ALOGV("reached EOS on output.");
- filterState->mSawOutputEOS = true;
- }
-}
-
-static int decode(
- const sp<android::ALooper> &looper,
- const char *path,
- const sp<Surface> &surface,
- bool renderSurface,
- bool useTimestamp,
- FilterType filterType) {
-
- static int64_t kTimeout = 500ll;
-
- sp<NuMediaExtractor> extractor = new NuMediaExtractor(NuMediaExtractor::EntryPoint::OTHER);
-
- if (extractor->setDataSource(NULL /* httpService */, path) != OK) {
- fprintf(stderr, "unable to instantiate extractor.\n");
- return 1;
- }
-
- KeyedVector<size_t, CodecState> stateByTrack;
-
- CodecState *vidState = NULL;
- for (size_t i = 0; i < extractor->countTracks(); ++i) {
- sp<AMessage> format;
- status_t err = extractor->getTrackFormat(i, &format);
- CHECK(err == OK);
-
- AString mime;
- CHECK(format->findString("mime", &mime));
- bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
- if (!isVideo) {
- continue;
- }
-
- ALOGV("selecting track %zu", i);
-
- err = extractor->selectTrack(i);
- CHECK(err == OK);
-
- CodecState *state =
- &stateByTrack.editValueAt(stateByTrack.add(i, CodecState()));
-
- vidState = state;
-
- state->mNumBuffersDecoded = 0;
-
- state->mCodec = MediaCodec::CreateByType(
- looper, mime.c_str(), false /* encoder */);
-
- CHECK(state->mCodec != NULL);
-
- err = state->mCodec->configure(
- format, NULL /* surface */, NULL /* crypto */, 0 /* flags */);
-
- CHECK(err == OK);
-
- state->mSignalledInputEOS = false;
- state->mSawOutputEOS = false;
-
- break;
- }
- CHECK(!stateByTrack.isEmpty());
- CHECK(vidState != NULL);
- sp<AMessage> vidFormat;
- vidState->mCodec->getOutputFormat(&vidFormat);
-
- // set filter to use ARGB8888
- vidFormat->setInt32("color-format", OMX_COLOR_Format32bitARGB8888);
- // set app cache directory path
- vidFormat->setString("cacheDir", "/system/bin");
-
- // create RenderScript context for RSFilters
- RSC::sp<RSC::RS> context = new RSC::RS();
- context->init("/system/bin");
-
- sp<RenderScriptWrapper::RSFilterCallback> rsFilter;
-
- // create renderscript wrapper for RSFilters
- sp<RenderScriptWrapper> rsWrapper = new RenderScriptWrapper;
- rsWrapper->mContext = context.get();
-
- CodecState *filterState = new CodecState();
- filterState->mNumBuffersDecoded = 0;
-
- sp<AMessage> params = new AMessage();
-
- switch (filterType) {
- case FILTERTYPE_ZERO:
- {
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.zerofilter");
- params->setInt32("invert", kInvert);
- break;
- }
- case FILTERTYPE_INTRINSIC_BLUR:
- {
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.intrinsicblur");
- params->setFloat("blur-radius", kBlurRadius);
- break;
- }
- case FILTERTYPE_SATURATION:
- {
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.saturation");
- params->setFloat("saturation", kSaturation);
- break;
- }
- case FILTERTYPE_RS_SATURATION:
- {
- SaturationRSFilter *satFilter = new SaturationRSFilter;
- satFilter->init(context);
- rsFilter = satFilter;
- rsWrapper->mCallback = rsFilter;
- vidFormat->setObject("rs-wrapper", rsWrapper);
-
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.RenderScript");
- break;
- }
- case FILTERTYPE_RS_NIGHT_VISION:
- {
- NightVisionRSFilter *nightVisionFilter = new NightVisionRSFilter;
- nightVisionFilter->init(context);
- rsFilter = nightVisionFilter;
- rsWrapper->mCallback = rsFilter;
- vidFormat->setObject("rs-wrapper", rsWrapper);
-
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.RenderScript");
- break;
- }
- case FILTERTYPE_RS_ARGB_TO_RGBA:
- {
- ARGBToRGBARSFilter *argbToRgbaFilter = new ARGBToRGBARSFilter;
- argbToRgbaFilter->init(context);
- rsFilter = argbToRgbaFilter;
- rsWrapper->mCallback = rsFilter;
- vidFormat->setObject("rs-wrapper", rsWrapper);
-
- filterState->mCodec = MediaCodec::CreateByComponentName(
- looper, "android.filter.RenderScript");
- break;
- }
- default:
- {
- LOG_ALWAYS_FATAL("mediacodec.cpp error: unrecognized FilterType");
- break;
- }
- }
- CHECK(filterState->mCodec != NULL);
-
- status_t err = filterState->mCodec->configure(
- vidFormat /* format */, surface, NULL /* crypto */, 0 /* flags */);
- CHECK(err == OK);
-
- filterState->mSignalledInputEOS = false;
- filterState->mSawOutputEOS = false;
-
- int64_t startTimeUs = android::ALooper::GetNowUs();
- int64_t startTimeRender = -1;
-
- for (size_t i = 0; i < stateByTrack.size(); ++i) {
- CodecState *state = &stateByTrack.editValueAt(i);
-
- sp<MediaCodec> codec = state->mCodec;
-
- CHECK_EQ((status_t)OK, codec->start());
-
- CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers));
- CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers));
-
- ALOGV("got %zu input and %zu output buffers",
- state->mInBuffers.size(), state->mOutBuffers.size());
- }
-
- CHECK_EQ((status_t)OK, filterState->mCodec->setParameters(params));
-
- if (kTestFlush) {
- status_t flushErr = filterState->mCodec->flush();
- if (flushErr == OK) {
- ALOGE("FAIL: Flush before start returned OK");
- } else {
- ALOGV("Flush before start returned status %d, usually ENOSYS (-38)",
- flushErr);
- }
- }
-
- CHECK_EQ((status_t)OK, filterState->mCodec->start());
- CHECK_EQ((status_t)OK, filterState->mCodec->getInputBuffers(
- &filterState->mInBuffers));
- CHECK_EQ((status_t)OK, filterState->mCodec->getOutputBuffers(
- &filterState->mOutBuffers));
-
- if (kTestFlush) {
- status_t flushErr = filterState->mCodec->flush();
- if (flushErr != OK) {
- ALOGE("FAIL: Flush after start returned %d, expect OK (0)",
- flushErr);
- } else {
- ALOGV("Flush immediately after start OK");
- }
- }
-
- List<DecodedFrame> decodedFrameIndices;
-
- // loop until decoder reaches EOS
- bool sawInputEOS = false;
- bool sawOutputEOSOnAllTracks = false;
- while (!sawOutputEOSOnAllTracks) {
- if (!sawInputEOS) {
- size_t trackIndex;
- status_t err = extractor->getSampleTrackIndex(&trackIndex);
-
- if (err != OK) {
- ALOGV("saw input eos");
- sawInputEOS = true;
- } else {
- CodecState *state = &stateByTrack.editValueFor(trackIndex);
-
- size_t index;
- err = state->mCodec->dequeueInputBuffer(&index, kTimeout);
-
- if (err == OK) {
- ALOGV("filling input buffer %zu", index);
-
- const sp<MediaCodecBuffer> &buffer = state->mInBuffers.itemAt(index);
- sp<ABuffer> abuffer = new ABuffer(buffer->base(), buffer->capacity());
-
- err = extractor->readSampleData(abuffer);
- CHECK(err == OK);
- buffer->setRange(abuffer->offset(), abuffer->size());
-
- int64_t timeUs;
- err = extractor->getSampleTime(&timeUs);
- CHECK(err == OK);
-
- uint32_t bufferFlags = 0;
-
- err = state->mCodec->queueInputBuffer(
- index, 0 /* offset */, buffer->size(),
- timeUs, bufferFlags);
-
- CHECK(err == OK);
-
- extractor->advance();
- } else {
- CHECK_EQ(err, -EAGAIN);
- }
- }
- } else {
- for (size_t i = 0; i < stateByTrack.size(); ++i) {
- CodecState *state = &stateByTrack.editValueAt(i);
-
- if (!state->mSignalledInputEOS) {
- size_t index;
- status_t err =
- state->mCodec->dequeueInputBuffer(&index, kTimeout);
-
- if (err == OK) {
- ALOGV("signalling input EOS on track %zu", i);
-
- err = state->mCodec->queueInputBuffer(
- index, 0 /* offset */, 0 /* size */,
- 0ll /* timeUs */, MediaCodec::BUFFER_FLAG_EOS);
-
- CHECK(err == OK);
-
- state->mSignalledInputEOS = true;
- } else {
- CHECK_EQ(err, -EAGAIN);
- }
- }
- }
- }
-
- sawOutputEOSOnAllTracks = true;
- for (size_t i = 0; i < stateByTrack.size(); ++i) {
- CodecState *state = &stateByTrack.editValueAt(i);
-
- if (state->mSawOutputEOS) {
- continue;
- } else {
- sawOutputEOSOnAllTracks = false;
- }
-
- DecodedFrame frame;
- status_t err = state->mCodec->dequeueOutputBuffer(
- &frame.index, &frame.offset, &frame.size,
- &frame.presentationTimeUs, &frame.flags, kTimeout);
-
- if (err == OK) {
- ALOGV("draining decoded buffer %zu, time = %lld us",
- frame.index, (long long)frame.presentationTimeUs);
-
- ++(state->mNumBuffersDecoded);
-
- decodedFrameIndices.push_back(frame);
-
- if (frame.flags & MediaCodec::BUFFER_FLAG_EOS) {
- ALOGV("reached EOS on decoder output.");
- state->mSawOutputEOS = true;
- }
-
- } else if (err == INFO_OUTPUT_BUFFERS_CHANGED) {
- ALOGV("INFO_OUTPUT_BUFFERS_CHANGED");
- CHECK_EQ((status_t)OK, state->mCodec->getOutputBuffers(
- &state->mOutBuffers));
-
- ALOGV("got %zu output buffers", state->mOutBuffers.size());
- } else if (err == INFO_FORMAT_CHANGED) {
- sp<AMessage> format;
- CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format));
-
- ALOGV("INFO_FORMAT_CHANGED: %s",
- format->debugString().c_str());
- } else {
- CHECK_EQ(err, -EAGAIN);
- }
-
- tryCopyDecodedBuffer(&decodedFrameIndices, filterState, vidState);
-
- tryDrainOutputBuffer(
- filterState, surface, renderSurface,
- useTimestamp, &startTimeRender);
- }
- }
-
- // after EOS on decoder, let filter reach EOS
- while (!filterState->mSawOutputEOS) {
- tryCopyDecodedBuffer(&decodedFrameIndices, filterState, vidState);
-
- tryDrainOutputBuffer(
- filterState, surface, renderSurface,
- useTimestamp, &startTimeRender);
- }
-
- int64_t elapsedTimeUs = android::ALooper::GetNowUs() - startTimeUs;
-
- for (size_t i = 0; i < stateByTrack.size(); ++i) {
- CodecState *state = &stateByTrack.editValueAt(i);
-
- CHECK_EQ((status_t)OK, state->mCodec->release());
-
- printf("track %zu: %" PRId64 " frames decoded and filtered, "
- "%.2f fps.\n", i, state->mNumBuffersDecoded,
- state->mNumBuffersDecoded * 1E6 / elapsedTimeUs);
- }
-
- return 0;
-}
-
-} // namespace android
-
-int main(int argc, char **argv) {
- using namespace android;
-
- const char *me = argv[0];
-
- bool useSurface = false;
- bool renderSurface = false;
- bool useTimestamp = false;
- FilterType filterType = FILTERTYPE_ZERO;
-
- int res;
- while ((res = getopt(argc, argv, "bcnrszTRSh")) >= 0) {
- switch (res) {
- case 'b':
- {
- filterType = FILTERTYPE_INTRINSIC_BLUR;
- break;
- }
- case 'c':
- {
- filterType = FILTERTYPE_RS_ARGB_TO_RGBA;
- break;
- }
- case 'n':
- {
- filterType = FILTERTYPE_RS_NIGHT_VISION;
- break;
- }
- case 'r':
- {
- filterType = FILTERTYPE_RS_SATURATION;
- break;
- }
- case 's':
- {
- filterType = FILTERTYPE_SATURATION;
- break;
- }
- case 'z':
- {
- filterType = FILTERTYPE_ZERO;
- break;
- }
- case 'T':
- {
- useTimestamp = true;
- FALLTHROUGH_INTENDED;
- }
- case 'R':
- {
- renderSurface = true;
- FALLTHROUGH_INTENDED;
- }
- case 'S':
- {
- useSurface = true;
- break;
- }
- case '?':
- case 'h':
- default:
- {
- usage(me);
- break;
- }
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc != 1) {
- usage(me);
- }
-
- ProcessState::self()->startThreadPool();
-
- android::sp<android::ALooper> looper = new android::ALooper;
- looper->start();
-
- android::sp<SurfaceComposerClient> composerClient;
- android::sp<SurfaceControl> control;
- android::sp<Surface> surface;
-
- if (useSurface) {
- composerClient = new SurfaceComposerClient;
- CHECK_EQ((status_t)OK, composerClient->initCheck());
-
- const std::vector<PhysicalDisplayId> ids = SurfaceComposerClient::getPhysicalDisplayIds();
- CHECK(!ids.empty());
-
- const android::sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(ids.front());
- CHECK(display != nullptr);
-
- ui::DisplayMode mode;
- CHECK_EQ(SurfaceComposerClient::getActiveDisplayMode(display, &mode), NO_ERROR);
-
- const ui::Size& resolution = mode.resolution;
- const ssize_t displayWidth = resolution.getWidth();
- const ssize_t displayHeight = resolution.getHeight();
-
- ALOGV("display is %zd x %zd", displayWidth, displayHeight);
-
- control = composerClient->createSurface(
- String8("A Surface"), displayWidth, displayHeight,
- PIXEL_FORMAT_RGBA_8888, 0);
-
- CHECK(control != NULL);
- CHECK(control->isValid());
-
- SurfaceComposerClient::Transaction{}
- .setLayer(control, INT_MAX)
- .show(control)
- .apply();
-
- surface = control->getSurface();
- CHECK(surface != NULL);
- }
-
- decode(looper, argv[0], surface, renderSurface, useTimestamp, filterType);
-
- if (useSurface) {
- composerClient->dispose();
- }
-
- looper->stop();
-
- return 0;
-}
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 5743ad6..87e8832 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -89,6 +89,9 @@
if (err != OK) {
return err;
}
+ if (buffer == nullptr) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
char x = (char)((double)rand() / RAND_MAX * 255);
memset((*buffer)->data(), x, mSize);
diff --git a/drm/README.md b/drm/README.md
new file mode 100644
index 0000000..2681aac
--- /dev/null
+++ b/drm/README.md
@@ -0,0 +1,13 @@
+## AIDL error handling
+
+Starting in **Android U (14)**, `libmediadrm` (app-side) understands extra error
+details from **AIDL** DRM HALs passed through the binder exception message
+as a json string. The supported fields are:
+* `cdmError` (*int*)
+* `oemError` (*int*)
+* `context` (*int*)
+* `errorMessage` (*str*)
+
+The errors details will be reported to apps through the java interface
+`android.media.MediaDrmThrowable`. Please see the javadoc of `MediaDrmThrowable`
+for detailed definitions of each field above.
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
index be2b546..6e55a16 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.bp
@@ -48,7 +48,6 @@
srcs: ["src/FwdLockEngine.cpp"],
shared_libs: [
- "libandroidicu",
"libutils",
"liblog",
"libdl",
diff --git a/drm/libmediadrm/Android.bp b/drm/libmediadrm/Android.bp
index 1667d5b..7d68c5b 100644
--- a/drm/libmediadrm/Android.bp
+++ b/drm/libmediadrm/Android.bp
@@ -35,6 +35,8 @@
"CryptoHalAidl.cpp",
"DrmUtils.cpp",
"DrmHalListener.cpp",
+ "DrmStatus.cpp",
+ "DrmMetricsLogger.cpp",
],
local_include_dirs: [
diff --git a/drm/libmediadrm/CryptoHal.cpp b/drm/libmediadrm/CryptoHal.cpp
index f95d527..fc1780d 100644
--- a/drm/libmediadrm/CryptoHal.cpp
+++ b/drm/libmediadrm/CryptoHal.cpp
@@ -71,7 +71,7 @@
mCryptoHalHidl->notifyResolution(width, height);
}
-status_t CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHal::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
// This requires plugin to be created.
if (mCryptoHalAidl->initCheck() == OK) return mCryptoHalAidl->setMediaDrmSession(sessionId);
return mCryptoHalHidl->setMediaDrmSession(sessionId);
diff --git a/drm/libmediadrm/CryptoHalAidl.cpp b/drm/libmediadrm/CryptoHalAidl.cpp
index f01ecb3..c1fd797 100644
--- a/drm/libmediadrm/CryptoHalAidl.cpp
+++ b/drm/libmediadrm/CryptoHalAidl.cpp
@@ -260,7 +260,7 @@
}
}
-status_t CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHalAidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
diff --git a/drm/libmediadrm/CryptoHalHidl.cpp b/drm/libmediadrm/CryptoHalHidl.cpp
index 55364b5..458a1ae 100644
--- a/drm/libmediadrm/CryptoHalHidl.cpp
+++ b/drm/libmediadrm/CryptoHalHidl.cpp
@@ -386,7 +386,7 @@
ALOGE_IF(!hResult.isOk(), "notifyResolution txn failed %s", hResult.description().c_str());
}
-status_t CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
+DrmStatus CryptoHalHidl::setMediaDrmSession(const Vector<uint8_t>& sessionId) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
diff --git a/drm/libmediadrm/DrmHalHidl.cpp b/drm/libmediadrm/DrmHalHidl.cpp
index 2e0bfee..56d63c5 100644
--- a/drm/libmediadrm/DrmHalHidl.cpp
+++ b/drm/libmediadrm/DrmHalHidl.cpp
@@ -514,10 +514,14 @@
if (mimeType == "") {
// isCryptoSchemeSupported(uuid)
*isSupported = true;
- } else {
- // isCryptoSchemeSupported(uuid, mimeType)
- *isSupported = factory->isContentTypeSupported(mimeType.string());
+ return DrmStatus(OK);
}
+ // isCryptoSchemeSupported(uuid, mimeType)
+ auto hResult = factory->isContentTypeSupported(mimeType.string());
+ if (!hResult.isOk()) {
+ return DrmStatus(DEAD_OBJECT);
+ }
+ *isSupported = hResult;
return DrmStatus(OK);
} else if (mimeType == "") {
return DrmStatus(BAD_VALUE);
@@ -527,8 +531,12 @@
if (factoryV1_2 == NULL) {
return DrmStatus(ERROR_UNSUPPORTED);
} else {
- *isSupported = factoryV1_2->isCryptoSchemeSupported_1_2(uuid, mimeType.string(),
+ auto hResult = factoryV1_2->isCryptoSchemeSupported_1_2(uuid, mimeType.string(),
toHidlSecurityLevel(level));
+ if (!hResult.isOk()) {
+ return DrmStatus(DEAD_OBJECT);
+ }
+ *isSupported = hResult;
return DrmStatus(OK);
}
}
@@ -538,7 +546,8 @@
Mutex::Autolock autoLock(mLock);
*isSupported = false;
for (ssize_t i = mFactories.size() - 1; i >= 0; i--) {
- if (mFactories[i]->isCryptoSchemeSupported(uuid)) {
+ auto hResult = mFactories[i]->isCryptoSchemeSupported(uuid);
+ if (hResult.isOk() && hResult) {
return matchMimeTypeAndSecurityLevel(mFactories[i], uuid, mimeType, level, isSupported);
}
}
diff --git a/drm/libmediadrm/DrmMetricsLogger.cpp b/drm/libmediadrm/DrmMetricsLogger.cpp
new file mode 100644
index 0000000..89b1dcc
--- /dev/null
+++ b/drm/libmediadrm/DrmMetricsLogger.cpp
@@ -0,0 +1,562 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+#define LOG_TAG "DrmMetricsLogger"
+
+#include <media/MediaMetrics.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/base64.h>
+#include <mediadrm/DrmHal.h>
+#include <mediadrm/DrmMetricsLogger.h>
+#include <mediadrm/DrmUtils.h>
+
+namespace android {
+
+namespace {
+
+std::vector<uint8_t> toStdVec(Vector<uint8_t> const& sessionId) {
+ auto sessionKey = sessionId.array();
+ std::vector<uint8_t> vec(sessionKey, sessionKey + sessionId.size());
+ return vec;
+}
+
+} // namespace
+
+DrmMetricsLogger::DrmMetricsLogger(IDrmFrontend frontend)
+ : mImpl(sp<DrmHal>::make()), mUuid(), mObjNonce(), mFrontend(frontend) {}
+
+DrmMetricsLogger::~DrmMetricsLogger() {}
+
+DrmStatus DrmMetricsLogger::initCheck() const {
+ DrmStatus status = mImpl->initCheck();
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::isCryptoSchemeSupported(const uint8_t uuid[IDRM_UUID_SIZE],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool* result) {
+ DrmStatus status = mImpl->isCryptoSchemeSupported(uuid, mimeType, securityLevel, result);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::createPlugin(const uint8_t uuid[IDRM_UUID_SIZE],
+ const String8& appPackageName) {
+ std::memcpy(mUuid.data(), uuid, IDRM_UUID_SIZE);
+ if (kUuidSchemeMap.count(mUuid)) {
+ mScheme = kUuidSchemeMap.at(mUuid);
+ } else {
+ mScheme = "Other";
+ }
+ if (generateNonce(&mObjNonce, kNonceSize, __func__) != OK) {
+ return ERROR_DRM_RESOURCE_BUSY;
+ }
+ DrmStatus status = mImpl->createPlugin(uuid, appPackageName);
+ if (status == OK) {
+ reportMediaDrmCreated();
+ } else {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::destroyPlugin() {
+ DrmStatus status = mImpl->destroyPlugin();
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t>& sessionId) {
+ SessionContext ctx{};
+ if (generateNonce(&ctx.mNonce, kNonceSize, __func__) != OK) {
+ return ERROR_DRM_RESOURCE_BUSY;
+ }
+ DrmStatus status = mImpl->openSession(securityLevel, sessionId);
+ if (status == OK) {
+ std::vector<uint8_t> sessionKey = toStdVec(sessionId);
+ ctx.mTargetSecurityLevel = securityLevel;
+ if (getSecurityLevel(sessionId, &ctx.mActualSecurityLevel) != OK) {
+ ctx.mActualSecurityLevel = DrmPlugin::kSecurityLevelUnknown;
+ }
+ {
+ const std::lock_guard<std::mutex> lock(mSessionMapMutex);
+ mSessionMap.insert({sessionKey, ctx});
+ }
+ reportMediaDrmSessionOpened(sessionKey);
+ } else {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::closeSession(Vector<uint8_t> const& sessionId) {
+ std::vector<uint8_t> sid = toStdVec(sessionId);
+ {
+ const std::lock_guard<std::mutex> lock(mSessionMapMutex);
+ mSessionMap.erase(sid);
+ }
+ DrmStatus status = mImpl->closeSession(sessionId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, sid);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType) {
+ DrmStatus status =
+ mImpl->getKeyRequest(sessionId, initData, mimeType, keyType, optionalParameters,
+ request, defaultUrl, keyRequestType);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId) {
+ DrmStatus status = mImpl->provideKeyResponse(sessionId, response, keySetId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::removeKeys(Vector<uint8_t> const& keySetId) {
+ DrmStatus status = mImpl->removeKeys(keySetId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId) {
+ DrmStatus status = mImpl->restoreKeys(sessionId, keySetId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const {
+ DrmStatus status = mImpl->queryKeyStatus(sessionId, infoMap);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getProvisionRequest(String8 const& certType,
+ String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl) {
+ DrmStatus status = mImpl->getProvisionRequest(certType, certAuthority, request, defaultUrl);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey) {
+ DrmStatus status = mImpl->provideProvisionResponse(response, certificate, wrappedKey);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getSecureStops(List<Vector<uint8_t>>& secureStops) {
+ DrmStatus status = mImpl->getSecureStops(secureStops);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getSecureStopIds(List<Vector<uint8_t>>& secureStopIds) {
+ DrmStatus status = mImpl->getSecureStopIds(secureStopIds);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getSecureStop(Vector<uint8_t> const& ssid,
+ Vector<uint8_t>& secureStop) {
+ DrmStatus status = mImpl->getSecureStop(ssid, secureStop);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::releaseSecureStops(Vector<uint8_t> const& ssRelease) {
+ DrmStatus status = mImpl->releaseSecureStops(ssRelease);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::removeSecureStop(Vector<uint8_t> const& ssid) {
+ DrmStatus status = mImpl->removeSecureStop(ssid);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::removeAllSecureStops() {
+ DrmStatus status = mImpl->removeAllSecureStops();
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const {
+ DrmStatus status = mImpl->getHdcpLevels(connectedLevel, maxLevel);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getNumberOfSessions(uint32_t* currentSessions,
+ uint32_t* maxSessions) const {
+ DrmStatus status = mImpl->getNumberOfSessions(currentSessions, maxSessions);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const {
+ DrmStatus status = mImpl->getSecurityLevel(sessionId, level);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const {
+ DrmStatus status = mImpl->getOfflineLicenseKeySetIds(keySetIds);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::removeOfflineLicense(Vector<uint8_t> const& keySetId) {
+ DrmStatus status = mImpl->removeOfflineLicense(keySetId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getOfflineLicenseState(
+ Vector<uint8_t> const& keySetId, DrmPlugin::OfflineLicenseState* licenseState) const {
+ DrmStatus status = mImpl->getOfflineLicenseState(keySetId, licenseState);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getPropertyString(String8 const& name, String8& value) const {
+ DrmStatus status = mImpl->getPropertyString(name, value);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getPropertyByteArray(String8 const& name,
+ Vector<uint8_t>& value) const {
+ DrmStatus status = mImpl->getPropertyByteArray(name, value);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setPropertyString(String8 const& name, String8 const& value) const {
+ DrmStatus status = mImpl->setPropertyString(name, value);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setPropertyByteArray(String8 const& name,
+ Vector<uint8_t> const& value) const {
+ DrmStatus status = mImpl->setPropertyByteArray(name, value);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getMetrics(const sp<IDrmMetricsConsumer>& consumer) {
+ DrmStatus status = mImpl->getMetrics(consumer);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ DrmStatus status = mImpl->setCipherAlgorithm(sessionId, algorithm);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setMacAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm) {
+ DrmStatus status = mImpl->setMacAlgorithm(sessionId, algorithm);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ DrmStatus status = mImpl->encrypt(sessionId, keyId, input, iv, output);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output) {
+ DrmStatus status = mImpl->decrypt(sessionId, keyId, input, iv, output);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature) {
+ DrmStatus status = mImpl->sign(sessionId, keyId, message, signature);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match) {
+ DrmStatus status = mImpl->verify(sessionId, keyId, message, signature, match);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message,
+ Vector<uint8_t> const& wrappedKey, Vector<uint8_t>& signature) {
+ DrmStatus status = mImpl->signRSA(sessionId, algorithm, message, wrappedKey, signature);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setListener(const sp<IDrmClient>& listener) {
+ DrmStatus status = mImpl->setListener(listener);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::requiresSecureDecoder(const char* mime, bool* required) const {
+ DrmStatus status = mImpl->requiresSecureDecoder(mime, required);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::requiresSecureDecoder(const char* mime,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const {
+ DrmStatus status = mImpl->requiresSecureDecoder(mime, securityLevel, required);
+ if (status != OK) {
+ reportMediaDrmErrored(status, "requiresSecureDecoderLevel");
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::setPlaybackId(Vector<uint8_t> const& sessionId,
+ const char* playbackId) {
+ DrmStatus status = mImpl->setPlaybackId(sessionId, playbackId);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__, toStdVec(sessionId));
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const {
+ DrmStatus status = mImpl->getLogMessages(logs);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+DrmStatus DrmMetricsLogger::getSupportedSchemes(std::vector<uint8_t>& schemes) const {
+ DrmStatus status = mImpl->getSupportedSchemes(schemes);
+ if (status != OK) {
+ reportMediaDrmErrored(status, __func__);
+ }
+ return status;
+}
+
+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_setInt32(handle, "frontend", mFrontend);
+ mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
+ mediametrics_selfRecord(handle);
+ mediametrics_delete(handle);
+}
+
+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_setInt32(handle, "frontend", mFrontend);
+ mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
+ const std::lock_guard<std::mutex> lock(mSessionMapMutex);
+ auto it = mSessionMap.find(sessionId);
+ if (it != mSessionMap.end()) {
+ mediametrics_setCString(handle, "session_nonce", it->second.mNonce.c_str());
+ mediametrics_setInt64(handle, "requested_seucrity_level", it->second.mTargetSecurityLevel);
+ mediametrics_setInt64(handle, "opened_seucrity_level", it->second.mActualSecurityLevel);
+ }
+ mediametrics_selfRecord(handle);
+ mediametrics_delete(handle);
+}
+
+void DrmMetricsLogger::reportMediaDrmErrored(const DrmStatus& error_code, const char* api,
+ 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_setInt32(handle, "frontend", mFrontend);
+ mediametrics_setCString(handle, "object_nonce", mObjNonce.c_str());
+ if (!sessionId.empty()) {
+ const std::lock_guard<std::mutex> lock(mSessionMapMutex);
+ auto it = mSessionMap.find(sessionId);
+ if (it != mSessionMap.end()) {
+ mediametrics_setCString(handle, "session_nonce", it->second.mNonce.c_str());
+ mediametrics_setInt64(handle, "seucrity_level", it->second.mActualSecurityLevel);
+ }
+ }
+ mediametrics_setCString(handle, "api", api);
+ mediametrics_setInt32(handle, "error_code", error_code);
+ mediametrics_setInt32(handle, "cdm_err", error_code.getCdmErr());
+ mediametrics_setInt32(handle, "oem_err", error_code.getOemErr());
+ mediametrics_setInt32(handle, "error_context", error_code.getContext());
+ mediametrics_selfRecord(handle);
+ mediametrics_delete(handle);
+}
+
+DrmStatus DrmMetricsLogger::generateNonce(std::string* out, size_t size, const char* api) {
+ std::vector<uint8_t> buf(size);
+ ssize_t bytes = getrandom(buf.data(), size, GRND_NONBLOCK);
+ if (bytes < size) {
+ ALOGE("getrandom failed: %d", errno);
+ reportMediaDrmErrored(ERROR_DRM_RESOURCE_BUSY, api);
+ return ERROR_DRM_RESOURCE_BUSY;
+ }
+ android::AString tmp;
+ encodeBase64(buf.data(), size, &tmp);
+ out->assign(tmp.c_str());
+ return OK;
+}
+
+const std::map<std::array<int64_t, 2>, std::string> DrmMetricsLogger::kUuidSchemeMap {
+ {{(int64_t)0x6DD8B3C345F44A68, (int64_t)0xBF3A64168D01A4A6}, "ABV DRM (MoDRM)"},
+ {{(int64_t)0xF239E769EFA34850, (int64_t)0x9C16A903C6932EFB},
+ "Adobe Primetime DRM version 4"},
+ {{(int64_t)0x616C746963617374, (int64_t)0x2D50726F74656374}, "Alticast"},
+ {{(int64_t)0x94CE86FB07FF4F43, (int64_t)0xADB893D2FA968CA2}, "Apple FairPlay"},
+ {{(int64_t)0x279FE473512C48FE, (int64_t)0xADE8D176FEE6B40F}, "Arris Titanium"},
+ {{(int64_t)0x3D5E6D359B9A41E8, (int64_t)0xB843DD3C6E72C42C}, "ChinaDRM"},
+ {{(int64_t)0x3EA8778F77424BF9, (int64_t)0xB18BE834B2ACBD47}, "Clear Key AES-128"},
+ {{(int64_t)0xBE58615B19C44684, (int64_t)0x88B3C8C57E99E957}, "Clear Key SAMPLE-AES"},
+ {{(int64_t)0xE2719D58A985B3C9, (int64_t)0x781AB030AF78D30E}, "Clear Key DASH-IF"},
+ {{(int64_t)0x644FE7B5260F4FAD, (int64_t)0x949A0762FFB054B4}, "CMLA (OMA DRM)"},
+ {{(int64_t)0x37C332587B994C7E, (int64_t)0xB15D19AF74482154}, "Commscope Titanium V3"},
+ {{(int64_t)0x45D481CB8FE049C0, (int64_t)0xADA9AB2D2455B2F2}, "CoreCrypt"},
+ {{(int64_t)0xDCF4E3E362F15818, (int64_t)0x7BA60A6FE33FF3DD}, "DigiCAP SmartXess"},
+ {{(int64_t)0x35BF197B530E42D7, (int64_t)0x8B651B4BF415070F}, "DivX DRM Series 5"},
+ {{(int64_t)0x80A6BE7E14484C37, (int64_t)0x9E70D5AEBE04C8D2}, "Irdeto Content Protection"},
+ {{(int64_t)0x5E629AF538DA4063, (int64_t)0x897797FFBD9902D4},
+ "Marlin Adaptive Streaming Simple Profile V1.0"},
+ {{(int64_t)0x9A04F07998404286, (int64_t)0xAB92E65BE0885F95}, "Microsoft PlayReady"},
+ {{(int64_t)0x6A99532D869F5922, (int64_t)0x9A91113AB7B1E2F3}, "MobiTV DRM"},
+ {{(int64_t)0xADB41C242DBF4A6D, (int64_t)0x958B4457C0D27B95}, "Nagra MediaAccess PRM 3.0"},
+ {{(int64_t)0x1F83E1E86EE94F0D, (int64_t)0xBA2F5EC4E3ED1A66}, "SecureMedia"},
+ {{(int64_t)0x992C46E6C4374899, (int64_t)0xB6A050FA91AD0E39}, "SecureMedia SteelKnot"},
+ {{(int64_t)0xA68129D3575B4F1A, (int64_t)0x9CBA3223846CF7C3},
+ "Synamedia/Cisco/NDS VideoGuard DRM"},
+ {{(int64_t)0xAA11967FCC014A4A, (int64_t)0x8E99C5D3DDDFEA2D}, "Unitend DRM (UDRM)"},
+ {{(int64_t)0x9A27DD82FDE24725, (int64_t)0x8CBC4234AA06EC09}, "Verimatrix VCAS"},
+ {{(int64_t)0xB4413586C58CFFB0, (int64_t)0x94A5D4896C1AF6C3}, "Viaccess-Orca DRM (VODRM)"},
+ {{(int64_t)0x793B79569F944946, (int64_t)0xA94223E7EF7E44B4}, "VisionCrypt"},
+ {{(int64_t)0x1077EFECC0B24D02, (int64_t)0xACE33C1E52E2FB4B}, "W3C Common PSSH box"},
+ {{(int64_t)0xEDEF8BA979D64ACE, (int64_t)0xA3C827DCD51D21ED}, "Widevine Content Protection"},
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/drm/libmediadrm/DrmStatus.cpp b/drm/libmediadrm/DrmStatus.cpp
new file mode 100644
index 0000000..f622160
--- /dev/null
+++ b/drm/libmediadrm/DrmStatus.cpp
@@ -0,0 +1,50 @@
+/*
+ * 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 <mediadrm/DrmStatus.h>
+#include <json/json.h>
+
+namespace android {
+
+DrmStatus::DrmStatus(status_t err, const char *msg) : mStatus(err) {
+ Json::Value errorDetails;
+ Json::Reader reader;
+ if (!reader.parse(msg, errorDetails)) {
+ mErrMsg = msg;
+ return;
+ }
+
+ auto val = errorDetails["cdmError"];
+ if (val.isInt()) {
+ mCdmErr = val.asInt();
+ }
+ val = errorDetails["oemError"];
+ if (val.isInt()) {
+ mOemErr = val.asInt();
+ }
+ val = errorDetails["context"];
+ if (val.isInt()) {
+ mCtx = val.asInt();
+ }
+ val = errorDetails["errorMessage"];
+ if (val.isString()) {
+ mErrMsg = val.asString();
+ } else {
+ mErrMsg = msg;
+ }
+}
+
+} // namespace android
diff --git a/drm/libmediadrm/DrmUtils.cpp b/drm/libmediadrm/DrmUtils.cpp
index b3271a2..a99b1d1 100644
--- a/drm/libmediadrm/DrmUtils.cpp
+++ b/drm/libmediadrm/DrmUtils.cpp
@@ -59,11 +59,11 @@
namespace {
-template <typename Hal>
-Hal* MakeObject(status_t* pstatus) {
+template <typename Hal, typename... Ts>
+Hal* MakeObject(status_t* pstatus, Ts... args) {
status_t err = OK;
status_t& status = pstatus ? *pstatus : err;
- auto obj = new Hal();
+ auto obj = new Hal(args...);
status = obj->initCheck();
if (status != OK && status != NO_INIT) {
return NULL;
@@ -192,8 +192,8 @@
return factories;
}
-sp<IDrm> MakeDrm(status_t* pstatus) {
- return MakeObject<DrmHal>(pstatus);
+sp<IDrm> MakeDrm(IDrmFrontend frontend, status_t* pstatus) {
+ return MakeObject<DrmMetricsLogger>(pstatus, frontend);
}
sp<ICrypto> MakeCrypto(status_t* pstatus) {
@@ -548,31 +548,7 @@
break;
}
- Json::Value errorDetails;
- Json::Reader reader;
- if (!reader.parse(statusAidl.getMessage(), errorDetails)) {
- return status;
- }
-
- int32_t cdmErr{}, oemErr{}, ctx{};
- std::string errMsg;
- auto val = errorDetails["cdmError"];
- if (!val.isNull()) {
- cdmErr = val.asInt();
- }
- val = errorDetails["oemError"];
- if (!val.isNull()) {
- oemErr = val.asInt();
- }
- val = errorDetails["context"];
- if (!val.isNull()) {
- ctx = val.asInt();
- }
- val = errorDetails["errorMessage"];
- if (!val.isNull()) {
- errMsg = val.asString();
- }
- return DrmStatus(status, cdmErr, oemErr, ctx, errMsg);
+ return DrmStatus(status, statusAidl.getMessage());
}
LogBuffer gLogBuf;
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHal.h b/drm/libmediadrm/include/mediadrm/CryptoHal.h
index 32a6741..60cbbf8 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHal.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHal.h
@@ -38,7 +38,7 @@
virtual bool requiresSecureDecoderComponent(
const char *mime) const;
virtual void notifyResolution(uint32_t width, uint32_t height);
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+ virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId);
virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
const drm::V1_0::SharedBuffer &source, size_t offset,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
index 50878a6..eec4585 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalAidl.h
@@ -49,7 +49,7 @@
virtual status_t destroyPlugin();
virtual bool requiresSecureDecoderComponent(const char* mime) const;
virtual void notifyResolution(uint32_t width, uint32_t height);
- virtual status_t setMediaDrmSession(const Vector<uint8_t>& sessionId);
+ virtual DrmStatus setMediaDrmSession(const Vector<uint8_t>& sessionId);
virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16], CryptoPlugin::Mode mode,
const CryptoPlugin::Pattern& pattern, const ::SharedBuffer& source,
size_t offset, const CryptoPlugin::SubSample* subSamples,
diff --git a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
index 6db1e89..0150d7c 100644
--- a/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
+++ b/drm/libmediadrm/include/mediadrm/CryptoHalHidl.h
@@ -57,7 +57,7 @@
virtual void notifyResolution(uint32_t width, uint32_t height);
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId);
+ virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId);
virtual ssize_t decrypt(const uint8_t key[16], const uint8_t iv[16],
CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
diff --git a/drm/libmediadrm/include/mediadrm/DrmHalHidl.h b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
index 45764a1..73a9e1d 100644
--- a/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
+++ b/drm/libmediadrm/include/mediadrm/DrmHalHidl.h
@@ -70,7 +70,7 @@
DrmPlugin::SecurityLevel level, bool* isSupported);
virtual DrmStatus createPlugin(const uint8_t uuid[16],
- const String8 &appPackageName);
+ const String8 &appPackageName);
virtual DrmStatus destroyPlugin();
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h b/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h
new file mode 100644
index 0000000..f4e3c3e
--- /dev/null
+++ b/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h
@@ -0,0 +1,172 @@
+/*
+ * 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 <mediadrm/DrmStatus.h>
+#include <mediadrm/IDrm.h>
+#include <sys/random.h>
+#include <map>
+#include <mutex>
+
+#ifndef DRM_METRICS_LOGGER_H
+#define DRM_METRICS_LOGGER_H
+
+namespace android {
+
+struct SessionContext {
+ std::string mNonce;
+ int64_t mTargetSecurityLevel;
+ DrmPlugin::SecurityLevel mActualSecurityLevel;
+};
+
+class DrmMetricsLogger : public IDrm {
+ public:
+ DrmMetricsLogger(IDrmFrontend);
+
+ virtual ~DrmMetricsLogger();
+
+ virtual DrmStatus initCheck() const;
+
+ virtual DrmStatus isCryptoSchemeSupported(const uint8_t uuid[IDRM_UUID_SIZE],
+ const String8& mimeType,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool* result);
+
+ virtual DrmStatus createPlugin(const uint8_t uuid[IDRM_UUID_SIZE],
+ const String8& appPackageName);
+
+ virtual DrmStatus destroyPlugin();
+
+ virtual DrmStatus openSession(DrmPlugin::SecurityLevel securityLevel,
+ Vector<uint8_t>& sessionId);
+
+ virtual DrmStatus closeSession(Vector<uint8_t> const& sessionId);
+
+ virtual DrmStatus getKeyRequest(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& initData, String8 const& mimeType,
+ DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const& optionalParameters,
+ Vector<uint8_t>& request, String8& defaultUrl,
+ DrmPlugin::KeyRequestType* keyRequestType);
+
+ virtual DrmStatus provideKeyResponse(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& response,
+ Vector<uint8_t>& keySetId);
+
+ virtual DrmStatus removeKeys(Vector<uint8_t> const& keySetId);
+
+ virtual DrmStatus restoreKeys(Vector<uint8_t> const& sessionId,
+ Vector<uint8_t> const& keySetId);
+
+ virtual DrmStatus queryKeyStatus(Vector<uint8_t> const& sessionId,
+ KeyedVector<String8, String8>& infoMap) const;
+
+ virtual DrmStatus getProvisionRequest(String8 const& certType, String8 const& certAuthority,
+ Vector<uint8_t>& request, String8& defaultUrl);
+
+ virtual DrmStatus provideProvisionResponse(Vector<uint8_t> const& response,
+ Vector<uint8_t>& certificate,
+ Vector<uint8_t>& wrappedKey);
+
+ virtual DrmStatus getSecureStops(List<Vector<uint8_t>>& secureStops);
+ virtual DrmStatus getSecureStopIds(List<Vector<uint8_t>>& secureStopIds);
+ virtual DrmStatus getSecureStop(Vector<uint8_t> const& ssid, Vector<uint8_t>& secureStop);
+
+ virtual DrmStatus releaseSecureStops(Vector<uint8_t> const& ssRelease);
+ virtual DrmStatus removeSecureStop(Vector<uint8_t> const& ssid);
+ virtual DrmStatus removeAllSecureStops();
+
+ virtual DrmStatus getHdcpLevels(DrmPlugin::HdcpLevel* connectedLevel,
+ DrmPlugin::HdcpLevel* maxLevel) const;
+ virtual DrmStatus getNumberOfSessions(uint32_t* currentSessions, uint32_t* maxSessions) const;
+ virtual DrmStatus getSecurityLevel(Vector<uint8_t> const& sessionId,
+ DrmPlugin::SecurityLevel* level) const;
+
+ virtual DrmStatus getOfflineLicenseKeySetIds(List<Vector<uint8_t>>& keySetIds) const;
+ virtual DrmStatus removeOfflineLicense(Vector<uint8_t> const& keySetId);
+ virtual DrmStatus getOfflineLicenseState(Vector<uint8_t> const& keySetId,
+ DrmPlugin::OfflineLicenseState* licenseState) const;
+
+ virtual DrmStatus getPropertyString(String8 const& name, String8& value) const;
+ virtual DrmStatus getPropertyByteArray(String8 const& name, Vector<uint8_t>& value) const;
+ virtual DrmStatus setPropertyString(String8 const& name, String8 const& value) const;
+ virtual DrmStatus setPropertyByteArray(String8 const& name, Vector<uint8_t> const& value) const;
+
+ virtual DrmStatus getMetrics(const sp<IDrmMetricsConsumer>& consumer);
+
+ virtual DrmStatus setCipherAlgorithm(Vector<uint8_t> const& sessionId,
+ String8 const& algorithm);
+
+ virtual DrmStatus setMacAlgorithm(Vector<uint8_t> const& sessionId, String8 const& algorithm);
+
+ virtual DrmStatus encrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+
+ virtual DrmStatus decrypt(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& input, Vector<uint8_t> const& iv,
+ Vector<uint8_t>& output);
+
+ virtual DrmStatus sign(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t>& signature);
+
+ virtual DrmStatus verify(Vector<uint8_t> const& sessionId, Vector<uint8_t> const& keyId,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& signature,
+ bool& match);
+
+ virtual DrmStatus signRSA(Vector<uint8_t> const& sessionId, String8 const& algorithm,
+ Vector<uint8_t> const& message, Vector<uint8_t> const& wrappedKey,
+ Vector<uint8_t>& signature);
+
+ virtual DrmStatus setListener(const sp<IDrmClient>& listener);
+
+ virtual DrmStatus requiresSecureDecoder(const char* mime, bool* required) const;
+
+ virtual DrmStatus requiresSecureDecoder(const char* mime,
+ DrmPlugin::SecurityLevel securityLevel,
+ bool* required) const;
+
+ virtual DrmStatus setPlaybackId(Vector<uint8_t> const& sessionId, const char* playbackId);
+
+ virtual DrmStatus getLogMessages(Vector<drm::V1_4::LogMessage>& logs) const;
+
+ virtual DrmStatus getSupportedSchemes(std::vector<uint8_t>& schemes) const;
+
+ void reportMediaDrmCreated() const;
+
+ void reportMediaDrmSessionOpened(const std::vector<uint8_t>& sessionId) const;
+
+ void reportMediaDrmErrored(
+ const DrmStatus& error_code, const char* api,
+ const std::vector<uint8_t>& sessionId = std::vector<uint8_t>()) const;
+
+ DrmStatus generateNonce(std::string* out, size_t size, const char* api);
+
+ private:
+ static const size_t kNonceSize = 16;
+ static const std::map<std::array<int64_t, 2>, std::string> kUuidSchemeMap;
+ sp<IDrm> mImpl;
+ std::array<int64_t, 2> mUuid;
+ std::string mObjNonce;
+ std::string mScheme;
+ std::map<std::vector<uint8_t>, SessionContext> mSessionMap;
+ mutable std::mutex mSessionMapMutex;
+ IDrmFrontend mFrontend;
+ DISALLOW_EVIL_CONSTRUCTORS(DrmMetricsLogger);
+};
+
+} // namespace android
+
+#endif // DRM_METRICS_LOGGER_H
\ No newline at end of file
diff --git a/drm/libmediadrm/include/mediadrm/IDrm.h b/drm/libmediadrm/include/mediadrm/IDrm.h
index 3dc7485..ff5f63b 100644
--- a/drm/libmediadrm/include/mediadrm/IDrm.h
+++ b/drm/libmediadrm/include/mediadrm/IDrm.h
@@ -24,6 +24,8 @@
#define ANDROID_IDRM_H_
+#define IDRM_UUID_SIZE (16)
+
namespace android {
namespace hardware {
namespace drm {
@@ -33,6 +35,13 @@
} // namespace drm
} // namespace hardware
+enum IDrmFrontend : int32_t {
+ IDRM_UNKNOWN = 0,
+ IDRM_JNI = 1,
+ IDRM_NDK = 2,
+ IDRM_NUPLAYER = 3,
+};
+
namespace drm = ::android::hardware::drm;
struct AString;
diff --git a/drm/libmediadrm/include/mediadrm/DrmStatus.h b/drm/libmediadrm/interface/mediadrm/DrmStatus.h
similarity index 95%
rename from drm/libmediadrm/include/mediadrm/DrmStatus.h
rename to drm/libmediadrm/interface/mediadrm/DrmStatus.h
index 1155af6..15826ca 100644
--- a/drm/libmediadrm/include/mediadrm/DrmStatus.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmStatus.h
@@ -32,6 +32,7 @@
int32_t ctx = 0, std::string errMsg = "")
: mStatus(status), mCdmErr(cdmErr), mOemErr(oemErr),
mCtx(ctx), mErrMsg(errMsg) {}
+ DrmStatus(status_t err, const char *msg);
operator status_t() const { return mStatus; }
int32_t getCdmErr() const { return mCdmErr; }
int32_t getOemErr() const { return mOemErr; }
@@ -41,7 +42,7 @@
bool operator!=(status_t other) const { return mStatus != other; }
private:
- status_t mStatus;
+ status_t mStatus{};
int32_t mCdmErr{}, mOemErr{}, mCtx{};
std::string mErrMsg;
};
diff --git a/drm/libmediadrm/interface/mediadrm/DrmUtils.h b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
index cb4c944..ce8536c 100644
--- a/drm/libmediadrm/interface/mediadrm/DrmUtils.h
+++ b/drm/libmediadrm/interface/mediadrm/DrmUtils.h
@@ -22,6 +22,7 @@
#include <android/hardware/drm/1.4/IDrmPlugin.h>
#include <android/hardware/drm/1.4/types.h>
#include <media/stagefright/MediaErrors.h>
+#include <mediadrm/DrmMetricsLogger.h>
#include <mediadrm/DrmStatus.h>
#include <utils/Errors.h> // for status_t
#include <utils/Log.h>
@@ -119,7 +120,7 @@
bool UseDrmService();
-sp<IDrm> MakeDrm(status_t *pstatus = nullptr);
+sp<IDrm> MakeDrm(IDrmFrontend frontend = IDRM_JNI, status_t* pstatus = nullptr);
sp<ICrypto> MakeCrypto(status_t *pstatus = nullptr);
@@ -289,7 +290,9 @@
template<typename T>
std::string GetExceptionMessage(const DrmStatus &err, const char *defaultMsg, const sp<T> &iface) {
Vector<::V1_4::LogMessage> logs;
- iface->getLogMessages(logs);
+ if (iface != NULL) {
+ iface->getLogMessages(logs);
+ }
return GetExceptionMessage(err, defaultMsg, logs);
}
diff --git a/drm/libmediadrm/interface/mediadrm/ICrypto.h b/drm/libmediadrm/interface/mediadrm/ICrypto.h
index 2c4df60..4087186 100644
--- a/drm/libmediadrm/interface/mediadrm/ICrypto.h
+++ b/drm/libmediadrm/interface/mediadrm/ICrypto.h
@@ -17,6 +17,7 @@
#include <cutils/native_handle.h>
#include <media/hardware/CryptoAPI.h>
#include <media/stagefright/foundation/ABase.h>
+#include <mediadrm/DrmStatus.h>
#include <utils/RefBase.h>
#include <utils/StrongPointer.h>
@@ -65,7 +66,7 @@
virtual void notifyResolution(uint32_t width, uint32_t height) = 0;
- virtual status_t setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
+ virtual DrmStatus setMediaDrmSession(const Vector<uint8_t> &sessionId) = 0;
enum DestinationType {
kDestinationTypeSharedMemory, // non-secure
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index 2732aa7..eaf5051 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -37,6 +37,7 @@
static_libs: [
"android.hardware.common-V2-ndk",
"libclearkeybase",
+ "libjsoncpp",
],
local_include_dirs: ["include"],
@@ -99,6 +100,7 @@
static_libs: [
"android.hardware.common-V2-ndk",
"libclearkeybase_fuzz",
+ "libjsoncpp",
],
local_include_dirs: ["include"],
@@ -114,13 +116,10 @@
"fuzz_aidl_clearkey_service_defaults",
"service_fuzzer_defaults",
],
- static_libs: [
- "liblog",
- ],
srcs: ["fuzzer.cpp"],
fuzz_config: {
cc: [
"hamzeh@google.com",
],
},
-}
\ No newline at end of file
+}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
index 054eabd..31cb7c0 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/aidl/DrmPlugin.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "clearkey-DrmPlugin"
#include <aidl/android/hardware/drm/DrmMetric.h>
+#include <android-base/parseint.h>
#include <utils/Log.h>
#include <inttypes.h>
@@ -83,12 +84,14 @@
void DrmPlugin::initProperties() {
mStringProperties.clear();
mStringProperties[kVendorKey] = kAidlVendorValue;
- mStringProperties[kVersionKey] = kAidlVersionValue;
+ mStringProperties[kVersionKey] = kVersionValue;
mStringProperties[kPluginDescriptionKey] = kAidlPluginDescriptionValue;
mStringProperties[kAlgorithmsKey] = kAidlAlgorithmsValue;
mStringProperties[kListenerTestSupportKey] = kAidlListenerTestSupportValue;
mStringProperties[kDrmErrorTestKey] = kAidlDrmErrorTestValue;
mStringProperties[kAidlVersionKey] = kAidlVersionValue;
+ mStringProperties[kOemErrorKey] = "0";
+ mStringProperties[kErrorContextKey] = "0";
std::vector<uint8_t> valueVector;
valueVector.clear();
@@ -102,6 +105,26 @@
mByteArrayProperties[kMetricsKey] = valueVector;
}
+int32_t DrmPlugin::getIntProperty(const std::string& prop, int32_t defaultVal) const {
+ if (!mStringProperties.count(prop)) {
+ return defaultVal;
+ }
+ int32_t out = defaultVal;
+ if (!::android::base::ParseInt(mStringProperties.at(prop), &out)) {
+ return defaultVal;
+ }
+ return out;
+}
+
+int32_t DrmPlugin::getOemError() const {
+ return getIntProperty(kOemErrorKey);
+}
+
+int32_t DrmPlugin::getErrorContext() const {
+ return getIntProperty(kErrorContextKey);
+}
+
+//
// The secure stop in ClearKey implementation is not installed securely.
// This function merely creates a test environment for testing secure stops APIs.
// The content in this secure stop is implementation dependent, the clearkey
@@ -127,7 +150,10 @@
mSessionLibrary->destroySession(session);
if (session->getMockError() != clearkeydrm::OK) {
sendSessionLostState(in_sessionId);
- return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE);
+ return toNdkScopedAStatus(Status::ERROR_DRM_INVALID_STATE,
+ nullptr,
+ getOemError(),
+ getErrorContext());
}
mCloseSessionOkCount++;
return toNdkScopedAStatus(Status::OK);
@@ -198,7 +224,8 @@
if (!session.get()) {
return toNdkScopedAStatus(Status::ERROR_DRM_SESSION_NOT_OPENED);
} else if (session->getMockError() != clearkeydrm::OK) {
- return toNdkScopedAStatus(session->getMockError());
+ auto err = static_cast<Status>(session->getMockError());
+ return toNdkScopedAStatus(err, nullptr, getOemError(), getErrorContext());
}
keyRequestType = KeyRequestType::INITIAL;
}
@@ -381,6 +408,10 @@
value = mStringProperties[kDrmErrorTestKey];
} else if (name == kAidlVersionKey) {
value = mStringProperties[kAidlVersionKey];
+ } else if (name == kOemErrorKey) {
+ value = mStringProperties[kOemErrorKey];
+ } else if (name == kErrorContextKey) {
+ value = mStringProperties[kErrorContextKey];
} else {
ALOGE("App requested unknown string property %s", name.c_str());
status = Status::ERROR_DRM_CANNOT_HANDLE;
@@ -921,6 +952,13 @@
}
}
+ if (in_propertyName == kOemErrorKey || in_propertyName == kErrorContextKey) {
+ int32_t err = 0;
+ if (!::android::base::ParseInt(in_value, &err)) {
+ return toNdkScopedAStatus(Status::BAD_VALUE);
+ }
+ }
+
mStringProperties[key] = std::string(in_value.c_str());
return toNdkScopedAStatus(Status::OK);
}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
index 9257b17..0db3c37 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/AidlUtils.h
@@ -15,9 +15,12 @@
*/
#pragma once
+#include <cstdint>
#include <string>
#include <vector>
+#include <json/json.h>
+
#include <android/binder_auto_utils.h>
#include "aidl/android/hardware/drm/Status.h"
#include "ClearKeyTypes.h"
@@ -41,17 +44,32 @@
}
inline ::ndk::ScopedAStatus toNdkScopedAStatus(::aidl::android::hardware::drm::Status status,
- const char* msg = nullptr) {
+ const char* msg = nullptr,
+ int32_t oemError = 0,
+ int32_t errorContext = 0) {
+
+
if (Status::OK == status) {
return ::ndk::ScopedAStatus::ok();
- } else {
- auto err = static_cast<int32_t>(status);
- if (msg) {
- return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(err, msg);
- } else {
- return ::ndk::ScopedAStatus::fromServiceSpecificError(err);
- }
}
+
+ Json::Value errObj(Json::objectValue);
+ auto err = static_cast<int32_t>(status);
+ errObj["cdmError"] = err;
+
+ if (oemError) {
+ errObj["oemError"] = oemError;
+ }
+ if (errorContext) {
+ errObj["context"] = errorContext;
+ }
+ if (msg) {
+ errObj["errorMessage"] = msg;
+ }
+
+ Json::FastWriter writer;
+ return ::ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ err, writer.write(errObj).c_str());
}
inline ::ndk::ScopedAStatus toNdkScopedAStatus(clearkeydrm::CdmResponseType res) {
diff --git a/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
index 7acc1b6..694013a 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/aidl/include/DrmPlugin.h
@@ -148,6 +148,9 @@
private:
void initProperties();
+ int32_t getIntProperty(const std::string& prop, int32_t defaultVal = 0) const;
+ int32_t getOemError() const;
+ int32_t getErrorContext() const;
void installSecureStop(const std::vector<uint8_t>& sessionId);
bool makeKeySetId(std::string* keySetId);
void setPlayPolicy();
diff --git a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
index bfda388..d4e641e 100644
--- a/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/common/include/clearkeydrm/ClearKeyDrmProperties.h
@@ -21,7 +21,7 @@
static const std::string kVendorKey("vendor");
static const std::string kVendorValue("Google");
static const std::string kVersionKey("version");
-static const std::string kVersionValue("1.2");
+static const std::string kVersionValue("14"); // sync with Android OS version
static const std::string kPluginDescriptionKey("description");
static const std::string kPluginDescriptionValue("ClearKey CDM");
static const std::string kAlgorithmsKey("algorithms");
@@ -35,6 +35,8 @@
static const std::string kFrameTooLargeValue("frameTooLarge");
static const std::string kInvalidStateValue("invalidState");
static const std::string kAidlVersionKey("aidlVersion");
+static const std::string kOemErrorKey("oemError");
+static const std::string kErrorContextKey("errorContext");
static const std::string kDeviceIdKey("deviceId");
static const uint8_t kTestDeviceIdData[] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
diff --git a/include/media/MicrophoneInfo.h b/include/media/MicrophoneInfo.h
index a5045b9..6d6c594 100644
--- a/include/media/MicrophoneInfo.h
+++ b/include/media/MicrophoneInfo.h
@@ -70,6 +70,9 @@
}
virtual status_t writeToParcelable(MicrophoneInfoData* parcelable) const {
+#if defined(BACKEND_NDK)
+ using ::aidl::android::convertReinterpret;
+#endif
parcelable->deviceId = mDeviceId;
parcelable->portId = mPortId;
parcelable->type = VALUE_OR_RETURN_STATUS(convertReinterpret<int32_t>(mType));
@@ -98,6 +101,9 @@
}
virtual status_t readFromParcelable(const MicrophoneInfoData& parcelable) {
+#if defined(BACKEND_NDK)
+ using ::aidl::android::convertReinterpret;
+#endif
mDeviceId = parcelable.deviceId;
mPortId = parcelable.portId;
mType = VALUE_OR_RETURN_STATUS(convertReinterpret<uint32_t>(parcelable.type));
@@ -208,6 +214,10 @@
int32_t mDirectionality;
};
+#if defined(BACKEND_NDK)
+using ::aidl::ConversionResult;
+#endif
+
// Conversion routines, according to AidlConversion.h conventions.
inline ConversionResult<MicrophoneInfo>
aidl2legacy_MicrophoneInfo(const media::MicrophoneInfoData& aidl) {
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index ea1ec0c..d0ff091 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -29,7 +29,7 @@
#include <media/stagefright/foundation/MediaDefs.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
-// Utilities
+// AIDL CPP/NDK backend to legacy audio data structure conversion utilities.
#if defined(BACKEND_NDK)
/* AIDL String generated in NDK is different than CPP */
@@ -53,6 +53,7 @@
using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioDeviceType;
+using media::audio::common::AudioDualMonoMode;
using media::audio::common::AudioEncapsulationMetadataType;
using media::audio::common::AudioEncapsulationMode;
using media::audio::common::AudioEncapsulationType;
@@ -63,9 +64,13 @@
using media::audio::common::AudioGainMode;
using media::audio::common::AudioInputFlags;
using media::audio::common::AudioIoFlags;
+using media::audio::common::AudioLatencyMode;
using media::audio::common::AudioMode;
using media::audio::common::AudioOffloadInfo;
using media::audio::common::AudioOutputFlags;
+using media::audio::common::AudioPlaybackRate;
+using media::audio::common::AudioPort;
+using media::audio::common::AudioPortConfig;
using media::audio::common::AudioPortDeviceExt;
using media::audio::common::AudioPortExt;
using media::audio::common::AudioPortMixExt;
@@ -474,6 +479,15 @@
{
AUDIO_DEVICE_IN_ECHO_REFERENCE, make_AudioDeviceDescription(
AudioDeviceType::IN_ECHO_REFERENCE)
+ },
+ {
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, make_AudioDeviceDescription(
+ AudioDeviceType::IN_SUBMIX)
+ },
+ {
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, make_AudioDeviceDescription(
+ AudioDeviceType::OUT_SUBMIX,
+ GET_DEVICE_DESC_CONNECTION(VIRTUAL))
}
}};
append_AudioDeviceDescription(pairs,
@@ -492,9 +506,6 @@
AudioDeviceType::IN_DEVICE, AudioDeviceType::OUT_DEVICE,
GET_DEVICE_DESC_CONNECTION(HDMI));
append_AudioDeviceDescription(pairs,
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- AudioDeviceType::IN_SUBMIX, AudioDeviceType::OUT_SUBMIX);
- append_AudioDeviceDescription(pairs,
AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,
AudioDeviceType::IN_DOCK, AudioDeviceType::OUT_DOCK,
GET_DEVICE_DESC_CONNECTION(ANALOG));
@@ -843,8 +854,8 @@
case Tag::indexMask:
// Index masks do not have pre-defined values.
if (const int bits = aidl.get<Tag::indexMask>();
- __builtin_popcount(bits) != 0 &&
- __builtin_popcount(bits) <= AUDIO_CHANNEL_COUNT_MAX) {
+ __builtin_popcount(bits) != 0 &&
+ __builtin_popcount(bits) <= (int)AUDIO_CHANNEL_COUNT_MAX) {
return audio_channel_mask_from_representation_and_bits(
AUDIO_CHANNEL_REPRESENTATION_INDEX, bits);
} else {
@@ -1120,7 +1131,7 @@
for (size_t i = 0; i < numValues; ++i) {
legacy.values[i] = VALUE_OR_RETURN(convertIntegral<int>(aidl.values[i]));
}
- legacy.ramp_duration_ms = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.rampDurationMs));
+ legacy.ramp_duration_ms = VALUE_OR_RETURN(convertIntegral<int>(aidl.rampDurationMs));
return legacy;
}
@@ -1164,6 +1175,10 @@
return AUDIO_INPUT_FLAG_DIRECT;
case AudioInputFlags::ULTRASOUND:
return AUDIO_INPUT_FLAG_ULTRASOUND;
+ case AudioInputFlags::HOTWORD_TAP:
+ return AUDIO_INPUT_FLAG_HOTWORD_TAP;
+ case AudioInputFlags::HW_LOOKBACK:
+ return AUDIO_INPUT_FLAG_HW_LOOKBACK;
}
return unexpected(BAD_VALUE);
}
@@ -1191,6 +1206,10 @@
return AudioInputFlags::DIRECT;
case AUDIO_INPUT_FLAG_ULTRASOUND:
return AudioInputFlags::ULTRASOUND;
+ case AUDIO_INPUT_FLAG_HOTWORD_TAP:
+ return AudioInputFlags::HOTWORD_TAP;
+ case AUDIO_INPUT_FLAG_HW_LOOKBACK:
+ return AudioInputFlags::HW_LOOKBACK;
}
return unexpected(BAD_VALUE);
}
@@ -1707,12 +1726,12 @@
legacy.format = base.format;
legacy.stream_type = VALUE_OR_RETURN(
aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
- legacy.bit_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitRatePerSecond));
+ legacy.bit_rate = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.bitRatePerSecond));
legacy.duration_us = VALUE_OR_RETURN(convertIntegral<int64_t>(aidl.durationUs));
legacy.has_video = aidl.hasVideo;
legacy.is_streaming = aidl.isStreaming;
- legacy.bit_width = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitWidth));
- legacy.offload_buffer_size = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.offloadBufferSize));
+ legacy.bit_width = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.bitWidth));
+ legacy.offload_buffer_size = VALUE_OR_RETURN(convertIntegral<int32_t>(aidl.offloadBufferSize));
legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
legacy.encapsulation_mode = VALUE_OR_RETURN(
aidl2legacy_AudioEncapsulationMode_audio_encapsulation_mode_t(aidl.encapsulationMode));
@@ -1757,6 +1776,60 @@
return aidl;
}
+ConversionResult<AudioPortDirection> portDirection(audio_port_role_t role, audio_port_type_t type) {
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ case AUDIO_PORT_TYPE_SESSION:
+ break; // must be listed -Werror,-Wswitch
+ case AUDIO_PORT_TYPE_DEVICE:
+ switch (role) {
+ case AUDIO_PORT_ROLE_NONE:
+ break; // must be listed -Werror,-Wswitch
+ case AUDIO_PORT_ROLE_SOURCE:
+ return AudioPortDirection::INPUT;
+ case AUDIO_PORT_ROLE_SINK:
+ return AudioPortDirection::OUTPUT;
+ }
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ switch (role) {
+ case AUDIO_PORT_ROLE_NONE:
+ break; // must be listed -Werror,-Wswitch
+ case AUDIO_PORT_ROLE_SOURCE:
+ return AudioPortDirection::OUTPUT;
+ case AUDIO_PORT_ROLE_SINK:
+ return AudioPortDirection::INPUT;
+ }
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_port_role_t> portRole(AudioPortDirection direction, audio_port_type_t type) {
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ case AUDIO_PORT_TYPE_SESSION:
+ break; // must be listed -Werror,-Wswitch
+ case AUDIO_PORT_TYPE_DEVICE:
+ switch (direction) {
+ case AudioPortDirection::INPUT:
+ return AUDIO_PORT_ROLE_SOURCE;
+ case AudioPortDirection::OUTPUT:
+ return AUDIO_PORT_ROLE_SINK;
+ }
+ break;
+ case AUDIO_PORT_TYPE_MIX:
+ switch (direction) {
+ case AudioPortDirection::OUTPUT:
+ return AUDIO_PORT_ROLE_SOURCE;
+ case AudioPortDirection::INPUT:
+ return AUDIO_PORT_ROLE_SINK;
+ }
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
ConversionResult<audio_config_t>
aidl2legacy_AudioConfig_audio_config_t(const AudioConfig& aidl, bool isInput) {
const audio_config_base_t legacyBase = VALUE_OR_RETURN(
@@ -1786,7 +1859,7 @@
ConversionResult<audio_config_base_t>
aidl2legacy_AudioConfigBase_audio_config_base_t(const AudioConfigBase& aidl, bool isInput) {
audio_config_base_t legacy;
- legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<int>(aidl.sampleRate));
legacy.channel_mask = VALUE_OR_RETURN(
aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.channelMask, isInput));
legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
@@ -1900,6 +1973,396 @@
enumToMask_index<int32_t, AudioEncapsulationMetadataType>);
}
+ConversionResult<audio_port_config_mix_ext_usecase>
+aidl2legacy_AudioPortMixExtUseCase_audio_port_config_mix_ext_usecase(
+ const AudioPortMixExtUseCase& aidl, bool isInput) {
+ audio_port_config_mix_ext_usecase legacy{};
+ if (aidl.getTag() != AudioPortMixExtUseCase::Tag::unspecified) {
+ if (!isInput) {
+ legacy.stream = VALUE_OR_RETURN(aidl2legacy_AudioStreamType_audio_stream_type_t(
+ VALUE_OR_RETURN(UNION_GET(aidl, stream))));
+ } else {
+ legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(
+ VALUE_OR_RETURN(UNION_GET(aidl, source))));
+ }
+ }
+ return legacy;
+}
+
+ConversionResult<AudioPortMixExtUseCase>
+legacy2aidl_audio_port_config_mix_ext_usecase_AudioPortMixExtUseCase(
+ const audio_port_config_mix_ext_usecase& legacy, bool isInput) {
+ AudioPortMixExtUseCase aidl;
+ if (!isInput) {
+ UNION_SET(aidl, stream, VALUE_OR_RETURN(
+ legacy2aidl_audio_stream_type_t_AudioStreamType(legacy.stream)));
+ } else {
+ UNION_SET(aidl, source, VALUE_OR_RETURN(
+ legacy2aidl_audio_source_t_AudioSource(legacy.source)));
+ }
+ return aidl;
+}
+
+ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortMixExt_audio_port_config_mix_ext(
+ const AudioPortMixExt& aidl, bool isInput) {
+ audio_port_config_mix_ext legacy{};
+ legacy.handle = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.handle));
+ legacy.usecase = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortMixExtUseCase_audio_port_config_mix_ext_usecase(
+ aidl.usecase, isInput));
+ return legacy;
+}
+
+ConversionResult<AudioPortMixExt> legacy2aidl_audio_port_config_mix_ext_AudioPortMixExt(
+ const audio_port_config_mix_ext& legacy, bool isInput) {
+ AudioPortMixExt aidl;
+ aidl.handle = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(legacy.handle));
+ aidl.usecase = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_config_mix_ext_usecase_AudioPortMixExtUseCase(
+ legacy.usecase, isInput));
+ return aidl;
+}
+
+ConversionResult<audio_port_config_device_ext>
+aidl2legacy_AudioPortDeviceExt_audio_port_config_device_ext(const AudioPortDeviceExt& aidl) {
+ audio_port_config_device_ext legacy{};
+ RETURN_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl.device, &legacy.type, legacy.address));
+ return legacy;
+}
+
+ConversionResult<AudioPortDeviceExt> legacy2aidl_audio_port_config_device_ext_AudioPortDeviceExt(
+ const audio_port_config_device_ext& legacy) {
+ AudioPortDeviceExt aidl;
+ aidl.device = VALUE_OR_RETURN(
+ legacy2aidl_audio_device_AudioDevice(legacy.type, legacy.address));
+ return aidl;
+}
+
+// This type is unnamed in the original definition, thus we name it here.
+using audio_port_config_ext = decltype(audio_port_config::ext);
+
+status_t aidl2legacy_AudioPortExt_audio_port_config_ext(
+ const AudioPortExt& aidl, bool isInput,
+ audio_port_config_ext* legacy, audio_port_type_t* type) {
+ switch (aidl.getTag()) {
+ case AudioPortExt::Tag::unspecified:
+ // Just verify that the union is empty.
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, unspecified));
+ *legacy = {};
+ *type = AUDIO_PORT_TYPE_NONE;
+ return OK;
+ case AudioPortExt::Tag::device:
+ legacy->device = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPortDeviceExt_audio_port_config_device_ext(
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, device))));
+ *type = AUDIO_PORT_TYPE_DEVICE;
+ return OK;
+ case AudioPortExt::Tag::mix:
+ legacy->mix = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPortMixExt_audio_port_config_mix_ext(
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, mix)), isInput));
+ *type = AUDIO_PORT_TYPE_MIX;
+ return OK;
+ case AudioPortExt::Tag::session:
+ // This variant is not used in the HAL scenario.
+ legacy->session.session = AUDIO_SESSION_NONE;
+ *type = AUDIO_PORT_TYPE_SESSION;
+ return OK;
+
+ }
+ LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
+}
+
+ConversionResult<AudioPortExt> legacy2aidl_audio_port_config_ext_AudioPortExt(
+ const audio_port_config_ext& legacy, audio_port_type_t type, bool isInput) {
+ AudioPortExt aidl;
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ UNION_SET(aidl, unspecified, false);
+ return aidl;
+ case AUDIO_PORT_TYPE_DEVICE: {
+ AudioPortDeviceExt device = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_config_device_ext_AudioPortDeviceExt(legacy.device));
+ UNION_SET(aidl, device, device);
+ return aidl;
+ }
+ case AUDIO_PORT_TYPE_MIX: {
+ AudioPortMixExt mix = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_config_mix_ext_AudioPortMixExt(legacy.mix, isInput));
+ UNION_SET(aidl, mix, mix);
+ return aidl;
+ }
+ case AUDIO_PORT_TYPE_SESSION:
+ // This variant is not used in the HAL scenario.
+ UNION_SET(aidl, unspecified, false);
+ return aidl;
+ }
+ LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
+}
+
+status_t aidl2legacy_AudioPortConfig_audio_port_config(
+ const AudioPortConfig& aidl, bool isInput, audio_port_config* legacy, int32_t* portId) {
+ legacy->id = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_port_handle_t(aidl.id));
+ *portId = aidl.portId;
+ if (aidl.sampleRate.has_value()) {
+ legacy->sample_rate = VALUE_OR_RETURN_STATUS(
+ convertIntegral<unsigned int>(aidl.sampleRate.value().value));
+ legacy->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+ }
+ if (aidl.channelMask.has_value()) {
+ legacy->channel_mask =
+ VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ aidl.channelMask.value(), isInput));
+ legacy->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ }
+ if (aidl.format.has_value()) {
+ legacy->format = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format.value()));
+ legacy->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+ }
+ if (aidl.gain.has_value()) {
+ legacy->gain = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioGainConfig_audio_gain_config(
+ aidl.gain.value(), isInput));
+ legacy->config_mask |= AUDIO_PORT_CONFIG_GAIN;
+ }
+ if (aidl.flags.has_value()) {
+ legacy->flags = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioIoFlags_audio_io_flags(aidl.flags.value(), isInput));
+ legacy->config_mask |= AUDIO_PORT_CONFIG_FLAGS;
+ }
+ RETURN_STATUS_IF_ERROR(aidl2legacy_AudioPortExt_audio_port_config_ext(
+ aidl.ext, isInput, &legacy->ext, &legacy->type));
+ legacy->role = VALUE_OR_RETURN_STATUS(portRole(isInput ?
+ AudioPortDirection::INPUT : AudioPortDirection::OUTPUT, legacy->type));
+ return OK;
+}
+
+ConversionResult<AudioPortConfig>
+legacy2aidl_audio_port_config_AudioPortConfig(
+ const audio_port_config& legacy, bool isInput, int32_t portId) {
+ AudioPortConfig aidl;
+ aidl.id = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.id));
+ aidl.portId = portId;
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
+ Int aidl_sampleRate;
+ aidl_sampleRate.value = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
+ aidl.sampleRate = aidl_sampleRate;
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
+ aidl.channelMask = VALUE_OR_RETURN(
+ legacy2aidl_audio_channel_mask_t_AudioChannelLayout(legacy.channel_mask, isInput));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_FORMAT) {
+ aidl.format = VALUE_OR_RETURN(
+ legacy2aidl_audio_format_t_AudioFormatDescription(legacy.format));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ aidl.gain = VALUE_OR_RETURN(
+ legacy2aidl_audio_gain_config_AudioGainConfig(legacy.gain, isInput));
+ }
+ if (legacy.config_mask & AUDIO_PORT_CONFIG_FLAGS) {
+ aidl.flags = VALUE_OR_RETURN(
+ legacy2aidl_audio_io_flags_AudioIoFlags(legacy.flags, isInput));
+ }
+ aidl.ext = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_config_ext_AudioPortExt(legacy.ext, legacy.type, isInput));
+ return aidl;
+}
+
+ConversionResult<audio_port_mix_ext> aidl2legacy_AudioPortMixExt_audio_port_mix_ext(
+ const AudioPortMixExt& aidl) {
+ audio_port_mix_ext legacy{};
+ legacy.handle = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.handle));
+ return legacy;
+}
+
+ConversionResult<AudioPortMixExt> legacy2aidl_audio_port_mix_ext_AudioPortMixExt(
+ const audio_port_mix_ext& legacy) {
+ AudioPortMixExt aidl;
+ aidl.handle = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(legacy.handle));
+ return aidl;
+}
+
+ConversionResult<audio_port_device_ext>
+aidl2legacy_AudioPortDeviceExt_audio_port_device_ext(const AudioPortDeviceExt& aidl) {
+ audio_port_device_ext legacy{};
+ RETURN_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl.device, &legacy.type, legacy.address));
+ return legacy;
+}
+
+ConversionResult<AudioPortDeviceExt> legacy2aidl_audio_port_device_ext_AudioPortDeviceExt(
+ const audio_port_device_ext& legacy) {
+ AudioPortDeviceExt aidl;
+ aidl.device = VALUE_OR_RETURN(
+ legacy2aidl_audio_device_AudioDevice(legacy.type, legacy.address));
+ return aidl;
+}
+
+// This type is unnamed in the original definition, thus we name it here.
+using audio_port_v7_ext = decltype(audio_port_v7::ext);
+
+status_t aidl2legacy_AudioPortExt_audio_port_v7_ext(
+ const AudioPortExt& aidl, audio_port_v7_ext* legacy, audio_port_type_t* type) {
+ switch (aidl.getTag()) {
+ case AudioPortExt::Tag::unspecified:
+ // Just verify that the union is empty.
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, unspecified));
+ *legacy = {};
+ *type = AUDIO_PORT_TYPE_NONE;
+ return OK;
+ case AudioPortExt::Tag::device:
+ legacy->device = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPortDeviceExt_audio_port_device_ext(
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, device))));
+ *type = AUDIO_PORT_TYPE_DEVICE;
+ return OK;
+ case AudioPortExt::Tag::mix:
+ legacy->mix = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPortMixExt_audio_port_mix_ext(
+ VALUE_OR_RETURN_STATUS(UNION_GET(aidl, mix))));
+ *type = AUDIO_PORT_TYPE_MIX;
+ return OK;
+ case AudioPortExt::Tag::session:
+ // This variant is not used in the HAL scenario.
+ legacy->session.session = AUDIO_SESSION_NONE;
+ *type = AUDIO_PORT_TYPE_SESSION;
+ return OK;
+
+ }
+ LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
+}
+
+ConversionResult<AudioPortExt> legacy2aidl_audio_port_v7_ext_AudioPortExt(
+ const audio_port_v7_ext& legacy, audio_port_type_t type) {
+ AudioPortExt aidl;
+ switch (type) {
+ case AUDIO_PORT_TYPE_NONE:
+ UNION_SET(aidl, unspecified, false);
+ return aidl;
+ case AUDIO_PORT_TYPE_DEVICE: {
+ AudioPortDeviceExt device = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_device_ext_AudioPortDeviceExt(legacy.device));
+ UNION_SET(aidl, device, device);
+ return aidl;
+ }
+ case AUDIO_PORT_TYPE_MIX: {
+ AudioPortMixExt mix = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_mix_ext_AudioPortMixExt(legacy.mix));
+ UNION_SET(aidl, mix, mix);
+ return aidl;
+ }
+ case AUDIO_PORT_TYPE_SESSION:
+ // This variant is not used in the HAL scenario.
+ UNION_SET(aidl, unspecified, false);
+ return aidl;
+ }
+ LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
+}
+
+ConversionResult<audio_port_v7>
+aidl2legacy_AudioPort_audio_port_v7(const AudioPort& aidl, bool isInput) {
+ audio_port_v7 legacy;
+ legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.id));
+ RETURN_IF_ERROR(aidl2legacy_string(aidl.name, legacy.name, sizeof(legacy.name)));
+
+ if (aidl.profiles.size() > std::size(legacy.audio_profiles)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(convertRange(
+ aidl.profiles.begin(), aidl.profiles.end(), legacy.audio_profiles,
+ [isInput](const AudioProfile& p) {
+ return aidl2legacy_AudioProfile_audio_profile(p, isInput);
+ }));
+ legacy.num_audio_profiles = aidl.profiles.size();
+
+ if (aidl.extraAudioDescriptors.size() > std::size(legacy.extra_audio_descriptors)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(
+ convertRange(
+ aidl.extraAudioDescriptors.begin(), aidl.extraAudioDescriptors.end(),
+ legacy.extra_audio_descriptors,
+ aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor));
+ legacy.num_extra_audio_descriptors = aidl.extraAudioDescriptors.size();
+
+ if (aidl.gains.size() > std::size(legacy.gains)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(convertRange(aidl.gains.begin(), aidl.gains.end(), legacy.gains,
+ [isInput](const AudioGain& g) {
+ return aidl2legacy_AudioGain_audio_gain(g, isInput);
+ }));
+ legacy.num_gains = aidl.gains.size();
+
+ RETURN_IF_ERROR(aidl2legacy_AudioPortExt_audio_port_v7_ext(
+ aidl.ext, &legacy.ext, &legacy.type));
+ legacy.role = VALUE_OR_RETURN(portRole(
+ isInput ? AudioPortDirection::INPUT : AudioPortDirection::OUTPUT, legacy.type));
+
+ AudioPortConfig aidlPortConfig;
+ int32_t portId;
+ aidlPortConfig.flags = aidl.flags;
+ aidlPortConfig.ext = aidl.ext;
+ RETURN_IF_ERROR(aidl2legacy_AudioPortConfig_audio_port_config(
+ aidlPortConfig, isInput, &legacy.active_config, &portId));
+ return legacy;
+}
+
+ConversionResult<AudioPort>
+legacy2aidl_audio_port_v7_AudioPort(const audio_port_v7& legacy, bool isInput) {
+ AudioPort aidl;
+ aidl.id = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.id));
+ aidl.name = VALUE_OR_RETURN(legacy2aidl_string(legacy.name, sizeof(legacy.name)));
+
+ if (legacy.num_audio_profiles > std::size(legacy.audio_profiles)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(
+ convertRange(legacy.audio_profiles, legacy.audio_profiles + legacy.num_audio_profiles,
+ std::back_inserter(aidl.profiles),
+ [isInput](const audio_profile& p) {
+ return legacy2aidl_audio_profile_AudioProfile(p, isInput);
+ }));
+
+ if (legacy.num_extra_audio_descriptors > std::size(legacy.extra_audio_descriptors)) {
+ return unexpected(BAD_VALUE);
+ }
+ aidl.profiles.resize(legacy.num_audio_profiles);
+ RETURN_IF_ERROR(
+ convertRange(legacy.extra_audio_descriptors,
+ legacy.extra_audio_descriptors + legacy.num_extra_audio_descriptors,
+ std::back_inserter(aidl.extraAudioDescriptors),
+ legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor));
+
+ if (legacy.num_gains > std::size(legacy.gains)) {
+ return unexpected(BAD_VALUE);
+ }
+ RETURN_IF_ERROR(
+ convertRange(legacy.gains, legacy.gains + legacy.num_gains,
+ std::back_inserter(aidl.gains),
+ [isInput](const audio_gain& g) {
+ return legacy2aidl_audio_gain_AudioGain(g, isInput);
+ }));
+ aidl.gains.resize(legacy.num_gains);
+
+ aidl.ext = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_v7_ext_AudioPortExt(legacy.ext, legacy.type));
+
+ AudioPortConfig aidlPortConfig = VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfig(
+ legacy.active_config, isInput, aidl.id));
+ if (aidlPortConfig.flags.has_value()) {
+ aidl.flags = aidlPortConfig.flags.value();
+ } else {
+ aidl.flags = isInput ?
+ AudioIoFlags::make<AudioIoFlags::Tag::input>(0) :
+ AudioIoFlags::make<AudioIoFlags::Tag::output>(0);
+ }
+ return aidl;
+}
+
ConversionResult<audio_profile>
aidl2legacy_AudioProfile_audio_profile(const AudioProfile& aidl, bool isInput) {
audio_profile legacy;
@@ -2046,6 +2509,10 @@
return AUDIO_STANDARD_NONE;
case AudioStandard::EDID:
return AUDIO_STANDARD_EDID;
+ case AudioStandard::SADB:
+ return AUDIO_STANDARD_SADB;
+ case AudioStandard::VSADB:
+ return AUDIO_STANDARD_VSADB;
}
return unexpected(BAD_VALUE);
}
@@ -2057,6 +2524,10 @@
return AudioStandard::NONE;
case AUDIO_STANDARD_EDID:
return AudioStandard::EDID;
+ case AUDIO_STANDARD_SADB:
+ return AudioStandard::SADB;
+ case AUDIO_STANDARD_VSADB:
+ return AudioStandard::VSADB;
}
return unexpected(BAD_VALUE);
}
@@ -2123,8 +2594,141 @@
return unexpected(BAD_VALUE);
}
+ConversionResult<audio_dual_mono_mode_t>
+aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(AudioDualMonoMode aidl) {
+ switch (aidl) {
+ case AudioDualMonoMode::OFF:
+ return AUDIO_DUAL_MONO_MODE_OFF;
+ case AudioDualMonoMode::LR:
+ return AUDIO_DUAL_MONO_MODE_LR;
+ case AudioDualMonoMode::LL:
+ return AUDIO_DUAL_MONO_MODE_LL;
+ case AudioDualMonoMode::RR:
+ return AUDIO_DUAL_MONO_MODE_RR;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioDualMonoMode>
+legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(audio_dual_mono_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_DUAL_MONO_MODE_OFF:
+ return AudioDualMonoMode::OFF;
+ case AUDIO_DUAL_MONO_MODE_LR:
+ return AudioDualMonoMode::LR;
+ case AUDIO_DUAL_MONO_MODE_LL:
+ return AudioDualMonoMode::LL;
+ case AUDIO_DUAL_MONO_MODE_RR:
+ return AudioDualMonoMode::RR;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_timestretch_fallback_mode_t>
+aidl2legacy_TimestretchFallbackMode_audio_timestretch_fallback_mode_t(
+ AudioPlaybackRate::TimestretchFallbackMode aidl) {
+ switch (aidl) {
+ case AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT:
+ return AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT;
+ case AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT:
+ return AUDIO_TIMESTRETCH_FALLBACK_DEFAULT;
+ case AudioPlaybackRate::TimestretchFallbackMode::MUTE:
+ return AUDIO_TIMESTRETCH_FALLBACK_MUTE;
+ case AudioPlaybackRate::TimestretchFallbackMode::FAIL:
+ return AUDIO_TIMESTRETCH_FALLBACK_FAIL;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPlaybackRate::TimestretchFallbackMode>
+legacy2aidl_audio_timestretch_fallback_mode_t_TimestretchFallbackMode(
+ audio_timestretch_fallback_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_TIMESTRETCH_FALLBACK_CUT_REPEAT:
+ return AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_CUT_REPEAT;
+ case AUDIO_TIMESTRETCH_FALLBACK_DEFAULT:
+ return AudioPlaybackRate::TimestretchFallbackMode::SYS_RESERVED_DEFAULT;
+ case AUDIO_TIMESTRETCH_FALLBACK_MUTE:
+ return AudioPlaybackRate::TimestretchFallbackMode::MUTE;
+ case AUDIO_TIMESTRETCH_FALLBACK_FAIL:
+ return AudioPlaybackRate::TimestretchFallbackMode::FAIL;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_timestretch_stretch_mode_t>
+aidl2legacy_TimestretchMode_audio_timestretch_stretch_mode_t(
+ AudioPlaybackRate::TimestretchMode aidl) {
+ switch (aidl) {
+ case AudioPlaybackRate::TimestretchMode::DEFAULT:
+ return AUDIO_TIMESTRETCH_STRETCH_DEFAULT;
+ case AudioPlaybackRate::TimestretchMode::VOICE:
+ return AUDIO_TIMESTRETCH_STRETCH_VOICE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPlaybackRate::TimestretchMode>
+legacy2aidl_audio_timestretch_stretch_mode_t_TimestretchMode(
+ audio_timestretch_stretch_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_TIMESTRETCH_STRETCH_DEFAULT:
+ return AudioPlaybackRate::TimestretchMode::DEFAULT;
+ case AUDIO_TIMESTRETCH_STRETCH_VOICE:
+ return AudioPlaybackRate::TimestretchMode::VOICE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_playback_rate_t>
+aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(const AudioPlaybackRate& aidl) {
+ audio_playback_rate_t legacy;
+ legacy.mSpeed = aidl.speed;
+ legacy.mPitch = aidl.pitch;
+ legacy.mFallbackMode = VALUE_OR_RETURN(
+ aidl2legacy_TimestretchFallbackMode_audio_timestretch_fallback_mode_t(
+ aidl.fallbackMode));
+ legacy.mStretchMode = VALUE_OR_RETURN(
+ aidl2legacy_TimestretchMode_audio_timestretch_stretch_mode_t(aidl.timestretchMode));
+ return legacy;
+}
+
+ConversionResult<AudioPlaybackRate>
+legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(const audio_playback_rate_t& legacy) {
+ AudioPlaybackRate aidl;
+ aidl.speed = legacy.mSpeed;
+ aidl.pitch = legacy.mPitch;
+ aidl.fallbackMode = VALUE_OR_RETURN(
+ legacy2aidl_audio_timestretch_fallback_mode_t_TimestretchFallbackMode(
+ legacy.mFallbackMode));
+ aidl.timestretchMode = VALUE_OR_RETURN(
+ legacy2aidl_audio_timestretch_stretch_mode_t_TimestretchMode(legacy.mStretchMode));
+ return aidl;
+}
+
+ConversionResult<audio_latency_mode_t>
+aidl2legacy_AudioLatencyMode_audio_latency_mode_t(AudioLatencyMode aidl) {
+ switch (aidl) {
+ case AudioLatencyMode::FREE:
+ return AUDIO_LATENCY_MODE_FREE;
+ case AudioLatencyMode::LOW:
+ return AUDIO_LATENCY_MODE_LOW;
+ }
+ return unexpected(BAD_VALUE);
+}
+ConversionResult<AudioLatencyMode>
+legacy2aidl_audio_latency_mode_t_AudioLatencyMode(audio_latency_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_LATENCY_MODE_FREE:
+ return AudioLatencyMode::FREE;
+ case AUDIO_LATENCY_MODE_LOW:
+ return AudioLatencyMode::LOW;
+ }
+ return unexpected(BAD_VALUE);
+}
+
} // namespace android
#if defined(BACKEND_NDK)
} // aidl
-#endif
\ No newline at end of file
+#endif
diff --git a/media/audioaidlconversion/AidlConversionEffect.cpp b/media/audioaidlconversion/AidlConversionEffect.cpp
new file mode 100644
index 0000000..ad27c64
--- /dev/null
+++ b/media/audioaidlconversion/AidlConversionEffect.cpp
@@ -0,0 +1,352 @@
+/*
+ * 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 <utility>
+
+#define LOG_TAG "AidlConversionEffect"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionEffect.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// AIDL NDK backend to legacy audio data structure conversion utilities.
+
+namespace aidl {
+namespace android {
+
+using ::aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::BassBoost;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Downmix;
+using ::aidl::android::hardware::audio::effect::DynamicsProcessing;
+using ::aidl::android::hardware::audio::effect::Flags;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::PresetReverb;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+
+using ::android::BAD_VALUE;
+using ::android::base::unexpected;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// Converters
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(Flags::Type type) {
+ switch (type) {
+ case Flags::Type::INSERT:
+ return EFFECT_FLAG_TYPE_INSERT;
+ case Flags::Type::AUXILIARY:
+ return EFFECT_FLAG_TYPE_AUXILIARY;
+ case Flags::Type::REPLACE:
+ return EFFECT_FLAG_TYPE_REPLACE;
+ case Flags::Type::PRE_PROC:
+ return EFFECT_FLAG_TYPE_PRE_PROC;
+ case Flags::Type::POST_PROC:
+ return EFFECT_FLAG_TYPE_POST_PROC;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::Type> legacy2aidl_uint32_Flags_Type(uint32_t legacy) {
+ switch (legacy & EFFECT_FLAG_TYPE_MASK) {
+ case EFFECT_FLAG_TYPE_INSERT:
+ return Flags::Type::INSERT;
+ case EFFECT_FLAG_TYPE_AUXILIARY:
+ return Flags::Type::AUXILIARY;
+ case EFFECT_FLAG_TYPE_REPLACE:
+ return Flags::Type::REPLACE;
+ case EFFECT_FLAG_TYPE_PRE_PROC:
+ return Flags::Type::PRE_PROC;
+ case EFFECT_FLAG_TYPE_POST_PROC:
+ return Flags::Type::POST_PROC;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Insert_uint32(Flags::Insert insert) {
+ switch (insert) {
+ case Flags::Insert::ANY:
+ return EFFECT_FLAG_INSERT_ANY;
+ case Flags::Insert::FIRST:
+ return EFFECT_FLAG_INSERT_FIRST;
+ case Flags::Insert::LAST:
+ return EFFECT_FLAG_INSERT_LAST;
+ case Flags::Insert::EXCLUSIVE:
+ return EFFECT_FLAG_INSERT_EXCLUSIVE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::Insert> legacy2aidl_uint32_Flags_Insert(uint32_t legacy) {
+ switch (legacy & EFFECT_FLAG_INSERT_MASK) {
+ case EFFECT_FLAG_INSERT_ANY:
+ return Flags::Insert::ANY;
+ case EFFECT_FLAG_INSERT_FIRST:
+ return Flags::Insert::FIRST;
+ case EFFECT_FLAG_INSERT_LAST:
+ return Flags::Insert::LAST;
+ case EFFECT_FLAG_INSERT_EXCLUSIVE:
+ return Flags::Insert::EXCLUSIVE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Volume_uint32(Flags::Volume volume) {
+ switch (volume) {
+ case Flags::Volume::NONE:
+ return 0;
+ case Flags::Volume::CTRL:
+ return EFFECT_FLAG_VOLUME_CTRL;
+ case Flags::Volume::IND:
+ return EFFECT_FLAG_VOLUME_IND;
+ case Flags::Volume::MONITOR:
+ return EFFECT_FLAG_VOLUME_MONITOR;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::Volume> legacy2aidl_uint32_Flags_Volume(uint32_t legacy) {
+ switch (legacy & EFFECT_FLAG_VOLUME_MASK) {
+ case EFFECT_FLAG_VOLUME_CTRL:
+ return Flags::Volume::CTRL;
+ case EFFECT_FLAG_VOLUME_IND:
+ return Flags::Volume::IND;
+ case EFFECT_FLAG_VOLUME_MONITOR:
+ return Flags::Volume::MONITOR;
+ case EFFECT_FLAG_VOLUME_NONE:
+ return Flags::Volume::NONE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_uint32(Flags aidl) {
+ uint32_t legacy = 0;
+ legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Type_uint32(aidl.type));
+ legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Insert_uint32(aidl.insert));
+ legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_Volume_uint32(aidl.volume));
+ legacy |= VALUE_OR_RETURN(aidl2legacy_Flags_HardwareAccelerator_uint32(aidl.hwAcceleratorMode));
+
+ if (aidl.offloadIndication) {
+ legacy |= EFFECT_FLAG_OFFLOAD_SUPPORTED;
+ }
+ if (aidl.deviceIndication) {
+ legacy |= EFFECT_FLAG_DEVICE_IND;
+ }
+ if (aidl.audioModeIndication) {
+ legacy |= EFFECT_FLAG_AUDIO_MODE_IND;
+ }
+ if (aidl.audioSourceIndication) {
+ legacy |= EFFECT_FLAG_AUDIO_SOURCE_IND;
+ }
+ if (aidl.bypass) {
+ legacy |= EFFECT_FLAG_NO_PROCESS;
+ }
+ return legacy;
+}
+
+ConversionResult<Flags> legacy2aidl_uint32_Flags(uint32_t legacy) {
+ Flags aidl;
+
+ aidl.type = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Type(legacy));
+ aidl.insert = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Insert(legacy));
+ aidl.volume = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_Volume(legacy));
+ aidl.hwAcceleratorMode = VALUE_OR_RETURN(legacy2aidl_uint32_Flags_HardwareAccelerator(legacy));
+ aidl.offloadIndication = (legacy & EFFECT_FLAG_OFFLOAD_SUPPORTED);
+ aidl.deviceIndication = (legacy & EFFECT_FLAG_DEVICE_IND);
+ aidl.audioModeIndication = (legacy & EFFECT_FLAG_AUDIO_MODE_IND);
+ aidl.audioSourceIndication = (legacy & EFFECT_FLAG_AUDIO_SOURCE_IND);
+ aidl.bypass = (legacy & EFFECT_FLAG_NO_PROCESS);
+ return aidl;
+}
+
+ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
+ Flags::HardwareAccelerator hwAcceleratorMode) {
+ switch (hwAcceleratorMode) {
+ case Flags::HardwareAccelerator::NONE:
+ return 0;
+ case Flags::HardwareAccelerator::SIMPLE:
+ return EFFECT_FLAG_HW_ACC_SIMPLE;
+ case Flags::HardwareAccelerator::TUNNEL:
+ return EFFECT_FLAG_HW_ACC_TUNNEL;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<Flags::HardwareAccelerator> legacy2aidl_uint32_Flags_HardwareAccelerator(
+ uint32_t legacy) {
+ switch (legacy & EFFECT_FLAG_HW_ACC_MASK) {
+ case EFFECT_FLAG_HW_ACC_SIMPLE:
+ return Flags::HardwareAccelerator::SIMPLE;
+ case EFFECT_FLAG_HW_ACC_TUNNEL:
+ return Flags::HardwareAccelerator::TUNNEL;
+ case 0:
+ return Flags::HardwareAccelerator::NONE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<effect_descriptor_t>
+aidl2legacy_Descriptor_effect_descriptor(const Descriptor& aidl) {
+ effect_descriptor_t legacy;
+ legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.common.id.type));
+ legacy.uuid = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.common.id.uuid));
+ // legacy descriptor doesn't have proxy information
+ // proxy = VALUE_OR_RETURN(aidl2legacy_AudioUuid_audio_uuid_t(aidl.proxy));
+ legacy.apiVersion = EFFECT_CONTROL_API_VERSION;
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_Flags_uint32(aidl.common.flags));
+ legacy.cpuLoad = VALUE_OR_RETURN(convertIntegral<uint16_t>(aidl.common.cpuLoad));
+ legacy.memoryUsage = VALUE_OR_RETURN(convertIntegral<uint16_t>(aidl.common.memoryUsage));
+ RETURN_IF_ERROR(aidl2legacy_string(aidl.common.name, legacy.name, sizeof(legacy.name)));
+ RETURN_IF_ERROR(aidl2legacy_string(aidl.common.implementor, legacy.implementor,
+ sizeof(legacy.implementor)));
+ return legacy;
+}
+
+ConversionResult<Descriptor>
+legacy2aidl_effect_descriptor_Descriptor(const effect_descriptor_t& legacy) {
+ Descriptor aidl;
+ aidl.common.id.type = VALUE_OR_RETURN(legacy2aidl_audio_uuid_t_AudioUuid(legacy.type));
+ aidl.common.id.uuid = VALUE_OR_RETURN(legacy2aidl_audio_uuid_t_AudioUuid(legacy.uuid));
+ // legacy descriptor doesn't have proxy information
+ // aidl.common.id.proxy
+ aidl.common.flags = VALUE_OR_RETURN(legacy2aidl_uint32_Flags(legacy.flags));
+ aidl.common.cpuLoad = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.cpuLoad));
+ aidl.common.memoryUsage = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.memoryUsage));
+ aidl.common.name = VALUE_OR_RETURN(legacy2aidl_string(legacy.name, sizeof(legacy.name)));
+ aidl.common.implementor =
+ VALUE_OR_RETURN(legacy2aidl_string(legacy.implementor, sizeof(legacy.implementor)));
+ return aidl;
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_echoDelay(const Parameter& aidl) {
+ int echoDelay = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, AcousticEchoCanceler, acousticEchoCanceler,
+ AcousticEchoCanceler::echoDelayUs, int));
+ return VALUE_OR_RETURN(convertReinterpret<uint32_t>(echoDelay));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_echoDelay_Parameter_aec(uint32_t legacy) {
+ int delay = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy));
+ return MAKE_SPECIFIC_PARAMETER(AcousticEchoCanceler, acousticEchoCanceler, echoDelayUs, delay);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_mobileMode(const Parameter& aidl) {
+ bool mobileMode = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, AcousticEchoCanceler, acousticEchoCanceler,
+ AcousticEchoCanceler::mobileMode, bool));
+ return VALUE_OR_RETURN(convertIntegral<uint32_t>(mobileMode));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_mobileMode_Parameter_aec(uint32_t legacy) {
+ bool mode = VALUE_OR_RETURN(convertIntegral<bool>(legacy));
+ return MAKE_SPECIFIC_PARAMETER(AcousticEchoCanceler, acousticEchoCanceler, mobileMode, mode);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(
+ const Parameter& aidl) {
+ int gain = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControl, automaticGainControl,
+ AutomaticGainControl::fixedDigitalGainMb, int));
+ return VALUE_OR_RETURN(convertReinterpret<uint32_t>(gain));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(uint32_t legacy) {
+ int gain = VALUE_OR_RETURN(convertReinterpret<int>(legacy));
+ return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, fixedDigitalGainMb,
+ gain);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_levelEstimator(
+ const Parameter& aidl) {
+ const auto& le = VALUE_OR_RETURN(GET_PARAMETER_SPECIFIC_FIELD(
+ aidl, AutomaticGainControl, automaticGainControl, AutomaticGainControl::levelEstimator,
+ AutomaticGainControl::LevelEstimator));
+ return static_cast<uint32_t>(le);
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_levelEstimator_Parameter_agc(uint32_t legacy) {
+ if (legacy > (uint32_t) AutomaticGainControl::LevelEstimator::PEAK) {
+ return unexpected(BAD_VALUE);
+ }
+ AutomaticGainControl::LevelEstimator le =
+ static_cast<AutomaticGainControl::LevelEstimator>(legacy);
+ return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, levelEstimator, le);
+}
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_saturationMargin(
+ const Parameter& aidl) {
+ int saturationMargin = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, AutomaticGainControl, automaticGainControl,
+ AutomaticGainControl::saturationMarginMb, int));
+ return VALUE_OR_RETURN(convertIntegral<uint32_t>(saturationMargin));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint32_saturationMargin_Parameter_agc(uint32_t legacy) {
+ int saturationMargin = VALUE_OR_RETURN(convertIntegral<int>(legacy));
+ return MAKE_SPECIFIC_PARAMETER(AutomaticGainControl, automaticGainControl, saturationMarginMb,
+ saturationMargin);
+}
+
+ConversionResult<uint16_t> aidl2legacy_Parameter_BassBoost_uint16_strengthPm(
+ const Parameter& aidl) {
+ int strength = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, BassBoost, bassBoost, BassBoost::strengthPm, int));
+ return VALUE_OR_RETURN(convertIntegral<uint16_t>(strength));
+}
+
+ConversionResult<Parameter> legacy2aidl_uint16_strengthPm_Parameter_BassBoost(uint16_t legacy) {
+ int strength = VALUE_OR_RETURN(convertIntegral<int>(legacy));
+ return MAKE_SPECIFIC_PARAMETER(BassBoost, bassBoost, strengthPm, strength);
+}
+
+ConversionResult<int16_t> aidl2legacy_Parameter_Downmix_int16_type(const Parameter& aidl) {
+ Downmix::Type aidlType = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, Downmix, downmix, Downmix::type, Downmix::Type));
+ return VALUE_OR_RETURN(convertIntegral<int16_t>(static_cast<uint32_t>(aidlType)));
+}
+
+ConversionResult<Parameter> legacy2aidl_int16_type_Parameter_Downmix(int16_t legacy) {
+ if (legacy > (uint32_t) Downmix::Type::FOLD) {
+ return unexpected(BAD_VALUE);
+ }
+ Downmix::Type aidlType = static_cast<Downmix::Type>(legacy);
+ return MAKE_SPECIFIC_PARAMETER(Downmix, downmix, type, aidlType);
+}
+
+ConversionResult<int16_t> aidl2legacy_DynamicsProcessing_ResolutionPreference_uint32_(
+ const Parameter& aidl) {
+ Downmix::Type aidlType = VALUE_OR_RETURN(
+ GET_PARAMETER_SPECIFIC_FIELD(aidl, Downmix, downmix, Downmix::type, Downmix::Type));
+ return VALUE_OR_RETURN(convertIntegral<int16_t>(static_cast<uint32_t>(aidlType)));
+}
+
+ConversionResult<DynamicsProcessing::ResolutionPreference>
+legacy2aidl_int32_DynamicsProcessing_ResolutionPreference(int32_t legacy) {
+ if (legacy > (int32_t)DynamicsProcessing::ResolutionPreference::FAVOR_TIME_RESOLUTION) {
+ return unexpected(BAD_VALUE);
+ }
+ return static_cast<DynamicsProcessing::ResolutionPreference>(legacy);
+}
+
+ConversionResult<int32_t> aidl2legacy_DynamicsProcessing_ResolutionPreference_int32(
+ DynamicsProcessing::ResolutionPreference aidl) {
+ return static_cast<int32_t>(aidl);
+}
+
+} // namespace android
+} // aidl
diff --git a/media/audioaidlconversion/AidlConversionNdk.cpp b/media/audioaidlconversion/AidlConversionNdk.cpp
new file mode 100644
index 0000000..7c63339
--- /dev/null
+++ b/media/audioaidlconversion/AidlConversionNdk.cpp
@@ -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.
+ */
+
+#include <utility>
+
+#define LOG_TAG "AidlConversionNdk"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+// AIDL NDK backend to legacy audio data structure conversion utilities.
+
+namespace aidl {
+namespace android {
+
+// buffer_provider_t is not supported thus skipped
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
+ const media::audio::common::AudioConfigBase& aidl, bool isInput) {
+ buffer_config_t legacy;
+
+ legacy.samplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.mask |= EFFECT_CONFIG_SMP_RATE;
+
+ legacy.channels = VALUE_OR_RETURN(
+ aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.channelMask, isInput));
+ legacy.mask |= EFFECT_CONFIG_CHANNELS;
+
+ legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
+ legacy.mask |= EFFECT_CONFIG_FORMAT;
+
+ // TODO: add accessMode and mask
+ return legacy;
+}
+
+ConversionResult<media::audio::common::AudioConfigBase>
+legacy2aidl_buffer_config_t_AudioConfigBase(const buffer_config_t& legacy, bool isInput) {
+ media::audio::common::AudioConfigBase aidl;
+
+ if (legacy.mask & EFFECT_CONFIG_SMP_RATE) {
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.samplingRate));
+ }
+ if (legacy.mask & EFFECT_CONFIG_CHANNELS) {
+ aidl.channelMask = VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+ static_cast<audio_channel_mask_t>(legacy.channels), isInput));
+ }
+ if (legacy.mask & EFFECT_CONFIG_FORMAT) {
+ aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(
+ static_cast<audio_format_t>(legacy.format)));
+ }
+
+ // TODO: add accessMode and mask
+ return aidl;
+}
+
+} // namespace android
+} // aidl
diff --git a/media/audioaidlconversion/Android.bp b/media/audioaidlconversion/Android.bp
index 4a1df3a..c0024ef 100644
--- a/media/audioaidlconversion/Android.bp
+++ b/media/audioaidlconversion/Android.bp
@@ -61,9 +61,9 @@
host_supported: true,
vendor_available: true,
double_loadable: true,
- min_sdk_version: "29",
header_libs: [
"libaudio_system_headers",
+ "libhardware_headers",
],
shared_libs: [
"libbase",
@@ -102,7 +102,9 @@
*/
cc_library {
name: "libaudio_aidl_conversion_common_cpp",
- srcs: ["AidlConversionCppNdk.cpp"],
+ srcs: [
+ "AidlConversionCppNdk.cpp",
+ ],
header_libs: [
"libaudio_aidl_conversion_common_util_cpp",
],
@@ -113,6 +115,7 @@
"audio_aidl_conversion_common_default",
"latest_android_media_audio_common_types_cpp_export_shared",
],
+ min_sdk_version: "29",
}
/**
@@ -120,7 +123,10 @@
*/
cc_library {
name: "libaudio_aidl_conversion_common_ndk",
- srcs: ["AidlConversionCppNdk.cpp"],
+ srcs: [
+ "AidlConversionCppNdk.cpp",
+ "AidlConversionNdk.cpp",
+ ],
header_libs: [
"libaudio_aidl_conversion_common_util_ndk",
],
@@ -133,8 +139,41 @@
],
shared_libs: [
"libbinder_ndk",
+ "libbase",
],
cflags: [
"-DBACKEND_NDK",
],
+ min_sdk_version: "31", //AParcelableHolder has been introduced in 31
+}
+
+/**
+ * Only including AIDL effect HAL conversion.
+ */
+cc_library {
+ name: "libaudio_aidl_conversion_effect_ndk",
+ srcs: [
+ "AidlConversionEffect.cpp",
+ ],
+ header_libs: [
+ "libaudio_aidl_conversion_common_util_ndk",
+ ],
+ export_header_lib_headers: [
+ "libaudio_aidl_conversion_common_util_ndk",
+ ],
+ defaults: [
+ "audio_aidl_conversion_common_default",
+ "latest_android_hardware_audio_common_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+ shared_libs: [
+ "libaudio_aidl_conversion_common_ndk",
+ "libbinder_ndk",
+ "libbase",
+ ],
+ cflags: [
+ "-DBACKEND_NDK",
+ ],
+ min_sdk_version: "31", //AParcelableHolder has been introduced in 31
}
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk.h
index e1efff9..c412238 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk.h
@@ -35,6 +35,7 @@
#include PREFIX(android/media/audio/common/AudioConfigBase.h)
#include PREFIX(android/media/audio/common/AudioContentType.h)
#include PREFIX(android/media/audio/common/AudioDeviceDescription.h)
+#include PREFIX(android/media/audio/common/AudioDualMonoMode.h)
#include PREFIX(android/media/audio/common/AudioEncapsulationMetadataType.h)
#include PREFIX(android/media/audio/common/AudioEncapsulationMode.h)
#include PREFIX(android/media/audio/common/AudioEncapsulationType.h)
@@ -44,11 +45,15 @@
#include PREFIX(android/media/audio/common/AudioGainMode.h)
#include PREFIX(android/media/audio/common/AudioInputFlags.h)
#include PREFIX(android/media/audio/common/AudioIoFlags.h)
+#include PREFIX(android/media/audio/common/AudioLatencyMode.h)
#include PREFIX(android/media/audio/common/AudioMode.h)
#include PREFIX(android/media/audio/common/AudioOffloadInfo.h)
#include PREFIX(android/media/audio/common/AudioOutputFlags.h)
+#include PREFIX(android/media/audio/common/AudioPort.h)
+#include PREFIX(android/media/audio/common/AudioPortConfig.h)
#include PREFIX(android/media/audio/common/AudioPortExt.h)
#include PREFIX(android/media/audio/common/AudioPortMixExt.h)
+#include PREFIX(android/media/audio/common/AudioPlaybackRate.h)
#include PREFIX(android/media/audio/common/AudioProfile.h)
#include PREFIX(android/media/audio/common/AudioSource.h)
#include PREFIX(android/media/audio/common/AudioStandard.h)
@@ -64,6 +69,7 @@
using ::android::String16;
using ::android::String8;
+using ::android::status_t;
#if defined(BACKEND_NDK)
namespace aidl {
@@ -73,7 +79,7 @@
// maxSize is the size of the C-string buffer (including the 0-terminator), NOT the max length of
// the string.
-::android::status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize);
+status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize);
ConversionResult<std::string> legacy2aidl_string(const char* legacy, size_t maxSize);
ConversionResult<audio_module_handle_t> aidl2legacy_int32_t_audio_module_handle_t(int32_t aidl);
@@ -119,6 +125,12 @@
ConversionResult<media::audio::common::AudioChannelLayout>
legacy2aidl_audio_channel_mask_t_AudioChannelLayout(audio_channel_mask_t legacy, bool isInput);
+enum class AudioPortDirection {
+ INPUT, OUTPUT
+};
+ConversionResult<AudioPortDirection> portDirection(audio_port_role_t role, audio_port_type_t type);
+ConversionResult<audio_port_role_t> portRole(AudioPortDirection direction, audio_port_type_t type);
+
ConversionResult<audio_config_t>
aidl2legacy_AudioConfig_audio_config_t(const media::audio::common::AudioConfig& aidl, bool isInput);
ConversionResult<media::audio::common::AudioConfig>
@@ -169,13 +181,13 @@
ConversionResult<media::audio::common::AudioDeviceDescription>
legacy2aidl_audio_devices_t_AudioDeviceDescription(audio_devices_t legacy);
-::android::status_t aidl2legacy_AudioDevice_audio_device(
+status_t aidl2legacy_AudioDevice_audio_device(
const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
char* legacyAddress);
-::android::status_t aidl2legacy_AudioDevice_audio_device(
+status_t aidl2legacy_AudioDevice_audio_device(
const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
String8* legacyAddress);
-::android::status_t aidl2legacy_AudioDevice_audio_device(
+status_t aidl2legacy_AudioDevice_audio_device(
const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
std::string* legacyAddress);
@@ -262,6 +274,48 @@
ConversionResult<media::audio::common::AudioOutputFlags>
legacy2aidl_audio_output_flags_t_AudioOutputFlags(audio_output_flags_t legacy);
+// This type is unnamed in the original definition, thus we name it here.
+using audio_port_config_mix_ext_usecase = decltype(audio_port_config_mix_ext::usecase);
+ConversionResult<audio_port_config_mix_ext_usecase>
+aidl2legacy_AudioPortMixExtUseCase_audio_port_config_mix_ext_usecase(
+ const media::audio::common::AudioPortMixExtUseCase& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioPortMixExtUseCase>
+legacy2aidl_audio_port_config_mix_ext_usecase_AudioPortMixExtUseCase(
+ const audio_port_config_mix_ext_usecase& legacy, bool isInput);
+
+ConversionResult<audio_port_config_device_ext>
+aidl2legacy_AudioPortDeviceExt_audio_port_config_device_ext(
+ const media::audio::common::AudioPortDeviceExt& aidl);
+ConversionResult<media::audio::common::AudioPortDeviceExt>
+ legacy2aidl_audio_port_config_device_ext_AudioPortDeviceExt(
+ const audio_port_config_device_ext& legacy);
+
+status_t aidl2legacy_AudioPortConfig_audio_port_config(
+ const media::audio::common::AudioPortConfig& aidl, bool isInput,
+ audio_port_config* legacy, int32_t* portId);
+ConversionResult<media::audio::common::AudioPortConfig>
+legacy2aidl_audio_port_config_AudioPortConfig(
+ const audio_port_config& legacy, bool isInput, int32_t portId);
+
+ConversionResult<audio_port_mix_ext> aidl2legacy_AudioPortMixExt_audio_port_mix_ext(
+ const media::audio::common::AudioPortMixExt& aidl);
+ConversionResult<media::audio::common::AudioPortMixExt>
+legacy2aidl_audio_port_mix_ext_AudioPortMixExt(
+ const audio_port_mix_ext& legacy);
+
+ConversionResult<audio_port_device_ext>
+aidl2legacy_AudioPortDeviceExt_audio_port_device_ext(
+ const media::audio::common::AudioPortDeviceExt& aidl);
+ConversionResult<media::audio::common::AudioPortDeviceExt>
+legacy2aidl_audio_port_device_ext_AudioPortDeviceExt(
+ const audio_port_device_ext& legacy);
+
+ConversionResult<audio_port_v7>
+aidl2legacy_AudioPort_audio_port_v7(
+ const media::audio::common::AudioPort& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioPort>
+legacy2aidl_audio_port_v7_AudioPort(const audio_port_v7& legacy, bool isInput);
+
ConversionResult<audio_profile> aidl2legacy_AudioProfile_audio_profile(
const media::audio::common::AudioProfile& aidl, bool isInput);
ConversionResult<media::audio::common::AudioProfile> legacy2aidl_audio_profile_AudioProfile(
@@ -287,8 +341,38 @@
ConversionResult<media::audio::common::AudioUuid> legacy2aidl_audio_uuid_t_AudioUuid(
const audio_uuid_t& legacy);
+ConversionResult<audio_dual_mono_mode_t>
+aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(media::audio::common::AudioDualMonoMode aidl);
+ConversionResult<media::audio::common::AudioDualMonoMode>
+legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(audio_dual_mono_mode_t legacy);
+
+ConversionResult<audio_timestretch_fallback_mode_t>
+aidl2legacy_TimestretchFallbackMode_audio_timestretch_fallback_mode_t(
+ media::audio::common::AudioPlaybackRate::TimestretchFallbackMode aidl);
+ConversionResult<media::audio::common::AudioPlaybackRate::TimestretchFallbackMode>
+legacy2aidl_audio_timestretch_fallback_mode_t_TimestretchFallbackMode(
+ audio_timestretch_fallback_mode_t legacy);
+
+ConversionResult<audio_timestretch_stretch_mode_t>
+aidl2legacy_TimestretchMode_audio_timestretch_stretch_mode_t(
+ media::audio::common::AudioPlaybackRate::TimestretchMode aidl);
+ConversionResult<media::audio::common::AudioPlaybackRate::TimestretchMode>
+legacy2aidl_audio_timestretch_stretch_mode_t_TimestretchMode(
+ audio_timestretch_stretch_mode_t legacy);
+
+ConversionResult<audio_playback_rate_t>
+aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(
+ const media::audio::common::AudioPlaybackRate& aidl);
+ConversionResult<media::audio::common::AudioPlaybackRate>
+legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(const audio_playback_rate_t& legacy);
+
+ConversionResult<audio_latency_mode_t>
+aidl2legacy_AudioLatencyMode_audio_latency_mode_t(media::audio::common::AudioLatencyMode aidl);
+ConversionResult<media::audio::common::AudioLatencyMode>
+legacy2aidl_audio_latency_mode_t_AudioLatencyMode(audio_latency_mode_t legacy);
+
} // namespace android
#if defined(BACKEND_NDK)
} // aidl
-#endif
\ No newline at end of file
+#endif
diff --git a/media/audioaidlconversion/include/media/AidlConversionEffect.h b/media/audioaidlconversion/include/media/AidlConversionEffect.h
new file mode 100644
index 0000000..83aa614
--- /dev/null
+++ b/media/audioaidlconversion/include/media/AidlConversionEffect.h
@@ -0,0 +1,130 @@
+/*
+ * 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/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+/**
+ * Can only handle conversion between AIDL (NDK backend) and legacy type.
+ */
+#include <hardware/audio_effect.h>
+#include <media/AidlConversionUtil.h>
+#include <system/audio_effect.h>
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+
+namespace aidl {
+namespace android {
+
+template <typename P, typename T, typename P::Specific::Tag tag>
+ConversionResult<T> getParameterSpecific(const P& u) {
+ const auto& spec = VALUE_OR_RETURN(UNION_GET(u, specific));
+ return unionGetField<typename P::Specific, tag>(spec);
+}
+
+template <typename P, typename T, typename P::Specific::Tag tag, typename T::Tag field, typename F>
+ConversionResult<F> getParameterSpecificField(const P& u) {
+ const auto& spec =
+ VALUE_OR_RETURN((getParameterSpecific<std::decay_t<decltype(u)>, T, tag>(u)));
+ return VALUE_OR_RETURN((unionGetField<T, field>(spec)));
+}
+
+#define GET_PARAMETER_SPECIFIC_FIELD(u, specific, tag, field, fieldType) \
+ getParameterSpecificField<std::decay_t<decltype(u)>, specific, \
+ aidl::android::hardware::audio::effect::Parameter::Specific::tag, \
+ specific::field, fieldType>(u)
+
+#define MAKE_SPECIFIC_PARAMETER(spec, tag, field, value) \
+ UNION_MAKE(aidl::android::hardware::audio::effect::Parameter, specific, \
+ UNION_MAKE(aidl::android::hardware::audio::effect::Parameter::Specific, tag, \
+ UNION_MAKE(spec, field, value)))
+
+#define MAKE_SPECIFIC_PARAMETER_ID(spec, tag, field) \
+ UNION_MAKE(aidl::android::hardware::audio::effect::Parameter::Id, tag, \
+ UNION_MAKE(spec::Id, commonTag, field))
+
+ConversionResult<uint32_t> aidl2legacy_Flags_Type_uint32(
+ ::aidl::android::hardware::audio::effect::Flags::Type type);
+ConversionResult<uint32_t> aidl2legacy_Flags_Insert_uint32(
+ ::aidl::android::hardware::audio::effect::Flags::Insert insert);
+ConversionResult<uint32_t> aidl2legacy_Flags_Volume_uint32(
+ ::aidl::android::hardware::audio::effect::Flags::Volume volume);
+ConversionResult<uint32_t> aidl2legacy_Flags_HardwareAccelerator_uint32(
+ ::aidl::android::hardware::audio::effect::Flags::HardwareAccelerator hwAcceleratorMode);
+ConversionResult<uint32_t> aidl2legacy_Flags_uint32(
+ const ::aidl::android::hardware::audio::effect::Flags aidl);
+
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Type>
+legacy2aidl_uint32_Flags_Type(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Insert>
+legacy2aidl_uint32_Flags_Insert(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::Volume>
+legacy2aidl_uint32_Flags_Volume(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags::HardwareAccelerator>
+legacy2aidl_uint32_Flags_HardwareAccelerator(uint32_t legacy);
+ConversionResult<::aidl::android::hardware::audio::effect::Flags> legacy2aidl_uint32_Flags(
+ uint32_t hal);
+
+ConversionResult<effect_descriptor_t> aidl2legacy_Descriptor_effect_descriptor(
+ const ::aidl::android::hardware::audio::effect::Descriptor& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Descriptor>
+legacy2aidl_effect_descriptor_Descriptor(const effect_descriptor_t& hal);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_echoDelay(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_echoDelay_Parameter_aec(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_aec_uint32_mobileMode(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_mobileMode_Parameter_aec(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_levelEstimator(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_levelEstimator_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint32_t> aidl2legacy_Parameter_agc_uint32_saturationMargin(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint32_saturationMargin_Parameter_agc(uint32_t legacy);
+
+ConversionResult<uint16_t> aidl2legacy_Parameter_BassBoost_uint16_strengthPm(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_uint16_strengthPm_Parameter_BassBoost(uint16_t legacy);
+
+ConversionResult<int16_t> aidl2legacy_Parameter_Downmix_int16_type(
+ const ::aidl::android::hardware::audio::effect::Parameter& aidl);
+ConversionResult<::aidl::android::hardware::audio::effect::Parameter>
+legacy2aidl_int16_type_Parameter_Downmix(int16_t legacy);
+
+ConversionResult<::aidl::android::hardware::audio::effect::DynamicsProcessing::ResolutionPreference>
+legacy2aidl_int32_DynamicsProcessing_ResolutionPreference(int32_t legacy);
+ConversionResult<int32_t> aidl2legacy_DynamicsProcessing_ResolutionPreference_int32(
+ ::aidl::android::hardware::audio::effect::DynamicsProcessing::ResolutionPreference aidl);
+
+} // namespace android
+} // namespace aidl
diff --git a/media/audioaidlconversion/include/media/AidlConversionNdk.h b/media/audioaidlconversion/include/media/AidlConversionNdk.h
new file mode 100644
index 0000000..98a7d41
--- /dev/null
+++ b/media/audioaidlconversion/include/media/AidlConversionNdk.h
@@ -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.
+ */
+
+#pragma once
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_manager.h>
+#include <android/binder_process.h>
+
+/**
+ * Can only handle conversion between AIDL (NDK backend) and legacy type.
+ */
+#include <hardware/audio_effect.h>
+#include <media/AidlConversionUtil.h>
+#include <system/audio_effect.h>
+#include <aidl/android/media/audio/common/AudioConfig.h>
+
+namespace aidl {
+namespace android {
+
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
+ const media::audio::common::AudioConfigBase& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioConfigBase> legacy2aidl_buffer_config_t_AudioConfigBase(
+ const buffer_config_t& legacy, bool isInput);
+
+} // namespace android
+} // namespace aidl
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil.h b/media/audioaidlconversion/include/media/AidlConversionUtil.h
index 95daa4a..8b2e0de 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil.h
@@ -25,7 +25,10 @@
#include <error/Result.h>
#if defined(BACKEND_NDK)
+#include <android/binder_auto_utils.h>
+#include <android/binder_enums.h>
#include <android/binder_status.h>
+
namespace aidl {
#else
#include <binder/Enums.h>
@@ -275,6 +278,8 @@
#define UNION_SET(u, field, value) \
(u).set<std::decay_t<decltype(u)>::Tag::field>(value)
+#define UNION_MAKE(u, field, value) u::make<u::Tag::field>(value)
+
namespace aidl_utils {
/**
@@ -360,6 +365,20 @@
// standard Java exception (fromExceptionCode)
}
+#if defined(BACKEND_NDK)
+static inline ::android::status_t statusTFromBinderStatus(const ::ndk::ScopedAStatus &status) {
+ // What we want to do is to 'return statusTFromBinderStatus(status.get()->get())'
+ // However, since the definition of AStatus is not exposed, we have to do the same
+ // via methods of ScopedAStatus:
+ return status.isOk() ? ::android::OK // check ::android::OK,
+ : status.getServiceSpecificError() // service-side error, not standard Java exception
+ // (fromServiceSpecificError)
+ ?: status.getStatus() // a native binder transaction error (fromStatusT)
+ ?: statusTFromExceptionCode(status.getExceptionCode()); // a service-side error with a
+ // standard Java exception (fromExceptionCode)
+}
+#endif
+
/**
* Return a binder::Status from native service status.
*
@@ -394,11 +413,10 @@
return Status::fromServiceSpecificError(status, emptyIfNull);
}
-
} // namespace aidl_utils
} // namespace android
#if defined(BACKEND_NDK)
} // namespace aidl
-#endif
\ No newline at end of file
+#endif
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index e3db5b4..1e3bfe0 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -50,6 +50,8 @@
int main(int argc __unused, char **argv)
{
+ ALOGD("%s: starting", __func__);
+ const auto startTime = std::chrono::steady_clock::now();
// TODO: update with refined parameters
limitProcessMemory(
"audio.maxmem", /* "ro.audio.maxmem", property that defines limit */
@@ -144,11 +146,36 @@
setpgid(0, 0); // but if I die first, don't kill my parent
}
android::hardware::configureRpcThreadpool(4, false /*callerWillJoin*/);
- sp<ProcessState> proc(ProcessState::self());
+
+ // Ensure threads for possible callbacks. Note that get_audio_flinger() does
+ // this automatically when called from AudioPolicy, but we do this anyways here.
+ ProcessState::self()->startThreadPool();
+
+ // Instantiating AudioFlinger (making it public, e.g. through ::initialize())
+ // and then instantiating AudioPolicy (and making it public)
+ // leads to situations where AudioFlinger is accessed remotely before
+ // AudioPolicy is initialized. Not only might this
+ // cause inaccurate results, but if AudioPolicy has slow audio HAL
+ // initialization, it can cause a TimeCheck abort to occur on an AudioFlinger
+ // call which tries to access AudioPolicy.
+ //
+ // We create AudioFlinger and AudioPolicy locally then make it public to ServiceManager.
+ // This requires both AudioFlinger and AudioPolicy to be in-proc.
+ //
+ const auto af = sp<AudioFlinger>::make();
+ const auto afAdapter = sp<AudioFlingerServerAdapter>::make(af);
+ ALOGD("%s: AudioFlinger created", __func__);
+ ALOGW_IF(AudioSystem::setLocalAudioFlinger(af) != OK,
+ "%s: AudioSystem already has an AudioFlinger instance!", __func__);
+ const auto aps = sp<AudioPolicyService>::make();
+ ALOGD("%s: AudioPolicy created", __func__);
+
+ // Add AudioFlinger and AudioPolicy to ServiceManager.
sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- AudioPolicyService::instantiate();
+ sm->addService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME), afAdapter,
+ false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
+ sm->addService(String16(AudioPolicyService::getServiceName()), aps,
+ false /* allowIsolated */, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT);
// AAudioService should only be used in OC-MR1 and later.
// And only enable the AAudioService if the system MMAP policy explicitly allows it.
@@ -156,7 +183,6 @@
// If we cannot get audio flinger here, there must be some serious problems. In that case,
// attempting to call audio flinger on a null pointer could make the process crash
// and attract attentions.
- sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
std::vector<AudioMMapPolicyInfo> policyInfos;
status_t status = af->getMmapPolicyInfos(
AudioMMapPolicyType::DEFAULT, &policyInfos);
@@ -169,11 +195,14 @@
})) {
AAudioService::instantiate();
} else {
- ALOGD("Do not init aaudio service, status %d, policy info size %zu",
- status, policyInfos.size());
+ ALOGD("%s: Do not init aaudio service, status %d, policy info size %zu",
+ __func__, status, policyInfos.size());
}
-
- ProcessState::self()->startThreadPool();
+ const auto endTime = std::chrono::steady_clock::now();
+ using FloatMillis = std::chrono::duration<float, std::milli>;
+ const float timeTaken = std::chrono::duration_cast<FloatMillis>(
+ endTime - startTime).count();
+ ALOGI("%s: initialization done in %.3f ms, joining thread pool", __func__, timeTaken);
IPCThreadState::self()->joinThreadPool();
}
}
diff --git a/media/codec2/components/aom/C2SoftAomDec.cpp b/media/codec2/components/aom/C2SoftAomDec.cpp
index 96b81d7..0eb47f4 100644
--- a/media/codec2/components/aom/C2SoftAomDec.cpp
+++ b/media/codec2/components/aom/C2SoftAomDec.cpp
@@ -578,7 +578,8 @@
size_t srcVStride = img->stride[AOM_PLANE_V];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (img->fmt == AOM_IMG_FMT_I42016) {
const uint16_t *srcY = (const uint16_t *)img->planes[AOM_PLANE_Y];
@@ -592,7 +593,7 @@
std::static_pointer_cast<const C2ColorAspectsStruct>(defaultColorAspects));
} else {
convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
mWidth, mHeight);
}
} else {
@@ -600,7 +601,7 @@
const uint8_t *srcU = (const uint8_t *)img->planes[AOM_PLANE_U];
const uint8_t *srcV = (const uint8_t *)img->planes[AOM_PLANE_V];
convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
+ srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight);
}
finishWork(*(int64_t*)img->user_priv, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index f5620a4..8b852a2 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -22,6 +22,7 @@
#include <media/stagefright/foundation/MediaDefs.h>
#include <C2Debug.h>
+#include <Codec2Mapper.h>
#include <C2PlatformSupport.h>
#include <SimpleC2Interface.h>
@@ -390,6 +391,36 @@
codec_return = aom_codec_control(mCodecContext, AV1E_SET_MAX_REFERENCE_FRAMES, 3);
if (codec_return != AOM_CODEC_OK) goto BailOut;
+ ColorAspects sfAspects;
+ if (!C2Mapper::map(mColorAspects->primaries, &sfAspects.mPrimaries)) {
+ sfAspects.mPrimaries = android::ColorAspects::PrimariesUnspecified;
+ }
+ if (!C2Mapper::map(mColorAspects->range, &sfAspects.mRange)) {
+ sfAspects.mRange = android::ColorAspects::RangeUnspecified;
+ }
+ if (!C2Mapper::map(mColorAspects->matrix, &sfAspects.mMatrixCoeffs)) {
+ sfAspects.mMatrixCoeffs = android::ColorAspects::MatrixUnspecified;
+ }
+ if (!C2Mapper::map(mColorAspects->transfer, &sfAspects.mTransfer)) {
+ sfAspects.mTransfer = android::ColorAspects::TransferUnspecified;
+ }
+ int32_t primaries, transfer, matrixCoeffs;
+ bool range;
+ ColorUtils::convertCodecColorAspectsToIsoAspects(sfAspects,
+ &primaries,
+ &transfer,
+ &matrixCoeffs,
+ &range);
+
+ codec_return = aom_codec_control(mCodecContext, AV1E_SET_COLOR_RANGE, range);
+ if (codec_return != AOM_CODEC_OK) goto BailOut;
+ codec_return = aom_codec_control(mCodecContext, AV1E_SET_COLOR_PRIMARIES, primaries);
+ if (codec_return != AOM_CODEC_OK) goto BailOut;
+ codec_return = aom_codec_control(mCodecContext, AV1E_SET_TRANSFER_CHARACTERISTICS, transfer);
+ if (codec_return != AOM_CODEC_OK) goto BailOut;
+ codec_return = aom_codec_control(mCodecContext, AV1E_SET_MATRIX_COEFFICIENTS, matrixCoeffs);
+ if (codec_return != AOM_CODEC_OK) goto BailOut;
+
BailOut:
return codec_return;
}
@@ -406,6 +437,7 @@
mFrameRate = mIntf->getFrameRate_l();
mIntraRefresh = mIntf->getIntraRefresh_l();
mRequestSync = mIntf->getRequestSync_l();
+ mColorAspects = mIntf->getCodedColorAspects_l();
}
diff --git a/media/codec2/components/aom/C2SoftAomEnc.h b/media/codec2/components/aom/C2SoftAomEnc.h
index 2d1bb07..3e42855 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.h
+++ b/media/codec2/components/aom/C2SoftAomEnc.h
@@ -104,6 +104,7 @@
std::shared_ptr<C2StreamBitrateInfo::output> mBitrate;
std::shared_ptr<C2StreamBitrateModeTuning::output> mBitrateMode;
std::shared_ptr<C2StreamRequestSyncFrameTuning::output> mRequestSync;
+ std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
aom_codec_err_t setupCodecParameters();
};
diff --git a/media/codec2/components/base/SimpleC2Component.cpp b/media/codec2/components/base/SimpleC2Component.cpp
index d549c3b..32f8fa8 100644
--- a/media/codec2/components/base/SimpleC2Component.cpp
+++ b/media/codec2/components/base/SimpleC2Component.cpp
@@ -38,8 +38,8 @@
void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
size_t srcUStride, size_t srcVStride, size_t dstYStride,
- size_t dstUVStride, uint32_t width, uint32_t height,
- bool isMonochrome) {
+ size_t dstUStride, size_t dstVStride, uint32_t width,
+ uint32_t height, bool isMonochrome) {
for (size_t i = 0; i < height; ++i) {
memcpy(dstY, srcY, width);
srcY += srcYStride;
@@ -51,8 +51,8 @@
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memset(dstV, kNeutralUVBitDepth8, (width + 1) / 2);
memset(dstU, kNeutralUVBitDepth8, (width + 1) / 2);
- dstV += dstUVStride;
- dstU += dstUVStride;
+ dstV += dstVStride;
+ dstU += dstUStride;
}
return;
}
@@ -60,13 +60,13 @@
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memcpy(dstV, srcV, (width + 1) / 2);
srcV += srcVStride;
- dstV += dstUVStride;
+ dstV += dstVStride;
}
for (size_t i = 0; i < (height + 1) / 2; ++i) {
memcpy(dstU, srcU, (width + 1) / 2);
srcU += srcUStride;
- dstU += dstUVStride;
+ dstU += dstUStride;
}
}
diff --git a/media/codec2/components/base/include/SimpleC2Component.h b/media/codec2/components/base/include/SimpleC2Component.h
index 38b7825..051f798 100644
--- a/media/codec2/components/base/include/SimpleC2Component.h
+++ b/media/codec2/components/base/include/SimpleC2Component.h
@@ -33,8 +33,8 @@
void convertYUV420Planar8ToYV12(uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, const uint8_t *srcY,
const uint8_t *srcU, const uint8_t *srcV, size_t srcYStride,
size_t srcUStride, size_t srcVStride, size_t dstYStride,
- size_t dstUVStride, uint32_t width, uint32_t height,
- bool isMonochrome = false);
+ size_t dstUStride, size_t dstVStride, uint32_t width,
+ uint32_t height, bool isMonochrome = false);
void convertYUV420Planar16ToY410OrRGBA1010102(
uint32_t *dst, const uint16_t *srcY,
diff --git a/media/codec2/components/gav1/Android.bp b/media/codec2/components/gav1/Android.bp
index 162339f..9781b6d 100644
--- a/media/codec2/components/gav1/Android.bp
+++ b/media/codec2/components/gav1/Android.bp
@@ -21,7 +21,10 @@
],
srcs: ["C2SoftGav1Dec.cpp"],
- static_libs: ["libgav1"],
+ static_libs: [
+ "libgav1",
+ "libyuv_static",
+ ],
apex_available: [
"//apex_available:platform",
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.cpp b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
index d234f21..8aed623 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.cpp
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.cpp
@@ -24,6 +24,7 @@
#include <Codec2CommonUtils.h>
#include <Codec2Mapper.h>
#include <SimpleC2Interface.h>
+#include <libyuv.h>
#include <log/log.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/MediaDefs.h>
@@ -725,6 +726,24 @@
}
}
+void C2SoftGav1Dec::setError(const std::unique_ptr<C2Work> &work, c2_status_t error) {
+ mSignalledError = true;
+ work->result = error;
+ work->workletsProcessed = 1u;
+}
+
+bool C2SoftGav1Dec::allocTmpFrameBuffer(size_t size) {
+ if (size > mTmpFrameBufferSize) {
+ mTmpFrameBuffer = std::make_unique<uint16_t[]>(size);
+ if (mTmpFrameBuffer == nullptr) {
+ mTmpFrameBufferSize = 0;
+ return false;
+ }
+ mTmpFrameBufferSize = size;
+ }
+ return true;
+}
+
bool C2SoftGav1Dec::outputBuffer(const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work) {
if (!(work && pool)) return false;
@@ -771,14 +790,6 @@
getHDRStaticParams(buffer, work);
getHDR10PlusInfoData(buffer, work);
- if (!(buffer->image_format == libgav1::kImageFormatYuv420 ||
- buffer->image_format == libgav1::kImageFormatMonochrome400)) {
- ALOGE("image_format %d not supported", buffer->image_format);
- mSignalledError = true;
- work->workletsProcessed = 1u;
- work->result = C2_CORRUPTED;
- return false;
- }
const bool isMonochrome =
buffer->image_format == libgav1::kImageFormatMonochrome400;
@@ -851,40 +862,112 @@
uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
uint8_t *dstU = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
uint8_t *dstV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_V]);
- size_t srcYStride = buffer->stride[0];
- size_t srcUStride = buffer->stride[1];
- size_t srcVStride = buffer->stride[2];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (buffer->bitdepth == 10) {
const uint16_t *srcY = (const uint16_t *)buffer->plane[0];
const uint16_t *srcU = (const uint16_t *)buffer->plane[1];
const uint16_t *srcV = (const uint16_t *)buffer->plane[2];
+ size_t srcYStride = buffer->stride[0] / 2;
+ size_t srcUStride = buffer->stride[1] / 2;
+ size_t srcVStride = buffer->stride[2] / 2;
if (format == HAL_PIXEL_FORMAT_RGBA_1010102) {
convertYUV420Planar16ToY410OrRGBA1010102(
- (uint32_t *)dstY, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2,
+ (uint32_t *)dstY, srcY, srcU, srcV, srcYStride,
+ srcUStride, srcVStride,
dstYStride / sizeof(uint32_t), mWidth, mHeight,
std::static_pointer_cast<const C2ColorAspectsStruct>(codedColorAspects));
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
- convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
- srcYStride / 2, srcUStride / 2, srcVStride / 2, dstYStride / 2,
- dstUVStride / 2, mWidth, mHeight, isMonochrome);
+ dstYStride /= 2;
+ dstUStride /= 2;
+ dstVStride /= 2;
+ if (buffer->image_format == libgav1::kImageFormatYuv444 ||
+ buffer->image_format == libgav1::kImageFormatYuv422) {
+ // TODO(https://crbug.com/libyuv/952): replace this block with libyuv::I410ToP010 and
+ // libyuv::I210ToP010 when they are available.
+ // Note it may be safe to alias dstY in I010ToP010, but the libyuv API doesn't make any
+ // guarantees.
+ const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ if (!allocTmpFrameBuffer(tmpSize)) {
+ ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
+ setError(work, C2_NO_MEMORY);
+ return false;
+ }
+ uint16_t *const tmpY = mTmpFrameBuffer.get();
+ uint16_t *const tmpU = tmpY + dstYStride * mHeight;
+ uint16_t *const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
+ if (buffer->image_format == libgav1::kImageFormatYuv444) {
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ mWidth, mHeight);
+ } else {
+ libyuv::I210ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ mWidth, mHeight);
+ }
+ libyuv::I010ToP010(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride,
+ (uint16_t*)dstY, dstYStride, (uint16_t*)dstU, dstUStride,
+ mWidth, mHeight);
+ } else {
+ convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
+ srcYStride, srcUStride, srcVStride, dstYStride,
+ dstUStride, mWidth, mHeight, isMonochrome);
+ }
} else {
- convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride, mWidth,
- mHeight, isMonochrome);
+ if (buffer->image_format == libgav1::kImageFormatYuv444) {
+ // TODO(https://crbug.com/libyuv/950): replace this block with libyuv::I410ToI420 when
+ // it's available.
+ const size_t tmpSize = dstYStride * mHeight + dstUStride * align(mHeight, 2);
+ if (!allocTmpFrameBuffer(tmpSize)) {
+ ALOGE("Error allocating temp conversion buffer (%zu bytes)", tmpSize);
+ setError(work, C2_NO_MEMORY);
+ return false;
+ }
+ uint16_t *const tmpY = mTmpFrameBuffer.get();
+ uint16_t *const tmpU = tmpY + dstYStride * mHeight;
+ uint16_t *const tmpV = tmpU + dstUStride * align(mHeight, 2) / 2;
+ libyuv::I410ToI010(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ tmpY, dstYStride, tmpU, dstUStride, tmpV, dstVStride,
+ mWidth, mHeight);
+ libyuv::I010ToI420(tmpY, dstYStride, tmpU, dstUStride, tmpV, dstUStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else if (buffer->image_format == libgav1::kImageFormatYuv422) {
+ libyuv::I210ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else {
+ convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
+ mWidth, mHeight, isMonochrome);
+ }
}
} else {
const uint8_t *srcY = (const uint8_t *)buffer->plane[0];
const uint8_t *srcU = (const uint8_t *)buffer->plane[1];
const uint8_t *srcV = (const uint8_t *)buffer->plane[2];
- convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight, isMonochrome);
+ size_t srcYStride = buffer->stride[0];
+ size_t srcUStride = buffer->stride[1];
+ size_t srcVStride = buffer->stride[2];
+
+ if (buffer->image_format == libgav1::kImageFormatYuv444) {
+ libyuv::I444ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else if (buffer->image_format == libgav1::kImageFormatYuv422) {
+ libyuv::I422ToI420(srcY, srcYStride, srcU, srcUStride, srcV, srcVStride,
+ dstY, dstYStride, dstU, dstUStride, dstV, dstVStride,
+ mWidth, mHeight);
+ } else {
+ convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
+ srcVStride, dstYStride, dstUStride, dstVStride, mWidth, mHeight,
+ isMonochrome);
+ }
}
finishWork(buffer->user_private_data, work, std::move(block));
block = nullptr;
diff --git a/media/codec2/components/gav1/C2SoftGav1Dec.h b/media/codec2/components/gav1/C2SoftGav1Dec.h
index f0e14d7..c3b27ea 100644
--- a/media/codec2/components/gav1/C2SoftGav1Dec.h
+++ b/media/codec2/components/gav1/C2SoftGav1Dec.h
@@ -19,6 +19,8 @@
#include <inttypes.h>
+#include <memory>
+
#include <media/stagefright/foundation/ColorUtils.h>
#include <SimpleC2Component.h>
@@ -60,6 +62,9 @@
uint32_t mHeight;
bool mSignalledOutputEos;
bool mSignalledError;
+ // Used during 10-bit I444/I422 to 10-bit P010 & 8-bit I420 conversions.
+ std::unique_ptr<uint16_t[]> mTmpFrameBuffer;
+ size_t mTmpFrameBufferSize = 0;
C2StreamHdrStaticMetadataInfo::output mHdrStaticMetadataInfo;
std::unique_ptr<C2StreamHdr10PlusInfo::output> mHdr10PlusInfo = nullptr;
@@ -97,6 +102,9 @@
void destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
const std::shared_ptr<C2GraphicBlock>& block);
+ // Sets |work->result| and mSignalledError. Returns false.
+ void setError(const std::unique_ptr<C2Work> &work, c2_status_t error);
+ bool allocTmpFrameBuffer(size_t size);
bool outputBuffer(const std::shared_ptr<C2BlockPool>& pool,
const std::unique_ptr<C2Work>& work);
c2_status_t drainInternal(uint32_t drainMode,
diff --git a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
index 3bf9c48..2137964 100644
--- a/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
+++ b/media/codec2/components/mpeg4_h263/C2SoftMpeg4Dec.cpp
@@ -603,7 +603,8 @@
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
size_t srcYStride = align(mWidth, 16);
size_t srcUStride = srcYStride / 2;
size_t srcVStride = srcYStride / 2;
@@ -613,8 +614,8 @@
const uint8_t *srcV = (const uint8_t *)srcY + vStride * srcYStride * 5 / 4;
convertYUV420Planar8ToYV12(outputBufferY, outputBufferU, outputBufferV, srcY, srcU, srcV,
- srcYStride, srcUStride, srcVStride, dstYStride, dstUVStride,
- mWidth, mHeight);
+ srcYStride, srcUStride, srcVStride, dstYStride, dstUStride,
+ dstVStride, mWidth, mHeight);
inPos += inSize - (size_t)tmpInSize;
finishWork(workIndex, work);
diff --git a/media/codec2/components/vpx/C2SoftVpxDec.cpp b/media/codec2/components/vpx/C2SoftVpxDec.cpp
index 18cd1bf..dab7b89 100644
--- a/media/codec2/components/vpx/C2SoftVpxDec.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxDec.cpp
@@ -766,7 +766,8 @@
size_t srcVStride = img->stride[VPX_PLANE_V];
C2PlanarLayout layout = wView.layout();
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
- size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstUStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
+ size_t dstVStride = layout.planes[C2PlanarLayout::PLANE_V].rowInc;
if (img->fmt == VPX_IMG_FMT_I42016) {
const uint16_t *srcY = (const uint16_t *)img->planes[VPX_PLANE_Y];
@@ -804,10 +805,10 @@
} else if (format == HAL_PIXEL_FORMAT_YCBCR_P010) {
convertYUV420Planar16ToP010((uint16_t *)dstY, (uint16_t *)dstU, srcY, srcU, srcV,
srcYStride / 2, srcUStride / 2, srcVStride / 2,
- dstYStride / 2, dstUVStride / 2, mWidth, mHeight);
+ dstYStride / 2, dstUStride / 2, mWidth, mHeight);
} else {
convertYUV420Planar16ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride / 2,
- srcUStride / 2, srcVStride / 2, dstYStride, dstUVStride,
+ srcUStride / 2, srcVStride / 2, dstYStride, dstUStride,
mWidth, mHeight);
}
} else {
@@ -816,7 +817,7 @@
const uint8_t *srcV = (const uint8_t *)img->planes[VPX_PLANE_V];
convertYUV420Planar8ToYV12(dstY, dstU, dstV, srcY, srcU, srcV, srcYStride, srcUStride,
- srcVStride, dstYStride, dstUVStride, mWidth, mHeight);
+ srcVStride, dstYStride, dstVStride, dstVStride, mWidth, mHeight);
}
finishWork(((c2_cntr64_t *)img->user_priv)->peekull(), work, std::move(block));
return OK;
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 09452c4..f5128ca 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -1722,6 +1722,8 @@
static_cast<uint64_t>(blockPoolId),
bqId == 0 ? nullHgbp : igbp);
+ mOutputBufferQueue->expireOldWaiters();
+
if (!transStatus.isOk()) {
LOG(ERROR) << "setOutputSurface -- transaction failed.";
return C2_TRANSACTION_FAILED;
@@ -1763,6 +1765,7 @@
<< status << ".";
}
}
+ mOutputBufferQueue->expireOldWaiters();
}
c2_status_t Codec2Client::Component::connectToInputSurface(
diff --git a/media/codec2/hal/client/include/codec2/hidl/output.h b/media/codec2/hal/client/include/codec2/hidl/output.h
index a13edf3..c208df0 100644
--- a/media/codec2/hal/client/include/codec2/hidl/output.h
+++ b/media/codec2/hal/client/include/codec2/hidl/output.h
@@ -50,6 +50,10 @@
int maxDequeueBufferCount,
std::shared_ptr<V1_2::SurfaceSyncObj> *syncObj);
+ // If there are waiters to allocate from the old surface, wake up and expire
+ // them.
+ void expireOldWaiters();
+
// Stop using the current output surface. Pending buffer opeations will not
// perform anymore.
void stop();
@@ -86,6 +90,8 @@
std::weak_ptr<_C2BlockPoolData> mPoolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
bool mStopped;
+ std::mutex mOldMutex;
+ std::shared_ptr<C2SurfaceSyncMemory> mOldMem;
bool registerBuffer(const C2ConstGraphicBlock& block);
};
diff --git a/media/codec2/hal/client/output.cpp b/media/codec2/hal/client/output.cpp
index f789030..6aaf9ab 100644
--- a/media/codec2/hal/client/output.cpp
+++ b/media/codec2/hal/client/output.cpp
@@ -217,6 +217,7 @@
sp<GraphicBuffer> buffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
std::weak_ptr<_C2BlockPoolData>
poolDatas[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ std::shared_ptr<C2SurfaceSyncMemory> oldMem;
{
std::scoped_lock<std::mutex> l(mMutex);
bool stopped = mStopped;
@@ -238,7 +239,7 @@
}
return false;
}
- std::shared_ptr<C2SurfaceSyncMemory> oldMem = mSyncMem;
+ oldMem = mSyncMem;
C2SyncVariables *oldSync = mSyncMem ? mSyncMem->mem() : nullptr;
if (oldSync) {
oldSync->lock();
@@ -314,11 +315,26 @@
newSync->unlock();
}
}
+ {
+ std::scoped_lock<std::mutex> l(mOldMutex);
+ mOldMem = oldMem;
+ }
ALOGD("remote graphic buffer migration %zu/%zu",
success, tryNum);
return true;
}
+void OutputBufferQueue::expireOldWaiters() {
+ std::scoped_lock<std::mutex> l(mOldMutex);
+ if (mOldMem) {
+ C2SyncVariables *oldSync = mOldMem->mem();
+ if (oldSync) {
+ oldSync->notifyAll();
+ }
+ mOldMem.reset();
+ }
+}
+
void OutputBufferQueue::stop() {
std::scoped_lock<std::mutex> l(mMutex);
mStopped = true;
diff --git a/media/codec2/hal/plugin/samples/Android.bp b/media/codec2/hal/plugin/samples/Android.bp
index 32b760d..e0f8280 100644
--- a/media/codec2/hal/plugin/samples/Android.bp
+++ b/media/codec2/hal/plugin/samples/Android.bp
@@ -28,6 +28,7 @@
"libGLESv1_CM",
"libGLESv2",
"libGLESv3",
+ "libvulkan",
"libbase",
"libcodec2",
"libcutils",
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index a008dc2..f258bff 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -1868,18 +1868,14 @@
}
state->set(STOPPING);
}
- {
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mPushBlankBuffersOnStop) {
- mChannel->pushBlankBufferToOutputSurface();
- }
- }
mChannel->reset();
- (new AMessage(kWhatStop, this))->post();
+ bool pushBlankBuffer = mConfig.lock().get()->mPushBlankBuffersOnStop;
+ sp<AMessage> stopMessage(new AMessage(kWhatStop, this));
+ stopMessage->setInt32("pushBlankBuffer", pushBlankBuffer);
+ stopMessage->post();
}
-void CCodec::stop() {
+void CCodec::stop(bool pushBlankBuffer) {
std::shared_ptr<Codec2Client::Component> comp;
{
Mutexed<State>::Locked state(mState);
@@ -1898,7 +1894,7 @@
comp = state->comp;
}
status_t err = comp->stop();
- mChannel->stopUseOutputSurface();
+ mChannel->stopUseOutputSurface(pushBlankBuffer);
if (err != C2_OK) {
// TODO: convert err into status_t
mCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
@@ -1963,21 +1959,16 @@
config->mInputSurfaceDataspace = HAL_DATASPACE_UNKNOWN;
}
}
- {
- Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
- const std::unique_ptr<Config> &config = *configLocked;
- if (config->mPushBlankBuffersOnStop) {
- mChannel->pushBlankBufferToOutputSurface();
- }
- }
mChannel->reset();
+ bool pushBlankBuffer = mConfig.lock().get()->mPushBlankBuffersOnStop;
// thiz holds strong ref to this while the thread is running.
sp<CCodec> thiz(this);
- std::thread([thiz, sendCallback] { thiz->release(sendCallback); }).detach();
+ std::thread([thiz, sendCallback, pushBlankBuffer]
+ { thiz->release(sendCallback, pushBlankBuffer); }).detach();
}
-void CCodec::release(bool sendCallback) {
+void CCodec::release(bool sendCallback, bool pushBlankBuffer) {
std::shared_ptr<Codec2Client::Component> comp;
{
Mutexed<State>::Locked state(mState);
@@ -1992,7 +1983,7 @@
comp = state->comp;
}
comp->release();
- mChannel->stopUseOutputSurface();
+ mChannel->stopUseOutputSurface(pushBlankBuffer);
{
Mutexed<State>::Locked state(mState);
@@ -2006,6 +1997,7 @@
}
status_t CCodec::setSurface(const sp<Surface> &surface) {
+ bool pushBlankBuffer = false;
{
Mutexed<std::unique_ptr<Config>>::Locked configLocked(mConfig);
const std::unique_ptr<Config> &config = *configLocked;
@@ -2031,8 +2023,9 @@
return err;
}
}
+ pushBlankBuffer = config->mPushBlankBuffersOnStop;
}
- return mChannel->setSurface(surface);
+ return mChannel->setSurface(surface, pushBlankBuffer);
}
void CCodec::signalFlush() {
@@ -2331,7 +2324,11 @@
case kWhatStop: {
// C2Component::stop() should return within 500ms.
setDeadline(now, 1500ms, "stop");
- stop();
+ int32_t pushBlankBuffer;
+ if (!msg->findInt32("pushBlankBuffer", &pushBlankBuffer)) {
+ pushBlankBuffer = 0;
+ }
+ stop(static_cast<bool>(pushBlankBuffer));
break;
}
case kWhatFlush: {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 4bf8dce..fff008b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -226,6 +226,9 @@
if (buffer->meta()->findInt32("tunnel-first-frame", &tmp) && tmp) {
tunnelFirstFrame = true;
}
+ if (buffer->meta()->findInt32("decode-only", &tmp) && tmp) {
+ flags |= C2FrameData::FLAG_DROP_FRAME;
+ }
ALOGV("[%s] queueInputBuffer: buffer->size() = %zu", mName, buffer->size());
std::list<std::unique_ptr<C2Work>> items;
std::unique_ptr<C2Work> work(new C2Work);
@@ -1578,14 +1581,22 @@
mFirstValidFrameIndex = mFrameIndex.load(std::memory_order_relaxed);
}
-void CCodecBufferChannel::stopUseOutputSurface() {
- if (mOutputSurface.lock()->surface) {
+void CCodecBufferChannel::stopUseOutputSurface(bool pushBlankBuffer) {
+ sp<Surface> surface = mOutputSurface.lock()->surface;
+ if (surface) {
C2BlockPool::local_id_t outputPoolId;
{
Mutexed<BlockPools>::Locked pools(mBlockPools);
outputPoolId = pools->outputPoolId;
}
if (mComponent) mComponent->stopUsingOutputSurface(outputPoolId);
+
+ if (pushBlankBuffer) {
+ sp<ANativeWindow> anw = static_cast<ANativeWindow *>(surface.get());
+ if (anw) {
+ pushBlankBuffersToNativeWindow(anw.get());
+ }
+ }
}
}
@@ -1995,6 +2006,12 @@
drop = true;
}
+ // Workaround: if C2FrameData::FLAG_DROP_FRAME is not implemented in
+ // HAL, the flag is then removed in the corresponding output buffer.
+ if (work->input.flags & C2FrameData::FLAG_DROP_FRAME) {
+ flags |= BUFFER_FLAG_DECODE_ONLY;
+ }
+
if (notifyClient && !buffer && !flags) {
if (mTunneled && drop && outputFormat) {
ALOGV("[%s] onWorkDone: Keep tunneled, drop frame with format change (%lld)",
@@ -2097,14 +2114,20 @@
}
}
-status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface) {
+status_t CCodecBufferChannel::setSurface(const sp<Surface> &newSurface, bool pushBlankBuffer) {
static std::atomic_uint32_t surfaceGeneration{0};
uint32_t generation = (getpid() << 10) |
((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1)
& ((1 << 10) - 1));
sp<IGraphicBufferProducer> producer;
- int maxDequeueCount = mOutputSurface.lock()->maxDequeueBuffers;
+ int maxDequeueCount;
+ sp<Surface> oldSurface;
+ {
+ Mutexed<OutputSurface>::Locked outputSurface(mOutputSurface);
+ maxDequeueCount = outputSurface->maxDequeueBuffers;
+ oldSurface = outputSurface->surface;
+ }
if (newSurface) {
newSurface->setScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
newSurface->setDequeueTimeout(kDequeueTimeoutNs);
@@ -2141,6 +2164,15 @@
output->generation = generation;
}
+ if (oldSurface && pushBlankBuffer) {
+ // When ReleaseSurface was set from MediaCodec,
+ // pushing a blank buffer at the end might be necessary.
+ sp<ANativeWindow> anw = static_cast<ANativeWindow *>(oldSurface.get());
+ if (anw) {
+ pushBlankBuffersToNativeWindow(anw.get());
+ }
+ }
+
return OK;
}
@@ -2230,13 +2262,4 @@
}
}
-status_t CCodecBufferChannel::pushBlankBufferToOutputSurface() {
- Mutexed<OutputSurface>::Locked output(mOutputSurface);
- sp<ANativeWindow> nativeWindow = static_cast<ANativeWindow *>(output->surface.get());
- if (nativeWindow == nullptr) {
- return INVALID_OPERATION;
- }
- return pushBlankBuffersToNativeWindow(nativeWindow.get());
-}
-
} // namespace android
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index 61fb06f..a52d4dc 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -102,7 +102,7 @@
/**
* Set output graphic surface for rendering.
*/
- status_t setSurface(const sp<Surface> &surface);
+ status_t setSurface(const sp<Surface> &surface, bool pushBlankBuffer);
/**
* Set GraphicBufferSource object from which the component extracts input
@@ -151,8 +151,10 @@
/**
* Stop using buffers of the current output surface for other Codec
* instances to use the surface safely.
+ *
+ * \param pushBlankBuffer[in] push a blank buffer at the end if true
*/
- void stopUseOutputSurface();
+ void stopUseOutputSurface(bool pushBlankBuffer);
/**
* Stop queueing buffers to the component. This object should never queue
@@ -201,11 +203,6 @@
void setMetaMode(MetaMode mode);
- /**
- * Push a blank buffer to the configured native output surface.
- */
- status_t pushBlankBufferToOutputSurface();
-
private:
class QueueGuard;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index b9270de..82c31a8 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -22,6 +22,7 @@
#include <aidl/android/hardware/graphics/common/Cta861_3.h>
#include <aidl/android/hardware/graphics/common/Smpte2086.h>
+#include <android-base/no_destructor.h>
#include <android-base/properties.h>
#include <android/hardware/cas/native/1.0/types.h>
#include <android/hardware/drm/1.0/types.h>
@@ -1018,8 +1019,8 @@
namespace {
sp<IMapper4> GetMapper4() {
- static sp<IMapper4> sMapper = IMapper4::getService();
- return sMapper;
+ static ::android::base::NoDestructor<sp<IMapper4>> sMapper(IMapper4::getService());
+ return *sMapper;
}
class Gralloc4Buffer {
@@ -1137,6 +1138,11 @@
err = C2_CORRUPTED;
}
}
+
+ if (err != C2_OK) {
+ staticInfo->reset();
+ }
+
if (dynamicInfo) {
ALOGV("Grabbing dynamic HDR info from gralloc4 metadata");
dynamicInfo->reset();
diff --git a/media/codec2/sfplugin/include/media/stagefright/CCodec.h b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
index ec18128..13713bc 100644
--- a/media/codec2/sfplugin/include/media/stagefright/CCodec.h
+++ b/media/codec2/sfplugin/include/media/stagefright/CCodec.h
@@ -109,9 +109,9 @@
void allocate(const sp<MediaCodecInfo> &codecInfo);
void configure(const sp<AMessage> &msg);
void start();
- void stop();
+ void stop(bool pushBlankBuffer);
void flush();
- void release(bool sendCallback);
+ void release(bool sendCallback, bool pushBlankBuffer);
/**
* Creates an input surface for the current device configuration compatible with CCodec.
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index 1d8aea3..ba25226 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -80,6 +80,7 @@
"libbase",
"libdmabufheap",
"android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.bufferpool2-V1-ndk",
],
local_include_dirs: [
@@ -94,8 +95,12 @@
shared_libs: [
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.2",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
"android.hardware.media.bufferpool@2.0",
+ "android.hardware.media.bufferpool2-V1-ndk",
"libbase",
+ "libbinder_ndk",
"libcutils",
"libdl",
"libdmabufheap",
@@ -107,6 +112,7 @@
"libnativewindow",
"libstagefright_foundation",
"libstagefright_bufferpool@2.0.1",
+ "libstagefright_aidl_bufferpool2",
"libui",
"libutils",
],
@@ -135,6 +141,7 @@
"libnativewindow",
"libcodec2_soft_common",
"libsfplugin_ccodec_utils",
+ "libstagefright_aidl_bufferpool2",
"libstagefright_foundation",
"libstagefright_bufferpool@2.0.1",
"libgralloctypes",
@@ -144,9 +151,13 @@
"android.hardware.graphics.allocator@2.0",
"android.hardware.graphics.allocator@3.0",
"android.hardware.graphics.bufferqueue@2.0",
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
+ "android.hardware.media.bufferpool2-V1-ndk",
],
shared_libs: [
+ "libbinder_ndk",
"libui",
"libdl",
"libvndksupport",
diff --git a/media/codec2/vndk/C2Buffer.cpp b/media/codec2/vndk/C2Buffer.cpp
index 143355f..018e269 100644
--- a/media/codec2/vndk/C2Buffer.cpp
+++ b/media/codec2/vndk/C2Buffer.cpp
@@ -29,19 +29,21 @@
#include <C2BlockInternal.h>
#include <C2PlatformSupport.h>
#include <bufferpool/ClientManager.h>
+#include <bufferpool2/ClientManager.h>
namespace {
using android::C2AllocatorBlob;
using android::C2AllocatorGralloc;
using android::C2AllocatorIon;
-using android::hardware::media::bufferpool::BufferPoolData;
+
+namespace bufferpool = android::hardware::media::bufferpool;
+namespace bufferpool_impl = android::hardware::media::bufferpool::V2_0::implementation;
using android::hardware::media::bufferpool::V2_0::ResultStatus;
-using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocation;
-using android::hardware::media::bufferpool::V2_0::implementation::BufferPoolAllocator;
-using android::hardware::media::bufferpool::V2_0::implementation::ClientManager;
-using android::hardware::media::bufferpool::V2_0::implementation::ConnectionId;
-using android::hardware::media::bufferpool::V2_0::implementation::INVALID_CONNECTIONID;
+
+namespace bufferpool2 = aidl::android::hardware::media::bufferpool2;
+namespace bufferpool2_impl = aidl::android::hardware::media::bufferpool2::implementation;
+using ResultStatus2 = aidl::android::hardware::media::bufferpool2::ResultStatus;
// This anonymous namespace contains the helper classes that allow our implementation to create
// block/buffer objects.
@@ -354,21 +356,21 @@
return TYPE_BUFFERPOOL;
}
- void getBufferPoolData(std::shared_ptr<BufferPoolData> *data) const {
+ void getBufferPoolData(std::shared_ptr<bufferpool::BufferPoolData> *data) const {
*data = mData;
}
- C2PooledBlockPoolData(const std::shared_ptr<BufferPoolData> &data) : mData(data) {}
+ C2PooledBlockPoolData(const std::shared_ptr<bufferpool::BufferPoolData> &data) : mData(data) {}
virtual ~C2PooledBlockPoolData() override {}
private:
- std::shared_ptr<BufferPoolData> mData;
+ std::shared_ptr<bufferpool::BufferPoolData> mData;
};
bool _C2BlockFactory::GetBufferPoolData(
const std::shared_ptr<const _C2BlockPoolData> &data,
- std::shared_ptr<BufferPoolData> *bufferPoolData) {
+ std::shared_ptr<bufferpool::BufferPoolData> *bufferPoolData) {
if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERPOOL) {
const std::shared_ptr<const C2PooledBlockPoolData> poolData =
std::static_pointer_cast<const C2PooledBlockPoolData>(data);
@@ -378,6 +380,37 @@
return false;
}
+struct C2_HIDE C2PooledBlockPoolData2 : _C2BlockPoolData { // AIDL BufferPool(bufferpool2)
+
+ type_t getType() const override {
+ return TYPE_BUFFERPOOL2;
+ }
+
+ void getBufferPoolData(std::shared_ptr<bufferpool2::BufferPoolData> *data) const {
+ *data = mData;
+ }
+
+ C2PooledBlockPoolData2(const std::shared_ptr<bufferpool2::BufferPoolData> &data)
+ : mData(data) {}
+
+ virtual ~C2PooledBlockPoolData2() override {}
+
+private:
+ std::shared_ptr<bufferpool2::BufferPoolData> mData;
+};
+
+bool _C2BlockFactory::GetBufferPoolData(
+ const std::shared_ptr<const _C2BlockPoolData> &data,
+ std::shared_ptr<bufferpool2::BufferPoolData> *bufferPoolData) {
+ if (data && data->getType() == _C2BlockPoolData::TYPE_BUFFERPOOL2) {
+ const std::shared_ptr<const C2PooledBlockPoolData2> poolData =
+ std::static_pointer_cast<const C2PooledBlockPoolData2>(data);
+ poolData->getBufferPoolData(bufferPoolData);
+ return true;
+ }
+ return false;
+}
+
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
const std::shared_ptr<C2LinearAllocation> &alloc,
const std::shared_ptr<_C2BlockPoolData> &data, size_t offset, size_t size) {
@@ -422,7 +455,7 @@
}
std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
- const C2Handle *cHandle, const std::shared_ptr<BufferPoolData> &data) {
+ const C2Handle *cHandle, const std::shared_ptr<bufferpool::BufferPoolData> &data) {
// TODO: get proper allocator? and mutex?
static std::shared_ptr<C2Allocator> sAllocator = []{
std::shared_ptr<C2Allocator> allocator;
@@ -452,11 +485,43 @@
return nullptr;
};
+std::shared_ptr<C2LinearBlock> _C2BlockFactory::CreateLinearBlock(
+ const C2Handle *cHandle, const std::shared_ptr<bufferpool2::BufferPoolData> &data) {
+ // TODO: get proper allocator? and mutex?
+ static std::shared_ptr<C2Allocator> sAllocator = []{
+ std::shared_ptr<C2Allocator> allocator;
+ std::shared_ptr<C2AllocatorStore> allocatorStore =
+ android::GetCodec2PlatformAllocatorStore();
+ allocatorStore->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &allocator);
+
+ return allocator;
+ }();
+
+ if (sAllocator == nullptr)
+ return nullptr;
+
+ bool isValidHandle = sAllocator->checkHandle(cHandle);
+
+ std::shared_ptr<C2LinearAllocation> alloc;
+ if (isValidHandle) {
+ c2_status_t err = sAllocator->priorLinearAllocation(cHandle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData2> poolData =
+ std::make_shared<C2PooledBlockPoolData2>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config params?
+ std::shared_ptr<C2LinearBlock> block =
+ _C2BlockFactory::CreateLinearBlock(alloc, poolData);
+ return block;
+ }
+ }
+ return nullptr;
+};
+
/**
* Wrapped C2Allocator which is injected to buffer pool on behalf of
* C2BlockPool.
*/
-class _C2BufferPoolAllocator : public BufferPoolAllocator {
+class _C2BufferPoolAllocator : public bufferpool_impl::BufferPoolAllocator {
public:
_C2BufferPoolAllocator(const std::shared_ptr<C2Allocator> &allocator)
: mAllocator(allocator) {}
@@ -464,7 +529,7 @@
~_C2BufferPoolAllocator() override {}
ResultStatus allocate(const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc,
+ std::shared_ptr<bufferpool_impl::BufferPoolAllocation> *alloc,
size_t *allocSize) override;
bool compatible(const std::vector<uint8_t> &newParams,
@@ -496,7 +561,7 @@
std::vector<uint8_t> *params);
/**
- * Transforms an existing native handle to an C2LinearAllcation.
+ * Transforms an existing native handle to a C2LinearAllocation.
* Wrapper to C2Allocator#priorLinearAllocation
*/
c2_status_t priorLinearAllocation(
@@ -504,7 +569,7 @@
std::shared_ptr<C2LinearAllocation> *c2Allocation);
/**
- * Transforms an existing native handle to an C2GraphicAllcation.
+ * Transforms an existing native handle to a C2GraphicAllocation.
* Wrapper to C2Allocator#priorGraphicAllocation
*/
c2_status_t priorGraphicAllocation(
@@ -545,7 +610,7 @@
LinearAllocationDtor(const std::shared_ptr<C2LinearAllocation> &alloc)
: mAllocation(alloc) {}
- void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+ void operator()(bufferpool_impl::BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
const std::shared_ptr<C2LinearAllocation> mAllocation;
};
@@ -554,14 +619,14 @@
GraphicAllocationDtor(const std::shared_ptr<C2GraphicAllocation> &alloc)
: mAllocation(alloc) {}
- void operator()(BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+ void operator()(bufferpool_impl::BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
const std::shared_ptr<C2GraphicAllocation> mAllocation;
};
ResultStatus _C2BufferPoolAllocator::allocate(
const std::vector<uint8_t> ¶ms,
- std::shared_ptr<BufferPoolAllocation> *alloc,
+ std::shared_ptr<bufferpool_impl::BufferPoolAllocation> *alloc,
size_t *allocSize) {
AllocParams c2Params;
memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
@@ -574,9 +639,10 @@
status = mAllocator->newLinearAllocation(
c2Params.data.params[0], c2Params.data.usage, &c2Linear);
if (status == C2_OK && c2Linear) {
- BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Linear->handle());
+ bufferpool_impl::BufferPoolAllocation *ptr =
+ new bufferpool_impl::BufferPoolAllocation(c2Linear->handle());
if (ptr) {
- *alloc = std::shared_ptr<BufferPoolAllocation>(
+ *alloc = std::shared_ptr<bufferpool_impl::BufferPoolAllocation>(
ptr, LinearAllocationDtor(c2Linear));
if (*alloc) {
*allocSize = (size_t)c2Params.data.params[0];
@@ -596,9 +662,10 @@
c2Params.data.params[2],
c2Params.data.usage, &c2Graphic);
if (status == C2_OK && c2Graphic) {
- BufferPoolAllocation *ptr = new BufferPoolAllocation(c2Graphic->handle());
+ bufferpool_impl::BufferPoolAllocation *ptr =
+ new bufferpool_impl::BufferPoolAllocation(c2Graphic->handle());
if (ptr) {
- *alloc = std::shared_ptr<BufferPoolAllocation>(
+ *alloc = std::shared_ptr<bufferpool_impl::BufferPoolAllocation>(
ptr, GraphicAllocationDtor(c2Graphic));
if (*alloc) {
*allocSize = c2Params.data.params[0] * c2Params.data.params[1];
@@ -624,7 +691,7 @@
memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
- // TODO: support not exact matching. e.g) newCapacity < oldCapacity
+ // TODO: support not exact matching. e.g.) newCapacity < oldCapacity
if (newAlloc.data.allocType == oldAlloc.data.allocType &&
newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
for (int i = 0; i < kMaxIntParams; ++i) {
@@ -666,7 +733,7 @@
public:
Impl(const std::shared_ptr<C2Allocator> &allocator)
: mInit(C2_OK),
- mBufferPoolManager(ClientManager::getInstance()),
+ mBufferPoolManager(bufferpool_impl::ClientManager::getInstance()),
mAllocator(std::make_shared<_C2BufferPoolAllocator>(allocator)) {
if (mAllocator && mBufferPoolManager) {
if (mBufferPoolManager->create(
@@ -692,7 +759,7 @@
}
std::vector<uint8_t> params;
mAllocator->getLinearParams(capacity, usage, ¶ms);
- std::shared_ptr<BufferPoolData> bufferPoolData;
+ std::shared_ptr<bufferpool::BufferPoolData> bufferPoolData;
native_handle_t *cHandle = nullptr;
ResultStatus status = mBufferPoolManager->allocate(
mConnectionId, params, &cHandle, &bufferPoolData);
@@ -725,7 +792,7 @@
}
std::vector<uint8_t> params;
mAllocator->getGraphicParams(width, height, format, usage, ¶ms);
- std::shared_ptr<BufferPoolData> bufferPoolData;
+ std::shared_ptr<bufferpool::BufferPoolData> bufferPoolData;
native_handle_t *cHandle = nullptr;
ResultStatus status = mBufferPoolManager->allocate(
mConnectionId, params, &cHandle, &bufferPoolData);
@@ -750,20 +817,340 @@
return C2_CORRUPTED;
}
- ConnectionId getConnectionId() {
- return mInit != C2_OK ? INVALID_CONNECTIONID : mConnectionId;
+ bufferpool_impl::ConnectionId getConnectionId() {
+ return mInit != C2_OK ? bufferpool_impl::INVALID_CONNECTIONID : mConnectionId;
}
private:
c2_status_t mInit;
- const android::sp<ClientManager> mBufferPoolManager;
- ConnectionId mConnectionId; // locally
+ const android::sp<bufferpool_impl::ClientManager> mBufferPoolManager;
+ bufferpool_impl::ConnectionId mConnectionId; // locally
const std::shared_ptr<_C2BufferPoolAllocator> mAllocator;
};
+/**
+ * Wrapped C2Allocator which is injected to AIDL buffer pool on behalf of
+ * C2BlockPool.
+ */
+class _C2BufferPoolAllocator2 : public bufferpool2_impl::BufferPoolAllocator {
+public:
+ _C2BufferPoolAllocator2(const std::shared_ptr<C2Allocator> &allocator)
+ : mAllocator(allocator) {}
+
+ ~_C2BufferPoolAllocator2() override {}
+
+ bufferpool2_impl::BufferPoolStatus allocate(const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<bufferpool2_impl::BufferPoolAllocation> *alloc,
+ size_t *allocSize) override;
+
+ bool compatible(const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) override;
+
+ // Methods for codec2 component (C2BlockPool).
+ /**
+ * Transforms linear allocation parameters for C2Allocator to parameters
+ * for buffer pool.
+ *
+ * @param capacity size of linear allocation
+ * @param usage memory usage pattern for linear allocation
+ * @param params allocation parameters for buffer pool
+ */
+ void getLinearParams(uint32_t capacity, C2MemoryUsage usage,
+ std::vector<uint8_t> *params);
+
+ /**
+ * Transforms graphic allocation parameters for C2Allocator to parameters
+ * for buffer pool.
+ *
+ * @param width width of graphic allocation
+ * @param height height of graphic allocation
+ * @param format color format of graphic allocation
+ * @param params allocation parameter for buffer pool
+ */
+ void getGraphicParams(uint32_t width, uint32_t height,
+ uint32_t format, C2MemoryUsage usage,
+ std::vector<uint8_t> *params);
+
+ /**
+ * Transforms an existing native handle to a C2LinearAllocation.
+ * Wrapper to C2Allocator#priorLinearAllocation
+ */
+ c2_status_t priorLinearAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2LinearAllocation> *c2Allocation);
+
+ /**
+ * Transforms an existing native handle to a C2GraphicAllocation.
+ * Wrapper to C2Allocator#priorGraphicAllocation
+ */
+ c2_status_t priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *c2Allocation);
+
+private:
+ static constexpr int kMaxIntParams = 5; // large enough number;
+
+ enum AllocType : uint8_t {
+ ALLOC_NONE = 0,
+
+ ALLOC_LINEAR,
+ ALLOC_GRAPHIC,
+ };
+
+ union AllocParams {
+ struct {
+ AllocType allocType;
+ C2MemoryUsage usage;
+ uint32_t params[kMaxIntParams];
+ } data;
+ uint8_t array[0];
+
+ AllocParams() : data{ALLOC_NONE, {0, 0}, {0}} {}
+ AllocParams(C2MemoryUsage usage, uint32_t capacity)
+ : data{ALLOC_LINEAR, usage, {[0] = capacity}} {}
+ AllocParams(
+ C2MemoryUsage usage,
+ uint32_t width, uint32_t height, uint32_t format)
+ : data{ALLOC_GRAPHIC, usage, {width, height, format}} {}
+ };
+
+ const std::shared_ptr<C2Allocator> mAllocator;
+};
+
+struct LinearAllocationDtor2 {
+ LinearAllocationDtor2(const std::shared_ptr<C2LinearAllocation> &alloc)
+ : mAllocation(alloc) {}
+
+ void operator()(bufferpool2_impl::BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+ const std::shared_ptr<C2LinearAllocation> mAllocation;
+};
+
+struct GraphicAllocationDtor2 {
+ GraphicAllocationDtor2(const std::shared_ptr<C2GraphicAllocation> &alloc)
+ : mAllocation(alloc) {}
+
+ void operator()(bufferpool2_impl::BufferPoolAllocation *poolAlloc) { delete poolAlloc; }
+
+ const std::shared_ptr<C2GraphicAllocation> mAllocation;
+};
+
+bufferpool2_impl::BufferPoolStatus _C2BufferPoolAllocator2::allocate(
+ const std::vector<uint8_t> ¶ms,
+ std::shared_ptr<bufferpool2_impl::BufferPoolAllocation> *alloc,
+ size_t *allocSize) {
+ AllocParams c2Params;
+ memcpy(&c2Params, params.data(), std::min(sizeof(AllocParams), params.size()));
+ c2_status_t status = C2_BAD_VALUE;
+ switch(c2Params.data.allocType) {
+ case ALLOC_NONE:
+ break;
+ case ALLOC_LINEAR: {
+ std::shared_ptr<C2LinearAllocation> c2Linear;
+ status = mAllocator->newLinearAllocation(
+ c2Params.data.params[0], c2Params.data.usage, &c2Linear);
+ if (status == C2_OK && c2Linear) {
+ bufferpool2_impl::BufferPoolAllocation *ptr =
+ new bufferpool2_impl::BufferPoolAllocation(c2Linear->handle());
+ if (ptr) {
+ *alloc = std::shared_ptr<bufferpool2_impl::BufferPoolAllocation>(
+ ptr, LinearAllocationDtor2(c2Linear));
+ if (*alloc) {
+ *allocSize = (size_t)c2Params.data.params[0];
+ return ResultStatus2::OK;
+ }
+ delete ptr;
+ }
+ return ResultStatus2::NO_MEMORY;
+ }
+ break;
+ }
+ case ALLOC_GRAPHIC: {
+ std::shared_ptr<C2GraphicAllocation> c2Graphic;
+ status = mAllocator->newGraphicAllocation(
+ c2Params.data.params[0],
+ c2Params.data.params[1],
+ c2Params.data.params[2],
+ c2Params.data.usage, &c2Graphic);
+ if (status == C2_OK && c2Graphic) {
+ bufferpool2_impl::BufferPoolAllocation *ptr =
+ new bufferpool2_impl::BufferPoolAllocation(c2Graphic->handle());
+ if (ptr) {
+ *alloc = std::shared_ptr<bufferpool2_impl::BufferPoolAllocation>(
+ ptr, GraphicAllocationDtor2(c2Graphic));
+ if (*alloc) {
+ *allocSize = c2Params.data.params[0] * c2Params.data.params[1];
+ return ResultStatus2::OK;
+ }
+ delete ptr;
+ }
+ return ResultStatus2::NO_MEMORY;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return ResultStatus2::CRITICAL_ERROR;
+}
+
+bool _C2BufferPoolAllocator2::compatible(
+ const std::vector<uint8_t> &newParams,
+ const std::vector<uint8_t> &oldParams) {
+ AllocParams newAlloc;
+ AllocParams oldAlloc;
+ memcpy(&newAlloc, newParams.data(), std::min(sizeof(AllocParams), newParams.size()));
+ memcpy(&oldAlloc, oldParams.data(), std::min(sizeof(AllocParams), oldParams.size()));
+
+ // TODO: support not exact matching. e.g.) newCapacity < oldCapacity
+ if (newAlloc.data.allocType == oldAlloc.data.allocType &&
+ newAlloc.data.usage.expected == oldAlloc.data.usage.expected) {
+ for (int i = 0; i < kMaxIntParams; ++i) {
+ if (newAlloc.data.params[i] != oldAlloc.data.params[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+ return false;
+}
+
+void _C2BufferPoolAllocator2::getLinearParams(
+ uint32_t capacity, C2MemoryUsage usage, std::vector<uint8_t> *params) {
+ AllocParams c2Params(usage, capacity);
+ params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+void _C2BufferPoolAllocator2::getGraphicParams(
+ uint32_t width, uint32_t height, uint32_t format, C2MemoryUsage usage,
+ std::vector<uint8_t> *params) {
+ AllocParams c2Params(usage, width, height, format);
+ params->assign(c2Params.array, c2Params.array + sizeof(AllocParams));
+}
+
+c2_status_t _C2BufferPoolAllocator2::priorLinearAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2LinearAllocation> *c2Allocation) {
+ return mAllocator->priorLinearAllocation(handle, c2Allocation);
+}
+
+c2_status_t _C2BufferPoolAllocator2::priorGraphicAllocation(
+ const C2Handle *handle,
+ std::shared_ptr<C2GraphicAllocation> *c2Allocation) {
+ return mAllocator->priorGraphicAllocation(handle, c2Allocation);
+}
+
+class C2PooledBlockPool::Impl2 {
+public:
+ Impl2(const std::shared_ptr<C2Allocator> &allocator)
+ : mInit(C2_OK),
+ mBufferPoolManager(bufferpool2_impl::ClientManager::getInstance()),
+ mAllocator(std::make_shared<_C2BufferPoolAllocator2>(allocator)) {
+ if (mAllocator && mBufferPoolManager) {
+ if (mBufferPoolManager->create(
+ mAllocator, &mConnectionId) == ResultStatus2::OK) {
+ return;
+ }
+ }
+ mInit = C2_NO_INIT;
+ }
+
+ ~Impl2() {
+ if (mInit == C2_OK) {
+ mBufferPoolManager->close(mConnectionId);
+ }
+ }
+
+ c2_status_t fetchLinearBlock(
+ uint32_t capacity, C2MemoryUsage usage,
+ std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
+ block->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+ std::vector<uint8_t> params;
+ mAllocator->getLinearParams(capacity, usage, ¶ms);
+ std::shared_ptr<bufferpool2::BufferPoolData> bufferPoolData;
+ native_handle_t *cHandle = nullptr;
+ bufferpool2_impl::BufferPoolStatus status = mBufferPoolManager->allocate(
+ mConnectionId, params, &cHandle, &bufferPoolData);
+ if (status == ResultStatus2::OK) {
+ std::shared_ptr<C2LinearAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData2> poolData =
+ std::make_shared<C2PooledBlockPoolData2>(bufferPoolData);
+ c2_status_t err = mAllocator->priorLinearAllocation(cHandle, &alloc);
+ if (err == C2_OK && poolData && alloc) {
+ *block = _C2BlockFactory::CreateLinearBlock(alloc, poolData, 0, capacity);
+ if (*block) {
+ return C2_OK;
+ }
+ }
+ return C2_NO_MEMORY;
+ }
+ if (status == ResultStatus2::NO_MEMORY) {
+ return C2_NO_MEMORY;
+ }
+ return C2_CORRUPTED;
+ }
+
+ c2_status_t fetchGraphicBlock(
+ uint32_t width, uint32_t height, uint32_t format,
+ C2MemoryUsage usage,
+ std::shared_ptr<C2GraphicBlock> *block) {
+ block->reset();
+ if (mInit != C2_OK) {
+ return mInit;
+ }
+ std::vector<uint8_t> params;
+ mAllocator->getGraphicParams(width, height, format, usage, ¶ms);
+ std::shared_ptr<bufferpool2::BufferPoolData> bufferPoolData;
+ native_handle_t *cHandle = nullptr;
+ bufferpool2_impl::BufferPoolStatus status = mBufferPoolManager->allocate(
+ mConnectionId, params, &cHandle, &bufferPoolData);
+ if (status == ResultStatus2::OK) {
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ std::shared_ptr<C2PooledBlockPoolData2> poolData =
+ std::make_shared<C2PooledBlockPoolData2>(bufferPoolData);
+ c2_status_t err = mAllocator->priorGraphicAllocation(
+ cHandle, &alloc);
+ if (err == C2_OK && poolData && alloc) {
+ *block = _C2BlockFactory::CreateGraphicBlock(
+ alloc, poolData, C2Rect(width, height));
+ if (*block) {
+ return C2_OK;
+ }
+ }
+ return C2_NO_MEMORY;
+ }
+ if (status == ResultStatus2::NO_MEMORY) {
+ return C2_NO_MEMORY;
+ }
+ return C2_CORRUPTED;
+ }
+
+ bufferpool2_impl::ConnectionId getConnectionId() {
+ return mInit != C2_OK ? bufferpool2_impl::INVALID_CONNECTIONID : mConnectionId;
+ }
+
+private:
+ c2_status_t mInit;
+ const std::shared_ptr<bufferpool2_impl::ClientManager> mBufferPoolManager;
+ bufferpool2_impl::ConnectionId mConnectionId; // locally
+ const std::shared_ptr<_C2BufferPoolAllocator2> mAllocator;
+};
+
C2PooledBlockPool::C2PooledBlockPool(
- const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId)
- : mAllocator(allocator), mLocalId(localId), mImpl(new Impl(allocator)) {}
+ const std::shared_ptr<C2Allocator> &allocator,
+ const local_id_t localId,
+ BufferPoolVer ver)
+ : mAllocator(allocator), mLocalId(localId), mBufferPoolVer(ver) {
+ if (mBufferPoolVer == VER_HIDL) {
+ mImpl = std::make_unique<Impl>(allocator);
+ }
+ if (mBufferPoolVer == VER_AIDL2) {
+ mImpl2 = std::make_unique<Impl2>(allocator);
+ }
+ }
C2PooledBlockPool::~C2PooledBlockPool() {
}
@@ -772,9 +1159,12 @@
uint32_t capacity,
C2MemoryUsage usage,
std::shared_ptr<C2LinearBlock> *block /* nonnull */) {
- if (mImpl) {
+ if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchLinearBlock(capacity, usage, block);
}
+ if (mBufferPoolVer == VER_AIDL2 && mImpl2) {
+ return mImpl2->fetchLinearBlock(capacity, usage, block);
+ }
return C2_CORRUPTED;
}
@@ -784,16 +1174,22 @@
uint32_t format,
C2MemoryUsage usage,
std::shared_ptr<C2GraphicBlock> *block) {
- if (mImpl) {
+ if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->fetchGraphicBlock(width, height, format, usage, block);
}
+ if (mBufferPoolVer == VER_AIDL2 && mImpl2) {
+ return mImpl2->fetchGraphicBlock(width, height, format, usage, block);
+ }
return C2_CORRUPTED;
}
int64_t C2PooledBlockPool::getConnectionId() {
- if (mImpl) {
+ if (mBufferPoolVer == VER_HIDL && mImpl) {
return mImpl->getConnectionId();
}
+ if (mBufferPoolVer == VER_AIDL2 && mImpl2) {
+ return mImpl2->getConnectionId();
+ }
return 0;
}
@@ -1128,7 +1524,7 @@
std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
const C2Handle *cHandle,
- const std::shared_ptr<BufferPoolData> &data) {
+ const std::shared_ptr<bufferpool::BufferPoolData> &data) {
// TODO: get proper allocator? and mutex?
static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
@@ -1147,6 +1543,26 @@
return nullptr;
};
+std::shared_ptr<C2GraphicBlock> _C2BlockFactory::CreateGraphicBlock(
+ const C2Handle *cHandle,
+ const std::shared_ptr<bufferpool2::BufferPoolData> &data) {
+ // TODO: get proper allocator? and mutex?
+ static std::unique_ptr<C2AllocatorGralloc> sAllocator = std::make_unique<C2AllocatorGralloc>(0);
+
+ std::shared_ptr<C2GraphicAllocation> alloc;
+ if (sAllocator->isValid(cHandle)) {
+ c2_status_t err = sAllocator->priorGraphicAllocation(cHandle, &alloc);
+ const std::shared_ptr<C2PooledBlockPoolData2> poolData =
+ std::make_shared<C2PooledBlockPoolData2>(data);
+ if (err == C2_OK && poolData) {
+ // TODO: config setup?
+ std::shared_ptr<C2GraphicBlock> block =
+ _C2BlockFactory::CreateGraphicBlock(alloc, poolData);
+ return block;
+ }
+ }
+ return nullptr;
+};
/* ========================================== BUFFER ========================================= */
diff --git a/media/codec2/vndk/include/C2BufferPriv.h b/media/codec2/vndk/include/C2BufferPriv.h
index be5f69c..527845f 100644
--- a/media/codec2/vndk/include/C2BufferPriv.h
+++ b/media/codec2/vndk/include/C2BufferPriv.h
@@ -74,7 +74,14 @@
class C2PooledBlockPool : public C2BlockPool {
public:
- C2PooledBlockPool(const std::shared_ptr<C2Allocator> &allocator, const local_id_t localId);
+ enum BufferPoolVer : int {
+ VER_HIDL = 0,
+ VER_AIDL2
+ };
+ C2PooledBlockPool(
+ const std::shared_ptr<C2Allocator> &allocator,
+ const local_id_t localId,
+ BufferPoolVer ver = VER_HIDL);
virtual ~C2PooledBlockPool() override;
@@ -117,9 +124,12 @@
private:
const std::shared_ptr<C2Allocator> mAllocator;
const local_id_t mLocalId;
+ const BufferPoolVer mBufferPoolVer;
- class Impl;
+ class Impl; // HIDL BufferPool VER_HIDL
std::unique_ptr<Impl> mImpl;
+ class Impl2; // AIDL BufferPool(bufferpool2) VER_AIDL2
+ std::unique_ptr<Impl2> mImpl2;
};
#endif // STAGEFRIGHT_CODEC2_BUFFER_PRIV_H_
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index d858f27..b193b4a 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -112,6 +112,11 @@
*/
c2_status_t waitForChange(uint32_t waitId, c2_nsecs_t timeoutNs);
+ /**
+ * Wake up and expire all waitors.
+ */
+ void notifyAll();
+
C2SyncVariables() {}
private:
diff --git a/media/codec2/vndk/internal/C2BlockInternal.h b/media/codec2/vndk/internal/C2BlockInternal.h
index c510fca..fe5390a 100644
--- a/media/codec2/vndk/internal/C2BlockInternal.h
+++ b/media/codec2/vndk/internal/C2BlockInternal.h
@@ -21,17 +21,22 @@
#include <C2Buffer.h>
-namespace android {
-namespace hardware {
-namespace media {
-namespace bufferpool {
+// Note: HIDL-BufferPool and AIDL-BufferPool are not compatible
+namespace android::hardware::media::bufferpool {
+// BuffePool Data for HIDL-BufferPool
struct BufferPoolData;
}
+namespace aidl::android::hardware::media::bufferpool2 {
+
+// BuffePool Data for AIDL-BufferPool
+struct BufferPoolData;
+
}
-}
-}
+
+using bufferpool_BufferPoolData = android::hardware::media::bufferpool::BufferPoolData;
+using bufferpool2_BufferPoolData = aidl::android::hardware::media::bufferpool2::BufferPoolData;
/**
* Stores informations from C2BlockPool implementations which are required by C2Block.
@@ -40,6 +45,7 @@
enum type_t : int {
TYPE_BUFFERPOOL = 0,
TYPE_BUFFERQUEUE,
+ TYPE_BUFFERPOOL2, // AIDL-BufferPool
};
virtual type_t getType() const = 0;
@@ -136,6 +142,7 @@
std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
const C2Handle *handle);
+ // HIDL-BufferPool
/**
* Create a linear block from the received bufferpool data.
*
@@ -147,7 +154,7 @@
static
std::shared_ptr<C2LinearBlock> CreateLinearBlock(
const C2Handle *handle,
- const std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> &data);
+ const std::shared_ptr<bufferpool_BufferPoolData> &data);
/**
* Create a graphic block from the received bufferpool data.
@@ -160,7 +167,7 @@
static
std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
const C2Handle *handle,
- const std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> &data);
+ const std::shared_ptr<bufferpool_BufferPoolData> &data);
/**
* Get bufferpool data from the blockpool data.
@@ -174,7 +181,48 @@
static
bool GetBufferPoolData(
const std::shared_ptr<const _C2BlockPoolData> &poolData,
- std::shared_ptr<android::hardware::media::bufferpool::BufferPoolData> *bufferPoolData);
+ std::shared_ptr<bufferpool_BufferPoolData> *bufferPoolData);
+
+ // AIDL-BufferPool
+ /**
+ * Create a linear block from the received bufferpool data.
+ *
+ * \param data bufferpool data to a linear block
+ *
+ * \return shared pointer to the linear block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2LinearBlock> CreateLinearBlock(
+ const C2Handle *handle,
+ const std::shared_ptr<bufferpool2_BufferPoolData> &data);
+
+ /**
+ * Create a graphic block from the received bufferpool data.
+ *
+ * \param data bufferpool data to a graphic block
+ *
+ * \return shared pointer to the graphic block. nullptr if there was not enough memory to
+ * create this block.
+ */
+ static
+ std::shared_ptr<C2GraphicBlock> CreateGraphicBlock(
+ const C2Handle *handle,
+ const std::shared_ptr<bufferpool2_BufferPoolData> &data);
+
+ /**
+ * Get bufferpool data from the blockpool data.
+ *
+ * \param poolData blockpool data
+ * \param bufferPoolData pointer to bufferpool data where the bufferpool
+ * data is stored.
+ *
+ * \return {\code true} when there is valid bufferpool data, {\code false} otherwise.
+ */
+ static
+ bool GetBufferPoolData(
+ const std::shared_ptr<const _C2BlockPoolData> &poolData,
+ std::shared_ptr<bufferpool2_BufferPoolData> *bufferPoolData);
/*
* Life Cycle Management of BufferQueue-Based Blocks
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index bf4ca32..d55a3d8 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -244,6 +244,12 @@
return C2_BAD_VALUE;
}
+void C2SyncVariables::notifyAll() {
+ this->lock();
+ this->broadcast();
+ this->unlock();
+}
+
int C2SyncVariables::signal() {
mCond++;
diff --git a/media/libaaudio/fuzzer/Android.bp b/media/libaaudio/fuzzer/Android.bp
index f5d2939..3393930 100644
--- a/media/libaaudio/fuzzer/Android.bp
+++ b/media/libaaudio/fuzzer/Android.bp
@@ -39,6 +39,7 @@
"libaudiomanager",
"libaudiopolicy",
"libaudioclient_aidl_conversion",
+ "libaudio_aidl_conversion_common_cpp",
"libutils",
],
static_libs: [
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 6c364c9..13e430a 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -758,7 +758,8 @@
*
* @return pointer to a text representation of an AAudio result code.
*/
-AAUDIO_API const char * AAudio_convertResultToText(aaudio_result_t returnCode) __INTRODUCED_IN(26);
+AAUDIO_API const char * _Nonnull AAudio_convertResultToText(aaudio_result_t returnCode)
+ __INTRODUCED_IN(26);
/**
* The text is the ASCII symbol corresponding to the stream state,
@@ -770,7 +771,7 @@
*
* @return pointer to a text representation of an AAudio state.
*/
-AAUDIO_API const char * AAudio_convertStreamStateToText(aaudio_stream_state_t state)
+AAUDIO_API const char * _Nonnull AAudio_convertStreamStateToText(aaudio_stream_state_t state)
__INTRODUCED_IN(26);
// ============================================================
@@ -791,8 +792,8 @@
*
* Available since API level 26.
*/
-AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder** builder)
- __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudio_createStreamBuilder(AAudioStreamBuilder* _Nullable* _Nonnull
+ builder) __INTRODUCED_IN(26);
/**
* Request an audio device identified by an ID.
@@ -814,7 +815,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param deviceId device identifier or {@link #AAUDIO_UNSPECIFIED}
*/
-AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setDeviceId(AAudioStreamBuilder* _Nonnull builder,
int32_t deviceId) __INTRODUCED_IN(26);
/**
@@ -834,8 +835,8 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param packageName packageName of the calling app.
*/
-AAUDIO_API void AAudioStreamBuilder_setPackageName(AAudioStreamBuilder* builder,
- const char * packageName) __INTRODUCED_IN(31);
+AAUDIO_API void AAudioStreamBuilder_setPackageName(AAudioStreamBuilder* _Nonnull builder,
+ const char * _Nonnull packageName) __INTRODUCED_IN(31);
/**
* Declare the attribution tag of the context creating the stream.
@@ -849,8 +850,8 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param attributionTag attributionTag of the calling context.
*/
-AAUDIO_API void AAudioStreamBuilder_setAttributionTag(AAudioStreamBuilder* builder,
- const char * attributionTag) __INTRODUCED_IN(31);
+AAUDIO_API void AAudioStreamBuilder_setAttributionTag(AAudioStreamBuilder* _Nonnull builder,
+ const char * _Nonnull attributionTag) __INTRODUCED_IN(31);
/**
* Request a sample rate in Hertz.
@@ -868,7 +869,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sampleRate frames per second. Common rates include 44100 and 48000 Hz.
*/
-AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setSampleRate(AAudioStreamBuilder* _Nonnull builder,
int32_t sampleRate) __INTRODUCED_IN(26);
/**
@@ -898,7 +899,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param channelCount Number of channels desired.
*/
-AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* _Nonnull builder,
int32_t channelCount) __INTRODUCED_IN(26);
/**
@@ -911,7 +912,7 @@
*
* @deprecated use {@link AAudioStreamBuilder_setChannelCount}
*/
-AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* _Nonnull builder,
int32_t samplesPerFrame) __INTRODUCED_IN(26);
/**
@@ -931,7 +932,7 @@
* @param format common formats are {@link #AAUDIO_FORMAT_PCM_FLOAT} and
* {@link #AAUDIO_FORMAT_PCM_I16}.
*/
-AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setFormat(AAudioStreamBuilder* _Nonnull builder,
aaudio_format_t format) __INTRODUCED_IN(26);
/**
@@ -947,7 +948,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sharingMode {@link #AAUDIO_SHARING_MODE_SHARED} or {@link #AAUDIO_SHARING_MODE_EXCLUSIVE}
*/
-AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setSharingMode(AAudioStreamBuilder* _Nonnull builder,
aaudio_sharing_mode_t sharingMode) __INTRODUCED_IN(26);
/**
@@ -960,7 +961,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param direction {@link #AAUDIO_DIRECTION_OUTPUT} or {@link #AAUDIO_DIRECTION_INPUT}
*/
-AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setDirection(AAudioStreamBuilder* _Nonnull builder,
aaudio_direction_t direction) __INTRODUCED_IN(26);
/**
@@ -974,8 +975,8 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param numFrames the desired buffer capacity in frames or {@link #AAUDIO_UNSPECIFIED}
*/
-AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(AAudioStreamBuilder* builder,
- int32_t numFrames) __INTRODUCED_IN(26);
+AAUDIO_API void AAudioStreamBuilder_setBufferCapacityInFrames(
+ AAudioStreamBuilder* _Nonnull builder, int32_t numFrames) __INTRODUCED_IN(26);
/**
* Set the requested performance mode.
@@ -994,7 +995,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param mode the desired performance mode, eg. {@link #AAUDIO_PERFORMANCE_MODE_LOW_LATENCY}
*/
-AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setPerformanceMode(AAudioStreamBuilder* _Nonnull builder,
aaudio_performance_mode_t mode) __INTRODUCED_IN(26);
/**
@@ -1011,7 +1012,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param usage the desired usage, eg. {@link #AAUDIO_USAGE_GAME}
*/
-AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setUsage(AAudioStreamBuilder* _Nonnull builder,
aaudio_usage_t usage) __INTRODUCED_IN(28);
/**
@@ -1028,7 +1029,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param contentType the type of audio data, eg. {@link #AAUDIO_CONTENT_TYPE_SPEECH}
*/
-AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setContentType(AAudioStreamBuilder* _Nonnull builder,
aaudio_content_type_t contentType) __INTRODUCED_IN(28);
/**
@@ -1043,7 +1044,8 @@
* @param spatializationBehavior the desired behavior with regards to spatialization, eg.
* {@link #AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO}
*/
-AAUDIO_API void AAudioStreamBuilder_setSpatializationBehavior(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setSpatializationBehavior(
+ AAudioStreamBuilder* _Nonnull builder,
aaudio_spatialization_behavior_t spatializationBehavior) __INTRODUCED_IN(32);
/**
@@ -1059,7 +1061,7 @@
* @param isSpatialized true if the content is already processed for binaural or transaural spatial
* rendering, false otherwise.
*/
-AAUDIO_API void AAudioStreamBuilder_setIsContentSpatialized(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setIsContentSpatialized(AAudioStreamBuilder* _Nonnull builder,
bool isSpatialized) __INTRODUCED_IN(32);
/**
@@ -1079,7 +1081,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param inputPreset the desired configuration for recording
*/
-AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setInputPreset(AAudioStreamBuilder* _Nonnull builder,
aaudio_input_preset_t inputPreset) __INTRODUCED_IN(28);
/**
@@ -1097,7 +1099,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param capturePolicy the desired level of opt-out from being captured.
*/
-AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setAllowedCapturePolicy(AAudioStreamBuilder* _Nonnull builder,
aaudio_allowed_capture_policy_t capturePolicy) __INTRODUCED_IN(29);
/** Set the requested session ID.
@@ -1127,7 +1129,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param sessionId an allocated sessionID or {@link #AAUDIO_SESSION_ID_ALLOCATE}
*/
-AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setSessionId(AAudioStreamBuilder* _Nonnull builder,
aaudio_session_id_t sessionId) __INTRODUCED_IN(28);
@@ -1149,7 +1151,7 @@
* @param privacySensitive true if capture from this stream must be marked as privacy sensitive,
* false otherwise.
*/
-AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setPrivacySensitive(AAudioStreamBuilder* _Nonnull builder,
bool privacySensitive) __INTRODUCED_IN(30);
/**
@@ -1223,9 +1225,9 @@
* @return AAUDIO_CALLBACK_RESULT_*
*/
typedef aaudio_data_callback_result_t (*AAudioStream_dataCallback)(
- AAudioStream *stream,
- void *userData,
- void *audioData,
+ AAudioStream* _Nonnull stream,
+ void* _Nullable userData,
+ void* _Nonnull audioData,
int32_t numFrames);
/**
@@ -1254,8 +1256,9 @@
* @param userData pointer to an application data structure that will be passed
* to the callback functions.
*/
-AAUDIO_API void AAudioStreamBuilder_setDataCallback(AAudioStreamBuilder* builder,
- AAudioStream_dataCallback callback, void *userData) __INTRODUCED_IN(26);
+AAUDIO_API void AAudioStreamBuilder_setDataCallback(AAudioStreamBuilder* _Nonnull builder,
+ AAudioStream_dataCallback _Nullable callback, void* _Nullable userData)
+ __INTRODUCED_IN(26);
/**
* Set the requested data callback buffer size in frames.
@@ -1282,8 +1285,8 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param numFrames the desired buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
*/
-AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* builder,
- int32_t numFrames) __INTRODUCED_IN(26);
+AAUDIO_API void AAudioStreamBuilder_setFramesPerDataCallback(AAudioStreamBuilder* _Nonnull builder,
+ int32_t numFrames) __INTRODUCED_IN(26);
/**
* Prototype for the callback function that is passed to
@@ -1310,8 +1313,8 @@
* @param error an AAUDIO_ERROR_* value.
*/
typedef void (*AAudioStream_errorCallback)(
- AAudioStream *stream,
- void *userData,
+ AAudioStream* _Nonnull stream,
+ void* _Nullable userData,
aaudio_result_t error);
/**
@@ -1337,8 +1340,9 @@
* @param userData pointer to an application data structure that will be passed
* to the callback functions.
*/
-AAUDIO_API void AAudioStreamBuilder_setErrorCallback(AAudioStreamBuilder* builder,
- AAudioStream_errorCallback callback, void *userData) __INTRODUCED_IN(26);
+AAUDIO_API void AAudioStreamBuilder_setErrorCallback(AAudioStreamBuilder* _Nonnull builder,
+ AAudioStream_errorCallback _Nullable callback, void* _Nullable userData)
+ __INTRODUCED_IN(26);
/**
* Open a stream based on the options in the StreamBuilder.
@@ -1352,8 +1356,8 @@
* @param stream pointer to a variable to receive the new stream reference
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_openStream(AAudioStreamBuilder* builder,
- AAudioStream** stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_openStream(AAudioStreamBuilder* _Nonnull builder,
+ AAudioStream* _Nullable* _Nonnull stream) __INTRODUCED_IN(26);
/**
* Delete the resources associated with the StreamBuilder.
@@ -1363,7 +1367,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* builder)
+AAUDIO_API aaudio_result_t AAudioStreamBuilder_delete(AAudioStreamBuilder* _Nonnull builder)
__INTRODUCED_IN(26);
/**
@@ -1389,7 +1393,7 @@
* @param builder reference provided by AAudio_createStreamBuilder()
* @param channelMask Audio channel mask desired.
*/
-AAUDIO_API void AAudioStreamBuilder_setChannelMask(AAudioStreamBuilder* builder,
+AAUDIO_API void AAudioStreamBuilder_setChannelMask(AAudioStreamBuilder* _Nonnull builder,
aaudio_channel_mask_t channelMask) __INTRODUCED_IN(32);
// ============================================================
@@ -1418,7 +1422,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_release(AAudioStream* stream) __INTRODUCED_IN(30);
+AAUDIO_API aaudio_result_t AAudioStream_release(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(30);
/**
* Delete the internal data structures associated with the stream created
@@ -1431,7 +1436,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_close(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* Asynchronously request to start playing the stream. For output streams, one should
@@ -1445,7 +1450,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_requestStart(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Asynchronous request for the stream to pause.
@@ -1462,7 +1468,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_requestPause(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_requestPause(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Asynchronous request for the stream to flush.
@@ -1482,7 +1489,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_requestFlush(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Asynchronous request for the stream to stop.
@@ -1495,7 +1503,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_requestStop(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Query the current state of the client, eg. {@link #AAUDIO_STREAM_STATE_PAUSING}
@@ -1509,7 +1518,8 @@
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
*/
-AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_stream_state_t AAudioStream_getState(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Wait until the current state no longer matches the input state.
@@ -1535,8 +1545,8 @@
* @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
* @return {@link #AAUDIO_OK} or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* stream,
- aaudio_stream_state_t inputState, aaudio_stream_state_t *nextState,
+AAUDIO_API aaudio_result_t AAudioStream_waitForStateChange(AAudioStream* _Nonnull stream,
+ aaudio_stream_state_t inputState, aaudio_stream_state_t* _Nullable nextState,
int64_t timeoutNanoseconds) __INTRODUCED_IN(26);
// ============================================================
@@ -1565,8 +1575,8 @@
* @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
* @return The number of frames actually read or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream* stream,
- void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_read(AAudioStream* _Nonnull stream,
+ void* _Nonnull buffer, int32_t numFrames, int64_t timeoutNanoseconds) __INTRODUCED_IN(26);
/**
* Write data to the stream.
@@ -1590,8 +1600,9 @@
* @param timeoutNanoseconds Maximum number of nanoseconds to wait for completion.
* @return The number of frames actually written or a negative error.
*/
-AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* stream,
- const void *buffer, int32_t numFrames, int64_t timeoutNanoseconds) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_write(AAudioStream* _Nonnull stream,
+ const void* _Nonnull buffer, int32_t numFrames, int64_t timeoutNanoseconds)
+ __INTRODUCED_IN(26);
// ============================================================
// Stream - queries
@@ -1615,7 +1626,7 @@
* @param numFrames requested number of frames that can be filled without blocking
* @return actual buffer size in frames or a negative error
*/
-AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* stream,
+AAUDIO_API aaudio_result_t AAudioStream_setBufferSizeInFrames(AAudioStream* _Nonnull stream,
int32_t numFrames) __INTRODUCED_IN(26);
/**
@@ -1626,7 +1637,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return buffer size in frames.
*/
-AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getBufferSizeInFrames(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Query the number of frames that the application should read or write at
@@ -1643,7 +1655,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return burst size
*/
-AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getFramesPerBurst(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Query maximum buffer capacity in frames.
@@ -1653,7 +1666,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return buffer capacity in frames
*/
-AAUDIO_API int32_t AAudioStream_getBufferCapacityInFrames(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getBufferCapacityInFrames(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Query the size of the buffer that will be passed to the dataProc callback
@@ -1676,7 +1690,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return callback buffer size in frames or {@link #AAUDIO_UNSPECIFIED}
*/
-AAUDIO_API int32_t AAudioStream_getFramesPerDataCallback(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getFramesPerDataCallback(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* An XRun is an Underrun or an Overrun.
@@ -1695,7 +1710,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return the underrun or overrun count
*/
-AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getXRunCount(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* Available since API level 26.
@@ -1703,13 +1718,13 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual sample rate of the stream
*/
-AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* There may be sample rate conversions in the Audio framework.
* The sample rate set in the stream builder may not be actual sample rate used in the hardware.
*
- * This returns the sample rate used by the hardware.
+ * This returns the sample rate used by the hardware in Hertz.
*
* If AAudioStreamBuilder_openStream() returned AAUDIO_OK, the result should always be valid.
*
@@ -1718,7 +1733,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual sample rate of the underlying hardware
*/
-AAUDIO_API int32_t AAudioStream_getHardwareSampleRate(AAudioStream* stream)
+AAUDIO_API int32_t AAudioStream_getHardwareSampleRate(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(__ANDROID_API_U__);
/**
@@ -1730,7 +1745,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual number of channels of the stream
*/
-AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* There may be channel conversions in the Audio framework.
@@ -1746,7 +1761,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual number of channels of the underlying hardware
*/
-AAUDIO_API int32_t AAudioStream_getHardwareChannelCount(AAudioStream* stream)
+AAUDIO_API int32_t AAudioStream_getHardwareChannelCount(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(__ANDROID_API_U__);
/**
@@ -1757,7 +1772,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual number of samples frame
*/
-AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Available since API level 26.
@@ -1765,7 +1781,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual device ID
*/
-AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int32_t AAudioStream_getDeviceId(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* Available since API level 26.
@@ -1773,22 +1789,30 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual data format of the stream
*/
-AAUDIO_API aaudio_format_t AAudioStream_getFormat(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_format_t AAudioStream_getFormat(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* There may be data format conversions in the Audio framework.
* The data format set in the stream builder may not be actual format used in the hardware.
*
* This returns the audio format used by the hardware.
+ *
+ * If AAudioStreamBuilder_openStream() returned AAUDIO_OK, this should always return an
+ * aaudio_format_t.
+ *
* AUDIO_FORMAT_PCM_8_24_BIT is currently not supported in AAudio, but the hardware may use it.
* If AUDIO_FORMAT_PCM_8_24_BIT is used by the hardware, return AAUDIO_FORMAT_PCM_I24_PACKED.
*
+ * If any other format used by the hardware is not supported by AAudio, this will return
+ * AAUDIO_FORMAT_INVALID.
+ *
* Available since API level 34.
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual data format of the underlying hardware.
*/
-AAUDIO_API aaudio_format_t AAudioStream_getHardwareFormat(AAudioStream* stream)
+AAUDIO_API aaudio_format_t AAudioStream_getHardwareFormat(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(__ANDROID_API_U__);
/**
@@ -1799,7 +1823,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual sharing mode
*/
-AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* stream)
+AAUDIO_API aaudio_sharing_mode_t AAudioStream_getSharingMode(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(26);
/**
@@ -1809,7 +1833,7 @@
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
*/
-AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* stream)
+AAUDIO_API aaudio_performance_mode_t AAudioStream_getPerformanceMode(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(26);
/**
@@ -1818,7 +1842,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return direction
*/
-AAUDIO_API aaudio_direction_t AAudioStream_getDirection(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_direction_t AAudioStream_getDirection(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Passes back the number of frames that have been written since the stream was created.
@@ -1833,7 +1858,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames written
*/
-AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int64_t AAudioStream_getFramesWritten(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(26);
/**
* Passes back the number of frames that have been read since the stream was created.
@@ -1848,7 +1874,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames read
*/
-AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* stream) __INTRODUCED_IN(26);
+AAUDIO_API int64_t AAudioStream_getFramesRead(AAudioStream* _Nonnull stream) __INTRODUCED_IN(26);
/**
* Passes back the session ID associated with this stream.
@@ -1873,7 +1899,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return session ID or {@link #AAUDIO_SESSION_ID_NONE}
*/
-AAUDIO_API aaudio_session_id_t AAudioStream_getSessionId(AAudioStream* stream) __INTRODUCED_IN(28);
+AAUDIO_API aaudio_session_id_t AAudioStream_getSessionId(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(28);
/**
* Passes back the time at which a particular frame was presented.
@@ -1899,8 +1926,9 @@
* @param timeNanoseconds pointer to a variable to receive the time
* @return {@link #AAUDIO_OK} or a negative error
*/
-AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* stream,
- clockid_t clockid, int64_t *framePosition, int64_t *timeNanoseconds) __INTRODUCED_IN(26);
+AAUDIO_API aaudio_result_t AAudioStream_getTimestamp(AAudioStream* _Nonnull stream,
+ clockid_t clockid, int64_t* _Nonnull framePosition, int64_t* _Nonnull timeNanoseconds)
+ __INTRODUCED_IN(26);
/**
* Return the use case for the stream.
@@ -1910,7 +1938,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return frames read
*/
-AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* stream) __INTRODUCED_IN(28);
+AAUDIO_API aaudio_usage_t AAudioStream_getUsage(AAudioStream* _Nonnull stream) __INTRODUCED_IN(28);
/**
* Return the content type for the stream.
@@ -1920,7 +1948,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return content type, for example {@link #AAUDIO_CONTENT_TYPE_MUSIC}
*/
-AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* stream)
+AAUDIO_API aaudio_content_type_t AAudioStream_getContentType(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(28);
/**
@@ -1935,7 +1963,7 @@
* @return spatialization behavior, for example {@link #AAUDIO_SPATIALIZATION_BEHAVIOR_AUTO}
*/
AAUDIO_API aaudio_spatialization_behavior_t AAudioStream_getSpatializationBehavior(
- AAudioStream* stream) __INTRODUCED_IN(32);
+ AAudioStream* _Nonnull stream) __INTRODUCED_IN(32);
/**
* Return whether the content of the stream is spatialized.
@@ -1945,7 +1973,8 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return true if the content is spatialized
*/
-AAUDIO_API bool AAudioStream_isContentSpatialized(AAudioStream* stream) __INTRODUCED_IN(32);
+AAUDIO_API bool AAudioStream_isContentSpatialized(AAudioStream* _Nonnull stream)
+ __INTRODUCED_IN(32);
/**
@@ -1956,7 +1985,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return input preset, for example {@link #AAUDIO_INPUT_PRESET_CAMCORDER}
*/
-AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* stream)
+AAUDIO_API aaudio_input_preset_t AAudioStream_getInputPreset(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(28);
/**
@@ -1969,7 +1998,7 @@
* @return the allowed capture policy, for example {@link #AAUDIO_ALLOW_CAPTURE_BY_ALL}
*/
AAUDIO_API aaudio_allowed_capture_policy_t AAudioStream_getAllowedCapturePolicy(
- AAudioStream* stream) __INTRODUCED_IN(29);
+ AAudioStream* _Nonnull stream) __INTRODUCED_IN(29);
/**
@@ -1982,7 +2011,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return true if privacy sensitive, false otherwise
*/
-AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* stream)
+AAUDIO_API bool AAudioStream_isPrivacySensitive(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(30);
/**
@@ -1994,7 +2023,7 @@
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @return actual channel mask
*/
-AAUDIO_API aaudio_channel_mask_t AAudioStream_getChannelMask(AAudioStream* stream)
+AAUDIO_API aaudio_channel_mask_t AAudioStream_getChannelMask(AAudioStream* _Nonnull stream)
__INTRODUCED_IN(32);
#ifdef __cplusplus
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index c31947f..56ef1e6 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -124,13 +124,17 @@
android::mediametrics::LogItem item(mMetricsId);
item.set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_OPEN)
.set(AMEDIAMETRICS_PROP_PERFORMANCEMODEACTUAL,
- AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
+ AudioGlobal_convertPerformanceModeToText(getPerformanceMode()))
.set(AMEDIAMETRICS_PROP_SHARINGMODEACTUAL,
- AudioGlobal_convertSharingModeToText(getSharingMode()))
+ AudioGlobal_convertSharingModeToText(getSharingMode()))
.set(AMEDIAMETRICS_PROP_BUFFERCAPACITYFRAMES, getBufferCapacity())
.set(AMEDIAMETRICS_PROP_BURSTFRAMES, getFramesPerBurst())
.set(AMEDIAMETRICS_PROP_DIRECTION,
- AudioGlobal_convertDirectionToText(getDirection()));
+ AudioGlobal_convertDirectionToText(getDirection()))
+ .set(AMEDIAMETRICS_PROP_ENCODINGHARDWARE,
+ android::toString(getHardwareFormat()).c_str())
+ .set(AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, (int32_t)getHardwareSamplesPerFrame())
+ .set(AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, (int32_t)getHardwareSampleRate());
if (getDirection() == AAUDIO_DIRECTION_OUTPUT) {
item.set(AMEDIAMETRICS_PROP_PLAYERIID, mPlayerBase->getPlayerIId());
diff --git a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
index 7193ff3..a3ce58c 100644
--- a/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/MultiChannelResampler.cpp
@@ -40,7 +40,7 @@
ratio.reduce();
mNumerator = ratio.getNumerator();
mDenominator = ratio.getDenominator();
- mIntegerPhase = mDenominator;
+ mIntegerPhase = mDenominator; // so we start with a write needed
}
// static factory method
diff --git a/media/libaaudio/src/flowgraph/resampler/README.md b/media/libaaudio/src/flowgraph/resampler/README.md
index ea319c7..356f06c 100644
--- a/media/libaaudio/src/flowgraph/resampler/README.md
+++ b/media/libaaudio/src/flowgraph/resampler/README.md
@@ -40,7 +40,7 @@
For example, suppose you are converting from 44100 Hz to 48000 Hz and using an input buffer with 960 frames. If you calculate the number of output frames you get:
- 960 * 48000 * 44100 = 1044.897959...
+ 960.0 * 48000 / 44100 = 1044.897959...
You cannot generate a fractional number of frames. So the resampler will sometimes generate 1044 frames and sometimes 1045 frames. On average it will generate 1044.897959 frames. The resampler stores the fraction internally and keeps track of when to consume or generate a frame.
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp b/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
index 42d0ca2..a14ee47 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/SincResampler.cpp
@@ -24,9 +24,10 @@
: MultiChannelResampler(builder)
, mSingleFrame2(builder.getChannelCount()) {
assert((getNumTaps() % 4) == 0); // Required for loop unrolling.
- mNumRows = kMaxCoefficients / getNumTaps(); // no guard row needed
- mPhaseScaler = (double) mNumRows / mDenominator;
- double phaseIncrement = 1.0 / mNumRows;
+ mNumRows = kMaxCoefficients / getNumTaps(); // includes guard row
+ const int32_t numRowsNoGuard = mNumRows - 1;
+ mPhaseScaler = (double) numRowsNoGuard / mDenominator;
+ const double phaseIncrement = 1.0 / numRowsNoGuard;
generateCoefficients(builder.getInputRate(),
builder.getOutputRate(),
mNumRows,
@@ -40,39 +41,31 @@
std::fill(mSingleFrame2.begin(), mSingleFrame2.end(), 0.0);
// Determine indices into coefficients table.
- double tablePhase = getIntegerPhase() * mPhaseScaler;
- int index1 = static_cast<int>(floor(tablePhase));
- if (index1 >= mNumRows) { // no guard row needed because we wrap the indices
- tablePhase -= mNumRows;
- index1 -= mNumRows;
- }
-
- int index2 = index1 + 1;
- if (index2 >= mNumRows) { // no guard row needed because we wrap the indices
- index2 -= mNumRows;
- }
-
- float *coefficients1 = &mCoefficients[static_cast<size_t>(index1)
- * static_cast<size_t>(getNumTaps())];
- float *coefficients2 = &mCoefficients[static_cast<size_t>(index2)
- * static_cast<size_t>(getNumTaps())];
+ const double tablePhase = getIntegerPhase() * mPhaseScaler;
+ const int indexLow = static_cast<int>(floor(tablePhase));
+ const int indexHigh = indexLow + 1; // OK because using a guard row.
+ assert (indexHigh < mNumRows);
+ float *coefficientsLow = &mCoefficients[static_cast<size_t>(indexLow)
+ * static_cast<size_t>(getNumTaps())];
+ float *coefficientsHigh = &mCoefficients[static_cast<size_t>(indexHigh)
+ * static_cast<size_t>(getNumTaps())];
float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
- for (int i = 0; i < mNumTaps; i++) {
- float coefficient1 = *coefficients1++;
- float coefficient2 = *coefficients2++;
+ for (int tap = 0; tap < mNumTaps; tap++) {
+ const float coefficientLow = *coefficientsLow++;
+ const float coefficientHigh = *coefficientsHigh++;
for (int channel = 0; channel < getChannelCount(); channel++) {
- float sample = *xFrame++;
- mSingleFrame[channel] += sample * coefficient1;
- mSingleFrame2[channel] += sample * coefficient2;
+ const float sample = *xFrame++;
+ mSingleFrame[channel] += sample * coefficientLow;
+ mSingleFrame2[channel] += sample * coefficientHigh;
}
}
// Interpolate and copy to output.
- float fraction = tablePhase - index1;
+ const float fraction = tablePhase - indexLow;
for (int channel = 0; channel < getChannelCount(); channel++) {
- float low = mSingleFrame[channel];
- float high = mSingleFrame2[channel];
+ const float low = mSingleFrame[channel];
+ const float high = mSingleFrame2[channel];
frame[channel] = low + (fraction * (high - low));
}
}
diff --git a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
index 432137e..d459abf 100644
--- a/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
+++ b/media/libaaudio/src/flowgraph/resampler/SincResamplerStereo.cpp
@@ -57,9 +57,6 @@
float *coefficients1 = &mCoefficients[static_cast<size_t>(index1)
* static_cast<size_t>(getNumTaps())];
int index2 = (index1 + 1);
- if (index2 >= mNumRows) { // no guard row needed because we wrap the indices
- index2 = 0;
- }
float *coefficients2 = &mCoefficients[static_cast<size_t>(index2)
* static_cast<size_t>(getNumTaps())];
float *xFrame = &mX[static_cast<size_t>(mCursor) * static_cast<size_t>(getChannelCount())];
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 438be0a..24041bc 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -228,3 +228,12 @@
"liblog",
],
}
+
+cc_test {
+ name: "test_resampler",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_resampler.cpp"],
+ shared_libs: [
+ "libaaudio_internal",
+ ],
+}
diff --git a/media/libaaudio/tests/test_attributes.cpp b/media/libaaudio/tests/test_attributes.cpp
index b88d562..e5676a7 100644
--- a/media/libaaudio/tests/test_attributes.cpp
+++ b/media/libaaudio/tests/test_attributes.cpp
@@ -20,6 +20,7 @@
// "test_aaudio_attributes.cpp". That other file is more current.
// So these tests could be deleted.
+#include <memory>
#include <stdio.h>
#include <unistd.h>
@@ -40,7 +41,7 @@
int privacyMode = DONT_SET,
aaudio_direction_t direction = AAUDIO_DIRECTION_OUTPUT) {
- float *buffer = new float[kNumFrames * kChannelCount];
+ std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
AAudioStreamBuilder *aaudioBuilder = nullptr;
AAudioStream *aaudioStream = nullptr;
@@ -109,16 +110,15 @@
if (direction == AAUDIO_DIRECTION_INPUT) {
EXPECT_EQ(kNumFrames,
- AAudioStream_read(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+ AAudioStream_read(aaudioStream, buffer.get(), kNumFrames, kNanosPerSecond));
} else {
EXPECT_EQ(kNumFrames,
- AAudioStream_write(aaudioStream, buffer, kNumFrames, kNanosPerSecond));
+ AAudioStream_write(aaudioStream, buffer.get(), kNumFrames, kNanosPerSecond));
}
EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream));
EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream));
- delete[] buffer;
}
static const aaudio_usage_t sUsages[] = {
diff --git a/media/libaaudio/tests/test_recovery.cpp b/media/libaaudio/tests/test_recovery.cpp
index 6e89f83..11331af 100644
--- a/media/libaaudio/tests/test_recovery.cpp
+++ b/media/libaaudio/tests/test_recovery.cpp
@@ -16,6 +16,7 @@
// Play silence and recover from dead servers or disconnected devices.
+#include <memory>
#include <stdio.h>
#include <aaudio/AAudio.h>
@@ -32,7 +33,6 @@
int32_t triesLeft = 3;
int32_t bufferCapacity;
int32_t framesPerBurst = 0;
- float *buffer = nullptr;
int32_t actualChannelCount = 0;
int32_t actualSampleRate = 0;
@@ -83,7 +83,7 @@
bufferCapacity, framesPerBurst);
int samplesPerBurst = framesPerBurst * actualChannelCount;
- buffer = new float[samplesPerBurst];
+ std::unique_ptr<float[]> buffer(new float[samplesPerBurst]);
result = AAudioStream_requestStart(aaudioStream);
if (result != AAUDIO_OK) {
@@ -98,7 +98,7 @@
int64_t printAt = actualSampleRate;
while (result == AAUDIO_OK && framesTotal < framesMax) {
int32_t framesWritten = AAudioStream_write(aaudioStream,
- buffer, framesPerBurst,
+ buffer.get(), framesPerBurst,
DEFAULT_TIMEOUT_NANOS);
if (framesWritten < 0) {
result = framesWritten;
@@ -134,6 +134,5 @@
AAudioStream_close(aaudioStream);
}
AAudioStreamBuilder_delete(aaudioBuilder);
- delete[] buffer;
printf(" result = %d = %s\n", result, AAudio_convertResultToText(result));
}
diff --git a/media/libaaudio/tests/test_resampler.cpp b/media/libaaudio/tests/test_resampler.cpp
new file mode 100644
index 0000000..1e4f59c
--- /dev/null
+++ b/media/libaaudio/tests/test_resampler.cpp
@@ -0,0 +1,221 @@
+/*
+ * Copyright 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.
+ */
+
+/*
+ * Test FlowGraph
+ *
+ * This file also tests a few different conversion techniques because
+ * sometimes that have caused compiler bugs.
+ */
+
+#include <iostream>
+
+#include <gtest/gtest.h>
+
+#include "flowgraph/resampler/MultiChannelResampler.h"
+
+using namespace RESAMPLER_OUTER_NAMESPACE::resampler;
+
+// Measure zero crossings.
+static int32_t countZeroCrossingsWithHysteresis(float *input, int32_t numSamples) {
+ const float kHysteresisLevel = 0.25f;
+ int zeroCrossingCount = 0;
+ int state = 0; // can be -1, 0, +1
+ for (int i = 0; i < numSamples; i++) {
+ if (input[i] >= kHysteresisLevel) {
+ if (state < 0) {
+ zeroCrossingCount++;
+ }
+ state = 1;
+ } else if (input[i] <= -kHysteresisLevel) {
+ if (state > 0) {
+ zeroCrossingCount++;
+ }
+ state = -1;
+ }
+ }
+ return zeroCrossingCount;
+}
+
+static constexpr int kChannelCount = 1;
+
+/**
+ * Convert a sine wave and then look for glitches.
+ * Glitches have a high value in the second derivative.
+ */
+static void checkResampler(int32_t sourceRate, int32_t sinkRate,
+ MultiChannelResampler::Quality quality) {
+ const int kNumOutputSamples = 10000;
+ const double framesPerCycle = 81.379; // target output period
+
+ int numInputSamples = kNumOutputSamples * sourceRate / sinkRate;
+
+ std::unique_ptr<float[]> inputBuffer = std::make_unique<float[]>(numInputSamples);
+ std::unique_ptr<float[]> outputBuffer = std::make_unique<float[]>(kNumOutputSamples);
+
+ // Generate a sine wave for input.
+ const double kPhaseIncrement = 2.0 * sinkRate / (framesPerCycle * sourceRate);
+ double phase = 0.0;
+ for (int i = 0; i < numInputSamples; i++) {
+ inputBuffer[i] = sin(phase * M_PI);
+ phase += kPhaseIncrement;
+ while (phase > 1.0) {
+ phase -= 2.0;
+ }
+ }
+ int sourceZeroCrossingCount = countZeroCrossingsWithHysteresis(
+ inputBuffer.get(), numInputSamples);
+
+ // Use a MultiChannelResampler to convert from the sourceRate to the sinkRate.
+ std::unique_ptr<MultiChannelResampler> mcResampler;
+ mcResampler.reset(MultiChannelResampler::make(kChannelCount,
+ sourceRate,
+ sinkRate,
+ quality));
+ int inputFramesLeft = numInputSamples;
+ int numRead = 0;
+ float *input = inputBuffer.get(); // for iteration
+ float *output = outputBuffer.get();
+ while (inputFramesLeft > 0) {
+ if (mcResampler->isWriteNeeded()) {
+ mcResampler->writeNextFrame(input);
+ input++;
+ inputFramesLeft--;
+ } else {
+ mcResampler->readNextFrame(output);
+ output++;
+ numRead++;
+ }
+ }
+
+ ASSERT_LE(numRead, kNumOutputSamples);
+ // Some frames are lost priming the FIR filter.
+ const int kMaxAlgorithmicFrameLoss = 16;
+ EXPECT_GT(numRead, kNumOutputSamples - kMaxAlgorithmicFrameLoss);
+
+ int sinkZeroCrossingCount = countZeroCrossingsWithHysteresis(outputBuffer.get(), numRead);
+ // Some cycles may get chopped off at the end.
+ const int kMaxZeroCrossingDelta = 3;
+ EXPECT_LE(abs(sourceZeroCrossingCount - sinkZeroCrossingCount), kMaxZeroCrossingDelta);
+
+ // Detect glitches by looking for spikes in the second derivative.
+ output = outputBuffer.get();
+ float previousValue = output[0];
+ float previousSlope = output[1] - output[0];
+ for (int i = 0; i < numRead; i++) {
+ float slope = output[i] - previousValue;
+ float slopeDelta = fabs(slope - previousSlope);
+ // Skip a few samples because there are often some steep slope changes at the beginning.
+ if (i > 10) {
+ EXPECT_LT(slopeDelta, 0.1);
+ }
+ previousValue = output[i];
+ previousSlope = slope;
+ }
+
+#if 0
+ // Save to disk for inspection.
+ FILE *fp = fopen( "/sdcard/Download/src_float_out.raw" , "wb" );
+ fwrite(outputBuffer.get(), sizeof(float), numRead, fp );
+ fclose(fp);
+#endif
+}
+
+
+TEST(test_resampler, resampler_scan_all) {
+ // TODO Add 64000, 88200, 96000 when they work. Failing now.
+ const int rates[] = {8000, 11025, 22050, 32000, 44100, 48000};
+ const MultiChannelResampler::Quality qualities[] =
+ {
+ MultiChannelResampler::Quality::Fastest,
+ MultiChannelResampler::Quality::Low,
+ MultiChannelResampler::Quality::Medium,
+ MultiChannelResampler::Quality::High,
+ MultiChannelResampler::Quality::Best
+ };
+ for (int srcRate : rates) {
+ for (int destRate : rates) {
+ for (auto quality : qualities) {
+ if (srcRate != destRate) {
+ checkResampler(srcRate, destRate, quality);
+ }
+ }
+ }
+ }
+}
+
+TEST(test_resampler, resampler_8000_11025_best) {
+ checkResampler(8000, 11025, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_8000_48000_best) {
+ checkResampler(8000, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_8000_44100_best) {
+ checkResampler(8000, 44100, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_24000_best) {
+ checkResampler(11025, 24000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_48000_fastest) {
+ checkResampler(11025, 48000, MultiChannelResampler::Quality::Fastest);
+}
+TEST(test_resampler, resampler_11025_48000_low) {
+ checkResampler(11025, 48000, MultiChannelResampler::Quality::Low);
+}
+TEST(test_resampler, resampler_11025_48000_medium) {
+ checkResampler(11025, 48000, MultiChannelResampler::Quality::Medium);
+}
+TEST(test_resampler, resampler_11025_48000_high) {
+ checkResampler(11025, 48000, MultiChannelResampler::Quality::High);
+}
+
+TEST(test_resampler, resampler_11025_48000_best) {
+ checkResampler(11025, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_11025_44100_best) {
+ checkResampler(11025, 44100, MultiChannelResampler::Quality::Best);
+}
+
+// TODO This fails because the output is very low.
+//TEST(test_resampler, resampler_11025_88200_best) {
+// checkResampler(11025, 88200, MultiChannelResampler::Quality::Best);
+//}
+
+TEST(test_resampler, resampler_16000_48000_best) {
+ checkResampler(16000, 48000, MultiChannelResampler::Quality::Best);
+}
+
+TEST(test_resampler, resampler_44100_48000_low) {
+ checkResampler(44100, 48000, MultiChannelResampler::Quality::Low);
+}
+TEST(test_resampler, resampler_44100_48000_best) {
+ checkResampler(44100, 48000, MultiChannelResampler::Quality::Best);
+}
+
+// Look for glitches when downsampling.
+TEST(test_resampler, resampler_48000_11025_best) {
+ checkResampler(48000, 11025, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_48000_44100_best) {
+ checkResampler(48000, 44100, MultiChannelResampler::Quality::Best);
+}
+TEST(test_resampler, resampler_44100_11025_best) {
+ checkResampler(44100, 11025, MultiChannelResampler::Quality::Best);
+}
diff --git a/media/libaaudio/tests/test_session_id.cpp b/media/libaaudio/tests/test_session_id.cpp
index 3f7d4fc..5968b5d 100644
--- a/media/libaaudio/tests/test_session_id.cpp
+++ b/media/libaaudio/tests/test_session_id.cpp
@@ -16,6 +16,7 @@
// Test AAudio SessionId, which is used to associate Effects with a stream
+#include <memory>
#include <stdio.h>
#include <unistd.h>
@@ -29,7 +30,7 @@
// Test AAUDIO_SESSION_ID_NONE default
static void checkSessionIdNone(aaudio_performance_mode_t perfMode) {
- float *buffer = new float[kNumFrames * kChannelCount];
+ std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
AAudioStreamBuilder *aaudioBuilder = nullptr;
@@ -51,12 +52,12 @@
ASSERT_EQ(AAUDIO_OK, AAudioStream_requestStart(aaudioStream1));
- ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1, buffer, kNumFrames, kNanosPerSecond));
+ ASSERT_EQ(kNumFrames,
+ AAudioStream_write(aaudioStream1, buffer.get(), kNumFrames, kNanosPerSecond));
EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
- delete[] buffer;
AAudioStreamBuilder_delete(aaudioBuilder);
}
@@ -72,7 +73,7 @@
static void checkSessionIdAllocate(aaudio_performance_mode_t perfMode,
aaudio_direction_t direction) {
- float *buffer = new float[kNumFrames * kChannelCount];
+ std::unique_ptr<float[]> buffer(new float[kNumFrames * kChannelCount]);
AAudioStreamBuilder *aaudioBuilder = nullptr;
@@ -106,10 +107,10 @@
if (direction == AAUDIO_DIRECTION_INPUT) {
ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream1,
- buffer, kNumFrames, kNanosPerSecond));
+ buffer.get(), kNumFrames, kNanosPerSecond));
} else {
ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream1,
- buffer, kNumFrames, kNanosPerSecond));
+ buffer.get(), kNumFrames, kNanosPerSecond));
}
EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream1));
@@ -135,10 +136,10 @@
if (otherDirection == AAUDIO_DIRECTION_INPUT) {
ASSERT_EQ(kNumFrames, AAudioStream_read(aaudioStream2,
- buffer, kNumFrames, kNanosPerSecond));
+ buffer.get(), kNumFrames, kNanosPerSecond));
} else {
ASSERT_EQ(kNumFrames, AAudioStream_write(aaudioStream2,
- buffer, kNumFrames, kNanosPerSecond));
+ buffer.get(), kNumFrames, kNanosPerSecond));
}
EXPECT_EQ(AAUDIO_OK, AAudioStream_requestStop(aaudioStream2));
@@ -147,7 +148,6 @@
EXPECT_EQ(AAUDIO_OK, AAudioStream_close(aaudioStream1));
- delete[] buffer;
AAudioStreamBuilder_delete(aaudioBuilder);
}
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 9fb0290..b3c8643 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -66,125 +66,6 @@
using media::audio::common::Int;
using media::audio::common::PcmType;
-namespace {
-
-enum class Direction {
- INPUT, OUTPUT
-};
-
-ConversionResult<Direction> direction(media::AudioPortRole role, media::AudioPortType type) {
- switch (type) {
- case media::AudioPortType::NONE:
- case media::AudioPortType::SESSION:
- break; // must be listed -Werror,-Wswitch
- case media::AudioPortType::DEVICE:
- switch (role) {
- case media::AudioPortRole::NONE:
- break; // must be listed -Werror,-Wswitch
- case media::AudioPortRole::SOURCE:
- return Direction::INPUT;
- case media::AudioPortRole::SINK:
- return Direction::OUTPUT;
- }
- break;
- case media::AudioPortType::MIX:
- switch (role) {
- case media::AudioPortRole::NONE:
- break; // must be listed -Werror,-Wswitch
- case media::AudioPortRole::SOURCE:
- return Direction::OUTPUT;
- case media::AudioPortRole::SINK:
- return Direction::INPUT;
- }
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<Direction> direction(audio_port_role_t role, audio_port_type_t type) {
- switch (type) {
- case AUDIO_PORT_TYPE_NONE:
- case AUDIO_PORT_TYPE_SESSION:
- break; // must be listed -Werror,-Wswitch
- case AUDIO_PORT_TYPE_DEVICE:
- switch (role) {
- case AUDIO_PORT_ROLE_NONE:
- break; // must be listed -Werror,-Wswitch
- case AUDIO_PORT_ROLE_SOURCE:
- return Direction::INPUT;
- case AUDIO_PORT_ROLE_SINK:
- return Direction::OUTPUT;
- }
- break;
- case AUDIO_PORT_TYPE_MIX:
- switch (role) {
- case AUDIO_PORT_ROLE_NONE:
- break; // must be listed -Werror,-Wswitch
- case AUDIO_PORT_ROLE_SOURCE:
- return Direction::OUTPUT;
- case AUDIO_PORT_ROLE_SINK:
- return Direction::INPUT;
- }
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
-} // namespace
-
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Converters
-
-ConversionResult<audio_io_config_event_t> aidl2legacy_AudioIoConfigEvent_audio_io_config_event_t(
- media::AudioIoConfigEvent aidl) {
- switch (aidl) {
- case media::AudioIoConfigEvent::OUTPUT_REGISTERED:
- return AUDIO_OUTPUT_REGISTERED;
- case media::AudioIoConfigEvent::OUTPUT_OPENED:
- return AUDIO_OUTPUT_OPENED;
- case media::AudioIoConfigEvent::OUTPUT_CLOSED:
- return AUDIO_OUTPUT_CLOSED;
- case media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED:
- return AUDIO_OUTPUT_CONFIG_CHANGED;
- case media::AudioIoConfigEvent::INPUT_REGISTERED:
- return AUDIO_INPUT_REGISTERED;
- case media::AudioIoConfigEvent::INPUT_OPENED:
- return AUDIO_INPUT_OPENED;
- case media::AudioIoConfigEvent::INPUT_CLOSED:
- return AUDIO_INPUT_CLOSED;
- case media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED:
- return AUDIO_INPUT_CONFIG_CHANGED;
- case media::AudioIoConfigEvent::CLIENT_STARTED:
- return AUDIO_CLIENT_STARTED;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_t_AudioIoConfigEvent(
- audio_io_config_event_t legacy) {
- switch (legacy) {
- case AUDIO_OUTPUT_REGISTERED:
- return media::AudioIoConfigEvent::OUTPUT_REGISTERED;
- case AUDIO_OUTPUT_OPENED:
- return media::AudioIoConfigEvent::OUTPUT_OPENED;
- case AUDIO_OUTPUT_CLOSED:
- return media::AudioIoConfigEvent::OUTPUT_CLOSED;
- case AUDIO_OUTPUT_CONFIG_CHANGED:
- return media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED;
- case AUDIO_INPUT_REGISTERED:
- return media::AudioIoConfigEvent::INPUT_REGISTERED;
- case AUDIO_INPUT_OPENED:
- return media::AudioIoConfigEvent::INPUT_OPENED;
- case AUDIO_INPUT_CLOSED:
- return media::AudioIoConfigEvent::INPUT_CLOSED;
- case AUDIO_INPUT_CONFIG_CHANGED:
- return media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED;
- case AUDIO_CLIENT_STARTED:
- return media::AudioIoConfigEvent::CLIENT_STARTED;
- }
- return unexpected(BAD_VALUE);
-}
-
ConversionResult<audio_port_role_t> aidl2legacy_AudioPortRole_audio_port_role_t(
media::AudioPortRole aidl) {
switch (aidl) {
@@ -241,52 +122,97 @@
return unexpected(BAD_VALUE);
}
-// This type is unnamed in the original definition, thus we name it here.
-using audio_port_config_mix_ext_usecase = decltype(audio_port_config_mix_ext::usecase);
+ConversionResult<AudioPortDirection> portDirection(
+ media::AudioPortRole role, media::AudioPortType type) {
+ audio_port_role_t legacyRole = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortRole_audio_port_role_t(role));
+ audio_port_type_t legacyType = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortType_audio_port_type_t(type));
+ return portDirection(legacyRole, legacyType);
+}
+ConversionResult<audio_io_config_event_t> aidl2legacy_AudioIoConfigEvent_audio_io_config_event_t(
+ media::AudioIoConfigEvent aidl) {
+ switch (aidl) {
+ case media::AudioIoConfigEvent::OUTPUT_REGISTERED:
+ return AUDIO_OUTPUT_REGISTERED;
+ case media::AudioIoConfigEvent::OUTPUT_OPENED:
+ return AUDIO_OUTPUT_OPENED;
+ case media::AudioIoConfigEvent::OUTPUT_CLOSED:
+ return AUDIO_OUTPUT_CLOSED;
+ case media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED:
+ return AUDIO_OUTPUT_CONFIG_CHANGED;
+ case media::AudioIoConfigEvent::INPUT_REGISTERED:
+ return AUDIO_INPUT_REGISTERED;
+ case media::AudioIoConfigEvent::INPUT_OPENED:
+ return AUDIO_INPUT_OPENED;
+ case media::AudioIoConfigEvent::INPUT_CLOSED:
+ return AUDIO_INPUT_CLOSED;
+ case media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED:
+ return AUDIO_INPUT_CONFIG_CHANGED;
+ case media::AudioIoConfigEvent::CLIENT_STARTED:
+ return AUDIO_CLIENT_STARTED;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_t_AudioIoConfigEvent(
+ audio_io_config_event_t legacy) {
+ switch (legacy) {
+ case AUDIO_OUTPUT_REGISTERED:
+ return media::AudioIoConfigEvent::OUTPUT_REGISTERED;
+ case AUDIO_OUTPUT_OPENED:
+ return media::AudioIoConfigEvent::OUTPUT_OPENED;
+ case AUDIO_OUTPUT_CLOSED:
+ return media::AudioIoConfigEvent::OUTPUT_CLOSED;
+ case AUDIO_OUTPUT_CONFIG_CHANGED:
+ return media::AudioIoConfigEvent::OUTPUT_CONFIG_CHANGED;
+ case AUDIO_INPUT_REGISTERED:
+ return media::AudioIoConfigEvent::INPUT_REGISTERED;
+ case AUDIO_INPUT_OPENED:
+ return media::AudioIoConfigEvent::INPUT_OPENED;
+ case AUDIO_INPUT_CLOSED:
+ return media::AudioIoConfigEvent::INPUT_CLOSED;
+ case AUDIO_INPUT_CONFIG_CHANGED:
+ return media::AudioIoConfigEvent::INPUT_CONFIG_CHANGED;
+ case AUDIO_CLIENT_STARTED:
+ return media::AudioIoConfigEvent::CLIENT_STARTED;
+ }
+ return unexpected(BAD_VALUE);
+}
ConversionResult<audio_port_config_mix_ext_usecase> aidl2legacy_AudioPortMixExtUseCase(
const AudioPortMixExtUseCase& aidl, media::AudioPortRole role) {
- audio_port_config_mix_ext_usecase legacy;
-
switch (role) {
- case media::AudioPortRole::NONE:
+ case media::AudioPortRole::NONE: {
+ audio_port_config_mix_ext_usecase legacy;
// Just verify that the union is empty.
VALUE_OR_RETURN(UNION_GET(aidl, unspecified));
return legacy;
-
+ }
case media::AudioPortRole::SOURCE:
- // This is not a bug. A SOURCE role corresponds to the stream field.
- legacy.stream = VALUE_OR_RETURN(aidl2legacy_AudioStreamType_audio_stream_type_t(
- VALUE_OR_RETURN(UNION_GET(aidl, stream))));
- return legacy;
-
+ return aidl2legacy_AudioPortMixExtUseCase_audio_port_config_mix_ext_usecase(
+ aidl, false /*isInput*/);
case media::AudioPortRole::SINK:
- // This is not a bug. A SINK role corresponds to the source field.
- legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(
- VALUE_OR_RETURN(UNION_GET(aidl, source))));
- return legacy;
+ return aidl2legacy_AudioPortMixExtUseCase_audio_port_config_mix_ext_usecase(
+ aidl, true /*isInput*/);
}
LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
}
ConversionResult<AudioPortMixExtUseCase> legacy2aidl_AudioPortMixExtUseCase(
const audio_port_config_mix_ext_usecase& legacy, audio_port_role_t role) {
- AudioPortMixExtUseCase aidl;
-
switch (role) {
- case AUDIO_PORT_ROLE_NONE:
+ case AUDIO_PORT_ROLE_NONE: {
+ AudioPortMixExtUseCase aidl;
UNION_SET(aidl, unspecified, false);
return aidl;
+ }
case AUDIO_PORT_ROLE_SOURCE:
- // This is not a bug. A SOURCE role corresponds to the stream field.
- UNION_SET(aidl, stream, VALUE_OR_RETURN(
- legacy2aidl_audio_stream_type_t_AudioStreamType(legacy.stream)));
- return aidl;
+ return legacy2aidl_audio_port_config_mix_ext_usecase_AudioPortMixExtUseCase(
+ legacy, false /*isInput*/);
case AUDIO_PORT_ROLE_SINK:
- // This is not a bug. A SINK role corresponds to the source field.
- UNION_SET(aidl, source,
- VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSource(legacy.source)));
- return aidl;
+ return legacy2aidl_audio_port_config_mix_ext_usecase_AudioPortMixExtUseCase(
+ legacy, true /*isInput*/);
}
LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
}
@@ -294,6 +220,8 @@
ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortMixExt(
const AudioPortMixExt& aidl, media::AudioPortRole role,
const media::AudioPortMixExtSys& aidlMixExt) {
+ // Not using HAL-level 'aidl2legacy_AudioPortMixExt' as it does not support
+ // 'media::AudioPortRole::NONE'.
audio_port_config_mix_ext legacy;
legacy.hw_module = VALUE_OR_RETURN(
aidl2legacy_int32_t_audio_module_handle_t(aidlMixExt.hwModule));
@@ -305,6 +233,8 @@
status_t legacy2aidl_AudioPortMixExt(
const audio_port_config_mix_ext& legacy, audio_port_role_t role,
AudioPortMixExt* aidl, media::AudioPortMixExtSys* aidlMixExt) {
+ // Not using HAL-level 'legacy2aidl_AudioPortMixExt' as it does not support
+ // 'AUDIO_PORT_ROLE_NONE'.
aidlMixExt->hwModule = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
aidl->handle = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(legacy.handle));
@@ -329,21 +259,20 @@
ConversionResult<audio_port_config_device_ext>
aidl2legacy_AudioPortDeviceExt_audio_port_config_device_ext(
const AudioPortDeviceExt& aidl, const media::AudioPortDeviceExtSys& aidlDeviceExt) {
- audio_port_config_device_ext legacy;
+ audio_port_config_device_ext legacy = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortDeviceExt_audio_port_config_device_ext(aidl));
legacy.hw_module = VALUE_OR_RETURN(
aidl2legacy_int32_t_audio_module_handle_t(aidlDeviceExt.hwModule));
- RETURN_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
- aidl.device, &legacy.type, legacy.address));
return legacy;
}
status_t legacy2aidl_audio_port_config_device_ext_AudioPortDeviceExt(
const audio_port_config_device_ext& legacy,
AudioPortDeviceExt* aidl, media::AudioPortDeviceExtSys* aidlDeviceExt) {
+ *aidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_config_device_ext_AudioPortDeviceExt(legacy));
aidlDeviceExt->hwModule = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
- aidl->device = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_device_AudioDevice(legacy.type, legacy.address));
return OK;
}
@@ -353,6 +282,8 @@
ConversionResult<audio_port_config_ext> aidl2legacy_AudioPortExt_audio_port_config_ext(
const AudioPortExt& aidl, media::AudioPortType type,
media::AudioPortRole role, const media::AudioPortExtSys& aidlSys) {
+ // Not using HAL-level 'aidl2legacy_AudioPortExt_audio_port_config_ext' as it does not support
+ // 'media::AudioPortType::SESSION'.
audio_port_config_ext legacy;
switch (type) {
case media::AudioPortType::NONE:
@@ -384,6 +315,8 @@
status_t legacy2aidl_AudioPortExt(
const audio_port_config_ext& legacy, audio_port_type_t type, audio_port_role_t role,
AudioPortExt* aidl, media::AudioPortExtSys* aidlSys) {
+ // Not using HAL-level 'aidl2legacy_AudioPortExt_audio_port_config_ext' as it does not support
+ // 'AUDIO_PORT_TYPE_SESSION'.
switch (type) {
case AUDIO_PORT_TYPE_NONE:
UNION_SET(*aidl, unspecified, false);
@@ -416,83 +349,39 @@
LOG_ALWAYS_FATAL("Shouldn't get here"); // with -Werror,-Wswitch may compile-time fail
}
-ConversionResult<audio_port_config> aidl2legacy_AudioPortConfig_audio_port_config(
- const media::AudioPortConfig& aidl) {
- audio_port_config legacy{};
- legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.hal.id));
+ConversionResult<audio_port_config> aidl2legacy_AudioPortConfigFw_audio_port_config(
+ const media::AudioPortConfigFw& aidl, int32_t* aidlPortId) {
+ const bool isInput = VALUE_OR_RETURN(
+ portDirection(aidl.sys.role, aidl.sys.type)) == AudioPortDirection::INPUT;
+ audio_port_config legacy;
+ int32_t aidlPortIdHolder;
+ RETURN_IF_ERROR(aidl2legacy_AudioPortConfig_audio_port_config(
+ aidl.hal, isInput, &legacy, &aidlPortIdHolder));
+ if (aidlPortId != nullptr) *aidlPortId = aidlPortIdHolder;
legacy.role = VALUE_OR_RETURN(aidl2legacy_AudioPortRole_audio_port_role_t(aidl.sys.role));
legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioPortType_audio_port_type_t(aidl.sys.type));
- const bool isInput =
- VALUE_OR_RETURN(direction(aidl.sys.role, aidl.sys.type)) == Direction::INPUT;
- if (aidl.hal.sampleRate.has_value()) {
- legacy.sample_rate = VALUE_OR_RETURN(
- convertIntegral<unsigned int>(aidl.hal.sampleRate.value().value));
- legacy.config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
- }
- if (aidl.hal.channelMask.has_value()) {
- legacy.channel_mask =
- VALUE_OR_RETURN(
- aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
- aidl.hal.channelMask.value(), isInput));
- legacy.config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
- }
- if (aidl.hal.format.has_value()) {
- legacy.format = VALUE_OR_RETURN(
- aidl2legacy_AudioFormatDescription_audio_format_t(aidl.hal.format.value()));
- legacy.config_mask |= AUDIO_PORT_CONFIG_FORMAT;
- }
- if (aidl.hal.gain.has_value()) {
- legacy.gain = VALUE_OR_RETURN(aidl2legacy_AudioGainConfig_audio_gain_config(
- aidl.hal.gain.value(), isInput));
- legacy.config_mask |= AUDIO_PORT_CONFIG_GAIN;
- }
- if (aidl.hal.flags.has_value()) {
- legacy.flags = VALUE_OR_RETURN(
- aidl2legacy_AudioIoFlags_audio_io_flags(aidl.hal.flags.value(), isInput));
- legacy.config_mask |= AUDIO_PORT_CONFIG_FLAGS;
- }
legacy.ext = VALUE_OR_RETURN(
aidl2legacy_AudioPortExt_audio_port_config_ext(
aidl.hal.ext, aidl.sys.type, aidl.sys.role, aidl.sys.ext));
return legacy;
}
-ConversionResult<media::AudioPortConfig> legacy2aidl_audio_port_config_AudioPortConfig(
- const audio_port_config& legacy) {
- media::AudioPortConfig aidl;
- aidl.hal.id = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.id));
+ConversionResult<media::AudioPortConfigFw> legacy2aidl_audio_port_config_AudioPortConfigFw(
+ const audio_port_config& legacy, int32_t portId) {
+ const bool isInput = VALUE_OR_RETURN(
+ portDirection(legacy.role, legacy.type)) == AudioPortDirection::INPUT;
+ media::AudioPortConfigFw aidl;
+ aidl.hal = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_config_AudioPortConfig(legacy, isInput, portId));
aidl.sys.role = VALUE_OR_RETURN(legacy2aidl_audio_port_role_t_AudioPortRole(legacy.role));
aidl.sys.type = VALUE_OR_RETURN(legacy2aidl_audio_port_type_t_AudioPortType(legacy.type));
- const bool isInput = VALUE_OR_RETURN(
- direction(legacy.role, legacy.type)) == Direction::INPUT;
- if (legacy.config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- Int aidl_sampleRate;
- aidl_sampleRate.value = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
- aidl.hal.sampleRate = aidl_sampleRate;
- }
- if (legacy.config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- aidl.hal.channelMask = VALUE_OR_RETURN(
- legacy2aidl_audio_channel_mask_t_AudioChannelLayout(legacy.channel_mask, isInput));
- }
- if (legacy.config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- aidl.hal.format = VALUE_OR_RETURN(
- legacy2aidl_audio_format_t_AudioFormatDescription(legacy.format));
- }
- if (legacy.config_mask & AUDIO_PORT_CONFIG_GAIN) {
- aidl.hal.gain = VALUE_OR_RETURN(
- legacy2aidl_audio_gain_config_AudioGainConfig(legacy.gain, isInput));
- }
- if (legacy.config_mask & AUDIO_PORT_CONFIG_FLAGS) {
- aidl.hal.flags = VALUE_OR_RETURN(
- legacy2aidl_audio_io_flags_AudioIoFlags(legacy.flags, isInput));
- }
RETURN_IF_ERROR(legacy2aidl_AudioPortExt(legacy.ext, legacy.type, legacy.role,
&aidl.hal.ext, &aidl.sys.ext));
return aidl;
}
-ConversionResult<struct audio_patch> aidl2legacy_AudioPatch_audio_patch(
- const media::AudioPatch& aidl) {
+ConversionResult<struct audio_patch> aidl2legacy_AudioPatchFw_audio_patch(
+ const media::AudioPatchFw& aidl) {
struct audio_patch legacy;
legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_patch_handle_t(aidl.id));
legacy.num_sinks = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sinks.size()));
@@ -501,7 +390,7 @@
}
for (size_t i = 0; i < legacy.num_sinks; ++i) {
legacy.sinks[i] =
- VALUE_OR_RETURN(aidl2legacy_AudioPortConfig_audio_port_config(aidl.sinks[i]));
+ VALUE_OR_RETURN(aidl2legacy_AudioPortConfigFw_audio_port_config(aidl.sinks[i]));
}
legacy.num_sources = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sources.size()));
if (legacy.num_sources > AUDIO_PATCH_PORTS_MAX) {
@@ -509,14 +398,14 @@
}
for (size_t i = 0; i < legacy.num_sources; ++i) {
legacy.sources[i] =
- VALUE_OR_RETURN(aidl2legacy_AudioPortConfig_audio_port_config(aidl.sources[i]));
+ VALUE_OR_RETURN(aidl2legacy_AudioPortConfigFw_audio_port_config(aidl.sources[i]));
}
return legacy;
}
-ConversionResult<media::AudioPatch> legacy2aidl_audio_patch_AudioPatch(
+ConversionResult<media::AudioPatchFw> legacy2aidl_audio_patch_AudioPatchFw(
const struct audio_patch& legacy) {
- media::AudioPatch aidl;
+ media::AudioPatchFw aidl;
aidl.id = VALUE_OR_RETURN(legacy2aidl_audio_patch_handle_t_int32_t(legacy.id));
if (legacy.num_sinks > AUDIO_PATCH_PORTS_MAX) {
@@ -524,14 +413,14 @@
}
for (unsigned int i = 0; i < legacy.num_sinks; ++i) {
aidl.sinks.push_back(
- VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfig(legacy.sinks[i])));
+ VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfigFw(legacy.sinks[i])));
}
if (legacy.num_sources > AUDIO_PATCH_PORTS_MAX) {
return unexpected(BAD_VALUE);
}
for (unsigned int i = 0; i < legacy.num_sources; ++i) {
aidl.sources.push_back(
- VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfig(legacy.sources[i])));
+ VALUE_OR_RETURN(legacy2aidl_audio_port_config_AudioPortConfigFw(legacy.sources[i])));
}
return aidl;
}
@@ -541,7 +430,7 @@
const audio_io_handle_t io_handle = VALUE_OR_RETURN(
aidl2legacy_int32_t_audio_io_handle_t(aidl.ioHandle));
const struct audio_patch patch = VALUE_OR_RETURN(
- aidl2legacy_AudioPatch_audio_patch(aidl.patch));
+ aidl2legacy_AudioPatchFw_audio_patch(aidl.patch));
const bool isInput = aidl.isInput;
const uint32_t sampling_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.samplingRate));
const audio_format_t format = VALUE_OR_RETURN(
@@ -561,7 +450,7 @@
const sp<AudioIoDescriptor>& legacy) {
media::AudioIoDescriptor aidl;
aidl.ioHandle = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(legacy->getIoHandle()));
- aidl.patch = VALUE_OR_RETURN(legacy2aidl_audio_patch_AudioPatch(legacy->getPatch()));
+ aidl.patch = VALUE_OR_RETURN(legacy2aidl_audio_patch_AudioPatchFw(legacy->getPatch()));
aidl.isInput = legacy->getIsInput();
aidl.samplingRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy->getSamplingRate()));
aidl.format = VALUE_OR_RETURN(
@@ -801,18 +690,18 @@
ConversionResult<audio_port_mix_ext>
aidl2legacy_AudioPortMixExt_audio_port_mix_ext(
const AudioPortMixExt& aidl, const media::AudioPortMixExtSys& aidlSys) {
- audio_port_mix_ext legacy{};
+ audio_port_mix_ext legacy = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortMixExt_audio_port_mix_ext(aidl));
legacy.hw_module = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_module_handle_t(aidlSys.hwModule));
- legacy.handle = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.handle));
return legacy;
}
status_t
legacy2aidl_audio_port_mix_ext_AudioPortMixExt(const audio_port_mix_ext& legacy,
AudioPortMixExt* aidl, media::AudioPortMixExtSys* aidlMixExt) {
+ *aidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_mix_ext_AudioPortMixExt(legacy));
aidlMixExt->hwModule = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
- aidl->handle = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(legacy.handle));
return OK;
}
@@ -831,11 +720,10 @@
ConversionResult<audio_port_device_ext>
aidl2legacy_AudioPortDeviceExt_audio_port_device_ext(
const AudioPortDeviceExt& aidl, const media::AudioPortDeviceExtSys& aidlSys) {
- audio_port_device_ext legacy;
+ audio_port_device_ext legacy = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortDeviceExt_audio_port_device_ext(aidl));
legacy.hw_module = VALUE_OR_RETURN(
aidl2legacy_int32_t_audio_module_handle_t(aidlSys.hwModule));
- RETURN_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
- aidl.device, &legacy.type, legacy.address));
legacy.encapsulation_modes = VALUE_OR_RETURN(
aidl2legacy_AudioEncapsulationMode_mask(aidlSys.encapsulationModes));
legacy.encapsulation_metadata_types = VALUE_OR_RETURN(
@@ -847,10 +735,9 @@
status_t legacy2aidl_audio_port_device_ext_AudioPortDeviceExt(
const audio_port_device_ext& legacy,
AudioPortDeviceExt* aidl, media::AudioPortDeviceExtSys* aidlDeviceExt) {
+ *aidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_device_ext_AudioPortDeviceExt(legacy));
aidlDeviceExt->hwModule = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
- aidl->device = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_device_AudioDevice(legacy.type, legacy.address));
aidlDeviceExt->encapsulationModes = VALUE_OR_RETURN_STATUS(
legacy2aidl_AudioEncapsulationMode_mask(legacy.encapsulation_modes));
aidlDeviceExt->encapsulationMetadataTypes = VALUE_OR_RETURN_STATUS(
@@ -930,93 +817,33 @@
}
ConversionResult<audio_port_v7>
-aidl2legacy_AudioPort_audio_port_v7(const media::AudioPort& aidl) {
- audio_port_v7 legacy;
- legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.hal.id));
+aidl2legacy_AudioPortFw_audio_port_v7(const media::AudioPortFw& aidl) {
+ const bool isInput = VALUE_OR_RETURN(
+ portDirection(aidl.sys.role, aidl.sys.type)) == AudioPortDirection::INPUT;
+ audio_port_v7 legacy = VALUE_OR_RETURN(aidl2legacy_AudioPort_audio_port_v7(aidl.hal, isInput));
legacy.role = VALUE_OR_RETURN(aidl2legacy_AudioPortRole_audio_port_role_t(aidl.sys.role));
legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioPortType_audio_port_type_t(aidl.sys.type));
- RETURN_IF_ERROR(aidl2legacy_string(aidl.hal.name, legacy.name, sizeof(legacy.name)));
-
- if (aidl.hal.profiles.size() > std::size(legacy.audio_profiles)) {
- return unexpected(BAD_VALUE);
- }
- const bool isInput =
- VALUE_OR_RETURN(direction(aidl.sys.role, aidl.sys.type)) == Direction::INPUT;
- RETURN_IF_ERROR(convertRange(
- aidl.hal.profiles.begin(), aidl.hal.profiles.end(), legacy.audio_profiles,
- [isInput](const AudioProfile& p) {
- return aidl2legacy_AudioProfile_audio_profile(p, isInput);
- }));
- legacy.num_audio_profiles = aidl.hal.profiles.size();
-
- if (aidl.hal.extraAudioDescriptors.size() > std::size(legacy.extra_audio_descriptors)) {
- return unexpected(BAD_VALUE);
- }
- RETURN_IF_ERROR(
- convertRange(
- aidl.hal.extraAudioDescriptors.begin(), aidl.hal.extraAudioDescriptors.end(),
- legacy.extra_audio_descriptors,
- aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor));
- legacy.num_extra_audio_descriptors = aidl.hal.extraAudioDescriptors.size();
-
- if (aidl.hal.gains.size() > std::size(legacy.gains)) {
- return unexpected(BAD_VALUE);
- }
- RETURN_IF_ERROR(convertRange(aidl.hal.gains.begin(), aidl.hal.gains.end(), legacy.gains,
- [isInput](const AudioGain& g) {
- return aidl2legacy_AudioGain_audio_gain(g, isInput);
- }));
- legacy.num_gains = aidl.hal.gains.size();
legacy.active_config = VALUE_OR_RETURN(
- aidl2legacy_AudioPortConfig_audio_port_config(aidl.sys.activeConfig));
+ aidl2legacy_AudioPortConfigFw_audio_port_config(aidl.sys.activeConfig));
legacy.ext = VALUE_OR_RETURN(
aidl2legacy_AudioPortExt_audio_port_v7_ext(aidl.hal.ext, aidl.sys.type, aidl.sys.ext));
return legacy;
}
-ConversionResult<media::AudioPort>
-legacy2aidl_audio_port_v7_AudioPort(const audio_port_v7& legacy) {
- media::AudioPort aidl;
- aidl.hal.id = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.id));
+ConversionResult<media::AudioPortFw>
+legacy2aidl_audio_port_v7_AudioPortFw(const audio_port_v7& legacy) {
+ const bool isInput = VALUE_OR_RETURN(
+ portDirection(legacy.role, legacy.type)) == AudioPortDirection::INPUT;
+ media::AudioPortFw aidl;
+ aidl.hal = VALUE_OR_RETURN(legacy2aidl_audio_port_v7_AudioPort(legacy, isInput));
aidl.sys.role = VALUE_OR_RETURN(legacy2aidl_audio_port_role_t_AudioPortRole(legacy.role));
aidl.sys.type = VALUE_OR_RETURN(legacy2aidl_audio_port_type_t_AudioPortType(legacy.type));
- aidl.hal.name = VALUE_OR_RETURN(legacy2aidl_string(legacy.name, sizeof(legacy.name)));
-
- if (legacy.num_audio_profiles > std::size(legacy.audio_profiles)) {
- return unexpected(BAD_VALUE);
- }
- const bool isInput = VALUE_OR_RETURN(direction(legacy.role, legacy.type)) == Direction::INPUT;
- RETURN_IF_ERROR(
- convertRange(legacy.audio_profiles, legacy.audio_profiles + legacy.num_audio_profiles,
- std::back_inserter(aidl.hal.profiles),
- [isInput](const audio_profile& p) {
- return legacy2aidl_audio_profile_AudioProfile(p, isInput);
- }));
-
- if (legacy.num_extra_audio_descriptors > std::size(legacy.extra_audio_descriptors)) {
- return unexpected(BAD_VALUE);
- }
+ // These get filled by the call to 'legacy2aidl_AudioPortExt' below.
aidl.sys.profiles.resize(legacy.num_audio_profiles);
- RETURN_IF_ERROR(
- convertRange(legacy.extra_audio_descriptors,
- legacy.extra_audio_descriptors + legacy.num_extra_audio_descriptors,
- std::back_inserter(aidl.hal.extraAudioDescriptors),
- legacy2aidl_audio_extra_audio_descriptor_ExtraAudioDescriptor));
-
- if (legacy.num_gains > std::size(legacy.gains)) {
- return unexpected(BAD_VALUE);
- }
- RETURN_IF_ERROR(
- convertRange(legacy.gains, legacy.gains + legacy.num_gains,
- std::back_inserter(aidl.hal.gains),
- [isInput](const audio_gain& g) {
- return legacy2aidl_audio_gain_AudioGain(g, isInput);
- }));
aidl.sys.gains.resize(legacy.num_gains);
-
aidl.sys.activeConfig = VALUE_OR_RETURN(
- legacy2aidl_audio_port_config_AudioPortConfig(legacy.active_config));
+ legacy2aidl_audio_port_config_AudioPortConfigFw(legacy.active_config, legacy.id));
aidl.sys.activeConfig.hal.portId = aidl.hal.id;
RETURN_IF_ERROR(
legacy2aidl_AudioPortExt(legacy.ext, legacy.type, &aidl.hal.ext, &aidl.sys.ext));
@@ -1091,80 +918,6 @@
return convertReinterpret<int32_t>(legacy);
}
-ConversionResult<audio_dual_mono_mode_t>
-aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(media::AudioDualMonoMode aidl) {
- switch (aidl) {
- case media::AudioDualMonoMode::OFF:
- return AUDIO_DUAL_MONO_MODE_OFF;
- case media::AudioDualMonoMode::LR:
- return AUDIO_DUAL_MONO_MODE_LR;
- case media::AudioDualMonoMode::LL:
- return AUDIO_DUAL_MONO_MODE_LL;
- case media::AudioDualMonoMode::RR:
- return AUDIO_DUAL_MONO_MODE_RR;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioDualMonoMode>
-legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(audio_dual_mono_mode_t legacy) {
- switch (legacy) {
- case AUDIO_DUAL_MONO_MODE_OFF:
- return media::AudioDualMonoMode::OFF;
- case AUDIO_DUAL_MONO_MODE_LR:
- return media::AudioDualMonoMode::LR;
- case AUDIO_DUAL_MONO_MODE_LL:
- return media::AudioDualMonoMode::LL;
- case AUDIO_DUAL_MONO_MODE_RR:
- return media::AudioDualMonoMode::RR;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<audio_timestretch_fallback_mode_t>
-aidl2legacy_int32_t_audio_timestretch_fallback_mode_t(int32_t aidl) {
- return convertReinterpret<audio_timestretch_fallback_mode_t>(aidl);
-}
-
-ConversionResult<int32_t>
-legacy2aidl_audio_timestretch_fallback_mode_t_int32_t(audio_timestretch_fallback_mode_t legacy) {
- return convertReinterpret<int32_t>(legacy);
-}
-
-ConversionResult<audio_timestretch_stretch_mode_t>
-aidl2legacy_int32_t_audio_timestretch_stretch_mode_t(int32_t aidl) {
- return convertReinterpret<audio_timestretch_stretch_mode_t>(aidl);
-}
-
-ConversionResult<int32_t>
-legacy2aidl_audio_timestretch_stretch_mode_t_int32_t(audio_timestretch_stretch_mode_t legacy) {
- return convertReinterpret<int32_t>(legacy);
-}
-
-ConversionResult<audio_playback_rate_t>
-aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(const media::AudioPlaybackRate& aidl) {
- audio_playback_rate_t legacy;
- legacy.mSpeed = aidl.speed;
- legacy.mPitch = aidl.pitch;
- legacy.mFallbackMode = VALUE_OR_RETURN(
- aidl2legacy_int32_t_audio_timestretch_fallback_mode_t(aidl.fallbackMode));
- legacy.mStretchMode = VALUE_OR_RETURN(
- aidl2legacy_int32_t_audio_timestretch_stretch_mode_t(aidl.stretchMode));
- return legacy;
-}
-
-ConversionResult<media::AudioPlaybackRate>
-legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(const audio_playback_rate_t& legacy) {
- media::AudioPlaybackRate aidl;
- aidl.speed = legacy.mSpeed;
- aidl.pitch = legacy.mPitch;
- aidl.fallbackMode = VALUE_OR_RETURN(
- legacy2aidl_audio_timestretch_fallback_mode_t_int32_t(legacy.mFallbackMode));
- aidl.stretchMode = VALUE_OR_RETURN(
- legacy2aidl_audio_timestretch_stretch_mode_t_int32_t(legacy.mStretchMode));
- return aidl;
-}
-
ConversionResult<TrackSecondaryOutputInfoPair>
aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
const media::TrackSecondaryOutputInfo& aidl) {
@@ -1237,25 +990,4 @@
indexToEnum_bitmask<audio_direct_mode_t>,
enumToMask_index<int32_t, media::AudioDirectMode>);
}
-
-ConversionResult<audio_latency_mode_t>
-aidl2legacy_LatencyMode_audio_latency_mode_t(media::LatencyMode aidl) {
- switch (aidl) {
- case media::LatencyMode::FREE:
- return AUDIO_LATENCY_MODE_FREE;
- case media::LatencyMode::LOW:
- return AUDIO_LATENCY_MODE_LOW;
- }
- return unexpected(BAD_VALUE);
-}
-ConversionResult<media::LatencyMode>
-legacy2aidl_audio_latency_mode_t_LatencyMode(audio_latency_mode_t legacy) {
- switch (legacy) {
- case AUDIO_LATENCY_MODE_FREE:
- return media::LatencyMode::FREE;
- case AUDIO_LATENCY_MODE_LOW:
- return media::LatencyMode::LOW;
- }
- return unexpected(BAD_VALUE);
-}
} // namespace android
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 4a1ba57..50e9ea7 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -128,6 +128,7 @@
"audiopolicy-types-aidl-cpp",
"av-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
+ "libaudio_aidl_conversion_common_cpp",
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudioutils",
@@ -281,17 +282,15 @@
"aidl/android/media/AudioAttributesInternal.aidl",
"aidl/android/media/AudioClient.aidl",
"aidl/android/media/AudioDirectMode.aidl",
- "aidl/android/media/AudioDualMonoMode.aidl",
"aidl/android/media/AudioFlag.aidl",
"aidl/android/media/AudioGainSys.aidl",
"aidl/android/media/AudioHalVersion.aidl",
"aidl/android/media/AudioIoConfigEvent.aidl",
"aidl/android/media/AudioIoDescriptor.aidl",
- "aidl/android/media/AudioPatch.aidl",
- "aidl/android/media/AudioPlaybackRate.aidl",
- "aidl/android/media/AudioPort.aidl",
+ "aidl/android/media/AudioPatchFw.aidl",
+ "aidl/android/media/AudioPortFw.aidl",
"aidl/android/media/AudioPortSys.aidl",
- "aidl/android/media/AudioPortConfig.aidl",
+ "aidl/android/media/AudioPortConfigFw.aidl",
"aidl/android/media/AudioPortConfigSys.aidl",
"aidl/android/media/AudioPortDeviceExtSys.aidl",
"aidl/android/media/AudioPortExtSys.aidl",
@@ -303,7 +302,6 @@
"aidl/android/media/AudioUniqueIdUse.aidl",
"aidl/android/media/AudioVibratorInfo.aidl",
"aidl/android/media/EffectDescriptor.aidl",
- "aidl/android/media/LatencyMode.aidl",
"aidl/android/media/TrackSecondaryOutputInfo.aidl",
],
imports: [
diff --git a/media/libaudioclient/AudioPolicy.cpp b/media/libaudioclient/AudioPolicy.cpp
index 6bb0cbe..1b9936f 100644
--- a/media/libaudioclient/AudioPolicy.cpp
+++ b/media/libaudioclient/AudioPolicy.cpp
@@ -203,9 +203,10 @@
return false;
}
-bool AudioMix::hasMatchUserIdRule() const {
+bool AudioMix::hasUserIdRule(bool match) const {
+ const uint32_t rule = match ? RULE_MATCH_USERID : RULE_EXCLUDE_USERID;
for (size_t i = 0; i < mCriteria.size(); i++) {
- if (mCriteria[i].mRule == RULE_MATCH_USERID) {
+ if (mCriteria[i].mRule == rule) {
return true;
}
}
@@ -214,7 +215,7 @@
bool AudioMix::isDeviceAffinityCompatible() const {
return ((mMixType == MIX_TYPE_PLAYERS)
- && (mRouteFlags == MIX_ROUTE_FLAG_RENDER));
+ && ((mRouteFlags & MIX_ROUTE_FLAG_RENDER) == MIX_ROUTE_FLAG_RENDER));
}
} // namespace android
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 1f107a6..59016ad 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -82,7 +82,7 @@
// Binder for the AudioFlinger service that's passed to this client process from the system server.
// This allows specific isolated processes to access the audio system. Currently used only for the
// HotwordDetectionService.
-sp<IBinder> gAudioFlingerBinder = nullptr;
+static sp<IBinder> gAudioFlingerBinder = nullptr;
void AudioSystem::setAudioFlingerBinder(const sp<IBinder>& audioFlinger) {
if (audioFlinger->getInterfaceDescriptor() != media::IAudioFlingerService::descriptor) {
@@ -98,6 +98,15 @@
gAudioFlingerBinder = audioFlinger;
}
+static sp<IAudioFlinger> gLocalAudioFlinger; // set if we are local.
+
+status_t AudioSystem::setLocalAudioFlinger(const sp<IAudioFlinger>& af) {
+ Mutex::Autolock _l(gLock);
+ if (gAudioFlinger != nullptr) return INVALID_OPERATION;
+ gLocalAudioFlinger = af;
+ return OK;
+}
+
// establish binder interface to AudioFlinger service
const sp<IAudioFlinger> AudioSystem::get_audio_flinger() {
sp<IAudioFlinger> af;
@@ -105,7 +114,19 @@
bool reportNoError = false;
{
Mutex::Autolock _l(gLock);
- if (gAudioFlinger == 0) {
+ if (gAudioFlinger != nullptr) {
+ return gAudioFlinger;
+ }
+
+ if (gAudioFlingerClient == nullptr) {
+ gAudioFlingerClient = sp<AudioFlingerClient>::make();
+ } else {
+ reportNoError = true;
+ }
+
+ if (gLocalAudioFlinger != nullptr) {
+ gAudioFlinger = gLocalAudioFlinger;
+ } else {
sp<IBinder> binder;
if (gAudioFlingerBinder != nullptr) {
binder = gAudioFlingerBinder;
@@ -113,32 +134,24 @@
sp<IServiceManager> sm = defaultServiceManager();
do {
binder = sm->getService(String16(IAudioFlinger::DEFAULT_SERVICE_NAME));
- if (binder != 0)
- break;
+ if (binder != nullptr) break;
ALOGW("AudioFlinger not published, waiting...");
usleep(500000); // 0.5 s
} while (true);
}
- if (gAudioFlingerClient == NULL) {
- gAudioFlingerClient = new AudioFlingerClient();
- } else {
- reportNoError = true;
- }
binder->linkToDeath(gAudioFlingerClient);
- gAudioFlinger = new AudioFlingerClientAdapter(
- interface_cast<media::IAudioFlingerService>(binder));
- LOG_ALWAYS_FATAL_IF(gAudioFlinger == 0);
- afc = gAudioFlingerClient;
- // Make sure callbacks can be received by gAudioFlingerClient
- ProcessState::self()->startThreadPool();
+ const auto afs = interface_cast<media::IAudioFlingerService>(binder);
+ LOG_ALWAYS_FATAL_IF(afs == nullptr);
+ gAudioFlinger = sp<AudioFlingerClientAdapter>::make(afs);
}
+ afc = gAudioFlingerClient;
af = gAudioFlinger;
+ // Make sure callbacks can be received by gAudioFlingerClient
+ ProcessState::self()->startThreadPool();
}
- if (afc != 0) {
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
- af->registerClient(afc);
- IPCThreadState::self()->restoreCallingIdentity(token);
- }
+ const int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ af->registerClient(afc);
+ IPCThreadState::self()->restoreCallingIdentity(token);
if (reportNoError) reportError(NO_ERROR);
return af;
}
@@ -672,12 +685,12 @@
}
Status AudioSystem::AudioFlingerClient::onSupportedLatencyModesChanged(
- int output, const std::vector<media::LatencyMode>& latencyModes) {
+ int output, const std::vector<media::audio::common::AudioLatencyMode>& latencyModes) {
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_io_handle_t(output));
std::vector<audio_latency_mode_t> modesLegacy = VALUE_OR_RETURN_BINDER_STATUS(
convertContainer<std::vector<audio_latency_mode_t>>(
- latencyModes, aidl2legacy_LatencyMode_audio_latency_mode_t));
+ latencyModes, aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
std::vector<sp<SupportedLatencyModesCallback>> callbacks;
{
@@ -1086,6 +1099,8 @@
responseAidl.secondaryOutputs, aidl2legacy_int32_t_audio_io_handle_t));
*isSpatialized = responseAidl.isSpatialized;
*isBitPerfect = responseAidl.isBitPerfect;
+ *attr = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioAttributesInternal_audio_attributes_t(responseAidl.attr));
return OK;
}
@@ -1549,7 +1564,7 @@
legacy2aidl_audio_port_type_t_AudioPortType(type));
Int numPortsAidl;
numPortsAidl.value = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*num_ports));
- std::vector<media::AudioPort> portsAidl;
+ std::vector<media::AudioPortFw> portsAidl;
int32_t generationAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
@@ -1557,7 +1572,7 @@
*num_ports = VALUE_OR_RETURN_STATUS(convertIntegral<unsigned int>(numPortsAidl.value));
*generation = VALUE_OR_RETURN_STATUS(convertIntegral<unsigned int>(generationAidl));
RETURN_STATUS_IF_ERROR(convertRange(portsAidl.begin(), portsAidl.end(), ports,
- aidl2legacy_AudioPort_audio_port_v7));
+ aidl2legacy_AudioPortFw_audio_port_v7));
return OK;
}
@@ -1568,10 +1583,10 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- media::AudioPort portAidl;
+ media::AudioPortFw portAidl;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(aps->getAudioPort(port->id, &portAidl)));
- *port = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPort_audio_port_v7(portAidl));
+ *port = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortFw_audio_port_v7(portAidl));
return OK;
}
@@ -1584,8 +1599,8 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- media::AudioPatch patchAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_patch_AudioPatch(*patch));
+ media::AudioPatchFw patchAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_patch_AudioPatchFw(*patch));
int32_t handleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_handle_t_int32_t(*handle));
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(aps->createAudioPatch(patchAidl, handleAidl, &handleAidl)));
@@ -1615,7 +1630,7 @@
Int numPatchesAidl;
numPatchesAidl.value = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*num_patches));
- std::vector<media::AudioPatch> patchesAidl;
+ std::vector<media::AudioPatchFw> patchesAidl;
int32_t generationAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
@@ -1623,7 +1638,7 @@
*num_patches = VALUE_OR_RETURN_STATUS(convertIntegral<unsigned int>(numPatchesAidl.value));
*generation = VALUE_OR_RETURN_STATUS(convertIntegral<unsigned int>(generationAidl));
RETURN_STATUS_IF_ERROR(convertRange(patchesAidl.begin(), patchesAidl.end(), patches,
- aidl2legacy_AudioPatch_audio_patch));
+ aidl2legacy_AudioPatchFw_audio_patch));
return OK;
}
@@ -1635,8 +1650,8 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- media::AudioPortConfig configAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_port_config_AudioPortConfig(*config));
+ media::AudioPortConfigFw configAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_config_AudioPortConfigFw(*config));
return statusTFromBinderStatus(aps->setAudioPortConfig(configAidl));
}
@@ -1856,8 +1871,8 @@
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- media::AudioPortConfig sourceAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_port_config_AudioPortConfig(*source));
+ media::AudioPortConfigFw sourceAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_config_AudioPortConfigFw(*source));
media::AudioAttributesInternal attributesAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributesInternal(*attributes));
int32_t portIdAidl;
@@ -2221,8 +2236,25 @@
aps->setDevicesRoleForStrategy(strategyAidl, roleAidl, devicesAidl));
}
+status_t AudioSystem::removeDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role,
+ const AudioDeviceTypeAddrVector& devices) {
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
+ media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
+ std::vector<AudioDevice> devicesAidl = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<AudioDevice>>(devices,
+ legacy2aidl_AudioDeviceTypeAddress));
+ return statusTFromBinderStatus(
+ aps->removeDevicesRoleForStrategy(strategyAidl, roleAidl, devicesAidl));
+}
+
status_t
-AudioSystem::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) {
+AudioSystem::clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) {
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) {
return PERMISSION_DENIED;
@@ -2230,7 +2262,7 @@
int32_t strategyAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_product_strategy_t_int32_t(strategy));
media::DeviceRole roleAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_device_role_t_DeviceRole(role));
return statusTFromBinderStatus(
- aps->removeDevicesRoleForStrategy(strategyAidl, roleAidl));
+ aps->clearDevicesRoleForStrategy(strategyAidl, roleAidl));
}
status_t AudioSystem::getDevicesForRoleAndStrategy(product_strategy_t strategy,
@@ -2457,6 +2489,32 @@
return af->getSupportedLatencyModes(output, modes);
}
+status_t AudioSystem::setBluetoothVariableLatencyEnabled(bool enabled) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ return PERMISSION_DENIED;
+ }
+ return af->setBluetoothVariableLatencyEnabled(enabled);
+}
+
+status_t AudioSystem::isBluetoothVariableLatencyEnabled(
+ bool *enabled) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ return PERMISSION_DENIED;
+ }
+ return af->isBluetoothVariableLatencyEnabled(enabled);
+}
+
+status_t AudioSystem::supportsBluetoothVariableLatency(
+ bool *support) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == nullptr) {
+ return PERMISSION_DENIED;
+ }
+ return af->supportsBluetoothVariableLatency(support);
+}
+
class CaptureStateListenerImpl : public media::BnCaptureStateListener,
public IBinder::DeathRecipient {
public:
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 22bd2a3..9386b9b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1266,7 +1266,7 @@
status_t AudioTrack::getDualMonoMode(audio_dual_mono_mode_t* mode) const
{
AutoMutex lock(mLock);
- media::AudioDualMonoMode mediaMode;
+ media::audio::common::AudioDualMonoMode mediaMode;
const status_t status = statusTFromBinderStatus(mAudioTrack->getDualMonoMode(&mediaMode));
if (status == NO_ERROR) {
*mode = VALUE_OR_RETURN_STATUS(
@@ -1381,7 +1381,7 @@
{
AutoMutex lock(mLock);
if (isOffloadedOrDirect_l()) {
- media::AudioPlaybackRate playbackRateTemp;
+ media::audio::common::AudioPlaybackRate playbackRateTemp;
const status_t status = statusTFromBinderStatus(
mAudioTrack->getPlaybackRateParameters(&playbackRateTemp));
if (status == NO_ERROR) { // update local version if changed.
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 141c84f..1c634e7 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -493,12 +493,6 @@
return statusTFromBinderStatus(mDelegate->closeInput(inputAidl));
}
-status_t AudioFlingerClientAdapter::invalidateStream(audio_stream_type_t stream) {
- AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
- return statusTFromBinderStatus(mDelegate->invalidateStream(streamAidl));
-}
-
status_t AudioFlingerClientAdapter::setVoiceVolume(float volume) {
return statusTFromBinderStatus(mDelegate->setVoiceVolume(volume));
}
@@ -679,17 +673,19 @@
}
status_t AudioFlingerClientAdapter::getAudioPort(struct audio_port_v7* port) {
- media::AudioPort portAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_v7_AudioPort(*port));
- media::AudioPort aidlRet;
+ media::AudioPortFw portAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_v7_AudioPortFw(*port));
+ media::AudioPortFw aidlRet;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
mDelegate->getAudioPort(portAidl, &aidlRet)));
- *port = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPort_audio_port_v7(aidlRet));
+ *port = VALUE_OR_RETURN_STATUS(aidl2legacy_AudioPortFw_audio_port_v7(aidlRet));
return OK;
}
status_t AudioFlingerClientAdapter::createAudioPatch(const struct audio_patch* patch,
audio_patch_handle_t* handle) {
- media::AudioPatch patchAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_AudioPatch(*patch));
+ media::AudioPatchFw patchAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_patch_AudioPatchFw(*patch));
int32_t aidlRet = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_patch_handle_t_int32_t(
AUDIO_PATCH_HANDLE_NONE));
if (handle != nullptr) {
@@ -710,18 +706,18 @@
status_t AudioFlingerClientAdapter::listAudioPatches(unsigned int* num_patches,
struct audio_patch* patches) {
- std::vector<media::AudioPatch> aidlRet;
+ std::vector<media::AudioPatchFw> aidlRet;
int32_t maxPatches = VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(*num_patches));
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
mDelegate->listAudioPatches(maxPatches, &aidlRet)));
*num_patches = VALUE_OR_RETURN_STATUS(convertIntegral<unsigned int>(aidlRet.size()));
return convertRange(aidlRet.begin(), aidlRet.end(), patches,
- aidl2legacy_AudioPatch_audio_patch);
+ aidl2legacy_AudioPatchFw_audio_patch);
}
status_t AudioFlingerClientAdapter::setAudioPortConfig(const struct audio_port_config* config) {
- media::AudioPortConfig configAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_port_config_AudioPortConfig(*config));
+ media::AudioPortConfigFw configAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_config_AudioPortConfigFw(*config));
return statusTFromBinderStatus(mDelegate->setAudioPortConfig(configAidl));
}
@@ -818,16 +814,16 @@
status_t AudioFlingerClientAdapter::setDeviceConnectedState(
const struct audio_port_v7 *port, bool connected) {
- media::AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_port_v7_AudioPort(*port));
+ media::AudioPortFw aidlPort = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_port_v7_AudioPortFw(*port));
return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
}
status_t AudioFlingerClientAdapter::setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) {
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
- media::LatencyMode modeAidl = VALUE_OR_RETURN_STATUS(
- legacy2aidl_audio_latency_mode_t_LatencyMode(mode));
+ media::audio::common::AudioLatencyMode modeAidl = VALUE_OR_RETURN_STATUS(
+ legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode));
return statusTFromBinderStatus(mDelegate->setRequestedLatencyMode(outputAidl, modeAidl));
}
@@ -838,14 +834,40 @@
}
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
- std::vector<media::LatencyMode> modesAidl;
+ std::vector<media::audio::common::AudioLatencyMode> modesAidl;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
mDelegate->getSupportedLatencyModes(outputAidl, &modesAidl)));
*modes = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<audio_latency_mode_t>>(modesAidl,
- aidl2legacy_LatencyMode_audio_latency_mode_t));
+ aidl2legacy_AudioLatencyMode_audio_latency_mode_t));
+
+ return NO_ERROR;
+}
+
+status_t AudioFlingerClientAdapter::setBluetoothVariableLatencyEnabled(bool enabled) {
+ return statusTFromBinderStatus(mDelegate->setBluetoothVariableLatencyEnabled(enabled));
+}
+
+status_t AudioFlingerClientAdapter::isBluetoothVariableLatencyEnabled(bool* enabled) {
+ if (enabled == nullptr) {
+ return BAD_VALUE;
+ }
+
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mDelegate->isBluetoothVariableLatencyEnabled(enabled)));
+
+ return NO_ERROR;
+}
+
+status_t AudioFlingerClientAdapter::supportsBluetoothVariableLatency(bool* support) {
+ if (support == nullptr) {
+ return BAD_VALUE;
+ }
+
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mDelegate->supportsBluetoothVariableLatency(support)));
return NO_ERROR;
}
@@ -856,6 +878,14 @@
return statusTFromBinderStatus(mDelegate->getSoundDoseInterface(callback, soundDose));
}
+status_t AudioFlingerClientAdapter::invalidateTracks(
+ const std::vector<audio_port_handle_t>& portIds) {
+ std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<int32_t>>(
+ portIds, legacy2aidl_audio_port_handle_t_int32_t));
+ return statusTFromBinderStatus(mDelegate->invalidateTracks(portIdsAidl));
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////
// AudioFlingerServerAdapter
AudioFlingerServerAdapter::AudioFlingerServerAdapter(
@@ -1088,12 +1118,6 @@
return Status::fromStatusT(mDelegate->closeInput(inputLegacy));
}
-Status AudioFlingerServerAdapter::invalidateStream(AudioStreamType stream) {
- audio_stream_type_t streamLegacy = VALUE_OR_RETURN_BINDER(
- aidl2legacy_AudioStreamType_audio_stream_type_t(stream));
- return Status::fromStatusT(mDelegate->invalidateStream(streamLegacy));
-}
-
Status AudioFlingerServerAdapter::setVoiceVolume(float volume) {
return Status::fromStatusT(mDelegate->setVoiceVolume(volume));
}
@@ -1230,17 +1254,17 @@
return Status::fromStatusT(mDelegate->setLowRamDevice(isLowRamDevice, totalMemory));
}
-Status AudioFlingerServerAdapter::getAudioPort(const media::AudioPort& port,
- media::AudioPort* _aidl_return) {
- audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPort_audio_port_v7(port));
+Status AudioFlingerServerAdapter::getAudioPort(const media::AudioPortFw& port,
+ media::AudioPortFw* _aidl_return) {
+ audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPortFw_audio_port_v7(port));
RETURN_BINDER_IF_ERROR(mDelegate->getAudioPort(&portLegacy));
- *_aidl_return = VALUE_OR_RETURN_BINDER(legacy2aidl_audio_port_v7_AudioPort(portLegacy));
+ *_aidl_return = VALUE_OR_RETURN_BINDER(legacy2aidl_audio_port_v7_AudioPortFw(portLegacy));
return Status::ok();
}
-Status AudioFlingerServerAdapter::createAudioPatch(const media::AudioPatch& patch,
+Status AudioFlingerServerAdapter::createAudioPatch(const media::AudioPatchFw& patch,
int32_t* _aidl_return) {
- audio_patch patchLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPatch_audio_patch(patch));
+ audio_patch patchLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPatchFw_audio_patch(patch));
audio_patch_handle_t handleLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_int32_t_audio_patch_handle_t(*_aidl_return));
RETURN_BINDER_IF_ERROR(mDelegate->createAudioPatch(&patchLegacy, &handleLegacy));
@@ -1255,7 +1279,7 @@
}
Status AudioFlingerServerAdapter::listAudioPatches(int32_t maxCount,
- std::vector<media::AudioPatch>* _aidl_return) {
+ std::vector<media::AudioPatchFw>* _aidl_return) {
unsigned int count = VALUE_OR_RETURN_BINDER(convertIntegral<unsigned int>(maxCount));
count = std::min(count, static_cast<unsigned int>(MAX_ITEMS_PER_LIST));
std::unique_ptr<audio_patch[]> patchesLegacy(new audio_patch[count]);
@@ -1263,13 +1287,13 @@
RETURN_BINDER_IF_ERROR(convertRange(&patchesLegacy[0],
&patchesLegacy[count],
std::back_inserter(*_aidl_return),
- legacy2aidl_audio_patch_AudioPatch));
+ legacy2aidl_audio_patch_AudioPatchFw));
return Status::ok();
}
-Status AudioFlingerServerAdapter::setAudioPortConfig(const media::AudioPortConfig& config) {
+Status AudioFlingerServerAdapter::setAudioPortConfig(const media::AudioPortConfigFw& config) {
audio_port_config configLegacy = VALUE_OR_RETURN_BINDER(
- aidl2legacy_AudioPortConfig_audio_port_config(config));
+ aidl2legacy_AudioPortConfigFw_audio_port_config(config));
return Status::fromStatusT(mDelegate->setAudioPortConfig(&configLegacy));
}
@@ -1347,23 +1371,23 @@
}
Status AudioFlingerServerAdapter::setDeviceConnectedState(
- const media::AudioPort& port, bool connected) {
- audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPort_audio_port_v7(port));
+ const media::AudioPortFw& port, bool connected) {
+ audio_port_v7 portLegacy = VALUE_OR_RETURN_BINDER(aidl2legacy_AudioPortFw_audio_port_v7(port));
return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
}
Status AudioFlingerServerAdapter::setRequestedLatencyMode(
- int32_t output, media::LatencyMode modeAidl) {
+ int32_t output, media::audio::common::AudioLatencyMode modeAidl) {
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_int32_t_audio_io_handle_t(output));
audio_latency_mode_t modeLegacy = VALUE_OR_RETURN_BINDER(
- aidl2legacy_LatencyMode_audio_latency_mode_t(modeAidl));
+ aidl2legacy_AudioLatencyMode_audio_latency_mode_t(modeAidl));
return Status::fromStatusT(mDelegate->setRequestedLatencyMode(
outputLegacy, modeLegacy));
}
Status AudioFlingerServerAdapter::getSupportedLatencyModes(
- int output, std::vector<media::LatencyMode>* _aidl_return) {
+ int output, std::vector<media::audio::common::AudioLatencyMode>* _aidl_return) {
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_int32_t_audio_io_handle_t(output));
std::vector<audio_latency_mode_t> modesLegacy;
@@ -1371,11 +1395,23 @@
RETURN_BINDER_IF_ERROR(mDelegate->getSupportedLatencyModes(outputLegacy, &modesLegacy));
*_aidl_return = VALUE_OR_RETURN_BINDER(
- convertContainer<std::vector<media::LatencyMode>>(
- modesLegacy, legacy2aidl_audio_latency_mode_t_LatencyMode));
+ convertContainer<std::vector<media::audio::common::AudioLatencyMode>>(
+ modesLegacy, legacy2aidl_audio_latency_mode_t_AudioLatencyMode));
return Status::ok();
}
+Status AudioFlingerServerAdapter::setBluetoothVariableLatencyEnabled(bool enabled) {
+ return Status::fromStatusT(mDelegate->setBluetoothVariableLatencyEnabled(enabled));
+}
+
+Status AudioFlingerServerAdapter::isBluetoothVariableLatencyEnabled(bool *enabled) {
+ return Status::fromStatusT(mDelegate->isBluetoothVariableLatencyEnabled(enabled));
+}
+
+Status AudioFlingerServerAdapter::supportsBluetoothVariableLatency(bool *support) {
+ return Status::fromStatusT(mDelegate->supportsBluetoothVariableLatency(support));
+}
+
Status AudioFlingerServerAdapter::getSoundDoseInterface(
const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose)
@@ -1383,4 +1419,12 @@
return Status::fromStatusT(mDelegate->getSoundDoseInterface(callback, soundDose));
}
+Status AudioFlingerServerAdapter::invalidateTracks(const std::vector<int32_t>& portIds) {
+ std::vector<audio_port_handle_t> portIdsLegacy = VALUE_OR_RETURN_BINDER(
+ convertContainer<std::vector<audio_port_handle_t>>(
+ portIds, aidl2legacy_int32_t_audio_port_handle_t));
+ RETURN_BINDER_IF_ERROR(mDelegate->invalidateTracks(portIdsLegacy));
+ return Status::ok();
+}
+
} // namespace android
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index f968a4b..f0b4d11 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1027,7 +1027,7 @@
if (property_get("gsm.operator.iso-country", value, "") == 0) {
property_get("gsm.sim.operator.iso-country", value, "");
}
- // If dual sim device has two SIM cards inserted and is not registerd to any network,
+ // If dual sim device has two SIM cards inserted and is not registered to any network,
// "," is set to "gsm.operator.iso-country" prop.
// In this case, "gsm.sim.operator.iso-country" prop should be used.
if (strlen(value) == 1 && strstr(value, ",") != NULL) {
diff --git a/media/libaudioclient/aidl/android/media/AudioDualMonoMode.aidl b/media/libaudioclient/aidl/android/media/AudioDualMonoMode.aidl
deleted file mode 100644
index f6220c2..0000000
--- a/media/libaudioclient/aidl/android/media/AudioDualMonoMode.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2020 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.media;
-
-// TODO(b/175167149): Reconcile AudioDualMonoMode with framework-media-sources
-
-@Backing(type="int")
-enum AudioDualMonoMode {
- OFF = 0,
- LR = 1,
- LL = 2,
- RR = 3,
-}
diff --git a/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl b/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl
index b01f902..5dd898c 100644
--- a/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioIoDescriptor.aidl
@@ -16,7 +16,7 @@
package android.media;
-import android.media.AudioPatch;
+import android.media.AudioPatchFw;
import android.media.audio.common.AudioChannelLayout;
import android.media.audio.common.AudioFormatDescription;
@@ -26,7 +26,7 @@
parcelable AudioIoDescriptor {
/** Interpreted as audio_io_handle_t. */
int ioHandle;
- AudioPatch patch;
+ AudioPatchFw patch;
boolean isInput;
int samplingRate;
AudioFormatDescription format;
diff --git a/media/libaudioclient/aidl/android/media/AudioPatch.aidl b/media/libaudioclient/aidl/android/media/AudioPatchFw.aidl
similarity index 74%
rename from media/libaudioclient/aidl/android/media/AudioPatch.aidl
rename to media/libaudioclient/aidl/android/media/AudioPatchFw.aidl
index 8519faf..9ec3fa9 100644
--- a/media/libaudioclient/aidl/android/media/AudioPatch.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPatchFw.aidl
@@ -16,17 +16,19 @@
package android.media;
-import android.media.AudioPortConfig;
+import android.media.AudioPortConfigFw;
/**
* {@hide}
+ * The Fw suffix is used to break a namespace collision with an SDK API.
+ * It contains the framework version of AudioPortConfig.
*/
-parcelable AudioPatch {
+parcelable AudioPatchFw {
/**
* Patch unique ID.
* Interpreted as audio_patch_handle_t.
*/
int id;
- AudioPortConfig[] sources;
- AudioPortConfig[] sinks;
+ AudioPortConfigFw[] sources;
+ AudioPortConfigFw[] sinks;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPlaybackRate.aidl b/media/libaudioclient/aidl/android/media/AudioPlaybackRate.aidl
deleted file mode 100644
index e29d398..0000000
--- a/media/libaudioclient/aidl/android/media/AudioPlaybackRate.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2020 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.media;
-
-/**
- * The AudioPlaybackRate.
- *
- * See https://developer.android.com/reference/android/media/PlaybackParams.
- * TODO(b/175166815): Reconcile with framework-media-sources PlaybackParams.aidl.
- * As this is used for native wire serialization, no need to define
- * audio_timestretch_stretch_mode_t and audio_timestretch_fallback_mode_t enums
- * until we attempt to unify with PlaybackParams.
- *
- * {@hide}
- */
-parcelable AudioPlaybackRate {
- /** Speed of audio playback, >= 0.f, 1.f nominal (system limits are further restrictive) */
- float speed;
- /** Pitch of audio, >= 0.f, 1.f nominal (system limits are further restrictive) */
- float pitch;
- /** Interpreted as audio_timestretch_stretch_mode_t */
- int stretchMode;
- /** Interpreted as audio_timestretch_fallback_mode_t */
- int fallbackMode;
-}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigFw.aidl
similarity index 89%
rename from media/libaudioclient/aidl/android/media/AudioPortConfig.aidl
rename to media/libaudioclient/aidl/android/media/AudioPortConfigFw.aidl
index 3a4ca31..e7565d7 100644
--- a/media/libaudioclient/aidl/android/media/AudioPortConfig.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigFw.aidl
@@ -21,8 +21,9 @@
/**
* {@hide}
+ * Suffixed with Fw to avoid name conflict with SDK class.
*/
-parcelable AudioPortConfig {
+parcelable AudioPortConfigFw {
AudioPortConfig hal;
AudioPortConfigSys sys;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPort.aidl b/media/libaudioclient/aidl/android/media/AudioPortFw.aidl
similarity index 88%
rename from media/libaudioclient/aidl/android/media/AudioPort.aidl
rename to media/libaudioclient/aidl/android/media/AudioPortFw.aidl
index ff177c0..5580e35 100644
--- a/media/libaudioclient/aidl/android/media/AudioPort.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortFw.aidl
@@ -21,8 +21,9 @@
/**
* {@hide}
+ * The Fw suffix is used to break a namespace collision with an SDK API.
*/
-parcelable AudioPort {
+parcelable AudioPortFw {
AudioPort hal;
AudioPortSys sys;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortSys.aidl b/media/libaudioclient/aidl/android/media/AudioPortSys.aidl
index f3b5c19..756c469 100644
--- a/media/libaudioclient/aidl/android/media/AudioPortSys.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortSys.aidl
@@ -17,7 +17,7 @@
package android.media;
import android.media.AudioGainSys;
-import android.media.AudioPortConfig;
+import android.media.AudioPortConfigFw;
import android.media.AudioPortExtSys;
import android.media.AudioPortRole;
import android.media.AudioPortType;
@@ -36,7 +36,7 @@
/** System-only parameters for each AudioGain from 'port.gains'. */
AudioGainSys[] gains;
/** Current audio port configuration. */
- AudioPortConfig activeConfig;
+ AudioPortConfigFw activeConfig;
/** System-only extra parameters for 'port.ext'. */
AudioPortExtSys ext;
}
diff --git a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
index 385f787..9d44bb0 100644
--- a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
@@ -18,7 +18,7 @@
import android.media.audio.common.AudioConfigBase;
import android.media.audio.common.AudioStreamType;
-
+import android.media.AudioAttributesInternal;
/**
* {@hide}
*/
@@ -37,4 +37,6 @@
/** The suggested audio config if fails to get an output. **/
AudioConfigBase configBase;
boolean isBitPerfect;
+ /** The corrected audio attributes. **/
+ AudioAttributesInternal attr;
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
index a2bb024..f055cc4 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerClient.aidl
@@ -18,7 +18,7 @@
import android.media.AudioIoConfigEvent;
import android.media.AudioIoDescriptor;
-import android.media.LatencyMode;
+import android.media.audio.common.AudioLatencyMode;
/**
* A callback interface for AudioFlinger.
@@ -31,7 +31,8 @@
/**
* Called when the latency modes supported on a given output stream change.
* output is the I/O handle of the output stream for which the change is signalled.
- * latencyModes is the new list of supported latency modes (See LatencyMode.aidl).
+ * latencyModes is the new list of supported latency modes (See AudioLatencyMode.aidl).
*/
- oneway void onSupportedLatencyModesChanged(int output, in LatencyMode[] latencyModes);
+ oneway void onSupportedLatencyModesChanged(
+ int output, in AudioLatencyMode[] latencyModes);
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 4383b9e..69810c0 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -16,9 +16,9 @@
package android.media;
-import android.media.AudioPatch;
-import android.media.AudioPort;
-import android.media.AudioPortConfig;
+import android.media.AudioPatchFw;
+import android.media.AudioPortFw;
+import android.media.AudioPortConfigFw;
import android.media.AudioUniqueIdUse;
import android.media.AudioVibratorInfo;
import android.media.CreateEffectRequest;
@@ -37,12 +37,12 @@
import android.media.IAudioTrack;
import android.media.ISoundDose;
import android.media.ISoundDoseCallback;
-import android.media.LatencyMode;
import android.media.MicrophoneInfoData;
import android.media.RenderPosition;
import android.media.TrackSecondaryOutputInfo;
import android.media.audio.common.AudioChannelLayout;
import android.media.audio.common.AudioFormatDescription;
+import android.media.audio.common.AudioLatencyMode;
import android.media.audio.common.AudioMMapPolicyInfo;
import android.media.audio.common.AudioMMapPolicyType;
import android.media.audio.common.AudioMode;
@@ -134,8 +134,6 @@
OpenInputResponse openInput(in OpenInputRequest request);
void closeInput(int /* audio_io_handle_t */ input);
- void invalidateStream(AudioStreamType stream);
-
void setVoiceVolume(float volume);
RenderPosition getRenderPosition(int /* audio_io_handle_t */ output);
@@ -184,18 +182,18 @@
void setLowRamDevice(boolean isLowRamDevice, long totalMemory);
/* Get attributes for a given audio port */
- AudioPort getAudioPort(in AudioPort port);
+ AudioPortFw getAudioPort(in AudioPortFw port);
/* Create an audio patch between several source and sink ports */
- int /* audio_patch_handle_t */ createAudioPatch(in AudioPatch patch);
+ int /* audio_patch_handle_t */ createAudioPatch(in AudioPatchFw patch);
/* Release an audio patch */
void releaseAudioPatch(int /* audio_patch_handle_t */ handle);
/* List existing audio patches */
- AudioPatch[] listAudioPatches(int maxCount);
+ AudioPatchFw[] listAudioPatches(int maxCount);
/* Set audio port configuration */
- void setAudioPortConfig(in AudioPortConfig config);
+ void setAudioPortConfig(in AudioPortConfigFw config);
/* Get the HW synchronization source used for an audio session */
int /* audio_hw_sync_t */ getAudioHwSyncForSession(int /* audio_session_t */ sessionId);
@@ -229,24 +227,44 @@
int getAAudioHardwareBurstMinUsec();
- void setDeviceConnectedState(in AudioPort devicePort, boolean connected);
+ void setDeviceConnectedState(in AudioPortFw devicePort, boolean connected);
/**
- * Requests a given latency mode (See LatencyMode.aidl) on an output stream.
+ * Requests a given latency mode (See AudioLatencyMode.aidl) on an output stream.
* This can be used when some use case on a given mixer/stream can only be enabled
* if a specific latency mode is selected on the audio path below the HAL.
* For instance spatial audio with head tracking.
* output is the I/O handle of the output stream for which the request is made.
* latencyMode is the requested latency mode.
*/
- void setRequestedLatencyMode(int output, LatencyMode latencyMode);
+ void setRequestedLatencyMode(int output, AudioLatencyMode latencyMode);
/**
* Queries the list of latency modes (See LatencyMode.aidl) supported by an output stream.
* output is the I/O handle of the output stream to which the query applies.
* returns the list of supported latency modes.
*/
- LatencyMode[] getSupportedLatencyModes(int output);
+ AudioLatencyMode[] getSupportedLatencyModes(int output);
+
+ /**
+ * Requests if the implementation supports controlling the latency modes
+ * over the Bluetooth A2DP or LE Audio links. If it does,
+ * setRequestedLatencyMode() and getSupportedLatencyModes() APIs can also be used
+ * for streams routed to Bluetooth and not just for the spatializer output.
+ */
+ boolean supportsBluetoothVariableLatency();
+
+ /**
+ * Enables or disables the variable Bluetooth latency control mechanism in the
+ * audio framework and the audio HAL. This does not apply to the latency mode control
+ * on the spatializer output as this is a built-in feature.
+ */
+ void setBluetoothVariableLatencyEnabled(boolean enabled);
+
+ /**
+ * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled.
+ */
+ boolean isBluetoothVariableLatencyEnabled();
/**
* Registers the sound dose callback and returns the interface for executing
@@ -254,6 +272,11 @@
*/
ISoundDose getSoundDoseInterface(in ISoundDoseCallback callback);
+ /**
+ * Invalidate all tracks with given port ids.
+ */
+ void invalidateTracks(in int[] /* audio_port_handle_t[] */ portIds);
+
// When adding a new method, please review and update
// IAudioFlinger.h AudioFlingerServerAdapter::Delegate::TransactionCode
// AudioFlinger.cpp AudioFlinger::onTransactWrapper()
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index e0db8f9..fa6c733 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -24,12 +24,12 @@
import android.media.AudioMix;
import android.media.AudioMixerAttributesInternal;
import android.media.AudioOffloadMode;
-import android.media.AudioPatch;
+import android.media.AudioPatchFw;
import android.media.AudioPolicyDeviceState;
import android.media.AudioPolicyForcedConfig;
import android.media.AudioPolicyForceUse;
-import android.media.AudioPort;
-import android.media.AudioPortConfig;
+import android.media.AudioPortFw;
+import android.media.AudioPortConfigFw;
import android.media.AudioPortRole;
import android.media.AudioPortType;
import android.media.AudioProductStrategy;
@@ -213,16 +213,16 @@
int listAudioPorts(AudioPortRole role,
AudioPortType type,
inout Int count,
- out AudioPort[] ports);
+ out AudioPortFw[] ports);
/** Get attributes for the audio port with the given id (AudioPort.hal.id field). */
- AudioPort getAudioPort(int /* audio_port_handle_t */ portId);
+ AudioPortFw getAudioPort(int /* audio_port_handle_t */ portId);
/**
* Create an audio patch between several source and sink ports.
* The handle argument is used when updating an existing patch.
*/
- int /* audio_patch_handle_t */ createAudioPatch(in AudioPatch patch, int handle);
+ int /* audio_patch_handle_t */ createAudioPatch(in AudioPatchFw patch, int handle);
/** Release an audio patch. */
void releaseAudioPatch(int /* audio_patch_handle_t */ handle);
@@ -235,10 +235,10 @@
* Passing '0' on input and inspecting the value on output is a common way of determining the
* number of elements without actually retrieving them.
*/
- int listAudioPatches(inout Int count, out AudioPatch[] patches);
+ int listAudioPatches(inout Int count, out AudioPatchFw[] patches);
/** Set audio port configuration. */
- void setAudioPortConfig(in AudioPortConfig config);
+ void setAudioPortConfig(in AudioPortConfigFw config);
void registerClient(IAudioPolicyServiceClient client);
@@ -262,7 +262,7 @@
void removeUserIdDeviceAffinities(int userId);
- int /* audio_port_handle_t */ startAudioSource(in AudioPortConfig source,
+ int /* audio_port_handle_t */ startAudioSource(in AudioPortConfigFw source,
in AudioAttributesInternal attributes);
void stopAudioSource(int /* audio_port_handle_t */ portId);
@@ -313,6 +313,15 @@
boolean isUltrasoundSupported();
+ /**
+ * Queries if there is hardware support for requesting audio capture content from
+ * the DSP hotword pipeline.
+ *
+ * @param lookbackAudio true if additionally querying for the ability to capture audio
+ * from the pipeline prior to capture stream open.
+ */
+ boolean isHotwordStreamSupported(boolean lookbackAudio);
+
AudioProductStrategy[] listAudioProductStrategies();
int /* product_strategy_t */ getProductStrategyFromAudioAttributes(
in AudioAttributesInternal aa, boolean fallbackOnDefault);
@@ -330,7 +339,10 @@
in AudioDevice[] devices);
void removeDevicesRoleForStrategy(int /* product_strategy_t */ strategy,
- DeviceRole role);
+ DeviceRole role,
+ in AudioDevice[] devices);
+
+ void clearDevicesRoleForStrategy(int /* product_strategy_t */ strategy, DeviceRole role);
AudioDevice[] getDevicesForRoleAndStrategy(int /* product_strategy_t */ strategy,
DeviceRole role);
diff --git a/media/libaudioclient/aidl/android/media/IAudioTrack.aidl b/media/libaudioclient/aidl/android/media/IAudioTrack.aidl
index ac58925..c3a2dbe 100644
--- a/media/libaudioclient/aidl/android/media/IAudioTrack.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioTrack.aidl
@@ -16,13 +16,13 @@
package android.media;
-import android.media.AudioDualMonoMode;
-import android.media.AudioPlaybackRate;
import android.media.AudioTimestampInternal;
import android.media.SharedFileRegion;
import android.media.VolumeShaperConfiguration;
import android.media.VolumeShaperOperation;
import android.media.VolumeShaperState;
+import android.media.audio.common.AudioDualMonoMode;
+import android.media.audio.common.AudioPlaybackRate;
/**
* Unless otherwise noted, methods returning int expect it to be interpreted as a status_t.
diff --git a/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl b/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
index 3b2206a..3ec6e7a 100644
--- a/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
+++ b/media/libaudioclient/aidl/android/media/ICaptureStateListener.aidl
@@ -19,6 +19,6 @@
/**
* {@hide}
*/
-interface ICaptureStateListener {
+oneway interface ICaptureStateListener {
void setCaptureState(boolean active);
}
diff --git a/media/libaudioclient/aidl/android/media/ISoundDose.aidl b/media/libaudioclient/aidl/android/media/ISoundDose.aidl
index f31f091..7310160 100644
--- a/media/libaudioclient/aidl/android/media/ISoundDose.aidl
+++ b/media/libaudioclient/aidl/android/media/ISoundDose.aidl
@@ -22,9 +22,9 @@
* Interface used to push the sound dose related information from the
* AudioService#SoundDoseHelper to the audio server
*/
-oneway interface ISoundDose {
+interface ISoundDose {
/** Set a new RS2 value used for momentary exposure warnings. */
- void setOutputRs2(float rs2Value);
+ oneway void setOutputRs2(float rs2Value);
/**
* Resets the native CSD values. This can happen after a crash in the
@@ -33,5 +33,15 @@
* dosage values and MELs together with their timestamps that lead to this
* CSD.
*/
- void resetCsd(float currentCsd, in SoundDoseRecord[] records);
+ oneway void resetCsd(float currentCsd, in SoundDoseRecord[] records);
+
+ /* -------------------------- Test API methods --------------------------
+ /** Get the currently used RS2 value. */
+ float getOutputRs2();
+ /** Get the current CSD from audioserver. */
+ float getCsd();
+ /** Enables/Disables MEL computations from framework. */
+ oneway void forceUseFrameworkMel(boolean useFrameworkMel);
+ /** Enables/Disables the computation of CSD on all devices. */
+ oneway void forceComputeCsdOnAllDevices(boolean computeCsdOnAllDevices);
}
diff --git a/media/libaudioclient/aidl/android/media/LatencyMode.aidl b/media/libaudioclient/aidl/android/media/LatencyMode.aidl
deleted file mode 100644
index 0b2a72b..0000000
--- a/media/libaudioclient/aidl/android/media/LatencyMode.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright 2021 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.media;
-
-/**
- * The latency mode currently used by the spatializer mixer.
- * {@hide}
- */
-@Backing(type="byte")
-enum LatencyMode {
- /** No specific constraint on the latency */
- FREE = 0,
- /** A relatively low latency compatible with head tracking operation (e.g less than 100ms) */
- LOW = 1,
-}
diff --git a/media/libaudioclient/aidl/android/media/OpenOutputRequest.aidl b/media/libaudioclient/aidl/android/media/OpenOutputRequest.aidl
index 90e7ea6..ddda8bb 100644
--- a/media/libaudioclient/aidl/android/media/OpenOutputRequest.aidl
+++ b/media/libaudioclient/aidl/android/media/OpenOutputRequest.aidl
@@ -16,7 +16,7 @@
package android.media;
-import android.media.AudioPort;
+import android.media.AudioPortFw;
import android.media.audio.common.AudioConfig;
import android.media.audio.common.AudioConfigBase;
@@ -29,7 +29,7 @@
AudioConfig halConfig;
AudioConfigBase mixerConfig;
/** Type must be DEVICE. */
- AudioPort device;
+ AudioPortFw device;
/** Bitmask, indexed by AudioOutputFlag. */
int flags;
}
diff --git a/media/libaudioclient/aidl/android/media/SoundDoseRecord.aidl b/media/libaudioclient/aidl/android/media/SoundDoseRecord.aidl
index 94b8ce2..1397e23 100644
--- a/media/libaudioclient/aidl/android/media/SoundDoseRecord.aidl
+++ b/media/libaudioclient/aidl/android/media/SoundDoseRecord.aidl
@@ -17,6 +17,7 @@
package android.media;
/** Record containing information about the computed sound dose. */
+@JavaDerive(toString = true)
parcelable SoundDoseRecord {
/**
* Corresponds to the time in seconds when the CSD value is calculated from.
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index dd3e3ba..b1feb60 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -56,6 +56,7 @@
"av-types-aidl-cpp",
"capture_state_listener-aidl-cpp",
"libaudioclient_aidl_conversion",
+ "libaudio_aidl_conversion_common_cpp",
"libaudioflinger",
"libaudiofoundation",
"libaudiomanager",
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index 5536bcb..47fe0f6 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -584,7 +584,12 @@
float balance = mFdp.ConsumeFloatingPoint<float>();
af->getMasterBalance(&balance);
- af->invalidateStream(static_cast<audio_stream_type_t>(mFdp.ConsumeIntegral<uint32_t>()));
+
+ std::vector<audio_port_handle_t> tracks;
+ for (int i = 0; i < mFdp.ConsumeIntegralInRange<int32_t>(0, MAX_ARRAY_LENGTH); ++i) {
+ tracks.push_back(static_cast<audio_port_handle_t>(mFdp.ConsumeIntegral<int32_t>()));
+ }
+ af->invalidateTracks(tracks);
}
status_t AudioFlingerFuzzer::invokeAudioInputDevice() {
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index afcb61a..f0e58ae 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -24,18 +24,15 @@
#include <android/media/AudioAttributesInternal.h>
#include <android/media/AudioClient.h>
#include <android/media/AudioDirectMode.h>
-#include <android/media/AudioDualMonoMode.h>
#include <android/media/AudioFlag.h>
#include <android/media/AudioIoConfigEvent.h>
#include <android/media/AudioIoDescriptor.h>
-#include <android/media/AudioPlaybackRate.h>
-#include <android/media/AudioPort.h>
-#include <android/media/AudioPortConfig.h>
+#include <android/media/AudioPortFw.h>
+#include <android/media/AudioPortConfigFw.h>
#include <android/media/AudioPortDeviceExtSys.h>
#include <android/media/AudioTimestampInternal.h>
#include <android/media/AudioUniqueIdUse.h>
#include <android/media/EffectDescriptor.h>
-#include <android/media/LatencyMode.h>
#include <android/media/TrackSecondaryOutputInfo.h>
#include <android/media/SharedFileRegion.h>
@@ -91,14 +88,15 @@
ConversionResult<int32_t> legacy2aidl_audio_port_config_session_ext_AudioPortConfigSessionExt(
const audio_port_config_session_ext& legacy);
-ConversionResult<audio_port_config> aidl2legacy_AudioPortConfig_audio_port_config(
- const media::AudioPortConfig& aidl);
-ConversionResult<media::AudioPortConfig> legacy2aidl_audio_port_config_AudioPortConfig(
- const audio_port_config& legacy);
+// portId needs to be set when dealing with the HAL.
+ConversionResult<audio_port_config> aidl2legacy_AudioPortConfigFw_audio_port_config(
+ const media::AudioPortConfigFw& aidl, int32_t* aidlPortId = nullptr);
+ConversionResult<media::AudioPortConfigFw> legacy2aidl_audio_port_config_AudioPortConfigFw(
+ const audio_port_config& legacy, int32_t portId = 0);
-ConversionResult<struct audio_patch> aidl2legacy_AudioPatch_audio_patch(
- const media::AudioPatch& aidl);
-ConversionResult<media::AudioPatch> legacy2aidl_audio_patch_AudioPatch(
+ConversionResult<struct audio_patch> aidl2legacy_AudioPatchFw_audio_patch(
+ const media::AudioPatchFw& aidl);
+ConversionResult<media::AudioPatchFw> legacy2aidl_audio_patch_AudioPatchFw(
const struct audio_patch& legacy);
ConversionResult<sp<AudioIoDescriptor>> aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(
@@ -170,9 +168,9 @@
legacy2aidl_audio_port_session_ext_int32_t(const audio_port_session_ext& legacy);
ConversionResult<audio_port_v7>
-aidl2legacy_AudioPort_audio_port_v7(const media::AudioPort& aidl);
-ConversionResult<media::AudioPort>
-legacy2aidl_audio_port_v7_AudioPort(const audio_port_v7& legacy);
+aidl2legacy_AudioPortFw_audio_port_v7(const media::AudioPortFw& aidl);
+ConversionResult<media::AudioPortFw>
+legacy2aidl_audio_port_v7_AudioPortFw(const audio_port_v7& legacy);
ConversionResult<audio_unique_id_use_t>
aidl2legacy_AudioUniqueIdUse_audio_unique_id_use_t(media::AudioUniqueIdUse aidl);
@@ -184,26 +182,6 @@
ConversionResult<int32_t>
legacy2aidl_volume_group_t_int32_t(volume_group_t legacy);
-ConversionResult<audio_dual_mono_mode_t>
-aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(media::AudioDualMonoMode aidl);
-ConversionResult<media::AudioDualMonoMode>
-legacy2aidl_audio_dual_mono_mode_t_AudioDualMonoMode(audio_dual_mono_mode_t legacy);
-
-ConversionResult<audio_timestretch_fallback_mode_t>
-aidl2legacy_int32_t_audio_timestretch_fallback_mode_t(int32_t aidl);
-ConversionResult<int32_t>
-legacy2aidl_audio_timestretch_fallback_mode_t_int32_t(audio_timestretch_fallback_mode_t legacy);
-
-ConversionResult<audio_timestretch_stretch_mode_t>
-aidl2legacy_int32_t_audio_timestretch_stretch_mode_t(int32_t aidl);
-ConversionResult<int32_t>
-legacy2aidl_audio_timestretch_stretch_mode_t_int32_t(audio_timestretch_stretch_mode_t legacy);
-
-ConversionResult<audio_playback_rate_t>
-aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(const media::AudioPlaybackRate& aidl);
-ConversionResult<media::AudioPlaybackRate>
-legacy2aidl_audio_playback_rate_t_AudioPlaybackRate(const audio_playback_rate_t& legacy);
-
using TrackSecondaryOutputInfoPair = std::pair<audio_port_handle_t, std::vector<audio_io_handle_t>>;
ConversionResult<TrackSecondaryOutputInfoPair>
aidl2legacy_TrackSecondaryOutputInfo_TrackSecondaryOutputInfoPair(
@@ -220,9 +198,4 @@
ConversionResult<audio_direct_mode_t> aidl2legacy_int32_t_audio_direct_mode_t_mask(int32_t aidl);
ConversionResult<int32_t> legacy2aidl_audio_direct_mode_t_int32_t_mask(audio_direct_mode_t legacy);
-ConversionResult<audio_latency_mode_t>
-aidl2legacy_LatencyMode_audio_latency_mode_t(media::LatencyMode aidl);
-ConversionResult<media::LatencyMode>
-legacy2aidl_audio_latency_mode_t_LatencyMode(audio_latency_mode_t legacy);
-
} // namespace android
diff --git a/media/libaudioclient/include/media/AudioCommonTypes.h b/media/libaudioclient/include/media/AudioCommonTypes.h
index 862a0f9..2567542 100644
--- a/media/libaudioclient/include/media/AudioCommonTypes.h
+++ b/media/libaudioclient/include/media/AudioCommonTypes.h
@@ -94,6 +94,7 @@
using AttributesVector = std::vector<audio_attributes_t>;
using StreamTypeVector = std::vector<audio_stream_type_t>;
+using PortHandleVector = std::vector<audio_port_handle_t>;
using TrackSecondaryOutputsMap = std::map<audio_port_handle_t, std::vector<audio_io_handle_t>>;
diff --git a/media/libaudioclient/include/media/AudioPolicy.h b/media/libaudioclient/include/media/AudioPolicy.h
index 61f2069..3fd438e 100644
--- a/media/libaudioclient/include/media/AudioPolicy.h
+++ b/media/libaudioclient/include/media/AudioPolicy.h
@@ -61,7 +61,10 @@
#define MIX_ROUTE_FLAG_LOOP_BACK (0x1 << 1)
/** Loop back some audio while it is rendered */
#define MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK)
-#define MIX_ROUTE_FLAG_ALL (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK)
+/** Control if audio routing disallows preferred device routing **/
+#define MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE (0x1 << 2)
+#define MIX_ROUTE_FLAG_ALL (MIX_ROUTE_FLAG_RENDER | MIX_ROUTE_FLAG_LOOP_BACK | \
+ MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE)
#define MAX_MIXES_PER_POLICY 10
#define MAX_CRITERIA_PER_MIX 20
@@ -112,9 +115,9 @@
void setMatchUserId(int userId);
/** returns true if this mix has a rule to match or exclude the given userId */
bool hasUserIdRule(bool match, int userId) const;
- /** returns true if this mix has a rule for userId match (any userId) */
- bool hasMatchUserIdRule() const;
- /** returns true if this mix can be used for uid-device affinity routing */
+ /** returns true if this mix has a rule to match or exclude (any userId) */
+ bool hasUserIdRule(bool match) const;
+ /** returns true if this mix has a rule for userId exclude (any userId) */
bool isDeviceAffinityCompatible() const;
std::vector<AudioMixMatchCriterion> mCriteria;
@@ -147,6 +150,11 @@
== MIX_ROUTE_FLAG_LOOP_BACK;
}
+static inline bool is_mix_disallows_preferred_device(uint32_t routeFlags) {
+ return (routeFlags & MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE)
+ == MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
+}
+
}; // namespace android
#endif // ANDROID_AUDIO_POLICY_H
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index e04b82e..23b0340 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -167,6 +167,10 @@
// HotwordDetectionService.
static void setAudioFlingerBinder(const sp<IBinder>& audioFlinger);
+ // Sets a local AudioFlinger interface to be used by AudioSystem.
+ // This is used by audioserver main() to avoid binder AIDL translation.
+ static status_t setLocalAudioFlinger(const sp<IAudioFlinger>& af);
+
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
@@ -523,7 +527,11 @@
static status_t setDevicesRoleForStrategy(product_strategy_t strategy,
device_role_t role, const AudioDeviceTypeAddrVector &devices);
- static status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role);
+ static status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role, const AudioDeviceTypeAddrVector &devices);
+
+ static status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role);
static status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
device_role_t role, AudioDeviceTypeAddrVector &devices);
@@ -629,6 +637,12 @@
static status_t getSupportedLatencyModes(audio_io_handle_t output,
std::vector<audio_latency_mode_t>* modes);
+ static status_t setBluetoothVariableLatencyEnabled(bool enabled);
+
+ static status_t isBluetoothVariableLatencyEnabled(bool *enabled);
+
+ static status_t supportsBluetoothVariableLatency(bool *support);
+
static status_t getSupportedMixerAttributes(audio_port_handle_t portId,
std::vector<audio_mixer_attributes_t> *mixerAttrs);
static status_t setPreferredMixerAttributes(const audio_attributes_t *attr,
@@ -772,7 +786,8 @@
const media::AudioIoDescriptor& ioDesc) override;
binder::Status onSupportedLatencyModesChanged(
- int output, const std::vector<media::LatencyMode>& latencyModes) override;
+ int output,
+ const std::vector<media::audio::common::AudioLatencyMode>& latencyModes) override;
status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
audio_io_handle_t audioIo,
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 6c89862..6b6c407 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -268,8 +268,6 @@
virtual status_t closeInput(audio_io_handle_t input) = 0;
- virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
-
virtual status_t setVoiceVolume(float volume) = 0;
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
@@ -374,6 +372,14 @@
virtual status_t getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose) = 0;
+
+ virtual status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) = 0;
+
+ virtual status_t setBluetoothVariableLatencyEnabled(bool enabled) = 0;
+
+ virtual status_t isBluetoothVariableLatencyEnabled(bool* enabled) = 0;
+
+ virtual status_t supportsBluetoothVariableLatency(bool* support) = 0;
};
/**
@@ -428,7 +434,6 @@
status_t openInput(const media::OpenInputRequest& request,
media::OpenInputResponse* response) override;
status_t closeInput(audio_io_handle_t input) override;
- status_t invalidateStream(audio_stream_type_t stream) override;
status_t setVoiceVolume(float volume) override;
status_t getRenderPosition(uint32_t* halFrames, uint32_t* dspFrames,
audio_io_handle_t output) const override;
@@ -480,8 +485,12 @@
audio_latency_mode_t mode) override;
status_t getSupportedLatencyModes(
audio_io_handle_t output, std::vector<audio_latency_mode_t>* modes) override;
+ status_t setBluetoothVariableLatencyEnabled(bool enabled) override;
+ status_t isBluetoothVariableLatencyEnabled(bool* enabled) override;
+ status_t supportsBluetoothVariableLatency(bool* support) override;
status_t getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose) override;
+ status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
private:
const sp<media::IAudioFlingerService> mDelegate;
@@ -535,7 +544,6 @@
RESTORE_OUTPUT = media::BnAudioFlingerService::TRANSACTION_restoreOutput,
OPEN_INPUT = media::BnAudioFlingerService::TRANSACTION_openInput,
CLOSE_INPUT = media::BnAudioFlingerService::TRANSACTION_closeInput,
- INVALIDATE_STREAM = media::BnAudioFlingerService::TRANSACTION_invalidateStream,
SET_VOICE_VOLUME = media::BnAudioFlingerService::TRANSACTION_setVoiceVolume,
GET_RENDER_POSITION = media::BnAudioFlingerService::TRANSACTION_getRenderPosition,
GET_INPUT_FRAMES_LOST = media::BnAudioFlingerService::TRANSACTION_getInputFramesLost,
@@ -573,7 +581,14 @@
SET_DEVICE_CONNECTED_STATE = media::BnAudioFlingerService::TRANSACTION_setDeviceConnectedState,
SET_REQUESTED_LATENCY_MODE = media::BnAudioFlingerService::TRANSACTION_setRequestedLatencyMode,
GET_SUPPORTED_LATENCY_MODES = media::BnAudioFlingerService::TRANSACTION_getSupportedLatencyModes,
+ SET_BLUETOOTH_VARIABLE_LATENCY_ENABLED =
+ media::BnAudioFlingerService::TRANSACTION_setBluetoothVariableLatencyEnabled,
+ IS_BLUETOOTH_VARIABLE_LATENCY_ENABLED =
+ media::BnAudioFlingerService::TRANSACTION_isBluetoothVariableLatencyEnabled,
+ SUPPORTS_BLUETOOTH_VARIABLE_LATENCY =
+ media::BnAudioFlingerService::TRANSACTION_supportsBluetoothVariableLatency,
GET_SOUND_DOSE_INTERFACE = media::BnAudioFlingerService::TRANSACTION_getSoundDoseInterface,
+ INVALIDATE_TRACKS = media::BnAudioFlingerService::TRANSACTION_invalidateTracks,
};
protected:
@@ -653,7 +668,6 @@
Status openInput(const media::OpenInputRequest& request,
media::OpenInputResponse* _aidl_return) override;
Status closeInput(int32_t input) override;
- Status invalidateStream(media::audio::common::AudioStreamType stream) override;
Status setVoiceVolume(float volume) override;
Status getRenderPosition(int32_t output, media::RenderPosition* _aidl_return) override;
Status getInputFramesLost(int32_t ioHandle, int32_t* _aidl_return) override;
@@ -674,12 +688,12 @@
Status getPrimaryOutputSamplingRate(int32_t* _aidl_return) override;
Status getPrimaryOutputFrameCount(int64_t* _aidl_return) override;
Status setLowRamDevice(bool isLowRamDevice, int64_t totalMemory) override;
- Status getAudioPort(const media::AudioPort& port, media::AudioPort* _aidl_return) override;
- Status createAudioPatch(const media::AudioPatch& patch, int32_t* _aidl_return) override;
+ Status getAudioPort(const media::AudioPortFw& port, media::AudioPortFw* _aidl_return) override;
+ Status createAudioPatch(const media::AudioPatchFw& patch, int32_t* _aidl_return) override;
Status releaseAudioPatch(int32_t handle) override;
Status listAudioPatches(int32_t maxCount,
- std::vector<media::AudioPatch>* _aidl_return) override;
- Status setAudioPortConfig(const media::AudioPortConfig& config) override;
+ std::vector<media::AudioPatchFw>* _aidl_return) override;
+ Status setAudioPortConfig(const media::AudioPortConfigFw& config) override;
Status getAudioHwSyncForSession(int32_t sessionId, int32_t* _aidl_return) override;
Status systemReady() override;
Status audioPolicyReady() override;
@@ -694,12 +708,17 @@
std::vector<media::audio::common::AudioMMapPolicyInfo> *_aidl_return) override;
Status getAAudioMixerBurstCount(int32_t* _aidl_return) override;
Status getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
- Status setDeviceConnectedState(const media::AudioPort& port, bool connected) override;
- Status setRequestedLatencyMode(int output, media::LatencyMode mode) override;
+ Status setDeviceConnectedState(const media::AudioPortFw& port, bool connected) override;
+ Status setRequestedLatencyMode(
+ int output, media::audio::common::AudioLatencyMode mode) override;
Status getSupportedLatencyModes(int output,
- std::vector<media::LatencyMode>* _aidl_return) override;
+ std::vector<media::audio::common::AudioLatencyMode>* _aidl_return) override;
+ Status setBluetoothVariableLatencyEnabled(bool enabled) override;
+ Status isBluetoothVariableLatencyEnabled(bool* enabled) override;
+ Status supportsBluetoothVariableLatency(bool* support) override;
Status getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* _aidl_return) override;
+ Status invalidateTracks(const std::vector<int32_t>& portIds) override;
private:
const sp<AudioFlingerServerAdapter::Delegate> mDelegate;
};
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index cbcef12..dcb6c25 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -110,6 +110,7 @@
"capture_state_listener-aidl-cpp",
"framework-permission-aidl-cpp",
"libaudioclient_aidl_conversion",
+ "libaudio_aidl_conversion_common_cpp",
"libbase",
"libbinder",
"libcgrouprc",
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 9e663bc..5cd17e1 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <iostream>
+
#include <gtest/gtest.h>
#include <media/AidlConversion.h>
@@ -22,19 +24,52 @@
using namespace android;
using namespace android::aidl_utils;
-using android::media::AudioDirectMode;
+using media::AudioDirectMode;
+using media::AudioPortConfigFw;
+using media::AudioPortDeviceExtSys;
+using media::AudioPortFw;
+using media::AudioPortRole;
+using media::AudioPortType;
using media::audio::common::AudioChannelLayout;
+using media::audio::common::AudioDevice;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioDeviceType;
using media::audio::common::AudioEncapsulationMetadataType;
using media::audio::common::AudioEncapsulationType;
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioFormatType;
+using media::audio::common::AudioGain;
+using media::audio::common::AudioGainConfig;
using media::audio::common::AudioGainMode;
+using media::audio::common::AudioIoFlags;
+using media::audio::common::AudioPortDeviceExt;
+using media::audio::common::AudioProfile;
using media::audio::common::AudioStandard;
using media::audio::common::ExtraAudioDescriptor;
+using media::audio::common::Int;
using media::audio::common::PcmType;
+// Provide value printers for types generated from AIDL
+// They need to be in the same namespace as the types we intend to print
+namespace android::media {
+#define DEFINE_PRINTING_TEMPLATES() \
+ template <typename P> \
+ std::enable_if_t<std::is_base_of_v<::android::Parcelable, P>, std::ostream&> operator<<( \
+ std::ostream& os, const P& p) { \
+ return os << p.toString(); \
+ } \
+ template <typename E> \
+ std::enable_if_t<std::is_enum_v<E>, std::ostream&> operator<<(std::ostream& os, const E& e) { \
+ return os << toString(e); \
+ }
+DEFINE_PRINTING_TEMPLATES();
+
+namespace audio::common {
+DEFINE_PRINTING_TEMPLATES();
+} // namespace audio::common
+#undef DEFINE_PRINTING_TEMPLATES
+} // namespace android::media
+
namespace {
template <typename T>
@@ -367,6 +402,134 @@
testing::Values(make_AFD_Invalid(), AudioFormatDescription{},
make_AFD_Pcm16Bit()));
+AudioPortConfigFw createAudioPortConfigFw(const AudioChannelLayout& layout,
+ const AudioFormatDescription& format,
+ const AudioDeviceDescription& device) {
+ const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
+ AudioPortConfigFw result;
+ result.hal.id = 43;
+ result.hal.portId = 42;
+ Int sr44100;
+ sr44100.value = 44100;
+ result.hal.sampleRate = sr44100;
+ result.hal.channelMask = layout;
+ result.hal.format = format;
+ AudioGainConfig gain;
+ gain.mode = 1 << static_cast<int>(AudioGainMode::JOINT);
+ gain.values = std::vector<int32_t>({100});
+ result.hal.gain = gain;
+ AudioPortDeviceExt ext;
+ AudioDevice audioDevice;
+ audioDevice.type = device;
+ ext.device = audioDevice;
+ result.hal.ext = ext;
+ result.sys.role = isInput ? AudioPortRole::SOURCE : AudioPortRole::SINK;
+ result.sys.type = AudioPortType::DEVICE;
+ AudioPortDeviceExtSys sysDevice;
+ sysDevice.hwModule = 1;
+ result.sys.ext = sysDevice;
+ return result;
+}
+
+using AudioPortConfigParam =
+ std::tuple<AudioChannelLayout, AudioFormatDescription, AudioDeviceDescription>;
+class AudioPortConfigRoundTripTest : public testing::TestWithParam<AudioPortConfigParam> {};
+TEST_P(AudioPortConfigRoundTripTest, Aidl2Legacy2Aidl) {
+ const AudioChannelLayout layout = std::get<0>(GetParam());
+ const AudioFormatDescription format = std::get<1>(GetParam());
+ const AudioDeviceDescription device = std::get<2>(GetParam());
+ const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
+ AudioPortConfigFw initial = createAudioPortConfigFw(layout, format, device);
+ {
+ audio_port_config conv{};
+ int32_t portId = -1;
+ status_t status =
+ aidl2legacy_AudioPortConfig_audio_port_config(initial.hal, isInput, &conv, &portId);
+ ASSERT_EQ(OK, status);
+ EXPECT_NE(-1, portId);
+ auto convBack = legacy2aidl_audio_port_config_AudioPortConfig(conv, isInput, portId);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial.hal, convBack.value());
+ }
+ {
+ int32_t portId = -1;
+ auto conv = aidl2legacy_AudioPortConfigFw_audio_port_config(initial, &portId);
+ ASSERT_TRUE(conv.ok());
+ EXPECT_NE(-1, portId);
+ auto convBack = legacy2aidl_audio_port_config_AudioPortConfigFw(conv.value(), portId);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial, convBack.value());
+ }
+}
+INSTANTIATE_TEST_SUITE_P(
+ AudioPortConfig, AudioPortConfigRoundTripTest,
+ testing::Combine(testing::Values(make_ACL_Stereo(), make_ACL_ChannelIndex2()),
+ testing::Values(make_AFD_Pcm16Bit()),
+ testing::Values(make_ADD_DefaultIn(), make_ADD_DefaultOut(),
+ make_ADD_WiredHeadset())));
+
+class AudioPortFwRoundTripTest : public testing::TestWithParam<AudioDeviceDescription> {
+ public:
+ AudioProfile createProfile(const AudioFormatDescription& format,
+ const std::vector<AudioChannelLayout>& channelMasks,
+ const std::vector<int32_t>& sampleRates) {
+ AudioProfile profile;
+ profile.format = format;
+ profile.channelMasks = channelMasks;
+ profile.sampleRates = sampleRates;
+ return profile;
+ }
+};
+TEST_P(AudioPortFwRoundTripTest, Aidl2Legacy2Aidl) {
+ const AudioDeviceDescription device = GetParam();
+ const bool isInput = device.type < AudioDeviceType::OUT_DEFAULT;
+ AudioPortFw initial;
+ initial.hal.id = 42;
+ initial.hal.profiles.push_back(createProfile(
+ make_AFD_Pcm16Bit(), {make_ACL_Stereo(), make_ACL_ChannelIndex2()}, {44100, 48000}));
+ if (isInput) {
+ initial.hal.flags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
+ } else {
+ initial.hal.flags = AudioIoFlags::make<AudioIoFlags::Tag::output>(0);
+ }
+ AudioGain initialGain;
+ initialGain.mode = 1 << static_cast<int>(AudioGainMode::JOINT);
+ initialGain.channelMask = make_ACL_Stereo();
+ initial.hal.gains.push_back(initialGain);
+ AudioPortDeviceExt initialExt;
+ AudioDevice initialDevice;
+ initialDevice.type = device;
+ initialExt.device = initialDevice;
+ initial.hal.ext = initialExt;
+ {
+ auto conv = aidl2legacy_AudioPort_audio_port_v7(initial.hal, isInput);
+ ASSERT_TRUE(conv.ok());
+ auto convBack = legacy2aidl_audio_port_v7_AudioPort(conv.value(), isInput);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial.hal, convBack.value());
+ }
+ initial.sys.role = isInput ? AudioPortRole::SOURCE : AudioPortRole::SINK;
+ initial.sys.type = AudioPortType::DEVICE;
+ initial.sys.profiles.resize(initial.hal.profiles.size());
+ initial.sys.gains.resize(initial.hal.gains.size());
+ initial.sys.activeConfig =
+ createAudioPortConfigFw(make_ACL_Stereo(), make_AFD_Pcm16Bit(), device);
+ initial.sys.activeConfig.hal.flags = initial.hal.flags;
+ AudioPortDeviceExtSys initialSysDevice;
+ initialSysDevice.hwModule = 1;
+ initial.sys.ext = initialSysDevice;
+ {
+ auto conv = aidl2legacy_AudioPortFw_audio_port_v7(initial);
+ ASSERT_TRUE(conv.ok());
+ auto convBack = legacy2aidl_audio_port_v7_AudioPortFw(conv.value());
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial, convBack.value());
+ }
+}
+INSTANTIATE_TEST_SUITE_P(AudioPortFw, AudioPortFwRoundTripTest,
+ testing::Values(make_ADD_DefaultIn(), make_ADD_DefaultOut(),
+ make_ADD_WiredHeadset()));
+
class AudioDirectModeRoundTripTest : public testing::TestWithParam<AudioDirectMode> {};
TEST_P(AudioDirectModeRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
@@ -391,7 +554,8 @@
EXPECT_EQ(initial, convBack.value());
}
INSTANTIATE_TEST_SUITE_P(AudioStandard, AudioStandardRoundTripTest,
- testing::Values(AudioStandard::NONE, AudioStandard::EDID));
+ testing::Values(AudioStandard::NONE, AudioStandard::EDID,
+ AudioStandard::SADB, AudioStandard::VSADB));
class AudioEncapsulationMetadataTypeRoundTripTest
: public testing::TestWithParam<AudioEncapsulationMetadataType> {};
@@ -450,7 +614,11 @@
ExtraAudioDescriptor, ExtraAudioDescriptorRoundTripTest,
testing::Values(std::make_tuple(AudioStandard::NONE, AudioEncapsulationType::NONE),
std::make_tuple(AudioStandard::EDID, AudioEncapsulationType::NONE),
- std::make_tuple(AudioStandard::EDID, AudioEncapsulationType::IEC61937)));
+ std::make_tuple(AudioStandard::EDID, AudioEncapsulationType::IEC61937),
+ std::make_tuple(AudioStandard::SADB, AudioEncapsulationType::NONE),
+ std::make_tuple(AudioStandard::SADB, AudioEncapsulationType::IEC61937),
+ std::make_tuple(AudioStandard::VSADB, AudioEncapsulationType::NONE),
+ std::make_tuple(AudioStandard::VSADB, AudioEncapsulationType::IEC61937)));
TEST(AudioPortSessionExtRoundTripTest, Aidl2Legacy2Aidl) {
const int32_t initial = 7;
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 2c5fcd7..19d1abc 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -73,7 +73,6 @@
}
}
ap->stop();
- ap->getAudioTrackHandle()->removeAudioDeviceCallback(cb);
}
}
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 3dd2c95..2e6915a 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -49,12 +49,12 @@
void TearDown() override {
if (mPlayback) {
mPlayback->stop();
- mPlayback->getAudioTrackHandle()->removeAudioDeviceCallback(mCbPlayback);
+ mCbPlayback.clear();
mPlayback.clear();
}
if (mCapture) {
mCapture->stop();
- mCapture->getAudioRecordHandle()->removeAudioDeviceCallback(mCbRecord);
+ mCbRecord.clear();
mCapture.clear();
}
}
@@ -405,8 +405,8 @@
EXPECT_EQ(OK, AudioSystem::getDevicesForRoleAndStrategy(mediaStrategy.getId(),
DEVICE_ROLE_PREFERRED, devices));
EXPECT_EQ(devices, outputDevices);
- EXPECT_EQ(OK, AudioSystem::removeDevicesRoleForStrategy(mediaStrategy.getId(),
- DEVICE_ROLE_PREFERRED));
+ EXPECT_EQ(OK, AudioSystem::clearDevicesRoleForStrategy(mediaStrategy.getId(),
+ DEVICE_ROLE_PREFERRED));
EXPECT_EQ(NAME_NOT_FOUND, AudioSystem::getDevicesForRoleAndStrategy(
mediaStrategy.getId(), DEVICE_ROLE_PREFERRED, devices));
}
diff --git a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
index 4a7e956..ad39d32 100644
--- a/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
+++ b/media/libaudiofoundation/AudioDeviceTypeAddr.cpp
@@ -150,6 +150,20 @@
return remainedDevices;
}
+AudioDeviceTypeAddrVector joinDeviceTypeAddrs(
+ const AudioDeviceTypeAddrVector& devices,
+ const AudioDeviceTypeAddrVector& devicesToJoin) {
+ std::set<AudioDeviceTypeAddr> devicesSet(devices.begin(), devices.end());
+ std::set<AudioDeviceTypeAddr> devicesToJoinSet(devicesToJoin.begin(), devicesToJoin.end());
+ AudioDeviceTypeAddrVector joinedDevices;
+
+ std::set_union(devicesSet.begin(), devicesSet.end(),
+ devicesToJoinSet.begin(), devicesToJoinSet.end(),
+ std::back_inserter(joinedDevices));
+
+ return joinedDevices;
+}
+
std::string dumpAudioDeviceTypeAddrVector(const AudioDeviceTypeAddrVector& deviceTypeAddrs,
bool includeSensitiveInfo) {
std::stringstream stream;
diff --git a/media/libaudiofoundation/AudioPort.cpp b/media/libaudiofoundation/AudioPort.cpp
index 4513323..6e05abc 100644
--- a/media/libaudiofoundation/AudioPort.cpp
+++ b/media/libaudiofoundation/AudioPort.cpp
@@ -222,7 +222,7 @@
mExtraAudioDescriptors == other->getExtraAudioDescriptors();
}
-status_t AudioPort::writeToParcelable(media::AudioPort* parcelable) const {
+status_t AudioPort::writeToParcelable(media::AudioPortFw* parcelable) const {
parcelable->hal.name = mName;
parcelable->sys.type = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_port_type_t_AudioPortType(mType));
@@ -249,7 +249,7 @@
return OK;
}
-status_t AudioPort::readFromParcelable(const media::AudioPort& parcelable) {
+status_t AudioPort::readFromParcelable(const media::AudioPortFw& parcelable) {
mName = parcelable.hal.name;
mType = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioPortType_audio_port_type_t(parcelable.sys.type));
diff --git a/media/libaudiofoundation/DeviceDescriptorBase.cpp b/media/libaudiofoundation/DeviceDescriptorBase.cpp
index 91efb96..c499513 100644
--- a/media/libaudiofoundation/DeviceDescriptorBase.cpp
+++ b/media/libaudiofoundation/DeviceDescriptorBase.cpp
@@ -181,7 +181,7 @@
return false;
}
-status_t DeviceDescriptorBase::writeToParcelable(media::AudioPort* parcelable) const {
+status_t DeviceDescriptorBase::writeToParcelable(media::AudioPortFw* parcelable) const {
AudioPort::writeToParcelable(parcelable);
AudioPortConfig::writeToParcelable(&parcelable->sys.activeConfig.hal, useInputChannelMask());
parcelable->hal.id = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_handle_t_int32_t(mId));
@@ -203,7 +203,7 @@
return OK;
}
-status_t DeviceDescriptorBase::readFromParcelable(const media::AudioPort& parcelable) {
+status_t DeviceDescriptorBase::readFromParcelable(const media::AudioPortFw& parcelable) {
if (parcelable.sys.type != media::AudioPortType::DEVICE) {
return BAD_VALUE;
}
@@ -252,7 +252,7 @@
}
ConversionResult<sp<DeviceDescriptorBase>>
-aidl2legacy_DeviceDescriptorBase(const media::AudioPort& aidl) {
+aidl2legacy_DeviceDescriptorBase(const media::AudioPortFw& aidl) {
sp<DeviceDescriptorBase> result = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
status_t status = result->readFromParcelable(aidl);
if (status != OK) {
@@ -261,9 +261,9 @@
return result;
}
-ConversionResult<media::AudioPort>
+ConversionResult<media::AudioPortFw>
legacy2aidl_DeviceDescriptorBase(const sp<DeviceDescriptorBase>& legacy) {
- media::AudioPort aidl;
+ media::AudioPortFw aidl;
status_t status = legacy->writeToParcelable(&aidl);
if (status != OK) {
return base::unexpected(status);
diff --git a/media/libaudiofoundation/include/media/AudioContainers.h b/media/libaudiofoundation/include/media/AudioContainers.h
index bce131c..2a14504 100644
--- a/media/libaudiofoundation/include/media/AudioContainers.h
+++ b/media/libaudiofoundation/include/media/AudioContainers.h
@@ -67,6 +67,9 @@
for (const auto &channel : channelMasks) {
if (audio_channel_mask_out_to_in(channel) != AUDIO_CHANNEL_INVALID) {
inMaskSet.insert(audio_channel_mask_out_to_in(channel));
+ } else if (audio_channel_mask_get_representation(channel)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+ inMaskSet.insert(channel);
}
}
return inMaskSet;
@@ -77,6 +80,9 @@
for (const auto &channel : channelMasks) {
if (audio_channel_mask_in_to_out(channel) != AUDIO_CHANNEL_INVALID) {
outMaskSet.insert(audio_channel_mask_in_to_out(channel));
+ } else if (audio_channel_mask_get_representation(channel)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
+ outMaskSet.insert(channel);
}
}
return outMaskSet;
diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
index 11aa222..b2f2bd0 100644
--- a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
+++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h
@@ -84,6 +84,14 @@
const AudioDeviceTypeAddrVector& devices,
const AudioDeviceTypeAddrVector& devicesToExclude);
+/**
+ * Return a collection of AudioDeviceTypeAddrs that is the union of `devices` and
+ * `devicesToJoin`
+ */
+AudioDeviceTypeAddrVector joinDeviceTypeAddrs(
+ const AudioDeviceTypeAddrVector& devices,
+ const AudioDeviceTypeAddrVector& devicesToJoin);
+
std::string dumpAudioDeviceTypeAddrVector(const AudioDeviceTypeAddrVector& deviceTypeAddrs,
bool includeSensitiveInfo=false);
diff --git a/media/libaudiofoundation/include/media/AudioPort.h b/media/libaudiofoundation/include/media/AudioPort.h
index b1235f5..77e58ed 100644
--- a/media/libaudiofoundation/include/media/AudioPort.h
+++ b/media/libaudiofoundation/include/media/AudioPort.h
@@ -19,8 +19,8 @@
#include <string>
#include <type_traits>
-#include <android/media/AudioPort.h>
-#include <android/media/AudioPortConfig.h>
+#include <android/media/AudioPortFw.h>
+#include <android/media/AudioPortConfigFw.h>
#include <android/media/audio/common/ExtraAudioDescriptor.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
@@ -118,8 +118,8 @@
bool equals(const sp<AudioPort>& other) const;
- status_t writeToParcelable(media::AudioPort* parcelable) const;
- status_t readFromParcelable(const media::AudioPort& parcelable);
+ status_t writeToParcelable(media::AudioPortFw* parcelable) const;
+ status_t readFromParcelable(const media::AudioPortFw& parcelable);
AudioGains mGains; // gain controllers
// Maximum number of input or output streams that can be simultaneously
diff --git a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
index dc2899a..501831d 100644
--- a/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
+++ b/media/libaudiofoundation/include/media/DeviceDescriptorBase.h
@@ -18,7 +18,7 @@
#include <vector>
-#include <android/media/AudioPort.h>
+#include <android/media/AudioPortFw.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
#include <media/AudioContainers.h>
@@ -79,8 +79,8 @@
bool equals(const sp<DeviceDescriptorBase>& other) const;
- status_t writeToParcelable(media::AudioPort* parcelable) const;
- status_t readFromParcelable(const media::AudioPort& parcelable);
+ status_t writeToParcelable(media::AudioPortFw* parcelable) const;
+ status_t readFromParcelable(const media::AudioPortFw& parcelable);
protected:
AudioDeviceTypeAddr mDeviceTypeAddr;
@@ -116,8 +116,8 @@
// Conversion routines, according to AidlConversion.h conventions.
ConversionResult<sp<DeviceDescriptorBase>>
-aidl2legacy_DeviceDescriptorBase(const media::AudioPort& aidl);
-ConversionResult<media::AudioPort>
+aidl2legacy_DeviceDescriptorBase(const media::AudioPortFw& aidl);
+ConversionResult<media::AudioPortFw>
legacy2aidl_DeviceDescriptorBase(const sp<DeviceDescriptorBase>& legacy);
} // namespace android
diff --git a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
index 50d8dc8..e315858 100644
--- a/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
+++ b/media/libaudiofoundation/tests/audiofoundation_parcelable_test.cpp
@@ -117,7 +117,7 @@
audioPort->setGains(getAudioGainsForTest());
audioPort->setAudioProfiles(getAudioProfileVectorForTest());
- media::AudioPort parcelable;
+ media::AudioPortFw parcelable;
ASSERT_EQ(NO_ERROR, audioPort->writeToParcelable(&parcelable));
sp<AudioPort> audioPortFromParcel = new AudioPort(
"", AUDIO_PORT_TYPE_NONE, AUDIO_PORT_ROLE_NONE);
@@ -152,7 +152,7 @@
ASSERT_EQ(desc->setEncapsulationMetadataTypes(
AUDIO_ENCAPSULATION_METADATA_TYPE_ALL_POSITION_BITS), NO_ERROR);
- media::AudioPort parcelable;
+ media::AudioPortFw parcelable;
ASSERT_EQ(NO_ERROR, desc->writeToParcelable(&parcelable));
sp<DeviceDescriptorBase> descFromParcel = new DeviceDescriptorBase(AUDIO_DEVICE_NONE);
ASSERT_EQ(NO_ERROR, descFromParcel->readFromParcelable(parcelable));
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index 320c639..f47dd0b 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -43,6 +43,7 @@
header_libs: [
"libaudiohal_headers",
"libbase_headers",
+ "liberror_headers",
"libmediautils_headers",
]
}
@@ -74,8 +75,4 @@
name: "libaudiohal_headers",
export_include_dirs: ["include"],
-
- // This is needed because the stream interface includes media/MicrophoneInfo.h
- header_libs: ["av-headers"],
- export_header_lib_headers: ["av-headers"],
}
diff --git a/media/libaudiohal/FactoryHal.cpp b/media/libaudiohal/FactoryHal.cpp
index 16d591c..f88915d 100644
--- a/media/libaudiohal/FactoryHal.cpp
+++ b/media/libaudiohal/FactoryHal.cpp
@@ -105,12 +105,12 @@
bool hasAidlHalService(const InterfaceName& interface, const AudioHalVersionInfo& version) {
const std::string name = interface.first + "." + interface.second + "/default";
- AIBinder* binder = AServiceManager_checkService(name.c_str());
- if (binder == nullptr) {
- ALOGW("%s Service %s doesn't exist", __func__, name.c_str());
+ const bool isDeclared = AServiceManager_isDeclared(name.c_str());
+ if (!isDeclared) {
+ ALOGW("%s %s: false", __func__, name.c_str());
return false;
}
- ALOGI("%s AIDL Service %s exist: %s", __func__, name.c_str(), version.toString().c_str());
+ ALOGI("%s %s: true, version %s", __func__, name.c_str(), version.toString().c_str());
return true;
}
@@ -141,7 +141,7 @@
auto halType = version.getType();
if (halType == AudioHalVersionInfo::Type::AIDL) {
return hasAidlHalService(interface, version);
- } else if (version.getType() == AudioHalVersionInfo::Type::HIDL) {
+ } else if (halType == AudioHalVersionInfo::Type::HIDL) {
return hasHidlHalService(interface, version);
} else {
ALOGE("HalType not supported %s", version.toString().c_str());
@@ -164,9 +164,9 @@
auto siblingInterfaceMap = isDevice ? sEffectsHALInterfaces : sDevicesHALInterfaces;
auto ifaceVersionIt = findMostRecentVersion(interfaceMap);
auto siblingVersionIt = findMostRecentVersion(siblingInterfaceMap);
- if (ifaceVersionIt != sAudioHALVersions.end() &&
- siblingVersionIt != sAudioHALVersions.end() &&
- // same major version
+ if (ifaceVersionIt != sAudioHALVersions.end() && siblingVersionIt != sAudioHALVersions.end() &&
+ // same HAL type (HIDL/AIDL) and same major version
+ ifaceVersionIt->getType() == siblingVersionIt->getType() &&
ifaceVersionIt->getMajorVersion() == siblingVersionIt->getMajorVersion()) {
void* rawInterface;
if (createHalService(std::max(*ifaceVersionIt, *siblingVersionIt), isDevice,
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index bb5601f..17993f5 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -207,6 +207,8 @@
cc_library_shared {
name: "libaudiohal@7.1",
defaults: [
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "latest_android_hardware_audio_sounddose_ndk_shared",
"libaudiohal_default",
"libaudiohal_hidl_default"
],
@@ -226,6 +228,9 @@
"android.hardware.audio@7.1-util",
"libaudiohal.effect@7.0",
],
+ shared_libs: [
+ "libbinder_ndk",
+ ],
cflags: [
"-DMAJOR_VERSION=7",
"-DMINOR_VERSION=1",
@@ -241,15 +246,55 @@
"libaudiohal_default",
"latest_android_hardware_audio_common_ndk_shared",
"latest_android_hardware_audio_core_ndk_shared",
- "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "latest_android_hardware_audio_effect_ndk_static",
+ "latest_android_media_audio_common_types_ndk_shared",
],
srcs: [
+ "DeviceHalAidl.cpp",
"DevicesFactoryHalEntry.cpp",
"DevicesFactoryHalAidl.cpp",
+ "EffectConversionHelperAidl.cpp",
+ "EffectBufferHalAidl.cpp",
+ "EffectHalAidl.cpp",
+ "effectsAidlConversion/AidlConversionAec.cpp",
+ "effectsAidlConversion/AidlConversionAgc2.cpp",
+ "effectsAidlConversion/AidlConversionBassBoost.cpp",
+ "effectsAidlConversion/AidlConversionDownmix.cpp",
+ "effectsAidlConversion/AidlConversionDynamicsProcessing.cpp",
+ "effectsAidlConversion/AidlConversionEnvReverb.cpp",
+ "effectsAidlConversion/AidlConversionEq.cpp",
+ "effectsAidlConversion/AidlConversionHapticGenerator.cpp",
+ "effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp",
+ "effectsAidlConversion/AidlConversionNoiseSuppression.cpp",
+ "effectsAidlConversion/AidlConversionPresetReverb.cpp",
+ "effectsAidlConversion/AidlConversionSpatializer.cpp",
+ "effectsAidlConversion/AidlConversionVendorExtension.cpp",
+ "effectsAidlConversion/AidlConversionVirtualizer.cpp",
+ "effectsAidlConversion/AidlConversionVisualizer.cpp",
"EffectsFactoryHalAidl.cpp",
"EffectsFactoryHalEntry.cpp",
+ "StreamHalAidl.cpp",
+ ],
+ static_libs: [
+ "android.hardware.common-V2-ndk",
+ "android.hardware.common.fmq-V1-ndk",
],
shared_libs: [
"libbinder_ndk",
- ]
-}
\ No newline at end of file
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudio_aidl_conversion_effect_ndk",
+ "libaudioaidlcommon",
+ ],
+ header_libs: [
+ "libaudio_aidl_conversion_common_util_ndk",
+ "libaudio_system_headers",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ "-DBACKEND_NDK",
+ ],
+}
diff --git a/media/libaudiohal/impl/ConversionHelperAidl.h b/media/libaudiohal/impl/ConversionHelperAidl.h
new file mode 100644
index 0000000..db6b6cf
--- /dev/null
+++ b/media/libaudiohal/impl/ConversionHelperAidl.h
@@ -0,0 +1,54 @@
+/*
+ * 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 <string>
+#include <string_view>
+#include <vector>
+
+#include <utils/String16.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class Args {
+ public:
+ explicit Args(const Vector<String16>& args)
+ : mValues(args.size()), mPtrs(args.size()) {
+ for (size_t i = 0; i < args.size(); ++i) {
+ mValues[i] = std::string(String8(args[i]));
+ mPtrs[i] = mValues[i].c_str();
+ }
+ }
+ const char** args() { return mPtrs.data(); }
+ private:
+ std::vector<std::string> mValues;
+ std::vector<const char*> mPtrs;
+};
+
+class ConversionHelperAidl {
+ protected:
+ ConversionHelperAidl(std::string_view className) : mClassName(className) {}
+
+ const std::string& getClassName() const {
+ return mClassName;
+ }
+
+ const std::string mClassName;
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
new file mode 100644
index 0000000..62b9ec7
--- /dev/null
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DeviceHalAidl"
+// #define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <forward_list>
+
+#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <error/expected_utils.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionUtil.h>
+#include <mediautils/TimeCheck.h>
+#include <Utils.h>
+#include <utils/Log.h>
+
+#include "DeviceHalAidl.h"
+#include "StreamHalAidl.h"
+
+using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::media::audio::common::AudioConfig;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceType;
+using aidl::android::media::audio::common::AudioInputFlags;
+using aidl::android::media::audio::common::AudioIoFlags;
+using aidl::android::media::audio::common::AudioMode;
+using aidl::android::media::audio::common::AudioOutputFlags;
+using aidl::android::media::audio::common::AudioPort;
+using aidl::android::media::audio::common::AudioPortConfig;
+using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioSource;
+using aidl::android::media::audio::common::Int;
+using aidl::android::media::audio::common::Float;
+using aidl::android::hardware::audio::common::RecordTrackMetadata;
+using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::IModule;
+using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::StreamDescriptor;
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using android::hardware::audio::common::getFrameSizeInBytes;
+using android::hardware::audio::common::isBitPositionFlagSet;
+using android::hardware::audio::common::makeBitPositionFlagMask;
+
+namespace android {
+
+namespace {
+
+bool isConfigEqualToPortConfig(const AudioConfig& config, const AudioPortConfig& portConfig) {
+ return portConfig.sampleRate.value().value == config.base.sampleRate &&
+ portConfig.channelMask.value() == config.base.channelMask &&
+ portConfig.format.value() == config.base.format;
+}
+
+void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
+ config->base.sampleRate = portConfig.sampleRate.value().value;
+ config->base.channelMask = portConfig.channelMask.value();
+ config->base.format = portConfig.format.value();
+}
+
+void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
+ portConfig->sampleRate = Int{ .value = config.base.sampleRate };
+ portConfig->channelMask = config.base.channelMask;
+ portConfig->format = config.base.format;
+}
+
+} // namespace
+
+status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
+ // Obsolete.
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalAidl::initCheck() {
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ std::vector<AudioPort> ports;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioPorts(&ports)));
+ ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports",
+ __func__, mInstance.c_str());
+ std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ mDefaultInputPortId = mDefaultOutputPortId = -1;
+ const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE;
+ for (const auto& pair : mPorts) {
+ const auto& p = pair.second;
+ if (p.ext.getTag() == AudioPortExt::Tag::device &&
+ (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) {
+ if (p.flags.getTag() == AudioIoFlags::Tag::input) {
+ mDefaultInputPortId = p.id;
+ } else if (p.flags.getTag() == AudioIoFlags::Tag::output) {
+ mDefaultOutputPortId = p.id;
+ }
+ }
+ }
+ ALOGI("%s: module %s default port ids: input %d, output %d",
+ __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
+ std::vector<AudioPortConfig> portConfigs;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
+ std::transform(portConfigs.begin(), portConfigs.end(),
+ std::inserter(mPortConfigs, mPortConfigs.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ std::vector<AudioPatch> patches;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioPatches(&patches))); // OK if empty
+ std::transform(patches.begin(), patches.end(),
+ std::inserter(mPatches, mPatches.end()),
+ [](const auto& p) { return std::make_pair(p.id, p); });
+ return OK;
+}
+
+status_t DeviceHalAidl::setVoiceVolume(float volume) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ std::shared_ptr<ITelephony> telephony;
+ if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
+ status.isOk() && telephony != nullptr) {
+ ITelephony::TelecomConfig inConfig{ .voiceVolume = Float{volume} }, outConfig;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(telephony->setTelecomConfig(inConfig, &outConfig)));
+ ALOGW_IF(outConfig.voiceVolume.has_value() && volume != outConfig.voiceVolume.value().value,
+ "%s: the resulting voice volume %f is not the same as requested %f",
+ __func__, outConfig.voiceVolume.value().value, volume);
+ }
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalAidl::setMasterVolume(float volume) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->setMasterVolume(volume));
+}
+
+status_t DeviceHalAidl::getMasterVolume(float *volume) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->getMasterVolume(volume));
+}
+
+status_t DeviceHalAidl::setMode(audio_mode_t mode) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ AudioMode audioMode = VALUE_OR_FATAL(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
+ std::shared_ptr<ITelephony> telephony;
+ if (ndk::ScopedAStatus status = mModule->getTelephony(&telephony);
+ status.isOk() && telephony != nullptr) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(telephony->switchAudioMode(audioMode)));
+ }
+ return statusTFromBinderStatus(mModule->updateAudioMode(audioMode));
+}
+
+status_t DeviceHalAidl::setMicMute(bool state) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->setMicMute(state));
+}
+
+status_t DeviceHalAidl::getMicMute(bool *state) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->getMicMute(state));
+}
+
+status_t DeviceHalAidl::setMasterMute(bool state) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->setMasterMute(state));
+}
+
+status_t DeviceHalAidl::getMasterMute(bool *state) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return statusTFromBinderStatus(mModule->getMasterMute(state));
+}
+
+status_t DeviceHalAidl::setParameters(const String8& kvPairs __unused) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t DeviceHalAidl::getParameters(const String8& keys __unused, String8 *values) {
+ TIME_CHECK();
+ values->clear();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+namespace {
+
+class Cleanup {
+ public:
+ typedef void (DeviceHalAidl::*Cleaner)(int32_t);
+
+ Cleanup(DeviceHalAidl* device, Cleaner cleaner, int32_t id) :
+ mDevice(device), mCleaner(cleaner), mId(id) {}
+ ~Cleanup() { clean(); }
+ void clean() {
+ if (mDevice != nullptr) (mDevice->*mCleaner)(mId);
+ disarm();
+ }
+ void disarm() { mDevice = nullptr; }
+
+ private:
+ DeviceHalAidl* mDevice;
+ const Cleaner mCleaner;
+ const int32_t mId;
+};
+
+} // namespace
+
+// Since the order of container elements destruction is unspecified,
+// ensure that cleanups are performed from the most recent one and upwards.
+// This is the same as if there were individual Cleanup instances on the stack,
+// however the bonus is that we can disarm all of them with just one statement.
+class DeviceHalAidl::Cleanups : public std::forward_list<Cleanup> {
+ public:
+ ~Cleanups() { for (auto& c : *this) c.clean(); }
+ void disarmAll() { for (auto& c : *this) c.disarm(); }
+};
+
+status_t DeviceHalAidl::getInputBufferSize(const struct audio_config* config, size_t* size) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (size == nullptr) return BAD_VALUE;
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
+ AudioDevice aidlDevice;
+ aidlDevice.type.type = AudioDeviceType::IN_DEFAULT;
+ AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(0);
+ AudioPortConfig mixPortConfig;
+ Cleanups cleanups;
+ audio_config writableConfig = *config;
+ int32_t nominalLatency;
+ RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, &writableConfig,
+ &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ *size = aidlConfig.frameCount *
+ getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
+ // Do not disarm cleanups to release temporary port configs.
+ return OK;
+}
+
+status_t DeviceHalAidl::prepareToOpenStream(
+ int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
+ struct audio_config* config,
+ Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
+ int32_t* nominalLatency) {
+ const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
+ // Find / create AudioPortConfigs for the device port and the mix port,
+ // then find / create a patch between them, and open a stream on the mix port.
+ AudioPortConfig devicePortConfig;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(aidlDevice, &devicePortConfig, &created));
+ if (created) {
+ cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
+ }
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle,
+ mixPortConfig, &created));
+ if (created) {
+ cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
+ }
+ setConfigFromPortConfig(aidlConfig, *mixPortConfig);
+ AudioPatch patch;
+ if (isInput) {
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+ {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
+ } else {
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(
+ {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
+ }
+ if (created) {
+ cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
+ }
+ *nominalLatency = patch.latenciesMs[0];
+ if (aidlConfig->frameCount <= 0) {
+ aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
+ }
+ *config = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
+ return OK;
+}
+
+status_t DeviceHalAidl::openOutputStream(
+ audio_io_handle_t handle, audio_devices_t devices,
+ audio_output_flags_t flags, struct audio_config* config,
+ const char* address,
+ sp<StreamOutHalInterface>* outStream) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!outStream || !config) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
+ AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, false /*isInput*/));
+ AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
+ int32_t aidlOutputFlags = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
+ AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
+ AudioPortConfig mixPortConfig;
+ Cleanups cleanups;
+ int32_t nominalLatency;
+ RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, config,
+ &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
+ args.portConfigId = mixPortConfig.id;
+ args.offloadInfo = aidlConfig.offloadInfo;
+ args.bufferSizeFrames = aidlConfig.frameCount;
+ ::aidl::android::hardware::audio::core::IModule::OpenOutputStreamReturn ret;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openOutputStream(args, &ret)));
+ StreamContextAidl context(ret.desc);
+ if (!context.isValid()) {
+ ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
+ __func__, ret.desc.toString().c_str());
+ return NO_INIT;
+ }
+ *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
+ std::move(ret.stream));
+ cleanups.disarmAll();
+ return OK;
+}
+
+status_t DeviceHalAidl::openInputStream(
+ audio_io_handle_t handle, audio_devices_t devices,
+ struct audio_config* config, audio_input_flags_t flags,
+ const char* address, audio_source_t source,
+ audio_devices_t outputDevice, const char* outputDeviceAddress,
+ sp<StreamInHalInterface>* inStream) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!inStream || !config) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ int32_t aidlHandle = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_io_handle_t_int32_t(handle));
+ AudioConfig aidlConfig = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_config_t_AudioConfig(*config, true /*isInput*/));
+ AudioDevice aidlDevice = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_device_AudioDevice(devices, address));
+ int32_t aidlInputFlags = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_input_flags_t_int32_t_mask(flags));
+ AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::input>(aidlInputFlags);
+ AudioSource aidlSource = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
+ AudioPortConfig mixPortConfig;
+ Cleanups cleanups;
+ int32_t nominalLatency;
+ RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, config,
+ &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ ::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
+ args.portConfigId = mixPortConfig.id;
+ RecordTrackMetadata aidlTrackMetadata{
+ .source = aidlSource, .gain = 1, .channelMask = aidlConfig.base.channelMask };
+ if (outputDevice != AUDIO_DEVICE_NONE) {
+ aidlTrackMetadata.destinationDevice = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_device_AudioDevice(
+ outputDevice, outputDeviceAddress));
+ }
+ args.sinkMetadata.tracks.push_back(std::move(aidlTrackMetadata));
+ args.bufferSizeFrames = aidlConfig.frameCount;
+ ::aidl::android::hardware::audio::core::IModule::OpenInputStreamReturn ret;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->openInputStream(args, &ret)));
+ StreamContextAidl context(ret.desc);
+ if (!context.isValid()) {
+ ALOGE("%s: Failed to created a valid stream context from the descriptor: %s",
+ __func__, ret.desc.toString().c_str());
+ return NO_INIT;
+ }
+ *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), nominalLatency,
+ std::move(ret.stream));
+ cleanups.disarmAll();
+ return OK;
+}
+
+status_t DeviceHalAidl::supportsAudioPatches(bool* supportsPatches) {
+ *supportsPatches = true;
+ return OK;
+}
+
+status_t DeviceHalAidl::createAudioPatch(unsigned int num_sources,
+ const struct audio_port_config* sources,
+ unsigned int num_sinks,
+ const struct audio_port_config* sinks,
+ audio_patch_handle_t* patch) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (num_sinks > AUDIO_PATCH_PORTS_MAX || num_sources > AUDIO_PATCH_PORTS_MAX ||
+ sources == nullptr || sinks == nullptr || patch == nullptr) {
+ return BAD_VALUE;
+ }
+ // Note that the patch handle (*patch) is provided by the framework.
+ // In tests it's possible that its value is AUDIO_PATCH_HANDLE_NONE.
+
+ // Upon conversion, mix port configs contain audio configuration, while
+ // device port configs contain device address. This data is used to find
+ // or create HAL configs.
+ std::vector<AudioPortConfig> aidlSources, aidlSinks;
+ for (unsigned int i = 0; i < num_sources; ++i) {
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+ sources[i].role, sources[i].type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ aidlSources.push_back(VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+ sources[i], isInput, 0)));
+ }
+ for (unsigned int i = 0; i < num_sinks; ++i) {
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+ sinks[i].role, sinks[i].type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ aidlSinks.push_back(VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+ sinks[i], isInput, 0)));
+ }
+ Cleanups cleanups;
+ auto existingPatchIt = mPatches.end();
+ auto fwkHandlesIt = *patch != AUDIO_PATCH_HANDLE_NONE ?
+ mFwkHandles.find(*patch) : mFwkHandles.end();
+ AudioPatch aidlPatch;
+ if (fwkHandlesIt != mFwkHandles.end()) {
+ existingPatchIt = mPatches.find(fwkHandlesIt->second);
+ if (existingPatchIt != mPatches.end()) {
+ aidlPatch = existingPatchIt->second;
+ aidlPatch.sourcePortConfigIds.clear();
+ aidlPatch.sinkPortConfigIds.clear();
+ }
+ }
+ ALOGD("%s: sources: %s, sinks: %s",
+ __func__, ::android::internal::ToString(aidlSources).c_str(),
+ ::android::internal::ToString(aidlSinks).c_str());
+ auto fillPortConfigs = [&](
+ const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
+ for (const auto& s : configs) {
+ AudioPortConfig portConfig;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
+ if (created) {
+ cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
+ }
+ ids->push_back(portConfig.id);
+ }
+ return OK;
+ };
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
+ if (existingPatchIt != mPatches.end()) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mModule->setAudioPatch(aidlPatch, &aidlPatch)));
+ existingPatchIt->second = aidlPatch;
+ } else {
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePatch(aidlPatch, &aidlPatch, &created));
+ // Since no cleanup of the patch is needed, 'created' is ignored.
+ if (fwkHandlesIt != mFwkHandles.end()) {
+ fwkHandlesIt->second = aidlPatch.id;
+ // Patch handle (*patch) stays the same.
+ } else {
+ if (*patch == AUDIO_PATCH_HANDLE_NONE) {
+ // This isn't good as the module can't provide a handle which is really unique.
+ // However, this situation should only happen in tests.
+ *patch = aidlPatch.id;
+ LOG_ALWAYS_FATAL_IF(mFwkHandles.count(*patch) > 0,
+ "%s: patch id %d clashes with another framework patch handle",
+ __func__, *patch);
+ }
+ mFwkHandles.emplace(*patch, aidlPatch.id);
+ }
+ }
+ cleanups.disarmAll();
+ return OK;
+}
+
+status_t DeviceHalAidl::releaseAudioPatch(audio_patch_handle_t patch) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ auto idMapIt = mFwkHandles.find(patch);
+ if (idMapIt == mFwkHandles.end()) {
+ return BAD_VALUE;
+ }
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->resetAudioPatch(idMapIt->second)));
+ mFwkHandles.erase(idMapIt);
+ return OK;
+}
+
+status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t DeviceHalAidl::getMicrophones(
+ std::vector<audio_microphone_characteristic_t>* microphones __unused) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t DeviceHalAidl::addDeviceEffect(audio_port_handle_t device __unused,
+ sp<EffectHalInterface> effect) {
+ if (!effect) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+status_t DeviceHalAidl::removeDeviceEffect(audio_port_handle_t device __unused,
+ sp<EffectHalInterface> effect) {
+ if (!effect) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t DeviceHalAidl::getMmapPolicyInfos(
+ media::audio::common::AudioMMapPolicyType policyType __unused,
+ std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return base::unexpected(INVALID_OPERATION);
+}
+
+status_t DeviceHalAidl::dump(int fd, const Vector<String16>& args) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ return mModule->dump(fd, Args(args).args(), args.size());
+};
+
+int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
+ TIME_CHECK();
+ ALOGE("%s not implemented yet", __func__);
+ return INVALID_OPERATION;
+}
+
+status_t DeviceHalAidl::getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (mSoundDose == nullptr) {
+ ndk::ScopedAStatus status = mModule->getSoundDose(&mSoundDose);
+ if (!status.isOk()) {
+ ALOGE("%s failed to return the sound dose interface for module %s: %s",
+ __func__,
+ module.c_str(),
+ status.getDescription().c_str());
+ return BAD_VALUE;
+ }
+ }
+ *soundDoseBinder = mSoundDose->asBinder();
+ ALOGI("%s using audio AIDL HAL sound dose interface", __func__);
+
+ return OK;
+}
+
+bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
+ if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+ return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPortConfig& p) {
+ if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
+ if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+ return p.portId == mDefaultInputPortId;
+ } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+ return p.portId == mDefaultOutputPortId;
+ }
+ return p.ext.get<AudioPortExt::Tag::device>().device == device;
+}
+
+status_t DeviceHalAidl::createPortConfig(const AudioPortConfig& requestedPortConfig,
+ AudioPortConfig* appliedPortConfig) {
+ TIME_CHECK();
+ bool applied = false;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+ requestedPortConfig, appliedPortConfig, &applied)));
+ if (!applied) {
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
+ *appliedPortConfig, appliedPortConfig, &applied)));
+ if (!applied) {
+ ALOGE("%s: module %s did not apply suggested config %s",
+ __func__, mInstance.c_str(), appliedPortConfig->toString().c_str());
+ return NO_INIT;
+ }
+ }
+ mPortConfigs.emplace(appliedPortConfig->id, *appliedPortConfig);
+ return OK;
+}
+
+status_t DeviceHalAidl::findOrCreatePatch(
+ const AudioPatch& requestedPatch, AudioPatch* patch, bool* created) {
+ std::set<int32_t> sourcePortConfigIds(requestedPatch.sourcePortConfigIds.begin(),
+ requestedPatch.sourcePortConfigIds.end());
+ std::set<int32_t> sinkPortConfigIds(requestedPatch.sinkPortConfigIds.begin(),
+ requestedPatch.sinkPortConfigIds.end());
+ return findOrCreatePatch(sourcePortConfigIds, sinkPortConfigIds, patch, created);
+}
+
+status_t DeviceHalAidl::findOrCreatePatch(
+ const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds,
+ AudioPatch* patch, bool* created) {
+ auto patchIt = findPatch(sourcePortConfigIds, sinkPortConfigIds);
+ if (patchIt == mPatches.end()) {
+ TIME_CHECK();
+ AudioPatch requestedPatch, appliedPatch;
+ requestedPatch.sourcePortConfigIds.insert(requestedPatch.sourcePortConfigIds.end(),
+ sourcePortConfigIds.begin(), sourcePortConfigIds.end());
+ requestedPatch.sinkPortConfigIds.insert(requestedPatch.sinkPortConfigIds.end(),
+ sinkPortConfigIds.begin(), sinkPortConfigIds.end());
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPatch(
+ requestedPatch, &appliedPatch)));
+ patchIt = mPatches.insert(mPatches.end(), std::make_pair(appliedPatch.id, appliedPatch));
+ *created = true;
+ } else {
+ *created = false;
+ }
+ *patch = patchIt->second;
+ return OK;
+}
+
+status_t DeviceHalAidl::findOrCreatePortConfig(const AudioDevice& device,
+ AudioPortConfig* portConfig, bool* created) {
+ auto portConfigIt = findPortConfig(device);
+ if (portConfigIt == mPortConfigs.end()) {
+ auto portsIt = findPort(device);
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: device port for device %s is not found in the module %s",
+ __func__, device.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ AudioPortConfig requestedPortConfig;
+ requestedPortConfig.portId = portsIt->first;
+ AudioPortConfig appliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &appliedPortConfig));
+ portConfigIt = mPortConfigs.insert(
+ mPortConfigs.end(), std::make_pair(appliedPortConfig.id, appliedPortConfig));
+ *created = true;
+ } else {
+ *created = false;
+ }
+ *portConfig = portConfigIt->second;
+ return OK;
+}
+
+status_t DeviceHalAidl::findOrCreatePortConfig(
+ const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
+ AudioPortConfig* portConfig, bool* created) {
+ auto portConfigIt = findPortConfig(config, flags, ioHandle);
+ if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
+ auto portsIt = findPort(config, flags.value());
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: mix port for config %s, flags %s is not found in the module %s",
+ __func__, config.toString().c_str(), flags.value().toString().c_str(),
+ mInstance.c_str());
+ return BAD_VALUE;
+ }
+ AudioPortConfig requestedPortConfig;
+ requestedPortConfig.portId = portsIt->first;
+ setPortConfigFromConfig(&requestedPortConfig, config);
+ AudioPortConfig appliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &appliedPortConfig));
+ appliedPortConfig.ext.get<AudioPortExt::Tag::mix>().handle = ioHandle;
+ portConfigIt = mPortConfigs.insert(
+ mPortConfigs.end(), std::make_pair(appliedPortConfig.id, appliedPortConfig));
+ *created = true;
+ } else if (!flags.has_value()) {
+ ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
+ "and was not created as flags are not specified",
+ __func__, config.toString().c_str(), ioHandle, mInstance.c_str());
+ return BAD_VALUE;
+ } else {
+ *created = false;
+ }
+ *portConfig = portConfigIt->second;
+ return OK;
+}
+
+status_t DeviceHalAidl::findOrCreatePortConfig(
+ const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
+ using Tag = AudioPortExt::Tag;
+ if (requestedPortConfig.ext.getTag() == Tag::mix) {
+ if (const auto& p = requestedPortConfig;
+ !p.sampleRate.has_value() || !p.channelMask.has_value() ||
+ !p.format.has_value()) {
+ ALOGW("%s: provided mix port config is not fully specified: %s",
+ __func__, p.toString().c_str());
+ return BAD_VALUE;
+ }
+ AudioConfig config;
+ setConfigFromPortConfig(&config, requestedPortConfig);
+ return findOrCreatePortConfig(config, requestedPortConfig.flags,
+ requestedPortConfig.ext.get<Tag::mix>().handle, portConfig, created);
+ } else if (requestedPortConfig.ext.getTag() == Tag::device) {
+ return findOrCreatePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, portConfig, created);
+ }
+ ALOGW("%s: unsupported audio port config: %s",
+ __func__, requestedPortConfig.toString().c_str());
+ return BAD_VALUE;
+}
+
+DeviceHalAidl::Patches::iterator DeviceHalAidl::findPatch(
+ const std::set<int32_t>& sourcePortConfigIds, const std::set<int32_t>& sinkPortConfigIds) {
+ return std::find_if(mPatches.begin(), mPatches.end(),
+ [&](const auto& pair) {
+ const auto& p = pair.second;
+ std::set<int32_t> patchSrcs(
+ p.sourcePortConfigIds.begin(), p.sourcePortConfigIds.end());
+ std::set<int32_t> patchSinks(
+ p.sinkPortConfigIds.begin(), p.sinkPortConfigIds.end());
+ return sourcePortConfigIds == patchSrcs && sinkPortConfigIds == patchSinks; });
+}
+
+DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(const AudioDevice& device) {
+ if (device.type.type == AudioDeviceType::IN_DEFAULT) {
+ return mPorts.find(mDefaultInputPortId);
+ } else if (device.type.type == AudioDeviceType::OUT_DEFAULT) {
+ return mPorts.find(mDefaultOutputPortId);
+ }
+ return std::find_if(mPorts.begin(), mPorts.end(),
+ [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+}
+
+DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
+ const AudioConfig& config, const AudioIoFlags& flags) {
+ using Tag = AudioPortExt::Tag;
+ AudioIoFlags matchFlags = flags;
+ auto matcher = [&](const auto& pair) {
+ const auto& p = pair.second;
+ return p.ext.getTag() == Tag::mix &&
+ p.flags == matchFlags &&
+ std::find_if(p.profiles.begin(), p.profiles.end(),
+ [&](const auto& prof) {
+ return prof.format == config.base.format &&
+ std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
+ config.base.channelMask) != prof.channelMasks.end() &&
+ std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
+ config.base.sampleRate) != prof.sampleRates.end();
+ }) != p.profiles.end(); };
+ auto it = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+ if (it == mPorts.end() && flags.getTag() == AudioIoFlags::Tag::input &&
+ isBitPositionFlagSet(flags.get<AudioIoFlags::Tag::input>(), AudioInputFlags::FAST)) {
+ // "Fast" input is not a mandatory flag, try without it.
+ matchFlags.set<AudioIoFlags::Tag::input>(flags.get<AudioIoFlags::Tag::input>() &
+ ~makeBitPositionFlagMask(AudioInputFlags::FAST));
+ it = std::find_if(mPorts.begin(), mPorts.end(), matcher);
+ }
+ return it;
+}
+
+DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(const AudioDevice& device) {
+ return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+ [&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
+}
+
+DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
+ const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle) {
+ using Tag = AudioPortExt::Tag;
+ return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+ [&](const auto& pair) {
+ const auto& p = pair.second;
+ LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
+ !p.sampleRate.has_value() || !p.channelMask.has_value() ||
+ !p.format.has_value() || !p.flags.has_value(),
+ "%s: stored mix port config is not fully specified: %s",
+ __func__, p.toString().c_str());
+ return p.ext.getTag() == Tag::mix &&
+ isConfigEqualToPortConfig(config, p) &&
+ (!flags.has_value() || p.flags.value() == flags.value()) &&
+ p.ext.template get<Tag::mix>().handle == ioHandle; });
+}
+/*
+DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
+ const AudioPortConfig& portConfig) {
+ using Tag = AudioPortExt::Tag;
+ if (portConfig.ext.getTag() == Tag::mix) {
+ return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
+ [&](const auto& pair) {
+ const auto& p = pair.second;
+ LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
+ !p.sampleRate.has_value() || !p.channelMask.has_value() ||
+ !p.format.has_value() || !p.flags.has_value(),
+ "%s: stored mix port config is not fully specified: %s",
+ __func__, p.toString().c_str());
+ return p.ext.getTag() == Tag::mix &&
+ (!portConfig.sampleRate.has_value() ||
+ p.sampleRate == portConfig.sampleRate) &&
+ (!portConfig.channelMask.has_value() ||
+ p.channelMask == portConfig.channelMask) &&
+ (!portConfig.format.has_value() || p.format == portConfig.format) &&
+ (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
+ p.ext.template get<Tag::mix>().handle ==
+ portConfig.ext.template get<Tag::mix>().handle; });
+ } else if (portConfig.ext.getTag() == Tag::device) {
+ return findPortConfig(portConfig.ext.get<Tag::device>().device);
+ }
+ return mPortConfigs.end();
+}
+*/
+void DeviceHalAidl::resetPatch(int32_t patchId) {
+ if (auto it = mPatches.find(patchId); it != mPatches.end()) {
+ mPatches.erase(it);
+ TIME_CHECK();
+ if (ndk::ScopedAStatus status = mModule->resetAudioPatch(patchId); !status.isOk()) {
+ ALOGE("%s: error while resetting patch %d: %s",
+ __func__, patchId, status.getDescription().c_str());
+ }
+ return;
+ }
+ ALOGE("%s: patch id %d not found", __func__, patchId);
+}
+
+void DeviceHalAidl::resetPortConfig(int32_t portConfigId) {
+ if (auto it = mPortConfigs.find(portConfigId); it != mPortConfigs.end()) {
+ mPortConfigs.erase(it);
+ TIME_CHECK();
+ if (ndk::ScopedAStatus status = mModule->resetAudioPortConfig(portConfigId);
+ !status.isOk()) {
+ ALOGE("%s: error while resetting port config %d: %s",
+ __func__, portConfigId, status.getDescription().c_str());
+ }
+ return;
+ }
+ ALOGE("%s: port config id %d not found", __func__, portConfigId);
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
new file mode 100644
index 0000000..d666c7c
--- /dev/null
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include <aidl/android/hardware/audio/core/BpModule.h>
+#include <aidl/android/hardware/audio/core/sounddose/BpSoundDose.h>
+#include <media/audiohal/DeviceHalInterface.h>
+#include <media/audiohal/EffectHalInterface.h>
+
+#include "ConversionHelperAidl.h"
+
+namespace android {
+
+class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl {
+ public:
+ // Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
+ status_t getSupportedDevices(uint32_t *devices) override;
+
+ // Check to see if the audio hardware interface has been initialized.
+ status_t initCheck() override;
+
+ // Set the audio volume of a voice call. Range is between 0.0 and 1.0.
+ status_t setVoiceVolume(float volume) override;
+
+ // Set the audio volume for all audio activities other than voice call.
+ status_t setMasterVolume(float volume) override;
+
+ // Get the current master volume value for the HAL.
+ status_t getMasterVolume(float *volume) override;
+
+ // Called when the audio mode changes.
+ status_t setMode(audio_mode_t mode) override;
+
+ // Muting control.
+ status_t setMicMute(bool state) override;
+
+ status_t getMicMute(bool* state) override;
+
+ status_t setMasterMute(bool state) override;
+
+ status_t getMasterMute(bool *state) override;
+
+ // Set global audio parameters.
+ status_t setParameters(const String8& kvPairs) override;
+
+ // Get global audio parameters.
+ status_t getParameters(const String8& keys, String8 *values) override;
+
+ // Returns audio input buffer size according to parameters passed.
+ status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
+
+ // Creates and opens the audio hardware output stream. The stream is closed
+ // by releasing all references to the returned object.
+ status_t openOutputStream(audio_io_handle_t handle, audio_devices_t devices,
+ audio_output_flags_t flags, struct audio_config* config,
+ const char* address, sp<StreamOutHalInterface>* outStream) override;
+
+ // Creates and opens the audio hardware input stream. The stream is closed
+ // by releasing all references to the returned object.
+ status_t openInputStream(audio_io_handle_t handle, audio_devices_t devices,
+ struct audio_config* config, audio_input_flags_t flags,
+ const char* address, audio_source_t source,
+ audio_devices_t outputDevice, const char* outputDeviceAddress,
+ sp<StreamInHalInterface>* inStream) override;
+
+ // Returns whether createAudioPatch and releaseAudioPatch operations are supported.
+ status_t supportsAudioPatches(bool* supportsPatches) override;
+
+ // Creates an audio patch between several source and sink ports.
+ status_t createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+ unsigned int num_sinks, const struct audio_port_config* sinks,
+ audio_patch_handle_t* patch) override;
+
+ // Releases an audio patch.
+ status_t releaseAudioPatch(audio_patch_handle_t patch) override;
+
+ // Fills the list of supported attributes for a given audio port.
+ status_t getAudioPort(struct audio_port* port) override;
+
+ // Fills the list of supported attributes for a given audio port.
+ status_t getAudioPort(struct audio_port_v7 *port) override;
+
+ // Set audio port configuration.
+ status_t setAudioPortConfig(const struct audio_port_config* config) override;
+
+ // List microphones
+ status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones);
+
+ status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
+ status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
+
+ status_t getMmapPolicyInfos(media::audio::common::AudioMMapPolicyType policyType __unused,
+ std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos
+ __unused) override;
+
+ int32_t getAAudioMixerBurstCount() override;
+
+ int32_t getAAudioHardwareBurstMinUsec() override;
+
+ error::Result<audio_hw_sync_t> getHwAvSync() override;
+
+ status_t dump(int __unused, const Vector<String16>& __unused) override;
+
+ int32_t supportsBluetoothVariableLatency(bool* supports __unused) override;
+
+ status_t getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) override;
+
+ private:
+ friend class sp<DeviceHalAidl>;
+ using Patches = std::map<int32_t /*patch ID*/,
+ ::aidl::android::hardware::audio::core::AudioPatch>;
+ using PortConfigs = std::map<int32_t /*port config ID*/,
+ ::aidl::android::media::audio::common::AudioPortConfig>;
+ using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
+ class Cleanups;
+
+ // Must not be constructed directly by clients.
+ DeviceHalAidl(
+ const std::string& instance,
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module)
+ : ConversionHelperAidl("DeviceHalAidl"), mInstance(instance), mModule(module) {}
+
+ ~DeviceHalAidl() override = default;
+
+ bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioPort& p);
+ bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioPortConfig& p);
+ status_t createPortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ ::aidl::android::media::audio::common::AudioPortConfig* appliedPortConfig);
+ status_t findOrCreatePatch(
+ const std::set<int32_t>& sourcePortConfigIds,
+ const std::set<int32_t>& sinkPortConfigIds,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+ status_t findOrCreatePatch(
+ const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+ bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioConfig& config,
+ const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+ int32_t ioHandle,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+ Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds,
+ const std::set<int32_t>& sinkPortConfigIds);
+ Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device);
+ Ports::iterator findPort(
+ const ::aidl::android::media::audio::common::AudioConfig& config,
+ const ::aidl::android::media::audio::common::AudioIoFlags& flags);
+ PortConfigs::iterator findPortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device);
+ PortConfigs::iterator findPortConfig(
+ const ::aidl::android::media::audio::common::AudioConfig& config,
+ const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
+ int32_t ioHandle);
+ // Currently unused but may be useful for implementing setAudioPortConfig
+ // PortConfigs::iterator findPortConfig(
+ // const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
+ status_t prepareToOpenStream(
+ int32_t aidlHandle,
+ const ::aidl::android::media::audio::common::AudioDevice& aidlDevice,
+ const ::aidl::android::media::audio::common::AudioIoFlags& aidlFlags,
+ struct audio_config* config,
+ Cleanups* cleanups,
+ ::aidl::android::media::audio::common::AudioConfig* aidlConfig,
+ ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
+ int32_t* nominalLatency);
+ void resetPatch(int32_t patchId);
+ void resetPortConfig(int32_t portConfigId);
+
+ const std::string mInstance;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule;
+ std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose>
+ mSoundDose = nullptr;
+ Ports mPorts;
+ int32_t mDefaultInputPortId = -1;
+ int32_t mDefaultOutputPortId = -1;
+ PortConfigs mPortConfigs;
+ Patches mPatches;
+ std::map<audio_patch_handle_t, int32_t /* patch ID */> mFwkHandles;
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0cdf621..e0b1afb 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -17,7 +17,7 @@
#include <stdio.h>
#define LOG_TAG "DeviceHalHidl"
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <cutils/native_handle.h>
#include <cutils/properties.h>
@@ -35,6 +35,17 @@
#include "ParameterUtils.h"
#include "StreamHalHidl.h"
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+#include <aidl/android/hardware/audio/core/sounddose/BpSoundDose.h>
+#include <aidl/android/hardware/audio/sounddose/BpSoundDoseFactory.h>
+#include <android/binder_manager.h>
+
+constexpr std::string_view kSoundDoseInterfaceModule = "/default";
+
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+using aidl::android::hardware::audio::sounddose::ISoundDoseFactory;
+#endif
+
using ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION::implementation::HidlUtils;
using ::android::hardware::audio::common::utils::EnumBitfield;
using ::android::hardware::audio::CORE_TYPES_CPP_VERSION::implementation::CoreUtils;
@@ -46,11 +57,21 @@
using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
-#define TIME_CHECK() auto timeCheck = \
- mediautils::makeTimeCheckStatsForClassMethod(getClassName(), __func__)
+class DeviceHalHidl::SoundDoseWrapper {
+public:
+ SoundDoseWrapper() = default;
+ ~SoundDoseWrapper() = default;
+
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+ std::shared_ptr<ISoundDoseFactory> mSoundDoseFactory;
+ std::shared_ptr<ISoundDose> mSoundDose;
+#endif
+};
DeviceHalHidl::DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device)
- : CoreConversionHelperHidl("DeviceHalHidl"), mDevice(device) {
+ : CoreConversionHelperHidl("DeviceHalHidl"),
+ mDevice(device),
+ mSoundDoseWrapper(std::make_unique<DeviceHalHidl::SoundDoseWrapper>()) {
}
DeviceHalHidl::DeviceHalHidl(
@@ -59,7 +80,8 @@
#if MAJOR_VERSION <= 6 || (MAJOR_VERSION == 7 && MINOR_VERSION == 0)
mDevice(device),
#endif
- mPrimaryDevice(device) {
+ mPrimaryDevice(device),
+ mSoundDoseWrapper(std::make_unique<DeviceHalHidl::SoundDoseWrapper>()) {
#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
auto getDeviceRet = mPrimaryDevice->getDevice();
if (getDeviceRet.isOk()) {
@@ -459,12 +481,13 @@
#if MAJOR_VERSION == 2
status_t DeviceHalHidl::getMicrophones(
- std::vector<media::MicrophoneInfo> *microphonesInfo __unused) {
+ std::vector<audio_microphone_characteristic_t> *microphonesInfo __unused) {
if (mDevice == 0) return NO_INIT;
return INVALID_OPERATION;
}
#elif MAJOR_VERSION >= 4
-status_t DeviceHalHidl::getMicrophones(std::vector<media::MicrophoneInfo> *microphonesInfo) {
+status_t DeviceHalHidl::getMicrophones(
+ std::vector<audio_microphone_characteristic_t> *microphonesInfo) {
TIME_CHECK();
if (mDevice == 0) return NO_INIT;
Result retval;
@@ -475,8 +498,7 @@
audio_microphone_characteristic_t dst;
//convert
(void)CoreUtils::microphoneInfoToHal(micArrayHal[k], &dst);
- media::MicrophoneInfo microphone = media::MicrophoneInfo(dst);
- microphonesInfo->push_back(microphone);
+ microphonesInfo->push_back(dst);
}
});
return processReturn("getMicrophones", ret, retval);
@@ -577,4 +599,50 @@
return processReturn("dump", ret);
}
+#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
+status_t DeviceHalHidl::getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) {
+ if (mSoundDoseWrapper->mSoundDose != nullptr) {
+ *soundDoseBinder = mSoundDoseWrapper->mSoundDose->asBinder();
+ return OK;
+ }
+
+ if (mSoundDoseWrapper->mSoundDoseFactory == nullptr) {
+ std::string interface =
+ std::string(ISoundDoseFactory::descriptor) + kSoundDoseInterfaceModule.data();
+ AIBinder* binder = AServiceManager_checkService(interface.c_str());
+ if (binder == nullptr) {
+ ALOGW("%s service %s doesn't exist", __func__, interface.c_str());
+ return NO_INIT;
+ }
+ mSoundDoseWrapper->mSoundDoseFactory =
+ ISoundDoseFactory::fromBinder(ndk::SpAIBinder(binder));
+ }
+
+ auto result = mSoundDoseWrapper->mSoundDoseFactory->getSoundDose(
+ module, &mSoundDoseWrapper->mSoundDose);
+ if (!result.isOk()) {
+ ALOGW("%s could not get sound dose interface: %s", __func__, result.getMessage());
+ return BAD_VALUE;
+ }
+
+ if (mSoundDoseWrapper->mSoundDose == nullptr) {
+ ALOGW("%s standalone sound dose interface is not implemented", __func__);
+ *soundDoseBinder = nullptr;
+ return OK;
+ }
+
+ *soundDoseBinder = mSoundDoseWrapper->mSoundDose->asBinder();
+ ALOGI("%s using standalone sound dose interface", __func__);
+ return OK;
+}
+#else
+status_t DeviceHalHidl::getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) {
+ (void)module; // avoid unused param
+ (void)soundDoseBinder; // avoid unused param
+ return INVALID_OPERATION;
+}
+#endif
+
} // namespace android
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index f6519b6..30fbd6d 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -30,87 +30,74 @@
{
public:
// Sets the value of 'devices' to a bitmask of 1 or more values of audio_devices_t.
- virtual status_t getSupportedDevices(uint32_t *devices);
+ status_t getSupportedDevices(uint32_t *devices) override;
// Check to see if the audio hardware interface has been initialized.
- virtual status_t initCheck();
+ status_t initCheck() override;
// Set the audio volume of a voice call. Range is between 0.0 and 1.0.
- virtual status_t setVoiceVolume(float volume);
+ status_t setVoiceVolume(float volume) override;
// Set the audio volume for all audio activities other than voice call.
- virtual status_t setMasterVolume(float volume);
+ status_t setMasterVolume(float volume) override;
// Get the current master volume value for the HAL.
- virtual status_t getMasterVolume(float *volume);
+ status_t getMasterVolume(float *volume) override;
// Called when the audio mode changes.
- virtual status_t setMode(audio_mode_t mode);
+ status_t setMode(audio_mode_t mode) override;
// Muting control.
- virtual status_t setMicMute(bool state);
- virtual status_t getMicMute(bool *state);
- virtual status_t setMasterMute(bool state);
- virtual status_t getMasterMute(bool *state);
+ status_t setMicMute(bool state) override;
+ status_t getMicMute(bool *state) override;
+ status_t setMasterMute(bool state) override;
+ status_t getMasterMute(bool *state) override;
// Set global audio parameters.
- virtual status_t setParameters(const String8& kvPairs);
+ status_t setParameters(const String8& kvPairs) override;
// Get global audio parameters.
- virtual status_t getParameters(const String8& keys, String8 *values);
+ status_t getParameters(const String8& keys, String8 *values) override;
// Returns audio input buffer size according to parameters passed.
- virtual status_t getInputBufferSize(const struct audio_config *config,
- size_t *size);
+ status_t getInputBufferSize(const struct audio_config* config, size_t* size) override;
// Creates and opens the audio hardware output stream. The stream is closed
// by releasing all references to the returned object.
- virtual status_t openOutputStream(
- audio_io_handle_t handle,
- audio_devices_t devices,
- audio_output_flags_t flags,
- struct audio_config *config,
- const char *address,
- sp<StreamOutHalInterface> *outStream);
+ status_t openOutputStream(audio_io_handle_t handle, audio_devices_t devices,
+ audio_output_flags_t flags, struct audio_config* config,
+ const char* address, sp<StreamOutHalInterface>* outStream) override;
// Creates and opens the audio hardware input stream. The stream is closed
// by releasing all references to the returned object.
- virtual status_t openInputStream(
- audio_io_handle_t handle,
- audio_devices_t devices,
- struct audio_config *config,
- audio_input_flags_t flags,
- const char *address,
- audio_source_t source,
- audio_devices_t outputDevice,
- const char *outputDeviceAddress,
- sp<StreamInHalInterface> *inStream);
+ status_t openInputStream(audio_io_handle_t handle, audio_devices_t devices,
+ struct audio_config* config, audio_input_flags_t flags,
+ const char* address, audio_source_t source,
+ audio_devices_t outputDevice, const char* outputDeviceAddress,
+ sp<StreamInHalInterface>* inStream) override;
// Returns whether createAudioPatch and releaseAudioPatch operations are supported.
- virtual status_t supportsAudioPatches(bool *supportsPatches);
+ status_t supportsAudioPatches(bool* supportsPatches) override;
// Creates an audio patch between several source and sink ports.
- virtual status_t createAudioPatch(
- unsigned int num_sources,
- const struct audio_port_config *sources,
- unsigned int num_sinks,
- const struct audio_port_config *sinks,
- audio_patch_handle_t *patch);
+ status_t createAudioPatch(unsigned int num_sources, const struct audio_port_config* sources,
+ unsigned int num_sinks, const struct audio_port_config* sinks,
+ audio_patch_handle_t* patch) override;
// Releases an audio patch.
- virtual status_t releaseAudioPatch(audio_patch_handle_t patch);
+ status_t releaseAudioPatch(audio_patch_handle_t patch) override;
// Fills the list of supported attributes for a given audio port.
- virtual status_t getAudioPort(struct audio_port *port);
+ status_t getAudioPort(struct audio_port *port) override;
// Fills the list of supported attributes for a given audio port.
- virtual status_t getAudioPort(struct audio_port_v7 *port);
+ status_t getAudioPort(struct audio_port_v7 *port) override;
// Set audio port configuration.
- virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+ status_t setAudioPortConfig(const struct audio_port_config *config) override;
// List microphones
- virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones);
+ status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
status_t removeDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
@@ -132,18 +119,28 @@
return INVALID_OPERATION;
}
+ int32_t supportsBluetoothVariableLatency(bool* supports __unused) override {
+ // TODO: Implement the HAL query when moving to AIDL HAL.
+ return INVALID_OPERATION;
+ }
+
status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
error::Result<audio_hw_sync_t> getHwAvSync() override;
status_t dump(int fd, const Vector<String16>& args) override;
+ status_t getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) override;
+
private:
friend class DevicesFactoryHalHidl;
sp<::android::hardware::audio::CPP_VERSION::IDevice> mDevice;
// Null if it's not a primary device.
sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice> mPrimaryDevice;
bool supportsSetConnectedState7_1 = true;
+ class SoundDoseWrapper;
+ const std::unique_ptr<SoundDoseWrapper> mSoundDoseWrapper;
// Can not be constructed directly by clients.
explicit DeviceHalHidl(const sp<::android::hardware::audio::CPP_VERSION::IDevice>& device);
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index 29fb558..b452fa3 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -17,22 +17,23 @@
#define LOG_TAG "DevicesFactoryHalAidl"
//#define LOG_NDEBUG 0
+#include <aidl/android/hardware/audio/core/IModule.h>
#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <memory>
#include <utils/Log.h>
+#include "DeviceHalAidl.h"
#include "DevicesFactoryHalAidl.h"
+using namespace ::aidl::android::hardware::audio::core;
using ::android::detail::AudioHalVersionInfo;
namespace android {
-DevicesFactoryHalAidl::DevicesFactoryHalAidl(std::shared_ptr<IConfig> iconfig) {
+DevicesFactoryHalAidl::DevicesFactoryHalAidl(std::shared_ptr<IConfig> iconfig)
+ : mIConfig(std::move(iconfig)) {
ALOG_ASSERT(iconfig != nullptr, "Provided default IConfig service is NULL");
- mIConfig = std::move(iconfig);
-}
-
-void DevicesFactoryHalAidl::onFirstRef() {
- ALOGE("%s not implemented yet", __func__);
}
// Opens a device with the specified name. To close the device, it is
@@ -41,34 +42,68 @@
if (name == nullptr || device == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+
+ std::shared_ptr<IModule> service;
+ // FIXME: Normally we will list available HAL modules and connect to them,
+ // however currently we still get the list of module names from the config.
+ // Since the example service does not have all modules, the SM will wait
+ // for the missing ones forever.
+ if (strcmp(name, "primary") == 0 || strcmp(name, "r_submix") == 0) {
+ if (strcmp(name, "primary") == 0) name = "default";
+ auto serviceName = std::string(IModule::descriptor) + "/" + name;
+ service = IModule::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+ ALOGE_IF(service == nullptr, "%s fromBinder %s failed", __func__, serviceName.c_str());
+ }
+ // If the service is a nullptr, the device will not be really functional,
+ // but will not crash either.
+ *device = sp<DeviceHalAidl>::make(name, service);
+ return OK;
}
status_t DevicesFactoryHalAidl::getHalPids(std::vector<pid_t> *pids) {
if (pids == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+ // The functionality for retrieving debug infos of services is not exposed via the NDK.
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == nullptr) {
+ return NO_INIT;
+ }
+ std::set<pid_t> pidsSet;
+ const auto moduleServiceName = std::string(IModule::descriptor) + "/";
+ auto debugInfos = sm->getServiceDebugInfo();
+ for (const auto& info : debugInfos) {
+ if (info.pid > 0 &&
+ info.name.size() > moduleServiceName.size() && // '>' as there must be instance name
+ info.name.substr(0, moduleServiceName.size()) == moduleServiceName) {
+ pidsSet.insert(info.pid);
+ }
+ }
+ *pids = {pidsSet.begin(), pidsSet.end()};
+ return NO_ERROR;
}
status_t DevicesFactoryHalAidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
- if (callback == nullptr) {
- return BAD_VALUE;
+ // Dynamic registration of module instances is not supported. The functionality
+ // in the audio server which is related to this callback can be removed together
+ // with HIDL support.
+ ALOG_ASSERT(callback != nullptr);
+ if (callback != nullptr) {
+ callback->onNewDevicesAvailable();
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+ return NO_ERROR;
}
AudioHalVersionInfo DevicesFactoryHalAidl::getHalVersion() const {
int32_t versionNumber = 0;
- if (mIConfig) {
- if (!mIConfig->getInterfaceVersion(&versionNumber).isOk()) {
- ALOGE("%s getInterfaceVersion failed", __func__);
- } else {
- ALOGI("%s getInterfaceVersion %d", __func__, versionNumber);
+ if (mIConfig != 0) {
+ if (ndk::ScopedAStatus status = mIConfig->getInterfaceVersion(&versionNumber);
+ !status.isOk()) {
+ ALOGE("%s getInterfaceVersion failed: %s", __func__, status.getDescription().c_str());
}
+ } else {
+ ALOGW("%s no IConfig instance", __func__);
}
// AIDL does not have minor version, fill 0 for all versions
return AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, versionNumber);
@@ -76,9 +111,14 @@
// Main entry-point to the shared library.
extern "C" __attribute__((visibility("default"))) void* createIDevicesFactoryImpl() {
+ auto serviceName = std::string(IConfig::descriptor) + "/default";
auto service = IConfig::fromBinder(
- ndk::SpAIBinder(AServiceManager_waitForService(IConfig::descriptor)));
- return service ? new DevicesFactoryHalAidl(service) : nullptr;
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+ if (!service) {
+ ALOGE("%s binder service %s not exist", __func__, serviceName.c_str());
+ return nullptr;
+ }
+ return new DevicesFactoryHalAidl(service);
}
} // namespace android
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.h b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
index f4812af..cb627bc 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
@@ -20,15 +20,13 @@
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <utils/RefBase.h>
-using namespace ::aidl::android::hardware::audio::core;
-
namespace android {
class DevicesFactoryHalAidl : public DevicesFactoryHalInterface
{
public:
- explicit DevicesFactoryHalAidl(std::shared_ptr<IConfig> iConfig);
- void onFirstRef() override;
+ explicit DevicesFactoryHalAidl(
+ std::shared_ptr<::aidl::android::hardware::audio::core::IConfig> iConfig);
// Opens a device with the specified name. To close the device, it is
// necessary to release references to the returned object.
@@ -41,8 +39,8 @@
android::detail::AudioHalVersionInfo getHalVersion() const override;
private:
- std::shared_ptr<IConfig> mIConfig;
- virtual ~DevicesFactoryHalAidl() = default;
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IConfig> mIConfig;
+ ~DevicesFactoryHalAidl() = default;
};
} // namespace android
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.cpp b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
new file mode 100644
index 0000000..5af8e24
--- /dev/null
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectBufferHalAidl"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+
+#include "EffectBufferHalAidl.h"
+
+namespace android {
+namespace effect {
+
+// static
+status_t EffectBufferHalAidl::allocate(size_t size, sp<EffectBufferHalInterface>* buffer) {
+ ALOGE("%s not implemented yet %zu %p", __func__, size, buffer);
+ return mirror(nullptr, size, buffer);
+}
+
+status_t EffectBufferHalAidl::mirror(void* external, size_t size,
+ sp<EffectBufferHalInterface>* buffer) {
+ // buffer->setExternalData(external);
+ ALOGW("%s not implemented yet %p %zu %p", __func__, external, size, buffer);
+ return OK;
+}
+
+EffectBufferHalAidl::EffectBufferHalAidl(size_t size)
+ : mBufferSize(size),
+ mFrameCountChanged(false),
+ mExternalData(nullptr),
+ mAudioBuffer{0, {nullptr}} {
+}
+
+EffectBufferHalAidl::~EffectBufferHalAidl() {
+}
+
+status_t EffectBufferHalAidl::init() {
+ ALOGW("%s not implemented yet", __func__);
+ return OK;
+}
+
+audio_buffer_t* EffectBufferHalAidl::audioBuffer() {
+ return &mAudioBuffer;
+}
+
+void* EffectBufferHalAidl::externalData() const {
+ return mExternalData;
+}
+
+void EffectBufferHalAidl::setFrameCount(size_t frameCount) {
+ mAudioBuffer.frameCount = frameCount;
+ mFrameCountChanged = true;
+}
+
+bool EffectBufferHalAidl::checkFrameCountChange() {
+ bool result = mFrameCountChanged;
+ mFrameCountChanged = false;
+ return result;
+}
+
+void EffectBufferHalAidl::setExternalData(void* external) {
+ mExternalData = external;
+}
+
+void EffectBufferHalAidl::update() {
+ ALOGW("%s not implemented yet", __func__);
+}
+
+void EffectBufferHalAidl::commit() {
+ ALOGW("%s not implemented yet", __func__);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectBufferHalAidl.h b/media/libaudiohal/impl/EffectBufferHalAidl.h
new file mode 100644
index 0000000..f488708
--- /dev/null
+++ b/media/libaudiohal/impl/EffectBufferHalAidl.h
@@ -0,0 +1,61 @@
+/*
+ * 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 <media/audiohal/EffectBufferHalInterface.h>
+#include <system/audio_effect.h>
+
+namespace android {
+namespace effect {
+
+class EffectBufferHalAidl : public EffectBufferHalInterface {
+ public:
+ static status_t allocate(size_t size, sp<EffectBufferHalInterface>* buffer);
+ static status_t mirror(void* external, size_t size, sp<EffectBufferHalInterface>* buffer);
+
+ audio_buffer_t* audioBuffer() override;
+ void* externalData() const override;
+
+ size_t getSize() const override { return mBufferSize; }
+
+ void setExternalData(void* external) override;
+ void setFrameCount(size_t frameCount) override;
+ bool checkFrameCountChange() override;
+
+ void update() override;
+ void commit() override;
+ void update(size_t size) override;
+ void commit(size_t size) override;
+
+ private:
+ friend class EffectBufferHalInterface;
+
+ const size_t mBufferSize;
+ bool mFrameCountChanged;
+ void* mExternalData;
+ audio_buffer_t mAudioBuffer;
+
+ // Can not be constructed directly by clients.
+ explicit EffectBufferHalAidl(size_t size);
+
+ ~EffectBufferHalAidl();
+
+ status_t init();
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
new file mode 100644
index 0000000..6190596
--- /dev/null
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -0,0 +1,304 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "EffectConversionHelperAidl"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+
+#include <utils/Log.h>
+
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::CommandId;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioMode;
+using ::aidl::android::media::audio::common::AudioSource;
+using android::effect::utils::EffectParamReader;
+using android::effect::utils::EffectParamWriter;
+
+using ::android::status_t;
+
+const std::map<uint32_t /* effect_command_e */, EffectConversionHelperAidl::CommandHandler>
+ EffectConversionHelperAidl::mCommandHandlerMap = {
+ {EFFECT_CMD_INIT, &EffectConversionHelperAidl::handleInit},
+ {EFFECT_CMD_SET_PARAM, &EffectConversionHelperAidl::handleSetParameter},
+ {EFFECT_CMD_GET_PARAM, &EffectConversionHelperAidl::handleGetParameter},
+ {EFFECT_CMD_SET_CONFIG, &EffectConversionHelperAidl::handleSetConfig},
+ {EFFECT_CMD_GET_CONFIG, &EffectConversionHelperAidl::handleGetConfig},
+ {EFFECT_CMD_RESET, &EffectConversionHelperAidl::handleReset},
+ {EFFECT_CMD_ENABLE, &EffectConversionHelperAidl::handleEnable},
+ {EFFECT_CMD_DISABLE, &EffectConversionHelperAidl::handleDisable},
+ {EFFECT_CMD_SET_AUDIO_SOURCE, &EffectConversionHelperAidl::handleSetAudioSource},
+ {EFFECT_CMD_SET_DEVICE, &EffectConversionHelperAidl::handleSetDevice},
+ {EFFECT_CMD_SET_INPUT_DEVICE, &EffectConversionHelperAidl::handleSetDevice},
+ {EFFECT_CMD_SET_VOLUME, &EffectConversionHelperAidl::handleSetVolume},
+ {EFFECT_CMD_OFFLOAD, &EffectConversionHelperAidl::handleSetOffload},
+ {EFFECT_CMD_FIRST_PROPRIETARY, &EffectConversionHelperAidl::handleFirstPriority}};
+
+EffectConversionHelperAidl::EffectConversionHelperAidl(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId, const Descriptor& desc)
+ : mSessionId(sessionId), mIoId(ioId), mDesc(desc), mEffect(std::move(effect)) {
+ mCommon.session = sessionId;
+ mCommon.ioHandle = ioId;
+ mCommon.input = mCommon.output = kDefaultAudioConfig;
+}
+
+status_t EffectConversionHelperAidl::handleCommand(uint32_t cmdCode, uint32_t cmdSize,
+ void* pCmdData, uint32_t* replySize,
+ void* pReplyData) {
+ const auto& handler = mCommandHandlerMap.find(cmdCode);
+ if (handler == mCommandHandlerMap.end() || !handler->second) {
+ ALOGE("%s handler for command %u doesn't exist", __func__, cmdCode);
+ return BAD_VALUE;
+ }
+ return (this->*handler->second)(cmdSize, pCmdData, replySize, pReplyData);
+}
+
+status_t EffectConversionHelperAidl::handleInit(uint32_t cmdSize __unused,
+ const void* pCmdData __unused, uint32_t* replySize,
+ void* pReplyData) {
+ if (!replySize || *replySize < sizeof(int) || !pReplyData) {
+ return BAD_VALUE;
+ }
+
+ return *(status_t*)pReplyData =
+ statusTFromBinderStatus(mEffect->open(mCommon, std::nullopt, &mOpenReturn));
+}
+
+status_t EffectConversionHelperAidl::handleSetParameter(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize < sizeof(effect_param_t) || !pCmdData || !replySize ||
+ *replySize < sizeof(int) || !pReplyData) {
+ return BAD_VALUE;
+ }
+
+ auto reader = EffectParamReader(*(effect_param_t*)pCmdData);
+ if (!reader.validateCmdSize(cmdSize)) {
+ ALOGE("%s illegal param %s size %u", __func__, reader.toString().c_str(), cmdSize);
+ return BAD_VALUE;
+ }
+
+ status_t ret = setParameter(reader);
+ EffectParamWriter writer(*(effect_param_t*)pReplyData);
+ writer.setStatus(ret);
+ return *(status_t*)pReplyData = ret;
+}
+
+status_t EffectConversionHelperAidl::handleGetParameter(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize < sizeof(effect_param_t) || !pCmdData || !replySize || !pReplyData) {
+ return BAD_VALUE;
+ }
+
+ const auto reader = EffectParamReader(*(effect_param_t*)pCmdData);
+ if (*replySize < sizeof(effect_param_t) + reader.getParameterSize()) {
+ ALOGE("%s illegal param %s, replySize %u", __func__, reader.toString().c_str(), *replySize);
+ return BAD_VALUE;
+ }
+
+ // copy effect_param_t and parameters
+ memcpy(pReplyData, pCmdData, sizeof(effect_param_t) + reader.getParameterSize());
+ auto writer = EffectParamWriter(*(effect_param_t*)pReplyData);
+ status_t ret = getParameter(writer);
+ writer.finishValueWrite();
+ writer.setStatus(ret);
+ *replySize = writer.getTotalSize();
+ if (ret != OK) {
+ ALOGE("%s error ret %d, %s", __func__, ret, writer.toString().c_str());
+ }
+ return ret;
+}
+
+status_t EffectConversionHelperAidl::handleSetConfig(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (!replySize || *replySize != sizeof(int) || !pReplyData ||
+ cmdSize != sizeof(effect_config_t)) {
+ return BAD_VALUE;
+ }
+
+ return *static_cast<int32_t*>(pReplyData) = OK;
+ const auto& legacyConfig = static_cast<const effect_config_t*>(pCmdData);
+ // already open, apply latest settings
+ Parameter::Common common;
+ common.input.base =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
+ legacyConfig->inputCfg, true /* isInput */));
+ common.output.base =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
+ legacyConfig->outputCfg, false /* isInput */));
+ common.session = mSessionId;
+ common.ioHandle = mIoId;
+ // TODO: add access mode support
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mEffect->setParameter(Parameter::make<Parameter::common>(common))));
+ mCommon = common;
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+
+status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
+ const void* pCmdData __unused,
+ uint32_t* replySize, void* pReplyData) {
+ if (!replySize || *replySize != sizeof(effect_config_t) || !pReplyData) {
+ ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
+ return BAD_VALUE;
+ }
+
+ Parameter param;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(
+ Parameter::Id::make<Parameter::Id::commonTag>(Parameter::common), ¶m)));
+
+ const auto& common = param.get<Parameter::common>();
+ effect_config_t* pConfig = (effect_config_t*)pReplyData;
+ pConfig->inputCfg = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfigBase_buffer_config_t(common.input.base, true));
+ pConfig->outputCfg =
+ VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioConfigBase_buffer_config_t(
+ common.output.base, false));
+ mCommon = common;
+ return OK;
+}
+
+status_t EffectConversionHelperAidl::handleReset(uint32_t cmdSize __unused,
+ const void* pCmdData __unused, uint32_t* replySize,
+ void* pReplyData) {
+ if (!replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
+ return BAD_VALUE;
+ }
+
+ return statusTFromBinderStatus(mEffect->command(CommandId::RESET));
+}
+
+status_t EffectConversionHelperAidl::handleEnable(uint32_t cmdSize __unused,
+ const void* pCmdData __unused,
+ uint32_t* replySize, void* pReplyData) {
+ if (!replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
+ return BAD_VALUE;
+ }
+
+ return statusTFromBinderStatus(mEffect->command(CommandId::START));
+}
+
+status_t EffectConversionHelperAidl::handleDisable(uint32_t cmdSize __unused,
+ const void* pCmdData __unused,
+ uint32_t* replySize, void* pReplyData) {
+ if (!replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
+ return BAD_VALUE;
+ }
+
+ return statusTFromBinderStatus(mEffect->command(CommandId::STOP));
+}
+
+status_t EffectConversionHelperAidl::handleSetAudioSource(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize != sizeof(uint32_t) || !pCmdData || !replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
+ pReplyData);
+ return BAD_VALUE;
+ }
+
+ audio_source_t source = *(audio_source_t*)pCmdData;
+ AudioSource aidlSource =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mEffect->setParameter(Parameter::make<Parameter::source>(aidlSource))));
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+
+status_t EffectConversionHelperAidl::handleSetAudioMode(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize != sizeof(uint32_t) || !pCmdData || !replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
+ pReplyData);
+ return BAD_VALUE;
+ }
+ audio_mode_t mode = *(audio_mode_t *)pCmdData;
+ AudioMode aidlMode =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_mode_t_AudioMode(mode));
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mEffect->setParameter(Parameter::make<Parameter::mode>(aidlMode))));
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+
+status_t EffectConversionHelperAidl::handleSetDevice(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize != sizeof(uint32_t) || !pCmdData || !replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
+ pReplyData);
+ return BAD_VALUE;
+ }
+ // TODO: convert from audio_devices_t to std::vector<AudioDeviceDescription>
+ // const auto& legacyDevice = *(uint32_t*)(pCmdData);
+ std::vector<AudioDeviceDescription> aidlDevices;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mEffect->setParameter(Parameter::make<Parameter::deviceDescription>(aidlDevices))));
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+status_t EffectConversionHelperAidl::handleSetVolume(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize != 2 * sizeof(uint32_t) || !pCmdData || !replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
+ pReplyData);
+ return BAD_VALUE;
+ }
+ Parameter::VolumeStereo volume = {.left = (float)(*(uint32_t*)pCmdData) / (1 << 24),
+ .right = (float)(*(uint32_t*)pCmdData + 1) / (1 << 24)};
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ mEffect->setParameter(Parameter::make<Parameter::volumeStereo>(volume))));
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+
+status_t EffectConversionHelperAidl::handleSetOffload(uint32_t cmdSize, const void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ if (cmdSize < sizeof(effect_offload_param_t) || !pCmdData || !replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %u %p %p %p", __func__, cmdSize, pCmdData, replySize,
+ pReplyData);
+ return BAD_VALUE;
+ }
+ // TODO: handle this after effectproxy implemented in libaudiohal
+ return *static_cast<int32_t*>(pReplyData) = OK;
+}
+
+status_t EffectConversionHelperAidl::handleFirstPriority(uint32_t cmdSize __unused,
+ const void* pCmdData __unused,
+ uint32_t* replySize, void* pReplyData) {
+ if (!replySize || !pReplyData) {
+ ALOGE("%s parameter invalid %p %p", __func__, replySize, pReplyData);
+ return BAD_VALUE;
+ }
+
+ // TODO to be implemented
+ return OK;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
new file mode 100644
index 0000000..94435c6
--- /dev/null
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -0,0 +1,104 @@
+/*
+ * 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 <utils/Errors.h>
+
+#include <aidl/android/hardware/audio/effect/BpEffect.h>
+#include <system/audio_effect.h>
+#include <system/audio_effects/audio_effects_utils.h>
+
+namespace android {
+namespace effect {
+
+class EffectConversionHelperAidl {
+ public:
+ status_t handleCommand(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ virtual ~EffectConversionHelperAidl() {}
+
+ protected:
+ const int32_t mSessionId;
+ const int32_t mIoId;
+ const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
+ ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn mOpenReturn;
+ ::aidl::android::hardware::audio::effect::Parameter::Common mCommon;
+
+ EffectConversionHelperAidl(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+
+ status_t handleSetParameter(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleGetParameter(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+
+ private:
+ const aidl::android::media::audio::common::AudioFormatDescription kDefaultFormatDescription = {
+ .type = aidl::android::media::audio::common::AudioFormatType::PCM,
+ .pcm = aidl::android::media::audio::common::PcmType::FLOAT_32_BIT};
+
+ static constexpr int kDefaultframeCount = 0x100;
+
+ using AudioChannelLayout = aidl::android::media::audio::common::AudioChannelLayout;
+ const aidl::android::media::audio::common::AudioConfig kDefaultAudioConfig = {
+ .base = {.sampleRate = 44100,
+ .channelMask = AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO),
+ .format = kDefaultFormatDescription},
+ .frameCount = kDefaultframeCount};
+ // command handler map
+ typedef status_t (EffectConversionHelperAidl::*CommandHandler)(uint32_t /* cmdSize */,
+ const void* /* pCmdData */,
+ uint32_t* /* replySize */,
+ void* /* pReplyData */);
+ static const std::map<uint32_t /* effect_command_e */, CommandHandler> mCommandHandlerMap;
+
+ status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetConfig(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleGetConfig(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleEnable(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleDisable(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleReset(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetAudioSource(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetAudioMode(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetDevice(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetVolume(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleSetOffload(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+ status_t handleFirstPriority(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
+ void* pReplyData);
+
+ // implemented by conversion of each effect
+ virtual status_t setParameter(utils::EffectParamReader& param) = 0;
+ virtual status_t getParameter(utils::EffectParamWriter& param) = 0;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
new file mode 100644
index 0000000..8fa301a
--- /dev/null
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "EffectHalAidl"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/AidlConversionUtil.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <media/EffectsFactoryApi.h>
+#include <mediautils/TimeCheck.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "EffectHalAidl.h"
+
+#include <aidl/android/hardware/audio/effect/IEffect.h>
+
+#include "effectsAidlConversion/AidlConversionAec.h"
+#include "effectsAidlConversion/AidlConversionAgc2.h"
+#include "effectsAidlConversion/AidlConversionBassBoost.h"
+#include "effectsAidlConversion/AidlConversionDownmix.h"
+#include "effectsAidlConversion/AidlConversionDynamicsProcessing.h"
+#include "effectsAidlConversion/AidlConversionEnvReverb.h"
+#include "effectsAidlConversion/AidlConversionEq.h"
+#include "effectsAidlConversion/AidlConversionHapticGenerator.h"
+#include "effectsAidlConversion/AidlConversionLoudnessEnhancer.h"
+#include "effectsAidlConversion/AidlConversionNoiseSuppression.h"
+#include "effectsAidlConversion/AidlConversionPresetReverb.h"
+#include "effectsAidlConversion/AidlConversionSpatializer.h"
+#include "effectsAidlConversion/AidlConversionVendorExtension.h"
+#include "effectsAidlConversion/AidlConversionVirtualizer.h"
+#include "effectsAidlConversion/AidlConversionVisualizer.h"
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::CommandId;
+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::Parameter;
+
+namespace android {
+namespace effect {
+
+EffectHalAidl::EffectHalAidl(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
+ uint64_t effectId, int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : mFactory(factory),
+ mEffect(effect),
+ mEffectId(effectId),
+ mSessionId(sessionId),
+ mIoId(ioId),
+ mDesc(desc) {
+ createAidlConversion(effect, sessionId, ioId, desc);
+}
+
+EffectHalAidl::~EffectHalAidl() {
+ if (mFactory) {
+ mFactory->destroyEffect(mEffect);
+ }
+}
+
+status_t EffectHalAidl::createAidlConversion(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc) {
+ const auto& typeUuid = desc.common.id.type;
+ ALOGI("%s create UUID %s", __func__, typeUuid.toString().c_str());
+ if (typeUuid == kAcousticEchoCancelerTypeUUID) {
+ mConversion =
+ std::make_unique<android::effect::AidlConversionAec>(effect, sessionId, ioId, desc);
+ } else if (typeUuid == kAutomaticGainControl2TypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionAgc2>(effect, sessionId, ioId,
+ desc);
+ } else if (typeUuid == kBassBoostTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionBassBoost>(effect, sessionId,
+ ioId, desc);
+ } else if (typeUuid == kDownmixTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionDownmix>(effect, sessionId,
+ ioId, desc);
+ } else if (typeUuid == kDynamicsProcessingTypeUUID) {
+ mConversion =
+ std::make_unique<android::effect::AidlConversionDp>(effect, sessionId, ioId, desc);
+ } else if (typeUuid == kEnvReverbTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionEnvReverb>(effect, sessionId,
+ ioId, desc);
+ } else if (typeUuid == kEqualizerTypeUUID) {
+ mConversion =
+ std::make_unique<android::effect::AidlConversionEq>(effect, sessionId, ioId, desc);
+ } else if (typeUuid == kHapticGeneratorTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionHapticGenerator>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kLoudnessEnhancerTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionLoudnessEnhancer>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kNoiseSuppressionTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionNoiseSuppression>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kPresetReverbTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionPresetReverb>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kSpatializerTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionSpatializer>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kVirtualizerTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionVirtualizer>(
+ effect, sessionId, ioId, desc);
+ } else if (typeUuid == kVisualizerTypeUUID) {
+ mConversion = std::make_unique<android::effect::AidlConversionVisualizer>(effect, sessionId,
+ ioId, desc);
+ } else {
+ // For unknown UUID, use vendor extension implementation
+ mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
+ effect, sessionId, ioId, desc);
+ }
+ return OK;
+}
+
+status_t EffectHalAidl::setInBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (buffer == nullptr) {
+ return BAD_VALUE;
+ }
+ ALOGW("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t EffectHalAidl::setOutBuffer(const sp<EffectBufferHalInterface>& buffer) {
+ if (buffer == nullptr) {
+ return BAD_VALUE;
+ }
+ ALOGW("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t EffectHalAidl::process() {
+ ALOGW("%s not implemented yet", __func__);
+ // write to input FMQ here, and wait for statusMQ STATUS_OK
+ return OK;
+}
+
+// TODO: no one using, maybe deprecate this interface
+status_t EffectHalAidl::processReverse() {
+ ALOGW("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t EffectHalAidl::command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData,
+ uint32_t* replySize, void* pReplyData) {
+ return mConversion
+ ? mConversion->handleCommand(cmdCode, cmdSize, pCmdData, replySize, pReplyData)
+ : INVALID_OPERATION;
+}
+
+status_t EffectHalAidl::getDescriptor(effect_descriptor_t* pDescriptor) {
+ ALOGW("%s %p", __func__, pDescriptor);
+ if (pDescriptor == nullptr) {
+ return BAD_VALUE;
+ }
+ Descriptor aidlDesc;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getDescriptor(&aidlDesc)));
+
+ *pDescriptor = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(aidlDesc));
+ return OK;
+}
+
+status_t EffectHalAidl::close() {
+ return statusTFromBinderStatus(mEffect->close());
+}
+
+status_t EffectHalAidl::dump(int fd) {
+ ALOGW("%s not implemented yet, fd %d", __func__, fd);
+ return OK;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
new file mode 100644
index 0000000..83b644b
--- /dev/null
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -0,0 +1,97 @@
+/*
+ * 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/IEffect.h>
+#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <system/audio_effect.h>
+#include <memory>
+
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class EffectHalAidl : public EffectHalInterface {
+ public:
+ // Set the input buffer.
+ status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer) override;
+
+ // Set the output buffer.
+ status_t setOutBuffer(const sp<EffectBufferHalInterface>& buffer) override;
+
+ // Effect process function.
+ status_t process() override;
+
+ // Process reverse stream function. This function is used to pass
+ // a reference stream to the effect engine.
+ status_t processReverse() override;
+
+ // Send a command and receive a response to/from effect engine.
+ status_t command(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize,
+ void* pReplyData) override;
+
+ // Returns the effect descriptor.
+ status_t getDescriptor(effect_descriptor_t *pDescriptor) override;
+
+ // Free resources on the remote side.
+ status_t close() override;
+
+ // Whether it's a local implementation.
+ bool isLocal() const override { return false; }
+
+ status_t dump(int fd) override;
+
+ uint64_t effectId() const override { return mEffectId; }
+
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> getIEffect() const {
+ return mEffect;
+ }
+
+ private:
+ friend class sp<EffectHalAidl>;
+
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory> mFactory;
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
+ const uint64_t mEffectId;
+ const int32_t mSessionId;
+ const int32_t mIoId;
+ const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
+ std::unique_ptr<EffectConversionHelperAidl> mConversion;
+
+ sp<EffectBufferHalInterface> mInBuffer, mOutBuffer;
+ effect_config_t mConfig;
+
+ status_t createAidlConversion(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+ // Can not be constructed directly by clients.
+ EffectHalAidl(
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
+ uint64_t effectId, int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+ bool setEffectReverse(bool reverse);
+
+ // The destructor automatically releases the effect.
+ virtual ~EffectHalAidl();
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectHalHidl.cpp b/media/libaudiohal/impl/EffectHalHidl.cpp
index 3956a6c..ed952a3 100644
--- a/media/libaudiohal/impl/EffectHalHidl.cpp
+++ b/media/libaudiohal/impl/EffectHalHidl.cpp
@@ -46,9 +46,6 @@
using namespace ::android::hardware::audio::common::CPP_VERSION;
using namespace ::android::hardware::audio::effect::CPP_VERSION;
-#define TIME_CHECK() auto timeCheck = \
- mediautils::makeTimeCheckStatsForClassMethod(getClassName(), __func__)
-
EffectHalHidl::EffectHalHidl(const sp<IEffect>& effect, uint64_t effectId)
: EffectConversionHelperHidl("EffectHalHidl"),
mEffect(effect), mEffectId(effectId), mBuffersChanged(true), mEfGroup(nullptr) {
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index 7aec859..0aae87b 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -14,69 +14,128 @@
* limitations under the License.
*/
-#include <random>
+#include <algorithm>
+#include <cstdint>
+#include <memory>
#define LOG_TAG "EffectsFactoryHalAidl"
//#define LOG_NDEBUG 0
#include <aidl/android/hardware/audio/effect/IFactory.h>
+#include <error/expected_utils.h>
#include <android/binder_manager.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <system/audio.h>
#include <utils/Log.h>
+#include "EffectBufferHalAidl.h"
+#include "EffectHalAidl.h"
#include "EffectsFactoryHalAidl.h"
+using ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid;
+using aidl::android::aidl_utils::statusTFromBinderStatus;
using aidl::android::hardware::audio::effect::IFactory;
+using aidl::android::media::audio::common::AudioUuid;
using android::detail::AudioHalVersionInfo;
namespace android {
namespace effect {
-EffectsFactoryHalAidl::EffectsFactoryHalAidl(std::shared_ptr<IFactory> effectsFactory) {
+EffectsFactoryHalAidl::EffectsFactoryHalAidl(std::shared_ptr<IFactory> effectsFactory)
+ : mFactory(effectsFactory),
+ mHalVersion(AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, [this]() {
+ int32_t majorVersion = 0;
+ return (mFactory && mFactory->getInterfaceVersion(&majorVersion).isOk()) ? majorVersion
+ : 0;
+ }())) {
ALOG_ASSERT(effectsFactory != nullptr, "Provided IEffectsFactory service is NULL");
- mEffectsFactory = effectsFactory;
}
status_t EffectsFactoryHalAidl::queryNumberEffects(uint32_t *pNumEffects) {
if (pNumEffects == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+
+ {
+ std::lock_guard lg(mLock);
+ RETURN_STATUS_IF_ERROR(queryEffectList_l());
+ *pNumEffects = mDescList->size();
+ }
+ ALOGI("%s %d", __func__, *pNumEffects);
+ return OK;
}
status_t EffectsFactoryHalAidl::getDescriptor(uint32_t index, effect_descriptor_t* pDescriptor) {
- if (index < 0 || pDescriptor == nullptr) {
+ if (pDescriptor == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+
+ std::lock_guard lg(mLock);
+ RETURN_STATUS_IF_ERROR(queryEffectList_l());
+
+ auto listSize = mDescList->size();
+ if (index >= listSize) {
+ ALOGE("%s index %d exceed size DescList %zd", __func__, index, listSize);
+ return INVALID_OPERATION;
+ }
+
+ *pDescriptor = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(mDescList->at(index)));
+ return OK;
}
-status_t EffectsFactoryHalAidl::getDescriptor(const effect_uuid_t* pEffectUuid,
+status_t EffectsFactoryHalAidl::getDescriptor(const effect_uuid_t* halUuid,
effect_descriptor_t* pDescriptor) {
- if (pEffectUuid == nullptr || pDescriptor == nullptr) {
+ if (halUuid == nullptr || pDescriptor == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+
+ AudioUuid uuid = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(*halUuid));
+ std::lock_guard lg(mLock);
+ return getHalDescriptorWithImplUuid_l(uuid, pDescriptor);
}
-status_t EffectsFactoryHalAidl::getDescriptors(const effect_uuid_t* pEffectType,
+status_t EffectsFactoryHalAidl::getDescriptors(const effect_uuid_t* halType,
std::vector<effect_descriptor_t>* descriptors) {
- if (pEffectType == nullptr || descriptors == nullptr) {
+ if (halType == nullptr || descriptors == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+
+ AudioUuid type = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(*halType));
+ std::lock_guard lg(mLock);
+ return getHalDescriptorWithTypeUuid_l(type, descriptors);
}
-status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* pEffectUuid, int32_t sessionId,
+status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* uuid, int32_t sessionId,
int32_t ioId, int32_t deviceId __unused,
sp<EffectHalInterface>* effect) {
- if (pEffectUuid == nullptr || effect == nullptr) {
+ if (uuid == nullptr || effect == nullptr) {
return BAD_VALUE;
}
- ALOGE("%s not implemented yet %d %d", __func__, sessionId, ioId);
- return INVALID_OPERATION;
+ if (sessionId == AUDIO_SESSION_DEVICE && ioId == AUDIO_IO_HANDLE_NONE) {
+ return INVALID_OPERATION;
+ }
+
+ ALOGI("%s session %d ioId %d", __func__, sessionId, ioId);
+
+ AudioUuid aidlUuid = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_uuid_t_AudioUuid(*uuid));
+ std::shared_ptr<IEffect> aidlEffect;
+ Descriptor desc;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect)));
+ if (aidlEffect == nullptr) {
+ ALOGE("%s IFactory::createFactory failed UUID %s", __func__, aidlUuid.toString().c_str());
+ return NAME_NOT_FOUND;
+ }
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(aidlEffect->getDescriptor(&desc)));
+
+ uint64_t effectId;
+ {
+ std::lock_guard lg(mLock);
+ effectId = ++mEffectIdCounter;
+ }
+
+ *effect = sp<EffectHalAidl>::make(mFactory, aidlEffect, effectId, sessionId, ioId, desc);
+ return OK;
}
status_t EffectsFactoryHalAidl::dumpEffects(int fd) {
@@ -85,33 +144,77 @@
}
status_t EffectsFactoryHalAidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) {
- if (size <= 0 || buffer == nullptr) {
- return BAD_VALUE;
- }
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+ ALOGI("%s size %zu buffer %p", __func__, size, buffer);
+ // Buffer doesn't allocated here for AIDL, instead each effect open will return I/O data FMQ.
+ return EffectBufferHalAidl::allocate(size, buffer);
}
status_t EffectsFactoryHalAidl::mirrorBuffer(void* external, size_t size,
sp<EffectBufferHalInterface>* buffer) {
- if (external == nullptr || size <= 0 || buffer == nullptr) {
- return BAD_VALUE;
- }
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
+ ALOGI("%s extern %p size %zu buffer %p", __func__, external, size, buffer);
+ // TODO: implement with FMQ
+ return EffectBufferHalAidl::mirror(external, size, buffer);
}
AudioHalVersionInfo EffectsFactoryHalAidl::getHalVersion() const {
- int32_t versionNumber = 0;
- if (mEffectsFactory) {
- if (!mEffectsFactory->getInterfaceVersion(&versionNumber).isOk()) {
- ALOGE("%s getInterfaceVersion failed", __func__);
- } else {
- ALOGI("%s getInterfaceVersion %d", __func__, versionNumber);
+ return mHalVersion;
+}
+
+status_t EffectsFactoryHalAidl::queryEffectList_l() {
+ if (!mDescList) {
+ std::vector<Descriptor> list;
+ auto status = mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &list);
+ if (!status.isOk()) {
+ ALOGE("%s IFactory::queryEffects failed %s", __func__, status.getDescription().c_str());
+ return status.getStatus();
}
+
+ mDescList = std::make_unique<std::vector<Descriptor>>(list);
}
- // AIDL does not have minor version, fill 0 for all versions
- return AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, versionNumber);
+ return OK;
+}
+
+status_t EffectsFactoryHalAidl::getHalDescriptorWithImplUuid_l(const AudioUuid& uuid,
+ effect_descriptor_t* pDescriptor) {
+ if (pDescriptor == nullptr) {
+ return BAD_VALUE;
+ }
+ if (!mDescList) {
+ RETURN_STATUS_IF_ERROR(queryEffectList_l());
+ }
+
+ auto matchIt = std::find_if(mDescList->begin(), mDescList->end(),
+ [&](const auto& desc) { return desc.common.id.uuid == uuid; });
+ if (matchIt == mDescList->end()) {
+ ALOGE("%s UUID %s not found", __func__, uuid.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ *pDescriptor = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(*matchIt));
+ return OK;
+}
+
+status_t EffectsFactoryHalAidl::getHalDescriptorWithTypeUuid_l(
+ const AudioUuid& type, std::vector<effect_descriptor_t>* descriptors) {
+ if (descriptors == nullptr) {
+ return BAD_VALUE;
+ }
+ if (!mDescList) {
+ RETURN_STATUS_IF_ERROR(queryEffectList_l());
+ }
+ std::vector<Descriptor> result;
+ std::copy_if(mDescList->begin(), mDescList->end(), std::back_inserter(result),
+ [&](auto& desc) { return desc.common.id.type == type; });
+ if (result.size() == 0) {
+ ALOGE("%s type UUID %s not found", __func__, type.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ *descriptors = VALUE_OR_RETURN_STATUS(
+ aidl::android::convertContainer<std::vector<effect_descriptor_t>>(
+ result, ::aidl::android::aidl2legacy_Descriptor_effect_descriptor));
+ return OK;
}
} // namespace effect
@@ -120,9 +223,14 @@
// exports from a static library are optimized out unless actually used by
// the shared library. See EffectsFactoryHalEntry.cpp.
extern "C" void* createIEffectsFactoryImpl() {
- auto factory = IFactory::fromBinder(
- ndk::SpAIBinder(AServiceManager_waitForService(IFactory::descriptor)));
- return factory ? new effect::EffectsFactoryHalAidl(factory) : nullptr;
+ auto serviceName = std::string(IFactory::descriptor) + "/default";
+ auto service = IFactory::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName.c_str())));
+ if (!service) {
+ ALOGE("%s binder service %s not exist", __func__, serviceName.c_str());
+ return nullptr;
+ }
+ return new effect::EffectsFactoryHalAidl(service);
}
} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
index d6b5684..1e85da9 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
@@ -16,7 +16,13 @@
#pragma once
+#include <cstddef>
+#include <memory>
+#include <mutex>
+
+#include <android-base/thread_annotations.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <system/thread_defs.h>
namespace android {
namespace effect {
@@ -40,8 +46,8 @@
std::vector<effect_descriptor_t>* descriptors) override;
// Creates an effect engine of the specified type.
- // To release the effect engine, it is necessary to release references
- // to the returned effect object.
+ // To release the effect engine, it is necessary to release references to the returned effect
+ // object.
status_t createEffect(const effect_uuid_t* pEffectUuid, int32_t sessionId, int32_t ioId,
int32_t deviceId, sp<EffectHalInterface>* effect) override;
@@ -51,11 +57,23 @@
status_t mirrorBuffer(void* external, size_t size,
sp<EffectBufferHalInterface>* buffer) override;
- android::detail::AudioHalVersionInfo getHalVersion() const override;
+ detail::AudioHalVersionInfo getHalVersion() const override;
private:
- std::shared_ptr<IFactory> mEffectsFactory;
+ std::mutex mLock;
+ const std::shared_ptr<IFactory> mFactory;
+ uint64_t mEffectIdCounter GUARDED_BY(mLock) = 0; // Align with HIDL (0 is INVALID_ID)
+ std::unique_ptr<std::vector<Descriptor>> mDescList GUARDED_BY(mLock) = nullptr;
+ const detail::AudioHalVersionInfo mHalVersion;
+
virtual ~EffectsFactoryHalAidl() = default;
+ status_t queryEffectList_l() REQUIRES(mLock);
+ status_t getHalDescriptorWithImplUuid_l(
+ const aidl::android::media::audio::common::AudioUuid& uuid,
+ effect_descriptor_t* pDescriptor) REQUIRES(mLock);
+ status_t getHalDescriptorWithTypeUuid_l(
+ const aidl::android::media::audio::common::AudioUuid& type,
+ std::vector<effect_descriptor_t>* descriptors) REQUIRES(mLock);
};
} // namespace effect
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
new file mode 100644
index 0000000..2b85f97
--- /dev/null
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -0,0 +1,792 @@
+/*
+ * 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 "StreamHalAidl"
+//#define LOG_NDEBUG 0
+
+#include <algorithm>
+#include <cstdint>
+
+#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
+#include <audio_utils/clock.h>
+#include <mediautils/TimeCheck.h>
+#include <utils/Log.h>
+
+#include "DeviceHalAidl.h"
+#include "StreamHalAidl.h"
+
+using ::aidl::android::hardware::audio::core::IStreamCommon;
+using ::aidl::android::hardware::audio::core::IStreamIn;
+using ::aidl::android::hardware::audio::core::IStreamOut;
+using ::aidl::android::hardware::audio::core::StreamDescriptor;
+
+namespace android {
+
+using HalCommand = StreamDescriptor::Command;
+namespace {
+template<HalCommand::Tag cmd> HalCommand makeHalCommand() {
+ return HalCommand::make<cmd>(::aidl::android::media::audio::common::Void{});
+}
+template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
+ return HalCommand::make<cmd>(data);
+}
+} // namespace
+
+// static
+template<class T>
+std::shared_ptr<IStreamCommon> StreamHalAidl::getStreamCommon(const std::shared_ptr<T>& stream) {
+ std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> streamCommon;
+ if (stream != nullptr) {
+ if (ndk::ScopedAStatus status = stream->getStreamCommon(&streamCommon);
+ !status.isOk()) {
+ ALOGE("%s: failed to retrieve IStreamCommon instance: %s", __func__,
+ status.getDescription().c_str());
+ }
+ }
+ return streamCommon;
+}
+
+StreamHalAidl::StreamHalAidl(
+ std::string_view className, bool isInput, const audio_config& config,
+ int32_t nominalLatency, StreamContextAidl&& context,
+ const std::shared_ptr<IStreamCommon>& stream)
+ : ConversionHelperAidl(className),
+ mIsInput(isInput),
+ mConfig(configToBase(config)),
+ mContext(std::move(context)),
+ mStream(stream) {
+ {
+ std::lock_guard l(mLock);
+ mLastReply.latencyMs = nominalLatency;
+ }
+ // Instrument audio signal power logging.
+ // Note: This assumes channel mask, format, and sample rate do not change after creation.
+ if (audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
+ /* mStreamPowerLog.isUserDebugOrEngBuild() && */
+ StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
+ mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
+ }
+}
+
+StreamHalAidl::~StreamHalAidl() {
+ if (mStream != nullptr) {
+ ndk::ScopedAStatus status = mStream->close();
+ ALOGE_IF(!status.isOk(), "%s: status %s", __func__, status.getDescription().c_str());
+ }
+}
+
+status_t StreamHalAidl::getBufferSize(size_t *size) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (size == nullptr) {
+ return BAD_VALUE;
+ }
+ if (mContext.getFrameSizeBytes() == 0 || mContext.getBufferSizeFrames() == 0 ||
+ !mStream) {
+ return NO_INIT;
+ }
+ *size = mContext.getBufferSizeBytes();
+ return OK;
+}
+
+status_t StreamHalAidl::getAudioProperties(audio_config_base_t *configBase) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (configBase == nullptr) {
+ return BAD_VALUE;
+ }
+ if (!mStream) return NO_INIT;
+ *configBase = mConfig;
+ return OK;
+}
+
+status_t StreamHalAidl::setParameters(const String8& kvPairs __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::getParameters(const String8& keys __unused, String8 *values) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ values->clear();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::getFrameSize(size_t *size) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (size == nullptr) {
+ return BAD_VALUE;
+ }
+ if (mContext.getFrameSizeBytes() == 0 || !mStream) {
+ return NO_INIT;
+ }
+ *size = mContext.getFrameSizeBytes();
+ return OK;
+}
+
+status_t StreamHalAidl::addEffect(sp<EffectHalInterface> effect __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::removeEffect(sp<EffectHalInterface> effect __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::standby() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ const auto state = getState();
+ StreamDescriptor::Reply reply;
+ switch (state) {
+ case StreamDescriptor::State::ACTIVE:
+ if (status_t status = pause(&reply); status != OK) return status;
+ if (reply.state != StreamDescriptor::State::PAUSED) {
+ ALOGE("%s: unexpected stream state: %s (expected PAUSED)",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ FALLTHROUGH_INTENDED;
+ case StreamDescriptor::State::PAUSED:
+ case StreamDescriptor::State::DRAIN_PAUSED:
+ return flush();
+ case StreamDescriptor::State::IDLE:
+ if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::standby>(),
+ &reply); status != OK) {
+ return status;
+ }
+ if (reply.state != StreamDescriptor::State::STANDBY) {
+ ALOGE("%s: unexpected stream state: %s (expected STANDBY)",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ FALLTHROUGH_INTENDED;
+ case StreamDescriptor::State::STANDBY:
+ return OK;
+ default:
+ ALOGE("%s: not supported from %s stream state %s",
+ __func__, mIsInput ? "input" : "output", toString(state).c_str());
+ return INVALID_OPERATION;
+ }
+}
+
+status_t StreamHalAidl::dump(int fd, const Vector<String16>& args) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ return mStream->dump(fd, Args(args).args(), args.size());
+}
+
+status_t StreamHalAidl::start() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::stop() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::getLatency(uint32_t *latency) {
+ ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!mStream) return NO_INIT;
+ StreamDescriptor::Reply reply;
+ if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
+ return status;
+ }
+ *latency = std::max<int32_t>(0, reply.latencyMs);
+ return OK;
+}
+
+status_t StreamHalAidl::getObservablePosition(int64_t *frames, int64_t *timestamp) {
+ ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!mStream) return NO_INIT;
+ StreamDescriptor::Reply reply;
+ if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
+ return status;
+ }
+ *frames = reply.observable.frames;
+ *timestamp = reply.observable.timeNs;
+ return OK;
+}
+
+status_t StreamHalAidl::getXruns(int32_t *frames) {
+ ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!mStream) return NO_INIT;
+ StreamDescriptor::Reply reply;
+ if (status_t status = updateCountersIfNeeded(&reply); status != OK) {
+ return status;
+ }
+ *frames = reply.xrunFrames;
+ return OK;
+}
+
+status_t StreamHalAidl::transfer(void *buffer, size_t bytes, size_t *transferred) {
+ ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
+ // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
+ if (!mStream || mContext.getDataMQ() == nullptr) return NO_INIT;
+ mWorkerTid.store(gettid(), std::memory_order_release);
+ // Switch the stream into an active state if needed.
+ // Note: in future we may add support for priming the audio pipeline
+ // with data prior to enabling output (thus we can issue a "burst" command in the "standby"
+ // stream state), however this scenario wasn't supported by the HIDL HAL.
+ if (getState() == StreamDescriptor::State::STANDBY) {
+ StreamDescriptor::Reply reply;
+ if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply);
+ status != OK) {
+ return status;
+ }
+ if (reply.state != StreamDescriptor::State::IDLE) {
+ ALOGE("%s: failed to get the stream out of standby, actual state: %s",
+ __func__, toString(reply.state).c_str());
+ return INVALID_OPERATION;
+ }
+ }
+ if (!mIsInput) {
+ bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
+ }
+ StreamDescriptor::Command burst =
+ StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
+ if (!mIsInput) {
+ if (!mContext.getDataMQ()->write(static_cast<const int8_t*>(buffer), bytes)) {
+ ALOGE("%s: failed to write %zu bytes to data MQ", __func__, bytes);
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ StreamDescriptor::Reply reply;
+ if (status_t status = sendCommand(burst, &reply); status != OK) {
+ return status;
+ }
+ if (mIsInput) {
+ *transferred = reply.fmqByteCount;
+ LOG_ALWAYS_FATAL_IF(*transferred > bytes,
+ "%s: HAL module read %zu bytes, which exceeds requested count %zu",
+ __func__, *transferred, bytes);
+ if (!mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), *transferred)) {
+ ALOGE("%s: failed to read %zu bytes to data MQ", __func__, *transferred);
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ mStreamPowerLog.log(buffer, *transferred);
+ return OK;
+}
+
+status_t StreamHalAidl::pause(StreamDescriptor::Reply* reply) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ return sendCommand(makeHalCommand<HalCommand::Tag::pause>(), reply,
+ true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
+}
+
+status_t StreamHalAidl::resume(StreamDescriptor::Reply* reply) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ if (mIsInput) {
+ return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), reply);
+ } else {
+ return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
+ }
+}
+
+status_t StreamHalAidl::drain(bool earlyNotify, StreamDescriptor::Reply* reply) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ return sendCommand(makeHalCommand<HalCommand::Tag::drain>(
+ mIsInput ? StreamDescriptor::DrainMode::DRAIN_UNSPECIFIED :
+ earlyNotify ? StreamDescriptor::DrainMode::DRAIN_EARLY_NOTIFY :
+ StreamDescriptor::DrainMode::DRAIN_ALL), reply);
+}
+
+status_t StreamHalAidl::flush(StreamDescriptor::Reply* reply) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ return sendCommand(makeHalCommand<HalCommand::Tag::flush>(), reply,
+ true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
+}
+
+status_t StreamHalAidl::exit() {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
+ struct audio_mmap_buffer_info *info __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamHalAidl::setHalThreadPriority(int priority __unused) {
+ // Obsolete, must be done by the HAL module.
+ return OK;
+}
+
+status_t StreamHalAidl::getHalPid(pid_t *pid __unused) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+bool StreamHalAidl::requestHalThreadPriority(pid_t threadPid __unused, pid_t threadId __unused) {
+ // Obsolete, must be done by the HAL module.
+ return true;
+}
+
+status_t StreamHalAidl::legacyCreateAudioPatch(const struct audio_port_config& port __unused,
+ std::optional<audio_source_t> source __unused,
+ audio_devices_t type __unused) {
+ // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
+ return INVALID_OPERATION;
+}
+
+status_t StreamHalAidl::legacyReleaseAudioPatch() {
+ // Obsolete since 'DeviceHalAidl.supportsAudioPatches' always returns 'true'.
+ return INVALID_OPERATION;
+}
+
+status_t StreamHalAidl::sendCommand(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply,
+ bool safeFromNonWorkerThread) {
+ // TIME_CHECK(); // TODO(b/238654698) reenable only when optimized.
+ if (!safeFromNonWorkerThread) {
+ const pid_t workerTid = mWorkerTid.load(std::memory_order_acquire);
+ LOG_ALWAYS_FATAL_IF(workerTid != gettid(),
+ "%s %s: must be invoked from the worker thread (%d)",
+ __func__, command.toString().c_str(), workerTid);
+ }
+ if (!mContext.getCommandMQ()->writeBlocking(&command, 1)) {
+ ALOGE("%s: failed to write command %s to MQ", __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
+ }
+ StreamDescriptor::Reply localReply{};
+ if (reply == nullptr) {
+ reply = &localReply;
+ }
+ if (!mContext.getReplyMQ()->readBlocking(reply, 1)) {
+ ALOGE("%s: failed to read from reply MQ, command %s", __func__, command.toString().c_str());
+ return NOT_ENOUGH_DATA;
+ }
+ {
+ std::lock_guard l(mLock);
+ mLastReply = *reply;
+ }
+ switch (reply->status) {
+ case STATUS_OK: return OK;
+ case STATUS_BAD_VALUE: return BAD_VALUE;
+ case STATUS_INVALID_OPERATION: return INVALID_OPERATION;
+ case STATUS_NOT_ENOUGH_DATA: return NOT_ENOUGH_DATA;
+ default:
+ ALOGE("%s: unexpected status %d returned for command %s",
+ __func__, reply->status, command.toString().c_str());
+ return INVALID_OPERATION;
+ }
+}
+
+status_t StreamHalAidl::updateCountersIfNeeded(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply) {
+ if (mWorkerTid.load(std::memory_order_acquire) == gettid()) {
+ if (const auto state = getState(); state != StreamDescriptor::State::ACTIVE &&
+ state != StreamDescriptor::State::DRAINING &&
+ state != StreamDescriptor::State::TRANSFERRING) {
+ return sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), reply);
+ }
+ }
+ if (reply != nullptr) {
+ std::lock_guard l(mLock);
+ *reply = mLastReply;
+ }
+ return OK;
+}
+
+namespace {
+
+/* Notes on callback ownership.
+
+This is how Binder ownership model looks like. The server implementation
+is owned by Binder framework (via sp<>). Proxies are owned by clients.
+When the last proxy disappears, Binder framework releases the server impl.
+
+Thus, it is not needed to keep any references to StreamCallback (this is
+the server impl) -- it will live as long as HAL server holds a strong ref to
+IStreamCallback proxy.
+
+The callback only keeps a weak reference to the stream. The stream is owned
+by AudioFlinger.
+
+*/
+
+class StreamCallback : public ::aidl::android::hardware::audio::core::BnStreamCallback {
+ ndk::ScopedAStatus onTransferReady() override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onError() override {
+ return ndk::ScopedAStatus::ok();
+ }
+ ndk::ScopedAStatus onDrainReady() override {
+ return ndk::ScopedAStatus::ok();
+ }
+};
+
+} // namespace
+
+StreamOutHalAidl::StreamOutHalAidl(
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
+ const std::shared_ptr<IStreamOut>& stream)
+ : StreamHalAidl("StreamOutHalAidl", false /*isInput*/, config, nominalLatency,
+ std::move(context), getStreamCommon(stream)),
+ mStream(stream) {}
+
+status_t StreamOutHalAidl::getLatency(uint32_t *latency) {
+ return StreamHalAidl::getLatency(latency);
+}
+
+status_t StreamOutHalAidl::setVolume(float left __unused, float right __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::selectPresentation(int presentationId __unused, int programId __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::write(const void *buffer, size_t bytes, size_t *written) {
+ if (buffer == nullptr || written == nullptr) {
+ return BAD_VALUE;
+ }
+ // For the output scenario, 'transfer' does not modify the buffer.
+ return transfer(const_cast<void*>(buffer), bytes, written);
+}
+
+status_t StreamOutHalAidl::getRenderPosition(uint32_t *dspFrames) {
+ if (dspFrames == nullptr) {
+ return BAD_VALUE;
+ }
+ int64_t aidlFrames = 0, aidlTimestamp = 0;
+ if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
+ return OK;
+ }
+ *dspFrames = std::clamp<int64_t>(aidlFrames, 0, UINT32_MAX);
+ return OK;
+}
+
+status_t StreamOutHalAidl::getNextWriteTimestamp(int64_t *timestamp __unused) {
+ // Obsolete, use getPresentationPosition.
+ return INVALID_OPERATION;
+}
+
+status_t StreamOutHalAidl::setCallback(wp<StreamOutHalInterfaceCallback> callback __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::supportsPauseAndResume(bool *supportsPause, bool *supportsResume) {
+ if (supportsPause == nullptr || supportsResume == nullptr) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ *supportsPause = *supportsResume = true;
+ return OK;
+}
+
+status_t StreamOutHalAidl::pause() {
+ return StreamHalAidl::pause();
+}
+
+status_t StreamOutHalAidl::resume() {
+ return StreamHalAidl::resume();
+}
+
+status_t StreamOutHalAidl::supportsDrain(bool *supportsDrain) {
+ if (supportsDrain == nullptr) {
+ return BAD_VALUE;
+ }
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ *supportsDrain = true;
+ return OK;
+}
+
+status_t StreamOutHalAidl::drain(bool earlyNotify) {
+ return StreamHalAidl::drain(earlyNotify);
+}
+
+status_t StreamOutHalAidl::flush() {
+ return StreamHalAidl::flush();
+}
+
+status_t StreamOutHalAidl::getPresentationPosition(uint64_t *frames, struct timespec *timestamp) {
+ if (frames == nullptr || timestamp == nullptr) {
+ return BAD_VALUE;
+ }
+ int64_t aidlFrames = 0, aidlTimestamp = 0;
+ if (status_t status = getObservablePosition(&aidlFrames, &aidlTimestamp); status != OK) {
+ return status;
+ }
+ *frames = std::max<int64_t>(0, aidlFrames);
+ timestamp->tv_sec = aidlTimestamp / NANOS_PER_SECOND;
+ timestamp->tv_nsec = aidlTimestamp - timestamp->tv_sec * NANOS_PER_SECOND;
+ return OK;
+}
+
+status_t StreamOutHalAidl::updateSourceMetadata(
+ const StreamOutHalInterface::SourceMetadata& sourceMetadata __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::getDualMonoMode(audio_dual_mono_mode_t* mode __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::setDualMonoMode(audio_dual_mono_mode_t mode __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::getAudioDescriptionMixLevel(float* leveldB __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::setAudioDescriptionMixLevel(float leveldB __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::getPlaybackRateParameters(
+ audio_playback_rate_t* playbackRate __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::setPlaybackRateParameters(
+ const audio_playback_rate_t& playbackRate __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamOutHalAidl::setEventCallback(
+ const sp<StreamOutHalInterfaceEventCallback>& callback __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+namespace {
+
+struct StreamOutEventCallback {
+ StreamOutEventCallback(const wp<StreamOutHalAidl>& stream) : mStream(stream) {}
+ private:
+ wp<StreamOutHalAidl> mStream;
+};
+
+} // namespace
+
+status_t StreamOutHalAidl::setLatencyMode(audio_latency_mode_t mode __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+};
+
+status_t StreamOutHalAidl::getRecommendedLatencyModes(
+ std::vector<audio_latency_mode_t> *modes __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+};
+
+status_t StreamOutHalAidl::setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+};
+
+void StreamOutHalAidl::onWriteReady() {
+ sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
+ if (callback == 0) return;
+ ALOGV("asyncCallback onWriteReady");
+ callback->onWriteReady();
+}
+
+void StreamOutHalAidl::onDrainReady() {
+ sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
+ if (callback == 0) return;
+ ALOGV("asyncCallback onDrainReady");
+ callback->onDrainReady();
+}
+
+void StreamOutHalAidl::onError() {
+ sp<StreamOutHalInterfaceCallback> callback = mCallback.load().promote();
+ if (callback == 0) return;
+ ALOGV("asyncCallback onError");
+ callback->onError();
+}
+
+void StreamOutHalAidl::onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs __unused) {
+ sp<StreamOutHalInterfaceEventCallback> callback = mEventCallback.load().promote();
+ if (callback == nullptr) return;
+ ALOGV("asyncCodecFormatCallback %s", __func__);
+ callback->onCodecFormatChanged(metadataBs);
+}
+
+void StreamOutHalAidl::onRecommendedLatencyModeChanged(
+ const std::vector<audio_latency_mode_t>& modes __unused) {
+ sp<StreamOutHalInterfaceLatencyModeCallback> callback = mLatencyModeCallback.load().promote();
+ if (callback == nullptr) return;
+ callback->onRecommendedLatencyModeChanged(modes);
+}
+
+status_t StreamOutHalAidl::exit() {
+ return StreamHalAidl::exit();
+}
+
+StreamInHalAidl::StreamInHalAidl(
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
+ const std::shared_ptr<IStreamIn>& stream)
+ : StreamHalAidl("StreamInHalAidl", true /*isInput*/, config, nominalLatency,
+ std::move(context), getStreamCommon(stream)),
+ mStream(stream) {}
+
+status_t StreamInHalAidl::setGain(float gain __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamInHalAidl::read(void *buffer, size_t bytes, size_t *read) {
+ if (buffer == nullptr || read == nullptr) {
+ return BAD_VALUE;
+ }
+ return transfer(buffer, bytes, read);
+}
+
+status_t StreamInHalAidl::getInputFramesLost(uint32_t *framesLost) {
+ if (framesLost == nullptr) {
+ return BAD_VALUE;
+ }
+ int32_t aidlXruns = 0;
+ if (status_t status = getXruns(&aidlXruns); status != OK) {
+ return status;
+ }
+ *framesLost = std::max<int32_t>(0, aidlXruns);
+ return OK;
+}
+
+status_t StreamInHalAidl::getCapturePosition(int64_t *frames, int64_t *time) {
+ if (frames == nullptr || time == nullptr) {
+ return BAD_VALUE;
+ }
+ return getObservablePosition(frames, time);
+}
+
+status_t StreamInHalAidl::getActiveMicrophones(
+ std::vector<media::MicrophoneInfo> *microphones __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamInHalAidl::updateSinkMetadata(
+ const StreamInHalInterface::SinkMetadata& sinkMetadata __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamInHalAidl::setPreferredMicrophoneDirection(
+ audio_microphone_direction_t direction __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+status_t StreamInHalAidl::setPreferredMicrophoneFieldDimension(float zoom __unused) {
+ TIME_CHECK();
+ if (!mStream) return NO_INIT;
+ ALOGE("%s not implemented yet", __func__);
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
new file mode 100644
index 0000000..ce6c31c
--- /dev/null
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -0,0 +1,367 @@
+/*
+ * 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 <atomic>
+#include <memory>
+#include <mutex>
+#include <string_view>
+
+#include <aidl/android/hardware/audio/core/BpStreamCommon.h>
+#include <aidl/android/hardware/audio/core/BpStreamIn.h>
+#include <aidl/android/hardware/audio/core/BpStreamOut.h>
+#include <fmq/AidlMessageQueue.h>
+#include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
+#include <mediautils/Synchronization.h>
+
+#include "ConversionHelperAidl.h"
+#include "StreamPowerLog.h"
+
+namespace android {
+
+class StreamContextAidl {
+ public:
+ typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Command,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> CommandMQ;
+ typedef AidlMessageQueue<::aidl::android::hardware::audio::core::StreamDescriptor::Reply,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> ReplyMQ;
+ typedef AidlMessageQueue<int8_t,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ;
+
+ explicit StreamContextAidl(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor)
+ : mFrameSizeBytes(descriptor.frameSizeBytes),
+ mCommandMQ(new CommandMQ(descriptor.command)),
+ mReplyMQ(new ReplyMQ(descriptor.reply)),
+ mBufferSizeFrames(descriptor.bufferSizeFrames),
+ mDataMQ(maybeCreateDataMQ(descriptor)) {}
+ StreamContextAidl(StreamContextAidl&& other) :
+ mFrameSizeBytes(other.mFrameSizeBytes),
+ mCommandMQ(std::move(other.mCommandMQ)),
+ mReplyMQ(std::move(other.mReplyMQ)),
+ mBufferSizeFrames(other.mBufferSizeFrames),
+ mDataMQ(std::move(other.mDataMQ)) {}
+ StreamContextAidl& operator=(StreamContextAidl&& other) {
+ mFrameSizeBytes = other.mFrameSizeBytes;
+ mCommandMQ = std::move(other.mCommandMQ);
+ mReplyMQ = std::move(other.mReplyMQ);
+ mBufferSizeFrames = other.mBufferSizeFrames;
+ mDataMQ = std::move(other.mDataMQ);
+ return *this;
+ }
+ bool isValid() const {
+ return mFrameSizeBytes != 0 &&
+ mCommandMQ != nullptr && mCommandMQ->isValid() &&
+ mReplyMQ != nullptr && mReplyMQ->isValid() &&
+ (mDataMQ != nullptr || (
+ mDataMQ->isValid() &&
+ mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() >=
+ mFrameSizeBytes * mBufferSizeFrames));
+ }
+ size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
+ size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
+ CommandMQ* getCommandMQ() const { return mCommandMQ.get(); }
+ DataMQ* getDataMQ() const { return mDataMQ.get(); }
+ size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
+ ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
+
+ private:
+ static std::unique_ptr<DataMQ> maybeCreateDataMQ(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
+ using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::fmq) {
+ return std::make_unique<DataMQ>(descriptor.audio.get<Tag::fmq>());
+ }
+ return nullptr;
+ }
+
+ size_t mFrameSizeBytes;
+ std::unique_ptr<CommandMQ> mCommandMQ;
+ std::unique_ptr<ReplyMQ> mReplyMQ;
+ size_t mBufferSizeFrames;
+ std::unique_ptr<DataMQ> mDataMQ;
+};
+
+class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelperAidl {
+ public:
+ // Return size of input/output buffer in bytes for this stream - eg. 4800.
+ status_t getBufferSize(size_t *size) override;
+
+ // Return the base configuration of the stream:
+ // - channel mask;
+ // - format - e.g. AUDIO_FORMAT_PCM_16_BIT;
+ // - sampling rate in Hz - eg. 44100.
+ status_t getAudioProperties(audio_config_base_t *configBase) override;
+
+ // Set audio stream parameters.
+ status_t setParameters(const String8& kvPairs) override;
+
+ // Get audio stream parameters.
+ status_t getParameters(const String8& keys, String8 *values) override;
+
+ // Return the frame size (number of bytes per sample) of a stream.
+ status_t getFrameSize(size_t *size) override;
+
+ // Add or remove the effect on the stream.
+ status_t addEffect(sp<EffectHalInterface> effect) override;
+ status_t removeEffect(sp<EffectHalInterface> effect) override;
+
+ // Put the audio hardware input/output into standby mode.
+ status_t standby() override;
+
+ status_t dump(int fd, const Vector<String16>& args) override;
+
+ // Start a stream operating in mmap mode.
+ status_t start() override;
+
+ // Stop a stream operating in mmap mode.
+ status_t stop() override;
+
+ // Retrieve information on the data buffer in mmap mode.
+ status_t createMmapBuffer(int32_t minSizeFrames,
+ struct audio_mmap_buffer_info *info) override;
+
+ // Get current read/write position in the mmap buffer
+ status_t getMmapPosition(struct audio_mmap_position *position) override;
+
+ // Set the priority of the thread that interacts with the HAL
+ // (must match the priority of the audioflinger's thread that calls 'read' / 'write')
+ status_t setHalThreadPriority(int priority) override;
+
+ status_t legacyCreateAudioPatch(const struct audio_port_config& port,
+ std::optional<audio_source_t> source,
+ audio_devices_t type) override;
+
+ status_t legacyReleaseAudioPatch() override;
+
+ protected:
+ template<class T>
+ static std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> getStreamCommon(
+ const std::shared_ptr<T>& stream);
+
+ // Subclasses can not be constructed directly by clients.
+ StreamHalAidl(std::string_view className,
+ bool isInput,
+ const audio_config& config,
+ int32_t nominalLatency,
+ StreamContextAidl&& context,
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon>& stream);
+
+ ~StreamHalAidl() override;
+
+ status_t getHalPid(pid_t *pid);
+
+ bool requestHalThreadPriority(pid_t threadPid, pid_t threadId);
+
+ status_t getLatency(uint32_t *latency);
+
+ status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
+
+ status_t getXruns(int32_t *frames);
+
+ status_t transfer(void *buffer, size_t bytes, size_t *transferred);
+
+ status_t pause(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t resume(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t drain(bool earlyNotify,
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t flush(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ status_t exit();
+
+ const bool mIsInput;
+ const audio_config_base_t mConfig;
+ const StreamContextAidl mContext;
+
+ private:
+ static audio_config_base_t configToBase(const audio_config& config) {
+ audio_config_base_t result = AUDIO_CONFIG_BASE_INITIALIZER;
+ result.sample_rate = config.sample_rate;
+ result.channel_mask = config.channel_mask;
+ result.format = config.format;
+ return result;
+ }
+ ::aidl::android::hardware::audio::core::StreamDescriptor::State getState() {
+ std::lock_guard l(mLock);
+ return mLastReply.state;
+ }
+ status_t sendCommand(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor::Command &command,
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr,
+ bool safeFromNonWorkerThread = false);
+ status_t updateCountersIfNeeded(
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply* reply = nullptr);
+
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamCommon> mStream;
+ std::mutex mLock;
+ ::aidl::android::hardware::audio::core::StreamDescriptor::Reply mLastReply GUARDED_BY(mLock);
+ // mStreamPowerLog is used for audio signal power logging.
+ StreamPowerLog mStreamPowerLog;
+ std::atomic<pid_t> mWorkerTid = -1;
+};
+
+class StreamOutHalAidl : public StreamOutHalInterface, public StreamHalAidl {
+ public:
+ // Return the audio hardware driver estimated latency in milliseconds.
+ status_t getLatency(uint32_t *latency) override;
+
+ // Use this method in situations where audio mixing is done in the hardware.
+ status_t setVolume(float left, float right) override;
+
+ // Selects the audio presentation (if available).
+ status_t selectPresentation(int presentationId, int programId) override;
+
+ // Write audio buffer to driver.
+ status_t write(const void *buffer, size_t bytes, size_t *written) override;
+
+ // Return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby.
+ status_t getRenderPosition(uint32_t *dspFrames) override;
+
+ // Get the local time at which the next write to the audio driver will be presented.
+ status_t getNextWriteTimestamp(int64_t *timestamp) override;
+
+ // Set the callback for notifying completion of non-blocking write and drain.
+ status_t setCallback(wp<StreamOutHalInterfaceCallback> callback) override;
+
+ // Returns whether pause and resume operations are supported.
+ status_t supportsPauseAndResume(bool *supportsPause, bool *supportsResume) override;
+
+ // Notifies to the audio driver to resume playback following a pause.
+ status_t pause() override;
+
+ // Notifies to the audio driver to resume playback following a pause.
+ status_t resume() override;
+
+ // Returns whether drain operation is supported.
+ status_t supportsDrain(bool *supportsDrain) override;
+
+ // Requests notification when data buffered by the driver/hardware has been played.
+ status_t drain(bool earlyNotify) override;
+
+ // Notifies to the audio driver to flush the queued data.
+ status_t flush() override;
+
+ // Return a recent count of the number of audio frames presented to an external observer.
+ status_t getPresentationPosition(uint64_t *frames, struct timespec *timestamp) override;
+
+ // Called when the metadata of the stream's source has been changed.
+ status_t updateSourceMetadata(const SourceMetadata& sourceMetadata) override;
+
+ // Returns the Dual Mono mode presentation setting.
+ status_t getDualMonoMode(audio_dual_mono_mode_t* mode) override;
+
+ // Sets the Dual Mono mode presentation on the output device.
+ status_t setDualMonoMode(audio_dual_mono_mode_t mode) override;
+
+ // Returns the Audio Description Mix level in dB.
+ status_t getAudioDescriptionMixLevel(float* leveldB) override;
+
+ // Sets the Audio Description Mix level in dB.
+ status_t setAudioDescriptionMixLevel(float leveldB) override;
+
+ // Retrieves current playback rate parameters.
+ status_t getPlaybackRateParameters(audio_playback_rate_t* playbackRate) override;
+
+ // Sets the playback rate parameters that control playback behavior.
+ status_t setPlaybackRateParameters(const audio_playback_rate_t& playbackRate) override;
+
+ status_t setEventCallback(const sp<StreamOutHalInterfaceEventCallback>& callback) override;
+
+ status_t setLatencyMode(audio_latency_mode_t mode) override;
+ status_t getRecommendedLatencyModes(std::vector<audio_latency_mode_t> *modes) override;
+ status_t setLatencyModeCallback(
+ const sp<StreamOutHalInterfaceLatencyModeCallback>& callback) override;
+
+ void onRecommendedLatencyModeChanged(const std::vector<audio_latency_mode_t>& modes);
+
+ status_t exit() override;
+
+ void onCodecFormatChanged(const std::basic_string<uint8_t>& metadataBs);
+
+ // Methods used by StreamOutCallback ().
+ // FIXME: Consider the required visibility.
+ void onWriteReady();
+ void onDrainReady();
+ void onError();
+
+ private:
+ friend class sp<StreamOutHalAidl>;
+
+ mediautils::atomic_wp<StreamOutHalInterfaceCallback> mCallback;
+ mediautils::atomic_wp<StreamOutHalInterfaceEventCallback> mEventCallback;
+ mediautils::atomic_wp<StreamOutHalInterfaceLatencyModeCallback> mLatencyModeCallback;
+
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut> mStream;
+
+ // Can not be constructed directly by clients.
+ StreamOutHalAidl(
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamOut>& stream);
+
+ ~StreamOutHalAidl() override = default;
+};
+
+class StreamInHalAidl : public StreamInHalInterface, public StreamHalAidl {
+ public:
+ // Set the input gain for the audio driver.
+ status_t setGain(float gain) override;
+
+ // Read audio buffer in from driver.
+ status_t read(void *buffer, size_t bytes, size_t *read) override;
+
+ // Return the amount of input frames lost in the audio driver.
+ status_t getInputFramesLost(uint32_t *framesLost) override;
+
+ // Return a recent count of the number of audio frames received and
+ // the clock time associated with that frame count.
+ status_t getCapturePosition(int64_t *frames, int64_t *time) override;
+
+ // Get active microphones
+ status_t getActiveMicrophones(std::vector<media::MicrophoneInfo> *microphones) override;
+
+ // Set microphone direction (for processing)
+ status_t setPreferredMicrophoneDirection(
+ audio_microphone_direction_t direction) override;
+
+ // Set microphone zoom (for processing)
+ status_t setPreferredMicrophoneFieldDimension(float zoom) override;
+
+ // Called when the metadata of the stream's sink has been changed.
+ status_t updateSinkMetadata(const SinkMetadata& sinkMetadata) override;
+
+ private:
+ friend class sp<StreamInHalAidl>;
+
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamIn> mStream;
+
+ // Can not be constructed directly by clients.
+ StreamInHalAidl(
+ const audio_config& config, StreamContextAidl&& context, int32_t nominalLatency,
+ const std::shared_ptr<::aidl::android::hardware::audio::core::IStreamIn>& stream);
+
+ ~StreamInHalAidl() override = default;
+};
+
+} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index 76f9a60..2c289e1 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -46,9 +46,6 @@
using namespace ::android::hardware::audio::common::COMMON_TYPES_CPP_VERSION;
using namespace ::android::hardware::audio::CORE_TYPES_CPP_VERSION;
-#define TIME_CHECK() auto TimeCheck = \
- mediautils::makeTimeCheckStatsForClassMethod(getClassName(), __func__)
-
StreamHalHidl::StreamHalHidl(std::string_view className, IStream *stream)
: CoreConversionHelperHidl(className),
mStream(stream),
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.cpp
new file mode 100644
index 0000000..15768b3
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionAec"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_aec.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionAec.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::AcousticEchoCanceler;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionAec::setParameter(EffectParamReader& param) {
+ uint32_t type, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type) ||
+ OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ Parameter aidlParam;
+ switch (type) {
+ case AEC_PARAM_ECHO_DELAY:
+ FALLTHROUGH_INTENDED;
+ case AEC_PARAM_PROPERTIES: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint32_echoDelay_Parameter_aec(value));
+ break;
+ }
+ case AEC_PARAM_MOBILE_MODE: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint32_mobileMode_Parameter_aec(value));
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionAec::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ param.setStatus(BAD_VALUE);
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case AEC_PARAM_ECHO_DELAY:
+ FALLTHROUGH_INTENDED;
+ case AEC_PARAM_PROPERTIES: {
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(AcousticEchoCanceler, acousticEchoCancelerTag,
+ AcousticEchoCanceler::echoDelayUs);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_aec_uint32_echoDelay(aidlParam));
+ break;
+ }
+ case AEC_PARAM_MOBILE_MODE: {
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(AcousticEchoCanceler, acousticEchoCancelerTag,
+ AcousticEchoCanceler::mobileMode);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_aec_uint32_mobileMode(aidlParam));
+ break;
+ }
+ default:
+ // use vendor extension implementation
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h
new file mode 100644
index 0000000..3ee419a
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAec.h
@@ -0,0 +1,39 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionAec : public EffectConversionHelperAidl {
+ public:
+ AidlConversionAec(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionAec() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp
new file mode 100644
index 0000000..80df2b8
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionAgc2"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_agc2.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionAgc2.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::AutomaticGainControl;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionAgc2::setParameter(EffectParamReader& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint32_fixedDigitalGain_Parameter_agc(value));
+ break;
+ }
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint32_levelEstimator_Parameter_agc(value));
+ break;
+ }
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint32_saturationMargin_Parameter_agc(value));
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionAgc2::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN: {
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
+ AutomaticGainControl::fixedDigitalGainMb);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_agc_uint32_fixedDigitalGain(aidlParam));
+ break;
+ }
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR: {
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
+ AutomaticGainControl::levelEstimator);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_agc_uint32_levelEstimator(aidlParam));
+ break;
+ }
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN: {
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(AutomaticGainControl, automaticGainControlTag,
+ AutomaticGainControl::saturationMarginMb);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_agc_uint32_saturationMargin(aidlParam));
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h
new file mode 100644
index 0000000..8f7eac7
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionAgc2.h
@@ -0,0 +1,39 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionAgc2 : public EffectConversionHelperAidl {
+ public:
+ AidlConversionAgc2(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionAgc2() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp
new file mode 100644
index 0000000..038b7df
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionBassBoost"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_bassboost.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionBassBoost.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::convertIntegral;
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::BassBoost;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionBassBoost::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case BASSBOOST_PARAM_STRENGTH: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_uint16_strengthPm_Parameter_BassBoost(value));
+ break;
+ }
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED: {
+ ALOGW("%s set BASSBOOST_PARAM_STRENGTH_SUPPORTED not supported", __func__);
+ return BAD_VALUE;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionBassBoost::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case BASSBOOST_PARAM_STRENGTH: {
+ uint32_t value;
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(BassBoost, bassBoostTag, BassBoost::strengthPm);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_BassBoost_uint16_strengthPm(aidlParam));
+ return param.writeToValue(&value);
+ }
+ case BASSBOOST_PARAM_STRENGTH_SUPPORTED: {
+ uint16_t value;
+ const auto& cap =
+ VALUE_OR_RETURN_STATUS(aidl::android::UNION_GET(mDesc.capability, bassBoost));
+ value = VALUE_OR_RETURN_STATUS(convertIntegral<uint32_t>(cap.strengthSupported));
+ return param.writeToValue(&value);
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h
new file mode 100644
index 0000000..9664aa1
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionBassBoost.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionBassBoost : public EffectConversionHelperAidl {
+ public:
+ AidlConversionBassBoost(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionBassBoost() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.cpp
new file mode 100644
index 0000000..17cedf7
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionDownmix"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_downmix.h>
+
+#include <system/audio_effect.h>
+#include <utils/Log.h>
+
+#include "AidlConversionDownmix.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Downmix;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionDownmix::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ int16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(int16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case DOWNMIX_PARAM_TYPE: {
+ aidlParam = VALUE_OR_RETURN_STATUS(
+ aidl::android::legacy2aidl_int16_type_Parameter_Downmix(value));
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionDownmix::getParameter(EffectParamWriter& param) {
+ int16_t value = 0;
+ uint32_t type = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type)) {
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case DOWNMIX_PARAM_TYPE: {
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Downmix, downmixTag, Downmix::type);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ value = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_Parameter_Downmix_int16_type(aidlParam));
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h
new file mode 100644
index 0000000..8b28ca3
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDownmix.h
@@ -0,0 +1,39 @@
+/*
+ * 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/BpEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionDownmix : public EffectConversionHelperAidl {
+ public:
+ AidlConversionDownmix(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionDownmix() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp
new file mode 100644
index 0000000..4ecaa07
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.cpp
@@ -0,0 +1,522 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionDp"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effect.h>
+#include <system/audio_effects/effect_dynamicsprocessing.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionDynamicsProcessing.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::convertIntegral;
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Capability;
+using ::aidl::android::hardware::audio::effect::DynamicsProcessing;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::toString;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionDp::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ if (OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case DP_PARAM_INPUT_GAIN: {
+ DynamicsProcessing::InputGain inputGainAidl;
+ if (OK != param.readFromParameter(&inputGainAidl.channel) ||
+ OK != param.readFromValue(&inputGainAidl.gainDb)) {
+ ALOGE("%s invalid inputGain %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, inputGain,
+ {inputGainAidl});
+ break;
+ }
+ case DP_PARAM_ENGINE_ARCHITECTURE: {
+ DynamicsProcessing::EngineArchitecture engine =
+ VALUE_OR_RETURN_STATUS(readEngineArchitectureFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing,
+ engineArchitecture, engine);
+ mEngine = engine;
+ break;
+ }
+ case DP_PARAM_PRE_EQ: {
+ DynamicsProcessing::ChannelConfig chConfig =
+ VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, preEq,
+ {chConfig});
+ break;
+ }
+ case DP_PARAM_POST_EQ: {
+ DynamicsProcessing::ChannelConfig chConfig =
+ VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, postEq,
+ {chConfig});
+ break;
+ }
+ case DP_PARAM_MBC: {
+ DynamicsProcessing::ChannelConfig chConfig =
+ VALUE_OR_RETURN_STATUS(readChannelConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, mbc,
+ {chConfig});
+ break;
+ }
+ case DP_PARAM_PRE_EQ_BAND: {
+ DynamicsProcessing::EqBandConfig bandConfig =
+ VALUE_OR_RETURN_STATUS(readEqBandConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, preEqBand,
+ {bandConfig});
+ break;
+ }
+ case DP_PARAM_POST_EQ_BAND: {
+ DynamicsProcessing::EqBandConfig bandConfig =
+ VALUE_OR_RETURN_STATUS(readEqBandConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, postEqBand,
+ {bandConfig});
+ break;
+ }
+ case DP_PARAM_MBC_BAND: {
+ DynamicsProcessing::MbcBandConfig bandConfig =
+ VALUE_OR_RETURN_STATUS(readMbcBandConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, mbcBand,
+ {bandConfig});
+ break;
+ }
+ case DP_PARAM_LIMITER: {
+ DynamicsProcessing::LimiterConfig config =
+ VALUE_OR_RETURN_STATUS(readLimiterConfigFromParam(param));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(DynamicsProcessing, dynamicsProcessing, limiter,
+ {config});
+ break;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionDp::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0;
+ if (OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case DP_PARAM_INPUT_GAIN: {
+ int32_t channel;
+ if (OK != param.readFromParameter(&channel)) {
+ ALOGE("%s invalid inputGain %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag,
+ DynamicsProcessing::inputGain);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ DynamicsProcessing::Capability cap =
+ mDesc.capability.get<Capability::dynamicsProcessing>();
+ std::vector<DynamicsProcessing::InputGain> gains =
+ VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing,
+ DynamicsProcessing::inputGain,
+ std::vector<DynamicsProcessing::InputGain>));
+ for (const auto& gain : gains) {
+ if (gain.channel == channel) {
+ return param.writeToValue(&gain.gainDb);
+ }
+ }
+ ALOGE("%s not able to find channel %d", __func__, channel);
+ return BAD_VALUE;
+ }
+ case DP_PARAM_ENGINE_ARCHITECTURE: {
+ int32_t channel;
+ if (OK != param.readFromParameter(&channel)) {
+ ALOGE("%s invalid inputGain %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag,
+ DynamicsProcessing::engineArchitecture);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ DynamicsProcessing::EngineArchitecture engine =
+ VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing,
+ DynamicsProcessing::engineArchitecture,
+ DynamicsProcessing::EngineArchitecture));
+ int32_t resolution = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_DynamicsProcessing_ResolutionPreference_int32(
+ engine.resolutionPreference));
+ int32_t preEqInUse =
+ VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.preEqStage.inUse));
+ int32_t mbcInUse =
+ VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.mbcStage.inUse));
+ int32_t postEqInUse =
+ VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.postEqStage.inUse));
+ int32_t limiterInUse =
+ VALUE_OR_RETURN_STATUS(convertIntegral<int32_t>(engine.limiterInUse));
+ if (OK != param.writeToValue(&resolution) ||
+ OK != param.writeToValue(&engine.preferredProcessingDurationMs) ||
+ OK != param.writeToValue(&preEqInUse) ||
+ OK != param.writeToValue(&engine.preEqStage.bandCount) ||
+ OK != param.writeToValue(&mbcInUse) ||
+ OK != param.writeToValue(&engine.mbcStage.bandCount) ||
+ OK != param.writeToValue(&postEqInUse) ||
+ OK != param.writeToValue(&engine.postEqStage.bandCount) ||
+ OK != param.writeToValue(&limiterInUse)) {
+ ALOGE("%s invalid engineArchitecture %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ mEngine = engine;
+ return OK;
+ }
+ case DP_PARAM_PRE_EQ: {
+ return getChannelConfig(DynamicsProcessing::preEq, param);
+ }
+ case DP_PARAM_POST_EQ: {
+ return getChannelConfig(DynamicsProcessing::postEq, param);
+ }
+ case DP_PARAM_MBC: {
+ return getChannelConfig(DynamicsProcessing::mbc, param);
+ }
+ case DP_PARAM_PRE_EQ_BAND: {
+ return getEqBandConfig(DynamicsProcessing::preEqBand, param);
+ }
+ case DP_PARAM_POST_EQ_BAND: {
+ return getEqBandConfig(DynamicsProcessing::postEqBand, param);
+ }
+ case DP_PARAM_MBC_BAND: {
+ return getMbcBandConfig(param);
+ }
+ case DP_PARAM_LIMITER: {
+ return getLimiterConfig(param);
+ }
+ case DP_PARAM_GET_CHANNEL_COUNT: {
+ uint32_t channel = VALUE_OR_RETURN_STATUS(
+ aidl::android::aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ mCommon.input.base.channelMask, true /* input */));
+ if (OK != param.writeToValue(&channel)) {
+ ALOGE("%s write channel number %d to param failed %s", __func__, channel,
+ param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ default: {
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+}
+
+aidl::ConversionResult<DynamicsProcessing::ChannelConfig>
+AidlConversionDp::readChannelConfigFromParam(EffectParamReader& param) {
+ int32_t enable, channel;
+ if (OK != param.readFromParameter(&channel) || OK != param.readFromValue(&enable)) {
+ ALOGE("%s invalid channel config param %s", __func__, param.toString().c_str());
+ return ::android::base::unexpected(::android::BAD_VALUE);
+ }
+ return DynamicsProcessing::ChannelConfig(
+ {.enable = VALUE_OR_RETURN(convertIntegral<bool>(enable)), .channel = channel});
+}
+
+aidl::ConversionResult<DynamicsProcessing::EqBandConfig>
+AidlConversionDp::readEqBandConfigFromParam(EffectParamReader& param) {
+ DynamicsProcessing::EqBandConfig config;
+ int32_t enable;
+ if (OK != param.readFromParameter(&config.channel) ||
+ OK != param.readFromParameter(&config.band) ||
+ OK != param.readFromValue(&enable) ||
+ OK != param.readFromValue(&config.cutoffFrequencyHz) ||
+ OK != param.readFromValue(&config.gainDb)) {
+ ALOGE("%s invalid eq band param %s", __func__, param.toString().c_str());
+ return ::android::base::unexpected(::android::BAD_VALUE);
+ }
+ config.enable = VALUE_OR_RETURN(convertIntegral<bool>(enable));
+ return config;
+}
+
+aidl::ConversionResult<DynamicsProcessing::MbcBandConfig>
+AidlConversionDp::readMbcBandConfigFromParam(EffectParamReader& param) {
+ DynamicsProcessing::MbcBandConfig config;
+ int32_t enable;
+ if (OK != param.readFromParameter(&config.channel) ||
+ OK != param.readFromParameter(&config.band) ||
+ OK != param.readFromValue(&enable) ||
+ OK != param.readFromValue(&config.cutoffFrequencyHz) ||
+ OK != param.readFromValue(&config.attackTimeMs) ||
+ OK != param.readFromValue(&config.releaseTimeMs) ||
+ OK != param.readFromValue(&config.ratio) ||
+ OK != param.readFromValue(&config.thresholdDb) ||
+ OK != param.readFromValue(&config.kneeWidthDb) ||
+ OK != param.readFromValue(&config.noiseGateThresholdDb) ||
+ OK != param.readFromValue(&config.expanderRatio) ||
+ OK != param.readFromValue(&config.preGainDb) ||
+ OK != param.readFromValue(&config.postGainDb)) {
+ ALOGE("%s invalid mbc band config param %s", __func__, param.toString().c_str());
+ return ::android::base::unexpected(::android::BAD_VALUE);
+ }
+ config.enable = VALUE_OR_RETURN(convertIntegral<bool>(enable));
+ return config;
+}
+
+aidl::ConversionResult<DynamicsProcessing::LimiterConfig>
+AidlConversionDp::readLimiterConfigFromParam(EffectParamReader& param) {
+ DynamicsProcessing::LimiterConfig config;
+ int32_t enable, inUse;
+ if (OK != param.readFromParameter(&config.channel) ||
+ OK != param.readFromValue(&inUse) ||
+ OK != param.readFromValue(&enable) ||
+ OK != param.readFromValue(&config.linkGroup) ||
+ OK != param.readFromValue(&config.attackTimeMs) ||
+ OK != param.readFromValue(&config.releaseTimeMs) ||
+ OK != param.readFromValue(&config.ratio) ||
+ OK != param.readFromValue(&config.thresholdDb) ||
+ OK != param.readFromValue(&config.postGainDb)) {
+ ALOGE("%s invalid limiter config param %s", __func__, param.toString().c_str());
+ return ::android::base::unexpected(::android::BAD_VALUE);
+ }
+ config.enable = VALUE_OR_RETURN(convertIntegral<bool>(enable));
+ return config;
+}
+
+aidl::ConversionResult<DynamicsProcessing::EngineArchitecture>
+AidlConversionDp::readEngineArchitectureFromParam(EffectParamReader& param) {
+ DynamicsProcessing::EngineArchitecture engine;
+ int32_t variant, preEqInUse, mbcInUse, postEqInUse, limiterInUse;
+ if (OK != param.readFromValue(&variant) &&
+ OK != param.readFromValue(&engine.preferredProcessingDurationMs) &&
+ OK != param.readFromValue(&preEqInUse) &&
+ OK != param.readFromValue(&engine.preEqStage.bandCount) &&
+ OK != param.readFromValue(&mbcInUse) &&
+ OK != param.readFromValue(&engine.mbcStage.bandCount) &&
+ OK != param.readFromValue(&postEqInUse) &&
+ OK != param.readFromValue(&engine.postEqStage.bandCount) &&
+ OK != param.readFromValue(&limiterInUse)) {
+ ALOGE("%s invalid engineArchitecture %s", __func__, param.toString().c_str());
+ return ::android::base::unexpected(::android::BAD_VALUE);
+ }
+
+ engine.resolutionPreference = VALUE_OR_RETURN(
+ aidl::android::legacy2aidl_int32_DynamicsProcessing_ResolutionPreference(variant));
+ engine.preEqStage.inUse = VALUE_OR_RETURN(convertIntegral<bool>(preEqInUse));
+ engine.mbcStage.inUse = VALUE_OR_RETURN(convertIntegral<bool>(mbcInUse));
+ engine.postEqStage.inUse = VALUE_OR_RETURN(convertIntegral<bool>(postEqInUse));
+ engine.limiterInUse = VALUE_OR_RETURN(convertIntegral<bool>(limiterInUse));
+ return engine;
+}
+
+status_t AidlConversionDp::getChannelConfig(DynamicsProcessing::Tag tag, EffectParamWriter& param) {
+ int32_t channel;
+ if (OK != param.readFromParameter(&channel)) {
+ ALOGE("%s invalid parameter %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, tag);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ std::vector<DynamicsProcessing::ChannelConfig> channels;
+ int32_t inUse, bandCount;
+ switch (tag) {
+ case DynamicsProcessing::preEq: {
+ inUse = mEngine.preEqStage.inUse;
+ bandCount = mEngine.preEqStage.bandCount;
+ channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::preEq,
+ std::vector<DynamicsProcessing::ChannelConfig>));
+ break;
+ }
+ case DynamicsProcessing::postEq: {
+ inUse = mEngine.postEqStage.inUse;
+ bandCount = mEngine.postEqStage.bandCount;
+ channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::postEq,
+ std::vector<DynamicsProcessing::ChannelConfig>));
+ break;
+ }
+ case DynamicsProcessing::mbc: {
+ inUse = mEngine.mbcStage.inUse;
+ bandCount = mEngine.mbcStage.bandCount;
+ channels = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, DynamicsProcessing::mbc,
+ std::vector<DynamicsProcessing::ChannelConfig>));
+ break;
+ }
+ default: {
+ ALOGE("%s unsupported tag %s", __func__, toString(tag).c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ for (const auto& ch : channels) {
+ if (ch.channel == channel) {
+ int32_t enable = ch.enable;
+ if (OK != param.writeToValue(&inUse) ||
+ OK != param.writeToValue(&enable) ||
+ OK != param.writeToValue(&bandCount)) {
+ ALOGE("%s failed to write into param value %s", __func__,
+ param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ }
+ ALOGE("%s not able to find channel %d", __func__, channel);
+ return BAD_VALUE;
+}
+
+status_t AidlConversionDp::getEqBandConfig(DynamicsProcessing::Tag tag, EffectParamWriter& param) {
+ int32_t channel, band;
+ if (OK != param.readFromParameter(&channel) || OK != param.readFromParameter(&band)) {
+ ALOGE("%s invalid parameter %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag, tag);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ std::vector<DynamicsProcessing::EqBandConfig> bands;
+ if (tag == DynamicsProcessing::preEqBand) {
+ bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, preEqBand,
+ std::vector<DynamicsProcessing::EqBandConfig>));
+ } else if (tag == DynamicsProcessing::postEqBand) {
+ bands = VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, postEqBand,
+ std::vector<DynamicsProcessing::EqBandConfig>));
+ } else {
+ return BAD_VALUE;
+ }
+
+ for (const auto& bandIt : bands) {
+ if (bandIt.channel == channel && bandIt.band == band) {
+ int32_t enable = bandIt.enable;
+ if (OK != param.writeToValue(&enable) ||
+ OK != param.writeToValue(&bandIt.cutoffFrequencyHz) ||
+ OK != param.writeToValue(&bandIt.gainDb)) {
+ ALOGE("%s failed to write into param value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ }
+ ALOGE("%s not able to find channel %d band %d", __func__, channel, band);
+ return BAD_VALUE;
+}
+
+status_t AidlConversionDp::getMbcBandConfig(EffectParamWriter& param) {
+ int32_t channel, band;
+ if (OK != param.readFromParameter(&channel) || OK != param.readFromParameter(&band)) {
+ ALOGE("%s invalid parameter %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag,
+ DynamicsProcessing::mbcBand);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ std::vector<DynamicsProcessing::MbcBandConfig> bands =
+ VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, mbcBand,
+ std::vector<DynamicsProcessing::MbcBandConfig>));
+
+ for (const auto& bandIt : bands) {
+ if (bandIt.channel == channel && bandIt.band == band) {
+ int32_t enable = bandIt.enable;
+ if (OK != param.writeToValue(&enable) ||
+ OK != param.writeToValue(&bandIt.cutoffFrequencyHz) ||
+ OK != param.writeToValue(&bandIt.attackTimeMs) ||
+ OK != param.writeToValue(&bandIt.releaseTimeMs) ||
+ OK != param.writeToValue(&bandIt.ratio) ||
+ OK != param.writeToValue(&bandIt.thresholdDb) ||
+ OK != param.writeToValue(&bandIt.kneeWidthDb) ||
+ OK != param.writeToValue(&bandIt.noiseGateThresholdDb) ||
+ OK != param.writeToValue(&bandIt.expanderRatio) ||
+ OK != param.writeToValue(&bandIt.preGainDb) ||
+ OK != param.writeToValue(&bandIt.postGainDb)) {
+ ALOGE("%s failed to write into param value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ }
+ ALOGE("%s not able to find channel %d band %d", __func__, channel, band);
+ return BAD_VALUE;
+}
+
+status_t AidlConversionDp::getLimiterConfig(EffectParamWriter& param) {
+ int32_t channel;
+ if (OK != param.readFromParameter(&channel)) {
+ ALOGE("%s invalid parameter %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(DynamicsProcessing, dynamicsProcessingTag,
+ DynamicsProcessing::limiter);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+
+ std::vector<DynamicsProcessing::LimiterConfig> configs =
+ VALUE_OR_RETURN_STATUS(aidl::android::GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, DynamicsProcessing, dynamicsProcessing, limiter,
+ std::vector<DynamicsProcessing::LimiterConfig>));
+
+ for (const auto& config : configs) {
+ if (config.channel == channel) {
+ int32_t inUse = mEngine.limiterInUse;
+ int32_t enable = config.enable;
+ if (OK != param.writeToValue(&inUse) ||
+ OK != param.writeToValue(&enable) ||
+ OK != param.writeToValue(&config.linkGroup) ||
+ OK != param.writeToValue(&config.attackTimeMs) ||
+ OK != param.writeToValue(&config.releaseTimeMs) ||
+ OK != param.writeToValue(&config.ratio) ||
+ OK != param.writeToValue(&config.thresholdDb) ||
+ OK != param.writeToValue(&config.postGainDb)) {
+ ALOGE("%s failed to write into param value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return OK;
+ }
+ }
+ ALOGE("%s not able to find channel %d", __func__, channel);
+ return BAD_VALUE;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h
new file mode 100644
index 0000000..6bab18d
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionDynamicsProcessing.h
@@ -0,0 +1,64 @@
+/*
+ * 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/BpEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionDp : public EffectConversionHelperAidl {
+ public:
+ AidlConversionDp(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionDp() {}
+
+ private:
+ aidl::android::hardware::audio::effect::DynamicsProcessing::EngineArchitecture mEngine;
+
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+
+ aidl::ConversionResult<
+ aidl::android::hardware::audio::effect::DynamicsProcessing::ChannelConfig>
+ readChannelConfigFromParam(utils::EffectParamReader& param);
+ aidl::ConversionResult<aidl::android::hardware::audio::effect::DynamicsProcessing::EqBandConfig>
+ readEqBandConfigFromParam(utils::EffectParamReader& param);
+ aidl::ConversionResult<
+ aidl::android::hardware::audio::effect::DynamicsProcessing::MbcBandConfig>
+ readMbcBandConfigFromParam(utils::EffectParamReader& param);
+ aidl::ConversionResult<
+ aidl::android::hardware::audio::effect::DynamicsProcessing::LimiterConfig>
+ readLimiterConfigFromParam(utils::EffectParamReader& param);
+ aidl::ConversionResult<
+ aidl::android::hardware::audio::effect::DynamicsProcessing::EngineArchitecture>
+ readEngineArchitectureFromParam(utils::EffectParamReader& param);
+
+ status_t getChannelConfig(aidl::android::hardware::audio::effect::DynamicsProcessing::Tag tag,
+ utils::EffectParamWriter& writer);
+ status_t getEqBandConfig(aidl::android::hardware::audio::effect::DynamicsProcessing::Tag tag,
+ utils::EffectParamWriter& param);
+ status_t getMbcBandConfig(utils::EffectParamWriter& param);
+ status_t getLimiterConfig(utils::EffectParamWriter& param);
+
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.cpp
new file mode 100644
index 0000000..960273b
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.cpp
@@ -0,0 +1,200 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionEnvReverb"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_environmentalreverb.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionEnvReverb.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::convertIntegral;
+using ::aidl::android::getParameterSpecificField;
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::EnvironmentalReverb;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+#define MAKE_AIDL_PARAMETER(aidlParam, param, value, tag) \
+ { \
+ if (OK != param.readFromValue(&value)) { \
+ ALOGE("%s invalid parameter %s %d", __func__, #tag, value); \
+ return BAD_VALUE; \
+ } \
+ aidlParam = MAKE_SPECIFIC_PARAMETER( \
+ EnvironmentalReverb, environmentalReverb, tag, \
+ VALUE_OR_RETURN_STATUS(aidl::android::convertIntegral<int>(value))); \
+ }
+
+#define GET_AIDL_PARAMETER(tag, value, param) \
+ { \
+ Parameter aidlParam; \
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(EnvironmentalReverb, environmentalReverbTag, \
+ EnvironmentalReverb::tag); \
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam))); \
+ value = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD( \
+ aidlParam, EnvironmentalReverb, environmentalReverb, EnvironmentalReverb::tag, \
+ std::decay_t<decltype(value)>)); \
+ return param.writeToValue(&value); \
+ }
+
+status_t AidlConversionEnvReverb::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ uint16_t value16;
+ uint32_t value32;
+ switch (type) {
+ case REVERB_PARAM_ROOM_LEVEL: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, roomLevelMb);
+ break;
+ }
+ case REVERB_PARAM_ROOM_HF_LEVEL: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, roomHfLevelMb);
+ break;
+ }
+ case REVERB_PARAM_DECAY_TIME: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value32, decayTimeMs);
+ break;
+ }
+ case REVERB_PARAM_DECAY_HF_RATIO: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, decayHfRatioPm);
+ break;
+ }
+ case REVERB_PARAM_REVERB_LEVEL: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, levelMb);
+ break;
+ }
+ case REVERB_PARAM_REVERB_DELAY: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value32, delayMs);
+ break;
+ }
+ case REVERB_PARAM_DIFFUSION: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, diffusionPm);
+ break;
+ }
+ case REVERB_PARAM_DENSITY: {
+ MAKE_AIDL_PARAMETER(aidlParam, param, value16, densityPm);
+ break;
+ }
+ case REVERB_PARAM_BYPASS: {
+ if (OK != param.readFromValue(&value32)) {
+ ALOGE("%s invalid bypass parameter %d", __func__, value32);
+ return BAD_VALUE;
+ }
+ bool isByPass = VALUE_OR_RETURN_STATUS(aidl::android::convertIntegral<bool>(value32));
+ aidlParam = MAKE_SPECIFIC_PARAMETER(EnvironmentalReverb, environmentalReverb, bypass,
+ isByPass);
+ break;
+ }
+ case REVERB_PARAM_REFLECTIONS_LEVEL: {
+ // TODO
+ break;
+ }
+ case REVERB_PARAM_REFLECTIONS_DELAY: {
+ // TODO
+ break;
+ }
+ case REVERB_PARAM_PROPERTIES: {
+ // TODO
+ break;
+ }
+ default: {
+ // TODO: handle with vendor extension
+ }
+ }
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionEnvReverb::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ uint16_t value16;
+ uint32_t value32;
+ switch (type) {
+ case REVERB_PARAM_ROOM_LEVEL: {
+ GET_AIDL_PARAMETER(roomLevelMb, value16, param);
+ }
+ case REVERB_PARAM_ROOM_HF_LEVEL: {
+ GET_AIDL_PARAMETER(roomHfLevelMb, value16, param);
+ }
+ case REVERB_PARAM_DECAY_TIME: {
+ GET_AIDL_PARAMETER(decayTimeMs, value32, param);
+ }
+ case REVERB_PARAM_DECAY_HF_RATIO: {
+ GET_AIDL_PARAMETER(decayHfRatioPm, value16, param);
+ }
+ case REVERB_PARAM_REVERB_LEVEL: {
+ GET_AIDL_PARAMETER(levelMb, value16, param);
+ }
+ case REVERB_PARAM_REVERB_DELAY: {
+ GET_AIDL_PARAMETER(delayMs, value32, param);
+ }
+ case REVERB_PARAM_DIFFUSION: {
+ GET_AIDL_PARAMETER(diffusionPm, value16, param);
+ }
+ case REVERB_PARAM_DENSITY: {
+ GET_AIDL_PARAMETER(densityPm, value16, param);
+ }
+ case REVERB_PARAM_BYPASS: {
+ bool isByPass;
+ GET_AIDL_PARAMETER(bypass, isByPass, param);
+ }
+ case REVERB_PARAM_REFLECTIONS_LEVEL: {
+ // TODO
+ break;
+ }
+ case REVERB_PARAM_REFLECTIONS_DELAY: {
+ // TODO
+ break;
+ }
+ case REVERB_PARAM_PROPERTIES: {
+ // TODO
+ break;
+ }
+ default: {
+ // TODO: handle with vendor extension
+ }
+ }
+ return BAD_VALUE;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h
new file mode 100644
index 0000000..8b92374
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEnvReverb.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionEnvReverb : public EffectConversionHelperAidl {
+ public:
+ AidlConversionEnvReverb(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionEnvReverb() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
new file mode 100644
index 0000000..efa9e89
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionEQ"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_equalizer.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionEq.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::getParameterSpecificField;
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Equalizer;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionEq::setParameter(EffectParamReader& param) {
+ uint32_t type;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type) ||
+ OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+
+ Parameter aidlParam;
+ switch (type) {
+ case EQ_PARAM_CUR_PRESET: {
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, preset, (int)value);
+ break;
+ }
+ case EQ_PARAM_BAND_LEVEL: {
+ int32_t band;
+ uint16_t level;
+ if (OK != param.readFromParameter(&band) || OK != param.readFromParameter(&level)) {
+ ALOGE("%s invalid bandLevel param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ std::vector<Equalizer::BandLevel> bandLevels = {{.index = band, .levelMb = level}};
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, bandLevels, bandLevels);
+ break;
+ }
+ case EQ_PARAM_PROPERTIES: {
+ if (value >= 0) {
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, preset, (int)value);
+ } else {
+ std::vector<Equalizer::BandLevel> bandLevels;
+ uint16_t numBands;
+ if (OK != param.readFromValue(&numBands)) {
+ ALOGE("%s invalid bandLevel param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ for (int i = 0; i < numBands; i++) {
+ uint16_t level;
+ if (OK != param.readFromValue(&level)) {
+ ALOGE("%s invalid property param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ bandLevels.push_back({.index = i, .levelMb = level});
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(Equalizer, equalizer, bandLevels, bandLevels);
+ }
+ break;
+ }
+ default: {
+ // TODO: implement vendor extension parameters
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+aidl::ConversionResult<Parameter> AidlConversionEq::getAidlParameter(Equalizer::Tag tag) {
+ Parameter aidlParam;
+ Parameter::Id id = MAKE_SPECIFIC_PARAMETER_ID(Equalizer, equalizerTag, tag);
+ RETURN_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ return aidlParam;
+}
+
+status_t AidlConversionEq::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ param.setStatus(BAD_VALUE);
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ switch (type) {
+ case EQ_PARAM_NUM_BANDS: {
+ aidlParam = VALUE_OR_RETURN_STATUS(getAidlParameter(Equalizer::bandLevels));
+ auto bandLevels = VALUE_OR_RETURN_STATUS(GET_PARAMETER_SPECIFIC_FIELD(
+ aidlParam, Equalizer, equalizer, Equalizer::bandLevels,
+ std::vector<Equalizer::BandLevel>));
+ uint32_t num = bandLevels.size();
+ return param.writeToValue(&num);
+ }
+ default:
+ ALOGW("%s unknown param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h
new file mode 100644
index 0000000..0433965
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionEq.h
@@ -0,0 +1,41 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionEq : public EffectConversionHelperAidl {
+ public:
+ AidlConversionEq(std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionEq() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+ aidl::ConversionResult<::aidl::android::hardware::audio::effect::Parameter> getAidlParameter(
+ ::aidl::android::hardware::audio::effect::Equalizer::Tag tag);
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp
new file mode 100644
index 0000000..814b58f
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionHapticGenerator"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_hapticgenerator.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionHapticGenerator.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionHapticGenerator::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionHapticGenerator::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h
new file mode 100644
index 0000000..03114a5
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionHapticGenerator.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionHapticGenerator : public EffectConversionHelperAidl {
+ public:
+ AidlConversionHapticGenerator(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionHapticGenerator() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp
new file mode 100644
index 0000000..70e0428
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionLoudnessEnhancer"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_loudnessenhancer.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionLoudnessEnhancer.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionLoudnessEnhancer::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionLoudnessEnhancer::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h
new file mode 100644
index 0000000..c0402f9
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionLoudnessEnhancer.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionLoudnessEnhancer : public EffectConversionHelperAidl {
+ public:
+ AidlConversionLoudnessEnhancer(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionLoudnessEnhancer() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp
new file mode 100644
index 0000000..5faf645
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionNoiseSuppression"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_ns.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionNoiseSuppression.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionNoiseSuppression::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionNoiseSuppression::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h
new file mode 100644
index 0000000..f51e13a
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionNoiseSuppression.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionNoiseSuppression : public EffectConversionHelperAidl {
+ public:
+ AidlConversionNoiseSuppression(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionNoiseSuppression() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.cpp
new file mode 100644
index 0000000..3e9bf4b
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.cpp
@@ -0,0 +1,94 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionPresetReverb"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_presetreverb.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionPresetReverb.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::convertIntegral;
+using ::aidl::android::getParameterSpecificField;
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::PresetReverb;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionPresetReverb::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ if (type == REVERB_PARAM_PRESET) {
+ uint16_t value = 0;
+ if (OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid preset value %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ aidlParam = MAKE_SPECIFIC_PARAMETER(PresetReverb, presetReverb, preset,
+ static_cast<PresetReverb::Presets>(value));
+ } else {
+ // handle vendor extension
+ }
+
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionPresetReverb::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ ALOGE("%s enter %s", __func__, param.toString().c_str());
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ if (type == REVERB_PARAM_PRESET) {
+ Parameter aidlParam;
+ Parameter::Id id =
+ MAKE_SPECIFIC_PARAMETER_ID(PresetReverb, presetReverbTag, PresetReverb::preset);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getParameter(id, &aidlParam)));
+ auto aidlPreset = VALUE_OR_RETURN_STATUS(
+ GET_PARAMETER_SPECIFIC_FIELD(aidlParam, PresetReverb, presetReverb,
+ PresetReverb::preset, PresetReverb::Presets));
+ value = static_cast<uint16_t>(aidlPreset);
+ } else {
+ // handle vendor extension
+ }
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h
new file mode 100644
index 0000000..397d6e6
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionPresetReverb.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionPresetReverb : public EffectConversionHelperAidl {
+ public:
+ AidlConversionPresetReverb(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionPresetReverb() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
new file mode 100644
index 0000000..1dac479
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionSpatializer"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_spatializer.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionSpatializer.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionSpatializer::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionSpatializer::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
new file mode 100644
index 0000000..c44567c
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionSpatializer.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionSpatializer : public EffectConversionHelperAidl {
+ public:
+ AidlConversionSpatializer(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionSpatializer() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp
new file mode 100644
index 0000000..a035614
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionVendorExtension"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionVendorExtension.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionVendorExtension::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionVendorExtension::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h
new file mode 100644
index 0000000..fd22e5c
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVendorExtension.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionVendorExtension : public EffectConversionHelperAidl {
+ public:
+ AidlConversionVendorExtension(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionVendorExtension() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.cpp
new file mode 100644
index 0000000..482114d
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionVirtualizer"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_spatializer.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionVirtualizer.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionVirtualizer::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionVirtualizer::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h
new file mode 100644
index 0000000..91c0fcd
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVirtualizer.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionVirtualizer : public EffectConversionHelperAidl {
+ public:
+ AidlConversionVirtualizer(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionVirtualizer() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.cpp b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.cpp
new file mode 100644
index 0000000..9ed601f
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.cpp
@@ -0,0 +1,68 @@
+/*
+ * 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 <cstdint>
+#include <cstring>
+#include <optional>
+#define LOG_TAG "AidlConversionVisualizer"
+//#define LOG_NDEBUG 0
+
+#include <error/expected_utils.h>
+#include <media/AidlConversionNdk.h>
+#include <media/AidlConversionEffect.h>
+#include <media/audiohal/AudioEffectUuid.h>
+#include <system/audio_effects/effect_visualizer.h>
+
+#include <utils/Log.h>
+
+#include "AidlConversionVisualizer.h"
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::aidl_utils::statusTFromBinderStatus;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::android::status_t;
+using utils::EffectParamReader;
+using utils::EffectParamWriter;
+
+status_t AidlConversionVisualizer::setParameter(EffectParamReader& param) {
+ uint32_t type = 0;
+ uint16_t value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint16_t)) ||
+ OK != param.readFromParameter(&type) || OK != param.readFromValue(&value)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ return BAD_VALUE;
+ }
+ Parameter aidlParam;
+ // TODO
+ return statusTFromBinderStatus(mEffect->setParameter(aidlParam));
+}
+
+status_t AidlConversionVisualizer::getParameter(EffectParamWriter& param) {
+ uint32_t type = 0, value = 0;
+ if (!param.validateParamValueSize(sizeof(uint32_t), sizeof(uint32_t)) ||
+ OK != param.readFromParameter(&type)) {
+ ALOGE("%s invalid param %s", __func__, param.toString().c_str());
+ param.setStatus(BAD_VALUE);
+ return BAD_VALUE;
+ }
+ // TODO
+ return param.writeToValue(&value);
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h
new file mode 100644
index 0000000..a7e4ea1
--- /dev/null
+++ b/media/libaudiohal/impl/effectsAidlConversion/AidlConversionVisualizer.h
@@ -0,0 +1,40 @@
+/*
+ * 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/IEffect.h>
+#include "EffectConversionHelperAidl.h"
+
+namespace android {
+namespace effect {
+
+class AidlConversionVisualizer : public EffectConversionHelperAidl {
+ public:
+ AidlConversionVisualizer(
+ std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
+ int32_t sessionId, int32_t ioId,
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc)
+ : EffectConversionHelperAidl(effect, sessionId, ioId, desc) {}
+ ~AidlConversionVisualizer() {}
+
+ private:
+ status_t setParameter(utils::EffectParamReader& param) override;
+ status_t getParameter(utils::EffectParamWriter& param) override;
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/include/media/audiohal/AudioEffectUuid.h b/media/libaudiohal/include/media/audiohal/AudioEffectUuid.h
new file mode 100644
index 0000000..b21e4c9
--- /dev/null
+++ b/media/libaudiohal/include/media/audiohal/AudioEffectUuid.h
@@ -0,0 +1,118 @@
+/*
+ * 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/media/audio/common/AudioUuid.h>
+
+namespace android {
+namespace effect {
+
+using ::aidl::android::media::audio::common::AudioUuid;
+
+// 7b491460-8d4d-11e0-bd61-0002a5d5c51b.
+static const AudioUuid kAcousticEchoCancelerTypeUUID = {static_cast<int32_t>(0x7b491460),
+ 0x8d4d,
+ 0x11e0,
+ 0xbd61,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 0xae3c653b-be18-4ab8-8938-418f0a7f06ac
+static const AudioUuid kAutomaticGainControl2TypeUUID = {static_cast<int32_t>(0xae3c653b),
+ 0xbe18,
+ 0x4ab8,
+ 0x8938,
+ {0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac}};
+// 0634f220-ddd4-11db-a0fc-0002a5d5c51b
+static const AudioUuid kBassBoostTypeUUID = {static_cast<int32_t>(0x0634f220),
+ 0xddd4,
+ 0x11db,
+ 0xa0fc,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa81862a-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kDownmixTypeUUID = {static_cast<int32_t>(0xfa81862a),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// 7261676f-6d75-7369-6364-28e2fd3ac39e
+static const AudioUuid kDynamicsProcessingTypeUUID = {static_cast<int32_t>(0x7261676f),
+ 0x6d75,
+ 0x7369,
+ 0x6364,
+ {0x28, 0xe2, 0xfd, 0x3a, 0xc3, 0x9e}};
+// 0bed4300-ddd6-11db-8f34-0002a5d5c51b.
+static const AudioUuid kEqualizerTypeUUID = {static_cast<int32_t>(0x0bed4300),
+ 0xddd6,
+ 0x11db,
+ 0x8f34,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 1411e6d6-aecd-4021-a1cf-a6aceb0d71e5
+static const AudioUuid kHapticGeneratorTypeUUID = {static_cast<int32_t>(0x1411e6d6),
+ 0xaecd,
+ 0x4021,
+ 0xa1cf,
+ {0xa6, 0xac, 0xeb, 0x0d, 0x71, 0xe5}};
+// fe3199be-aed0-413f-87bb-11260eb63cf1
+static const AudioUuid kLoudnessEnhancerTypeUUID = {static_cast<int32_t>(0xfe3199be),
+ 0xaed0,
+ 0x413f,
+ 0x87bb,
+ {0x11, 0x26, 0x0e, 0xb6, 0x3c, 0xf1}};
+// c2e5d5f0-94bd-4763-9cac-4e234d06839e
+static const AudioUuid kEnvReverbTypeUUID = {static_cast<int32_t>(0xc2e5d5f0),
+ 0x94bd,
+ 0x4763,
+ 0x9cac,
+ {0x4e, 0x23, 0x4d, 0x06, 0x83, 0x9e}};
+// 58b4b260-8e06-11e0-aa8e-0002a5d5c51b
+static const AudioUuid kNoiseSuppressionTypeUUID = {static_cast<int32_t>(0x58b4b260),
+ 0x8e06,
+ 0x11e0,
+ 0xaa8e,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// 47382d60-ddd8-11db-bf3a-0002a5d5c51b
+static const AudioUuid kPresetReverbTypeUUID = {static_cast<int32_t>(0x47382d60),
+ 0xddd8,
+ 0x11db,
+ 0xbf3a,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// ccd4cf09-a79d-46c2-9aae-06a1698d6c8f
+static const AudioUuid kSpatializerTypeUUID = {static_cast<int32_t>(0xccd4cf09),
+ 0xa79d,
+ 0x46c2,
+ 0x9aae,
+ {0x06, 0xa1, 0x69, 0x8d, 0x6c, 0x8f}};
+// 37cc2c00-dddd-11db-8577-0002a5d5c51b
+static const AudioUuid kVirtualizerTypeUUID = {static_cast<int32_t>(0x37cc2c00),
+ 0xdddd,
+ 0x11db,
+ 0x8577,
+ {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}};
+// fa819f3e-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVisualizerTypeUUID = {static_cast<int32_t>(0xfa819f3e),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+// fa81a2b8-588b-11ed-9b6a-0242ac120002
+static const AudioUuid kVolumeTypeUUID = {static_cast<int32_t>(0xfa81a2b8),
+ 0x588b,
+ 0x11ed,
+ 0x9b6a,
+ {0x02, 0x42, 0xac, 0x12, 0x00, 0x02}};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index d27ad4c..d5a1a60 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -21,12 +21,15 @@
#include <android/media/audio/common/AudioMMapPolicyType.h>
#include <error/Result.h>
#include <media/audiohal/EffectHalInterface.h>
-#include <media/MicrophoneInfo.h>
#include <system/audio.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
+namespace ndk {
+class SpAIBinder;
+}
+
namespace android {
class StreamInHalInterface;
@@ -107,7 +110,7 @@
virtual status_t releaseAudioPatch(audio_patch_handle_t patch) = 0;
// Fills the list of supported attributes for a given audio port.
- virtual status_t getAudioPort(struct audio_port *port) = 0;
+ virtual status_t getAudioPort(struct audio_port* port) = 0;
// Fills the list of supported attributes for a given audio port.
virtual status_t getAudioPort(struct audio_port_v7 *port) = 0;
@@ -116,7 +119,8 @@
virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0;
// List microphones
- virtual status_t getMicrophones(std::vector<media::MicrophoneInfo> *microphones) = 0;
+ virtual status_t getMicrophones(
+ std::vector<audio_microphone_characteristic_t>* microphones) = 0;
virtual status_t addDeviceEffect(
audio_port_handle_t device, sp<EffectHalInterface> effect) = 0;
@@ -125,17 +129,25 @@
virtual status_t getMmapPolicyInfos(
media::audio::common::AudioMMapPolicyType policyType,
- std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
+ std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+ virtual int32_t supportsBluetoothVariableLatency(bool* supports) = 0;
// Update the connection status of an external device.
- virtual status_t setConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+ virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) {
+ ALOGE("%s override me port %p connected %d", __func__, port, connected);
+ return OK;
+ }
virtual error::Result<audio_hw_sync_t> getHwAvSync() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+ // Returns the sound dose binder interface if it is supported by the HAL, nullptr otherwise
+ virtual status_t getSoundDoseInterface(const std::string& module,
+ ::ndk::SpAIBinder* soundDoseBinder) = 0;
+
protected:
// Subclasses can not be constructed directly by clients.
DeviceHalInterface() {}
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
new file mode 100644
index 0000000..6600713
--- /dev/null
+++ b/media/libaudiohal/tests/Android.bp
@@ -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.
+
+// Headers module is in frameworks/av/Android.bp because modules are not allowed
+// to refer to headers in parent directories and the headers live in
+// frameworks/av/include.
+
+package {
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_test {
+ name: "EffectsFactoryHalInterfaceTest",
+ test_suites: ["device-tests"],
+
+ srcs: [
+ "EffectsFactoryHalInterface_test.cpp",
+ ],
+
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-Wthread-safety",
+ "-DBACKEND_NDK",
+ ],
+
+ shared_libs: [
+ "audioclient-types-aidl-cpp",
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudiohal",
+ "liblog",
+ "libutils",
+ ],
+
+ header_libs: [
+ "libaudiohal_headers",
+ ],
+}
diff --git a/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
new file mode 100644
index 0000000..b7742e4
--- /dev/null
+++ b/media/libaudiohal/tests/EffectsFactoryHalInterface_test.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#include <cstddef>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <utility>
+#define LOG_TAG "EffectsFactoryHalInterfaceTest"
+
+#include <aidl/android/media/audio/common/AudioUuid.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/audiohal/EffectsFactoryHalInterface.h>
+#include <system/audio_effects/audio_effects_utils.h>
+#include <system/audio_effects/effect_aec.h>
+#include <system/audio_effects/effect_agc2.h>
+#include <system/audio_effects/effect_bassboost.h>
+#include <system/audio_effects/effect_downmix.h>
+#include <system/audio_effects/effect_dynamicsprocessing.h>
+#include <system/audio_effect.h>
+
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+using effect::utils::EffectParamReader;
+using effect::utils::EffectParamWriter;
+using ::aidl::android::media::audio::common::AudioUuid;
+
+// EffectsFactoryHalInterface
+TEST(libAudioHalTest, createEffectsFactoryHalInterface) {
+ ASSERT_NE(nullptr, EffectsFactoryHalInterface::create());
+}
+
+TEST(libAudioHalTest, queryNumberEffects) {
+ auto factory = EffectsFactoryHalInterface::create();
+ ASSERT_NE(nullptr, factory);
+
+ uint32_t numEffects = 0;
+ EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+ EXPECT_NE(0ul, numEffects);
+}
+
+TEST(libAudioHalTest, getDescriptorByNumber) {
+ auto factory = EffectsFactoryHalInterface::create();
+ ASSERT_NE(nullptr, factory);
+
+ uint32_t numEffects = 0;
+ EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+ EXPECT_NE(0ul, numEffects);
+
+ effect_descriptor_t desc;
+ for (uint32_t i = 0; i < numEffects; i++) {
+ EXPECT_EQ(OK, factory->getDescriptor(i, &desc));
+ }
+}
+
+TEST(libAudioHalTest, createEffect) {
+ auto factory = EffectsFactoryHalInterface::create();
+ ASSERT_NE(nullptr, factory);
+
+ uint32_t numEffects = 0;
+ EXPECT_EQ(OK, factory->queryNumberEffects(&numEffects));
+ EXPECT_NE(0ul, numEffects);
+
+ effect_descriptor_t desc;
+ for (uint32_t i = 0; i < numEffects; i++) {
+ sp<EffectHalInterface> interface;
+ EXPECT_EQ(OK, factory->getDescriptor(i, &desc));
+ EXPECT_EQ(OK, factory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */,
+ 1 /* deviceId */, &interface));
+ }
+}
+
+TEST(libAudioHalTest, getHalVersion) {
+ auto factory = EffectsFactoryHalInterface::create();
+ ASSERT_NE(nullptr, factory);
+
+ auto version = factory->getHalVersion();
+ EXPECT_NE(0, version.getMajorVersion());
+}
+
+class EffectParamCombination {
+ public:
+ template <typename P, typename V>
+ void init(const P& p, const V& v, size_t len) {
+ setBuffer.resize(sizeof(effect_param_t) + sizeof(p) + sizeof(v) + 4);
+ getBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
+ expectBuffer.resize(sizeof(effect_param_t) + sizeof(p) + len + 4);
+ parameterSet =
+ std::make_shared<EffectParamReader>(createEffectParam(setBuffer.data(), p, v));
+ parameterGet =
+ std::make_shared<EffectParamReader>(createEffectParam(getBuffer.data(), p, v));
+ parameterExpect =
+ std::make_shared<EffectParamReader>(createEffectParam(expectBuffer.data(), p, v));
+ valueSize = len;
+ }
+
+ std::shared_ptr<EffectParamReader> parameterSet; /* setParameter */
+ std::shared_ptr<EffectParamReader> parameterGet; /* getParameter */
+ std::shared_ptr<EffectParamReader> parameterExpect; /* expected from getParameter */
+ size_t valueSize; /* ValueSize expect to write in reply data buffer */
+
+ private:
+ std::vector<uint8_t> setBuffer;
+ std::vector<uint8_t> getBuffer;
+ std::vector<uint8_t> expectBuffer;
+
+ template <typename P, typename V>
+ EffectParamReader createEffectParam(void* buf, const P& p, const V& v) {
+ effect_param_t* paramRet = (effect_param_t*)buf;
+ paramRet->psize = sizeof(P);
+ paramRet->vsize = sizeof(V);
+ EffectParamWriter writer(*paramRet);
+ EXPECT_EQ(OK, writer.writeToParameter(&p));
+ EXPECT_EQ(OK, writer.writeToValue(&v));
+ writer.finishValueWrite();
+ return writer;
+ }
+};
+
+template <typename P, typename V>
+std::shared_ptr<EffectParamCombination> createEffectParamCombination(const P& p, const V& v,
+ size_t len) {
+ auto comb = std::make_shared<EffectParamCombination>();
+ comb->init(p, v, len);
+ return comb;
+}
+
+enum ParamName { TUPLE_UUID, TUPLE_PARAM_COMBINATION };
+using EffectParamTestTuple =
+ std::tuple<const effect_uuid_t* /* type UUID */, std::shared_ptr<EffectParamCombination>>;
+
+std::vector<EffectParamTestTuple> testPairs = {
+ std::make_tuple(FX_IID_AEC,
+ createEffectParamCombination(AEC_PARAM_ECHO_DELAY, 0xff /* echoDelayMs */,
+ sizeof(int32_t) /* returnValueSize */)),
+ std::make_tuple(FX_IID_AGC2, createEffectParamCombination(
+ AGC2_PARAM_FIXED_DIGITAL_GAIN, 15 /* digitalGainDb */,
+ sizeof(int32_t) /* returnValueSize */)),
+ std::make_tuple(SL_IID_BASSBOOST,
+ createEffectParamCombination(BASSBOOST_PARAM_STRENGTH, 20 /* strength */,
+ sizeof(int32_t) /* returnValueSize */)),
+ std::make_tuple(EFFECT_UIID_DOWNMIX,
+ createEffectParamCombination(DOWNMIX_PARAM_TYPE, DOWNMIX_TYPE_FOLD,
+ sizeof(int32_t) /* returnValueSize */)),
+ std::make_tuple(SL_IID_DYNAMICSPROCESSING,
+ createEffectParamCombination(
+ std::array<uint32_t, 2>({DP_PARAM_INPUT_GAIN, 0 /* channel */}),
+ 30 /* gainDb */, sizeof(int32_t) /* returnValueSize */))};
+
+class libAudioHalEffectParamTest : public ::testing::TestWithParam<EffectParamTestTuple> {
+ public:
+ libAudioHalEffectParamTest()
+ : mParamTuple(GetParam()),
+ mFactory(EffectsFactoryHalInterface::create()),
+ mTypeUuid(std::get<TUPLE_UUID>(mParamTuple)),
+ mCombination(std::get<TUPLE_PARAM_COMBINATION>(mParamTuple)),
+ mExpectedValue([&]() {
+ std::vector<uint8_t> expectData(mCombination->valueSize);
+ mCombination->parameterExpect->readFromValue(expectData.data(),
+ mCombination->valueSize);
+ return expectData;
+ }()),
+ mDescs([&]() {
+ std::vector<effect_descriptor_t> descs;
+ if (mFactory && mTypeUuid && OK == mFactory->getDescriptors(mTypeUuid, &descs)) {
+ return descs;
+ }
+ return descs;
+ }()) {}
+
+ void SetUp() override {
+ for (const auto& desc : mDescs) {
+ sp<EffectHalInterface> interface = createEffectHal(desc);
+ ASSERT_NE(nullptr, interface);
+ mHalInterfaces.push_back(interface);
+ }
+ }
+
+ void initEffect(const sp<EffectHalInterface>& interface) {
+ uint32_t initReply = 0;
+ uint32_t initReplySize = sizeof(initReply);
+ ASSERT_EQ(OK, interface->command(EFFECT_CMD_INIT, 0, nullptr, &initReplySize, &initReply));
+ }
+
+ void TearDown() override {
+ for (auto& interface : mHalInterfaces) {
+ interface->close();
+ }
+ }
+
+ sp<EffectHalInterface> createEffectHal(const effect_descriptor_t& desc) {
+ sp<EffectHalInterface> interface = nullptr;
+ if (0 == std::memcmp(&desc.type, mTypeUuid, sizeof(effect_uuid_t)) &&
+ OK == mFactory->createEffect(&desc.uuid, 1 /* sessionId */, 1 /* ioId */,
+ 1 /* deviceId */, &interface)) {
+ return interface;
+ }
+ return nullptr;
+ }
+
+ void setAndGetParameter(const sp<EffectHalInterface>& interface) {
+ uint32_t replySize = sizeof(uint32_t);
+ uint8_t reply[replySize];
+ auto parameterSet = mCombination->parameterSet;
+ ASSERT_EQ(OK,
+ interface->command(EFFECT_CMD_SET_PARAM, (uint32_t)parameterSet->getTotalSize(),
+ const_cast<effect_param_t*>(¶meterSet->getEffectParam()),
+ &replySize, &reply))
+ << parameterSet->toString();
+ ASSERT_EQ(replySize, sizeof(uint32_t));
+
+ effect_param_t* getParam =
+ const_cast<effect_param_t*>(&mCombination->parameterGet->getEffectParam());
+ size_t maxReplySize = mCombination->valueSize + sizeof(effect_param_t) +
+ sizeof(parameterSet->getPaddedParameterSize());
+ replySize = maxReplySize;
+ EXPECT_EQ(OK,
+ interface->command(EFFECT_CMD_GET_PARAM, (uint32_t)parameterSet->getTotalSize(),
+ const_cast<effect_param_t*>(¶meterSet->getEffectParam()),
+ &replySize, getParam));
+ EffectParamReader parameterGet(*getParam);
+ EXPECT_EQ(replySize, parameterGet.getTotalSize()) << parameterGet.toString();
+ std::vector<uint8_t> response(mCombination->valueSize);
+ EXPECT_EQ(OK, parameterGet.readFromValue(response.data(), mCombination->valueSize))
+ << parameterGet.toString();
+ EXPECT_EQ(response, mExpectedValue);
+ }
+
+ const EffectParamTestTuple mParamTuple;
+ const sp<EffectsFactoryHalInterface> mFactory;
+ const effect_uuid_t* mTypeUuid;
+ std::shared_ptr<EffectParamCombination> mCombination;
+ const std::vector<uint8_t> mExpectedValue;
+ const std::vector<effect_descriptor_t> mDescs;
+ std::vector<sp<EffectHalInterface>> mHalInterfaces;
+};
+
+TEST_P(libAudioHalEffectParamTest, setAndGetParam) {
+ for (auto& interface : mHalInterfaces) {
+ EXPECT_NO_FATAL_FAILURE(initEffect(interface));
+ EXPECT_NO_FATAL_FAILURE(setAndGetParameter(interface));
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ libAudioHalEffectParamTest, libAudioHalEffectParamTest, ::testing::ValuesIn(testPairs),
+ [](const testing::TestParamInfo<libAudioHalEffectParamTest::ParamType>& info) {
+ AudioUuid uuid = ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(
+ *std::get<TUPLE_UUID>(info.param))
+ .value();
+ std::string name = "UUID_" + uuid.toString();
+ std::replace_if(
+ name.begin(), name.end(), [](const char c) { return !std::isalnum(c); }, '_');
+ return name;
+ });
+GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(libAudioHalEffectParamTest);
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
+
+// TODO: b/263986405 Add multi-thread testing
+
+} // namespace android
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index c2b82d1..6a39108 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -116,6 +116,9 @@
track->mKeepContractedChannels = false;
}
+ track->mInputFrameSize = audio_bytes_per_frame(
+ track->channelCount + track->mHapticChannelCount, track->mFormat);
+
// channel masks have changed, does this track need a downmixer?
// update to try using our desired format (if we aren't already using it)
const status_t status = track->prepareForDownmix();
@@ -309,9 +312,8 @@
ALOGV("AudioMixer::%s(%p) teeBuffer=%p", __func__, this, teeBuffer);
unprepareForTee();
if (teeBuffer != nullptr) {
- const size_t frameSize = audio_bytes_per_frame(channelCount + mHapticChannelCount, mFormat);
mTeeBufferProvider.reset(new TeeBufferProvider(
- frameSize, frameSize, kCopyBufferFrameCount,
+ mInputFrameSize, mInputFrameSize, kCopyBufferFrameCount,
(uint8_t*)teeBuffer, mTeeBufferFrameCount));
reconfigureBufferProviders();
}
@@ -590,6 +592,8 @@
t->mAdjustInChannelCount = t->channelCount + t->mHapticChannelCount;
t->mAdjustOutChannelCount = t->channelCount;
t->mKeepContractedChannels = false;
+ t->mInputFrameSize = audio_bytes_per_frame(
+ t->channelCount + t->mHapticChannelCount, t->mFormat);
// Check the downmixing (or upmixing) requirements.
status_t status = t->prepareForDownmix();
if (status != OK) {
@@ -641,6 +645,10 @@
}
break;
}
+ if (t->teeBuffer != nullptr && t->volumeRL == 0) {
+ // Need to mute tee
+ memset(t->teeBuffer, 0, t->mTeeBufferFrameCount * t->mInputFrameSize);
+ }
}
}
}
diff --git a/media/libaudioprocessing/AudioMixerBase.cpp b/media/libaudioprocessing/AudioMixerBase.cpp
index fd06991..427bd55 100644
--- a/media/libaudioprocessing/AudioMixerBase.cpp
+++ b/media/libaudioprocessing/AudioMixerBase.cpp
@@ -152,6 +152,7 @@
AUDIO_CHANNEL_REPRESENTATION_POSITION, AUDIO_CHANNEL_OUT_STEREO);
t->mMixerChannelCount = audio_channel_count_from_out_mask(t->mMixerChannelMask);
t->mTeeBufferFrameCount = 0;
+ t->mInputFrameSize = audio_bytes_per_frame(t->channelCount, t->mFormat);
status_t status = postCreateTrack(t.get());
if (status != OK) return status;
mTracks[name] = t;
@@ -178,6 +179,7 @@
track->channelCount = trackChannelCount;
track->mMixerChannelMask = mixerChannelMask;
track->mMixerChannelCount = mixerChannelCount;
+ track->mInputFrameSize = audio_bytes_per_frame(track->channelCount, track->mFormat);
// Resampler channels may have changed.
track->recreateResampler(mSampleRate);
diff --git a/media/libaudioprocessing/include/media/AudioMixerBase.h b/media/libaudioprocessing/include/media/AudioMixerBase.h
index caccb6a..4bd85d8 100644
--- a/media/libaudioprocessing/include/media/AudioMixerBase.h
+++ b/media/libaudioprocessing/include/media/AudioMixerBase.h
@@ -297,6 +297,8 @@
int32_t mTeeBufferFrameCount;
+ uint32_t mInputFrameSize; // The track input frame size, used for tee buffer
+
protected:
// hooks
diff --git a/media/libaudiousecasevalidation/Android.bp b/media/libaudiousecasevalidation/Android.bp
new file mode 100644
index 0000000..3ee7e32
--- /dev/null
+++ b/media/libaudiousecasevalidation/Android.bp
@@ -0,0 +1,49 @@
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+cc_library {
+ name: "libaudiousecasevalidation",
+ host_supported: true,
+ srcs: [
+ "UsecaseLookup.cpp",
+ "UsecaseValidator.cpp",
+ ],
+ header_libs: [
+ "liberror_headers",
+ ],
+ shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libaudioutils",
+ "libbase",
+ "liblog",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
+}
+
+cc_test_host {
+ name: "libaudiousecasevalidation-test",
+ srcs: [
+ "tests/UsecaseValidator-test.cpp",
+ ],
+ header_libs: [
+ "liberror_headers",
+ ],
+ shared_libs: [
+ "framework-permission-aidl-cpp",
+ "libaudiousecasevalidation",
+ "libutils",
+ ],
+}
diff --git a/media/libaudiousecasevalidation/UsecaseLookup.cpp b/media/libaudiousecasevalidation/UsecaseLookup.cpp
new file mode 100644
index 0000000..01e667f
--- /dev/null
+++ b/media/libaudiousecasevalidation/UsecaseLookup.cpp
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "UsecaseLookup"
+// #define LOG_NDEBUG 0
+
+#include "media/UsecaseLookup.h"
+
+#include <utils/Log.h>
+
+namespace android {
+namespace media {
+
+/**
+ * Add streamId and outputFlags to stream list.
+ */
+void UsecaseLookup::addStream(STREAMID streamId, bool outputFlagGame) {
+ ALOGV("%s streamId: %d outputFlagGame: %d", __func__, streamId, outputFlagGame);
+
+ mutex_lock lock(m_mutex);
+ m_streams[streamId] = outputFlagGame;
+}
+
+/**
+ * Remove streamId from stream list.
+ */
+void UsecaseLookup::removeStream(STREAMID streamId) {
+ ALOGV("%s streamId: %d ", __func__, streamId);
+
+ mutex_lock lock(m_mutex);
+ m_streams.erase(streamId);
+
+ // Shouldn't happen but it might.
+ for (auto it = m_tracks.begin(); it != m_tracks.end();) {
+ if (it->second == streamId) {
+ it = m_tracks.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+/**
+ * Add streamId and portId to track list.
+ */
+void UsecaseLookup::addTrack(STREAMID streamId, PORTID portId) {
+ ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);
+
+ mutex_lock lock(m_mutex);
+
+ if (m_tracks.find(portId) == m_tracks.end()) {
+ m_tracks[portId] = streamId;
+ }
+}
+
+/**
+ * Remove streamId and portId from track list.
+ */
+void UsecaseLookup::removeTrack(STREAMID streamId, PORTID portId) {
+ ALOGV("%s streamId: %d portId: %d", __func__, streamId, portId);
+
+ mutex_lock lock(m_mutex);
+ auto it = m_tracks.find(portId);
+
+ if (it != m_tracks.end() && it->second == streamId) {
+ m_tracks.erase(portId);
+ }
+}
+
+/**
+ * Check if stream list contains streamId with Game outputFlag.
+ */
+bool UsecaseLookup::isGameStream(STREAMID streamId) {
+ ALOGV("%s streamId: %d ", __func__, streamId);
+ mutex_lock lock(m_mutex);
+ auto it = m_streams.find(streamId);
+
+ return (it != m_streams.end()) ? it->second : false;
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/UsecaseValidator.cpp b/media/libaudiousecasevalidation/UsecaseValidator.cpp
new file mode 100644
index 0000000..0e5a824
--- /dev/null
+++ b/media/libaudiousecasevalidation/UsecaseValidator.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#define LOG_TAG "UsecaseValidator"
+// #define LOG_NDEBUG 0
+
+#include <inttypes.h>
+
+#include <utils/Log.h>
+
+#include "media/UsecaseValidator.h"
+#include "media/UsecaseLookup.h"
+
+namespace android {
+namespace media {
+namespace {
+
+class UsecaseValidatorImpl : public UsecaseValidator {
+ public:
+ UsecaseValidatorImpl() {}
+
+ /**
+ * Register a new mixer/stream.
+ * Called when the stream is opened at the HAL and communicates
+ * immutable stream attributes like flags, sampling rate, format.
+ */
+ status_t registerStream(audio_io_handle_t streamId,
+ const audio_config_base_t& audioConfig __attribute__((unused)),
+ const audio_output_flags_t outputFlags) override {
+ ALOGV("%s output: %d flags: %#x", __func__, streamId, outputFlags);
+
+ // Check if FAST or MMAP output flag has been set.
+ bool outputFlagGame = outputFlags & (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);
+ m_lookup.addStream(streamId, outputFlagGame);
+ return OK;
+ };
+
+ /**
+ * Unregister a stream/mixer.
+ * Called when the stream is closed.
+ */
+ status_t unregisterStream(audio_io_handle_t streamId) override {
+ ALOGV("%s output: %d", __func__, streamId);
+
+ m_lookup.removeStream(streamId);
+ return OK;
+ };
+
+ /**
+ * Indicates that some playback activity started on the stream.
+ * Called each time an audio track starts or resumes.
+ */
+ error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId, const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes,
+ const AttributesChangedCallback *callback __attribute__((unused))) override {
+ ALOGV("%s output: %d portId: %d usage: %d pid: %d package: %s",
+ __func__, streamId, portId, attributes.usage, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+
+ m_lookup.addTrack(streamId, portId);
+
+ return verifyAudioAttributes(streamId, attributionSource, attributes);
+ };
+
+ /**
+ * Indicates that some playback activity stopped on the stream.
+ * Called each time an audio track stops or pauses.
+ */
+ status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) override {
+ ALOGV("%s output: %d portId: %d", __func__, streamId, portId);
+
+ m_lookup.removeTrack(streamId, portId);
+ return OK;
+ };
+
+ /**
+ * Called to verify and update audio attributes for a track that is connected
+ * to the specified stream.
+ */
+ error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes) override {
+ ALOGV("%s output: %d usage: %d pid: %d package: %s",
+ __func__, streamId, attributes.usage, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+
+ audio_attributes_t attrRet = attributes;
+
+ // Check if attribute usage media or unknown has been set.
+ bool isUsageValid = this->isUsageValid(attributes);
+
+ if (isUsageValid && m_lookup.isGameStream(streamId)) {
+ ALOGI("%s update usage: %d to AUDIO_USAGE_GAME for output: %d pid: %d package: %s",
+ __func__, attributes.usage, streamId, attributionSource.pid,
+ attributionSource.packageName.value_or("").c_str());
+ // Set attribute usage Game.
+ attrRet.usage = AUDIO_USAGE_GAME;
+ }
+
+ return {attrRet};
+ };
+
+ protected:
+ /**
+ * Check if attribute usage valid.
+ */
+ bool isUsageValid(const audio_attributes_t& attr) {
+ ALOGV("isUsageValid attr.usage: %d", attr.usage);
+ switch (attr.usage) {
+ case AUDIO_USAGE_MEDIA:
+ case AUDIO_USAGE_UNKNOWN:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ protected:
+ UsecaseLookup m_lookup;
+};
+
+} // namespace
+
+std::unique_ptr<UsecaseValidator> createUsecaseValidator() {
+ return std::make_unique<UsecaseValidatorImpl>();
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/include/media/UsecaseLookup.h b/media/libaudiousecasevalidation/include/media/UsecaseLookup.h
new file mode 100644
index 0000000..a35d88d
--- /dev/null
+++ b/media/libaudiousecasevalidation/include/media/UsecaseLookup.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+namespace android {
+namespace media {
+
+typedef int STREAMID;
+typedef int PORTID;
+
+// List of streamId and outputFlag state.
+typedef std::map<STREAMID, bool> STREAMLIST;
+// List of portId and streamId.
+typedef std::map<PORTID, STREAMID> TRACKLIST;
+typedef std::lock_guard<std::mutex> mutex_lock;
+
+class UsecaseLookup {
+ public:
+ UsecaseLookup() { }
+ virtual ~UsecaseLookup() { }
+
+ // Required for testing.
+ void clear() {
+ m_streams.clear();
+ m_tracks.clear();
+ }
+
+ /**
+ * Add streamId and outputFlag to stream list.
+ */
+ void addStream(STREAMID streamId, bool outputFlagGame = false);
+
+ /**
+ * Remove streamId from stream list.
+ */
+ void removeStream(STREAMID streamId);
+
+ /**
+ * Add streamId and portId to track list.
+ */
+ void addTrack(STREAMID streamId, PORTID portId);
+
+ /**
+ * Remove streamId and portId from track list.
+ */
+ void removeTrack(STREAMID streamId, PORTID portId);
+
+ /**
+ * Check if stream list contains streamId with Game output flag.
+ */
+ bool isGameStream(STREAMID streamId);
+
+ protected:
+ STREAMLIST m_streams;
+ TRACKLIST m_tracks;
+ std::mutex m_mutex;
+};
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASELOOKUP_H_
diff --git a/media/libaudiousecasevalidation/include/media/UsecaseValidator.h b/media/libaudiousecasevalidation/include/media/UsecaseValidator.h
new file mode 100644
index 0000000..2e1d7f4
--- /dev/null
+++ b/media/libaudiousecasevalidation/include/media/UsecaseValidator.h
@@ -0,0 +1,97 @@
+/*
+ * 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.
+ */
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
+
+#pragma once
+
+#include <error/Result.h>
+#include <system/audio.h>
+#include <android/content/AttributionSourceState.h>
+
+#include <limits>
+#include <memory>
+
+namespace android {
+namespace media {
+
+/**
+ * Main entry-point for this library.
+ */
+class UsecaseValidator {
+ public:
+ virtual ~UsecaseValidator() = default;
+
+ /**
+ * A callback called by the module when the audio attributes for
+ * an active portId changes.
+ */
+ class AttributesChangedCallback {
+ public:
+ virtual ~AttributesChangedCallback() = default;
+ virtual void onAttributesChanged(audio_port_handle_t portId,
+ const audio_attributes_t& attributes) = 0;
+ };
+
+ /**
+ * Register a new mixer/stream.
+ * Called when the stream is opened at the HAL and communicates
+ * immutable stream attributes like flags, sampling rate, format.
+ */
+ virtual status_t registerStream(audio_io_handle_t streamId,
+ const audio_config_base_t& audioConfig,
+ const audio_output_flags_t outputFlags) = 0;
+
+ /**
+ * Unregister a stream/mixer.
+ * Called when the stream is closed.
+ */
+ virtual status_t unregisterStream(audio_io_handle_t streamId) = 0;
+
+ /**
+ * Indicates that some playback activity started on the stream.
+ * Called each time an audio track starts or resumes.
+ */
+ virtual error::Result<audio_attributes_t> startClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes,
+ const AttributesChangedCallback *callback) = 0;
+
+ /**
+ * Indicates that some playback activity stopped on the stream.
+ * Called each time an audio track stops or pauses.
+ */
+ virtual status_t stopClient(audio_io_handle_t streamId, audio_port_handle_t portId) = 0;
+
+ /**
+ * Called to verify and update audio attributes for a track that is connected
+ * to the specified stream.
+ */
+ virtual error::Result<audio_attributes_t> verifyAudioAttributes(audio_io_handle_t streamId,
+ const content::AttributionSourceState& attributionSource,
+ const audio_attributes_t& attributes) = 0;
+};
+
+/**
+ * Creates an instance featuring a default implementation of the UsecaseValidator interface.
+ */
+std::unique_ptr<UsecaseValidator> createUsecaseValidator();
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_INCLUDE_MEDIA_USECASEVALIDATOR_H_
diff --git a/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp
new file mode 100644
index 0000000..d92c8ba
--- /dev/null
+++ b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "tests/UsecaseValidator-test.h"
+
+#include <gtest/gtest.h>
+
+namespace android {
+namespace media {
+
+/**
+ * Helper test functions.
+ */
+
+/**
+ * Register a mock stream.
+ */
+audio_io_handle_t UsecaseValidatorTest::testRegisterStream(bool outputFlagGame) {
+ static int streamId = 0;
+ status_t result;
+ static audio_config_base_t audioConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ audio_output_flags_t outputFlags = outputFlagGame ? GAME_OUTPUT_FLAGS : MEDIA_OUTPUT_FLAGS;
+
+ result = m_validator->registerStream(++streamId, audioConfig, outputFlags);
+
+ return result == OK ? streamId : 0;
+}
+
+/**
+ * Create a mock portId.
+ */
+audio_port_handle_t UsecaseValidatorTest::testCreatePortId(audio_io_handle_t streamId) {
+ static int portId = 0;
+
+ return (streamId << 8) | (++portId);
+}
+
+/**
+ * Add a mock portId to a stream and verify.
+ */
+error::Result<audio_attributes_t> UsecaseValidatorTest::testStartClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ audio_usage_t usage) {
+ content::AttributionSourceState attributionSource;
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = usage;
+
+ return m_validator->startClient(streamId, portId, attributionSource, attributes, NULL);
+}
+
+/**
+ * Verify a mock stream.
+ */
+error::Result<audio_attributes_t> UsecaseValidatorTest::testVerifyAudioAttributes(
+ audio_io_handle_t streamId,
+ audio_usage_t usage) {
+ content::AttributionSourceState attributionSource;
+ audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
+ attributes.usage = usage;
+
+ return m_validator->verifyAudioAttributes(streamId, attributionSource, attributes);
+}
+
+/**
+ * Test functions.
+ */
+
+/**
+ * Test adding and removing streams.
+ */
+TEST_F(UsecaseLookupTest, testAddAndRemoveStream) {
+ addStream(1, false);
+ addStream(2, true);
+
+ EXPECT_NE(m_streams.find(1), m_streams.end());
+ EXPECT_NE(m_streams.find(2), m_streams.end());
+ EXPECT_EQ(m_streams.find(3), m_streams.end());
+
+ EXPECT_FALSE(isGameStream(1));
+ EXPECT_TRUE(isGameStream(2));
+ EXPECT_FALSE(isGameStream(3));
+
+ removeStream(2);
+
+ EXPECT_FALSE(isGameStream(2));
+}
+
+/**
+ * Verify attributes usage for stream.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsage) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(gameStreamId, 0);
+ EXPECT_NE(mediaStreamId, 0);
+ EXPECT_NE(gameStreamId, mediaStreamId);
+
+ // Verify attributes on game stream.
+ auto attr = testVerifyAudioAttributes(gameStreamId, AUDIO_USAGE_GAME);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ // Verify attributes on media stream.
+ attr = testVerifyAudioAttributes(mediaStreamId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_MEDIA);
+
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Test hanging client.
+ */
+TEST_F(UsecaseValidatorTest, testHangingClient) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+ audio_port_handle_t gamePortId, mediaPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(mediaStreamId, 0);
+
+ // Assign portId.
+ gamePortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(gamePortId, 0);
+ mediaPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(mediaPortId, 0);
+
+ // Start client on game stream.
+ testStartClient(gameStreamId, gamePortId, AUDIO_USAGE_GAME);
+
+ // Start client on media stream.
+ testStartClient(mediaStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+
+ // Unregister media stream before stopClient.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Verify attributes usage does not change.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsageUnchanged) {
+ audio_io_handle_t gameStreamId, mediaStreamId;
+ audio_port_handle_t gamePortId, mediaPortId, unknownPortId, voiceCommPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+ mediaStreamId = testRegisterStream(false);
+ EXPECT_NE(mediaStreamId, 0);
+
+ // Assign portId.
+ gamePortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(gamePortId, 0);
+ mediaPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(mediaPortId, 0);
+ unknownPortId = testCreatePortId(mediaStreamId);
+ EXPECT_NE(unknownPortId, 0);
+ voiceCommPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(voiceCommPortId, 0);
+
+ // Verify attributes on game stream.
+ auto attr = testStartClient(gameStreamId, gamePortId, AUDIO_USAGE_GAME);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ attr = testStartClient(gameStreamId, voiceCommPortId, AUDIO_USAGE_VOICE_COMMUNICATION);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_VOICE_COMMUNICATION);
+
+ // Verify attributes on media stream.
+ attr = testStartClient(mediaStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_MEDIA);
+
+ attr = testStartClient(mediaStreamId, unknownPortId, AUDIO_USAGE_UNKNOWN);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_UNKNOWN);
+
+ // Stop client on game and media stream.
+ EXPECT_EQ(m_validator->stopClient(gameStreamId, gamePortId), 0);
+ EXPECT_EQ(m_validator->stopClient(mediaStreamId, mediaPortId), 0);
+
+ // Unregister game and media stream.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+ EXPECT_EQ(m_validator->unregisterStream(mediaStreamId), 0);
+}
+
+/**
+ * Verify attributes usage changes.
+ */
+TEST_F(UsecaseValidatorTest, testAttributesUsageChanged) {
+ audio_io_handle_t gameStreamId;
+ audio_port_handle_t mediaPortId, unknownPortId;
+
+ // Register game and media stream.
+ gameStreamId = testRegisterStream(true);
+ EXPECT_NE(gameStreamId, 0);
+
+ // Assign portId.
+ mediaPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(mediaPortId, 0);
+ unknownPortId = testCreatePortId(gameStreamId);
+ EXPECT_NE(unknownPortId, 0);
+
+ // Verify attributes on game stream.
+ auto attr = testStartClient(gameStreamId, mediaPortId, AUDIO_USAGE_MEDIA);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ attr = testStartClient(gameStreamId, unknownPortId, AUDIO_USAGE_UNKNOWN);
+ EXPECT_EQ(attr.value().usage, AUDIO_USAGE_GAME);
+
+ // Unregister game stream.
+ EXPECT_EQ(m_validator->unregisterStream(gameStreamId), 0);
+}
+
+} // namespace media
+} // namespace android
diff --git a/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h
new file mode 100644
index 0000000..3159ab4
--- /dev/null
+++ b/media/libaudiousecasevalidation/tests/UsecaseValidator-test.h
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+#ifndef MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_
+#define MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_
+
+#include <gtest/gtest.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include "media/UsecaseLookup.h"
+#include "media/UsecaseValidator.h"
+
+namespace android {
+namespace media {
+
+#define MEDIA_OUTPUT_FLAGS (audio_output_flags_t)(0xFFFFF &\
+ ~(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ))
+
+#define GAME_OUTPUT_FLAGS (audio_output_flags_t)\
+ (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)
+
+class TestCallback : public UsecaseValidator::AttributesChangedCallback {
+ public:
+ TestCallback() {
+ m_iCallCnt = 0;
+ }
+ virtual ~TestCallback() { }
+ virtual void onAttributesChanged(audio_port_handle_t /*portId*/,
+ const audio_attributes_t& /*attributes*/) {
+ ++m_iCallCnt;
+ }
+
+ public:
+ int m_iCallCnt;
+};
+
+class UsecaseLookupTest : public UsecaseLookup, public ::testing::Test {
+ public:
+ UsecaseLookupTest() { }
+ virtual ~UsecaseLookupTest() = default;
+};
+
+class UsecaseValidatorTest : public ::testing::Test {
+ public:
+ UsecaseValidatorTest() {
+ m_validator = createUsecaseValidator();
+ }
+
+ virtual ~UsecaseValidatorTest() = default;
+
+ protected:
+ audio_io_handle_t testRegisterStream(bool outputFlagGame);
+ audio_port_handle_t testCreatePortId(audio_io_handle_t streamId);
+ error::Result<audio_attributes_t> testStartClient(audio_io_handle_t streamId,
+ audio_port_handle_t portId,
+ audio_usage_t usage);
+ error::Result<audio_attributes_t> testVerifyAudioAttributes(audio_io_handle_t streamId,
+ audio_usage_t usage);
+
+ std::unique_ptr<UsecaseValidator> m_validator;
+};
+
+} // namespace media
+} // namespace android
+
+#endif // MEDIA_LIBAUDIOUSECASEVALIDATION_TESTS_USECASEVALIDATOR_TEST_H_
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index abe622d..a5259aa 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -47,3 +47,30 @@
"libhardware_headers",
],
}
+
+cc_library_shared {
+ name: "libdownmixaidl",
+ srcs: [
+ "aidl/EffectDownmix.cpp",
+ "aidl/DownmixContext.cpp",
+ ":effectCommonFile",
+ ],
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers"
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "libcutils",
+ "liblog",
+ ],
+ relative_install_path: "soundfx",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/media/libeffects/downmix/aidl/DownmixContext.cpp b/media/libeffects/downmix/aidl/DownmixContext.cpp
new file mode 100644
index 0000000..43bfeed
--- /dev/null
+++ b/media/libeffects/downmix/aidl/DownmixContext.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_DownmixContext"
+
+#include <android-base/logging.h>
+
+#include "DownmixContext.h"
+
+using aidl::android::hardware::audio::effect::IEffect;
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::android::hardware::audio::common::getChannelCount;
+
+namespace aidl::android::hardware::audio::effect {
+
+DownmixContext::DownmixContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ mState = DOWNMIX_STATE_UNINITIALIZED;
+ init_params(common);
+}
+
+DownmixContext::~DownmixContext() {
+ LOG(DEBUG) << __func__;
+ mState = DOWNMIX_STATE_UNINITIALIZED;
+}
+
+RetCode DownmixContext::enable() {
+ LOG(DEBUG) << __func__;
+ if (mState != DOWNMIX_STATE_INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = DOWNMIX_STATE_ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode DownmixContext::disable() {
+ LOG(DEBUG) << __func__;
+ if (mState != DOWNMIX_STATE_ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = DOWNMIX_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+void DownmixContext::reset() {
+ LOG(DEBUG) << __func__;
+ disable();
+ resetBuffer();
+}
+
+IEffect::Status DownmixContext::lvmProcess(float* in, float* out, int samples) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
+ IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
+
+ if (in == nullptr || out == nullptr || getInputFrameSize() != getOutputFrameSize() ||
+ getInputFrameSize() == 0) {
+ return status;
+ }
+
+ status = {EX_ILLEGAL_STATE, 0, 0};
+ if (mState == DOWNMIX_STATE_UNINITIALIZED) {
+ LOG(ERROR) << __func__ << "Trying to use an uninitialized downmixer";
+ return status;
+ } else if (mState == DOWNMIX_STATE_INITIALIZED) {
+ LOG(ERROR) << __func__ << "Trying to use a non-configured downmixer";
+ return status;
+ }
+
+ LOG(DEBUG) << __func__ << " start processing";
+ bool accumulate = false;
+ int frames = samples * sizeof(float) / getInputFrameSize();
+ if (mType == Downmix::Type::STRIP) {
+ int inputChannelCount = getChannelCount(mChMask);
+ while (frames) {
+ if (accumulate) {
+ out[0] = std::clamp(out[0] + in[0], -1.f, 1.f);
+ out[1] = std::clamp(out[1] + in[1], -1.f, 1.f);
+ } else {
+ out[0] = in[0];
+ out[1] = in[1];
+ }
+ in += inputChannelCount;
+ out += 2;
+ frames--;
+ }
+ } else {
+ int chMask = mChMask.get<AudioChannelLayout::layoutMask>();
+ if (!mChannelMix.process(in, out, frames, accumulate, (audio_channel_mask_t)chMask)) {
+ LOG(ERROR) << "Multichannel configuration " << mChMask.toString()
+ << " is not supported";
+ return status;
+ }
+ }
+ LOG(DEBUG) << __func__ << " done processing";
+ return {STATUS_OK, samples, samples};
+}
+
+void DownmixContext::init_params(const Parameter::Common& common) {
+ // when configuring the effect, do not allow a blank or unsupported channel mask
+ AudioChannelLayout channelMask = common.input.base.channelMask;
+ if (isChannelMaskValid(channelMask)) {
+ LOG(ERROR) << "Downmix_Configure error: input channel mask " << channelMask.toString()
+ << " not supported";
+ } else {
+ mType = Downmix::Type::FOLD;
+ mChMask = channelMask;
+ mState = DOWNMIX_STATE_INITIALIZED;
+ }
+}
+
+bool DownmixContext::isChannelMaskValid(AudioChannelLayout channelMask) {
+ if (channelMask.getTag() == AudioChannelLayout::layoutMask) return false;
+ int chMask = channelMask.get<AudioChannelLayout::layoutMask>();
+ // check against unsupported channels (up to FCC_26)
+ constexpr uint32_t MAXIMUM_CHANNEL_MASK = AudioChannelLayout::LAYOUT_22POINT2 |
+ AudioChannelLayout::CHANNEL_FRONT_WIDE_LEFT |
+ AudioChannelLayout::CHANNEL_FRONT_WIDE_RIGHT;
+ if (chMask & ~MAXIMUM_CHANNEL_MASK) {
+ LOG(ERROR) << "Unsupported channels in " << (chMask & ~MAXIMUM_CHANNEL_MASK);
+ return false;
+ }
+ return true;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/downmix/aidl/DownmixContext.h b/media/libeffects/downmix/aidl/DownmixContext.h
new file mode 100644
index 0000000..9a9f2da
--- /dev/null
+++ b/media/libeffects/downmix/aidl/DownmixContext.h
@@ -0,0 +1,66 @@
+/*
+ * 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 "effect-impl/EffectContext.h"
+
+#include <audio_utils/ChannelMix.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+enum DownmixState {
+ DOWNMIX_STATE_UNINITIALIZED,
+ DOWNMIX_STATE_INITIALIZED,
+ DOWNMIX_STATE_ACTIVE,
+};
+
+class DownmixContext final : public EffectContext {
+ public:
+ DownmixContext(int statusDepth, const Parameter::Common& common);
+ ~DownmixContext();
+ RetCode enable();
+ RetCode disable();
+ void reset();
+
+ RetCode setDmType(Downmix::Type type) {
+ mType = type;
+ return RetCode::SUCCESS;
+ }
+ Downmix::Type getDmType() const { return mType; }
+
+ RetCode setOutputDevice(
+ const std::vector<::aidl::android::media::audio::common::AudioDeviceDescription>&
+ device) override {
+ // FIXME change type if playing on headset vs speaker
+ mOutputDevice = device;
+ return RetCode::SUCCESS;
+ }
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ DownmixState mState;
+ Downmix::Type mType;
+ ::aidl::android::media::audio::common::AudioChannelLayout mChMask;
+ ::android::audio_utils::channels::ChannelMix mChannelMix;
+
+ // Common Params
+ void init_params(const Parameter::Common& common);
+ bool isChannelMaskValid(::aidl::android::media::audio::common::AudioChannelLayout channelMask);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.cpp b/media/libeffects/downmix/aidl/EffectDownmix.cpp
new file mode 100644
index 0000000..17d0736
--- /dev/null
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_DownmixImpl"
+
+#include <android-base/logging.h>
+
+#include "EffectDownmix.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DownmixImpl;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDownmixImplUUID;
+using aidl::android::hardware::audio::effect::kDownmixTypeUUID;
+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 != kDownmixImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<DownmixImpl>();
+ 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 != kDownmixImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = DownmixImpl::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DownmixImpl::kEffectName = "Multichannel Downmix To Stereo";
+const Descriptor DownmixImpl::kDescriptor = {
+ .common = {
+ .id = {.type = kDownmixTypeUUID, .uuid = kDownmixImplUUID, .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
+ .name = DownmixImpl::kEffectName,
+ .implementor = "The Android Open Source Project"}};
+
+ndk::ScopedAStatus DownmixImpl::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixImpl::setParameterCommon(const Parameter& param) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto tag = param.getTag();
+ switch (tag) {
+ case Parameter::common:
+ RETURN_IF(mContext->setCommon(param.get<Parameter::common>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setCommFailed");
+ break;
+ case Parameter::deviceDescription:
+ RETURN_IF(mContext->setOutputDevice(param.get<Parameter::deviceDescription>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
+ break;
+ case Parameter::mode:
+ RETURN_IF(mContext->setAudioMode(param.get<Parameter::mode>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setModeFailed");
+ break;
+ case Parameter::source:
+ RETURN_IF(mContext->setAudioSource(param.get<Parameter::source>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setSourceFailed");
+ break;
+ case Parameter::volumeStereo:
+ RETURN_IF(mContext->setVolumeStereo(param.get<Parameter::volumeStereo>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setVolumeStereoFailed");
+ break;
+ default: {
+ LOG(ERROR) << __func__ << " unsupportedParameterTag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commonParamNotSupported");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixImpl::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->reset();
+ break;
+ default:
+ LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commandIdNotSupported");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DownmixImpl::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::downmix != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& dmParam = specific.get<Parameter::Specific::downmix>();
+ auto tag = dmParam.getTag();
+
+ switch (tag) {
+ case Downmix::type: {
+ RETURN_IF(mContext->setDmType(dmParam.get<Downmix::type>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setTypeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus DownmixImpl::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::downmixTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto dmId = id.get<Parameter::Id::downmixTag>();
+ auto dmIdTag = dmId.getTag();
+ switch (dmIdTag) {
+ case Downmix::Id::commonTag:
+ return getParameterDownmix(dmId.get<Downmix::Id::commonTag>(), specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(dmIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DownmixImpl::getParameterDownmix(const Downmix::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ Downmix dmParam;
+ switch (tag) {
+ case Downmix::type: {
+ dmParam.set<Downmix::type>(mContext->getDmType());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "DownmixTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::downmix>(dmParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> DownmixImpl::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+
+ mContext = std::make_shared<DownmixContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode DownmixImpl::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DownmixImpl::effectProcessImpl(float* in, float* out, int sampleToProcess) {
+ if (!mContext) {
+ LOG(ERROR) << __func__ << " nullContext";
+ return {EX_NULL_POINTER, 0, 0};
+ }
+ return mContext->lvmProcess(in, out, sampleToProcess);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/downmix/aidl/EffectDownmix.h b/media/libeffects/downmix/aidl/EffectDownmix.h
new file mode 100644
index 0000000..d590133
--- /dev/null
+++ b/media/libeffects/downmix/aidl/EffectDownmix.h
@@ -0,0 +1,55 @@
+/*
+ * 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 <audio_effects/effect_downmix.h>
+
+#include "DownmixContext.h"
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DownmixImpl final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Descriptor kDescriptor;
+ DownmixImpl() { LOG(DEBUG) << __func__; }
+ ~DownmixImpl() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus getDescriptor(Descriptor* _aidl_return) override;
+ ndk::ScopedAStatus setParameterCommon(const Parameter& param) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ std::shared_ptr<EffectContext> getContext() override { return mContext; }
+ std::string getEffectName() override { return kEffectName; }
+
+ private:
+ std::shared_ptr<DownmixContext> mContext;
+ ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 84131a4..736a086 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -32,34 +32,67 @@
],
}
+cc_defaults {
+ name : "dynamicsprocessingdefaults",
+ srcs: [
+ "dsp/DPBase.cpp",
+ "dsp/DPFrequency.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ "libeigen",
+ ],
+ cflags: [
+ "-Wthread-safety",
+ "-Wall",
+ "-Werror",
+ ],
+ relative_install_path: "soundfx",
+}
+
cc_library_shared {
name: "libdynproc",
vendor: true,
+ defaults: [
+ "dynamicsprocessingdefaults",
+ ],
+
srcs: [
"EffectDynamicsProcessing.cpp",
- "dsp/DPBase.cpp",
- "dsp/DPFrequency.cpp",
],
cflags: [
"-O2",
"-fvisibility=hidden",
+ ],
+}
- "-Wall",
- "-Werror",
+cc_library_shared {
+ name: "libdynamicsprocessingaidl",
+
+ srcs: [
+ "aidl/DynamicsProcessing.cpp",
+ "aidl/DynamicsProcessingContext.cpp",
+ ":effectCommonFile",
],
- shared_libs: [
- "libcutils",
- "liblog",
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "dynamicsprocessingdefaults",
],
- relative_install_path: "soundfx",
-
- header_libs: [
- "libaudioeffects",
- "libeigen",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
],
}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
new file mode 100644
index 0000000..203a27b
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -0,0 +1,313 @@
+/*
+ * 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 "AHAL_DynamicsProcessingLibEffects"
+
+#include <android-base/logging.h>
+
+#include "DynamicsProcessing.h"
+
+#include <dsp/DPBase.h>
+#include <dsp/DPFrequency.h>
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::DynamicsProcessingImpl;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kDynamicsProcessingImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+using aidl::android::media::audio::common::PcmType;
+
+extern "C" binder_exception_t createEffect(const AudioUuid* in_impl_uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (!in_impl_uuid || *in_impl_uuid != kDynamicsProcessingImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<DynamicsProcessingImpl>();
+ 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 != kDynamicsProcessingImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = DynamicsProcessingImpl::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
+const DynamicsProcessing::Capability DynamicsProcessingImpl::kCapability = {.minCutOffFreq = 220,
+ .maxCutOffFreq = 20000};
+const Descriptor DynamicsProcessingImpl::kDescriptor = {
+ .common = {.id = {.type = kDynamicsProcessingTypeUUID,
+ .uuid = kDynamicsProcessingImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::LAST,
+ .volume = Flags::Volume::CTRL},
+ .name = DynamicsProcessingImpl::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::dynamicsProcessing>(
+ DynamicsProcessingImpl::kCapability)};
+
+ndk::ScopedAStatus DynamicsProcessingImpl::open(const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ OpenEffectReturn* ret) {
+ LOG(DEBUG) << __func__;
+ // effect only support 32bits float
+ RETURN_IF(common.input.base.format.pcm != common.output.base.format.pcm ||
+ common.input.base.format.pcm != PcmType::FLOAT_32_BIT,
+ EX_ILLEGAL_ARGUMENT, "dataMustBe32BitsFloat");
+ RETURN_OK_IF(mState != State::INIT);
+ auto context = createContext(common);
+ RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+
+ RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
+ if (specific.has_value()) {
+ RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
+ } else {
+ Parameter::Specific defaultSpecific =
+ Parameter::Specific::make<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+ mContext->getEngineArchitecture()));
+ RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(defaultSpecific), "setDefaultEngineErr");
+ }
+
+ mState = State::IDLE;
+ context->dupeFmq(ret);
+ RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ "FailedToCreateWorker");
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::commandImpl(CommandId command) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ switch (command) {
+ case CommandId::START:
+ mContext->enable();
+ return ndk::ScopedAStatus::ok();
+ case CommandId::STOP:
+ mContext->disable();
+ return ndk::ScopedAStatus::ok();
+ case CommandId::RESET:
+ mContext->disable();
+ mContext->resetBuffer();
+ return ndk::ScopedAStatus::ok();
+ default:
+ // Need this default handling for vendor extendable CommandId::VENDOR_COMMAND_*
+ LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commandIdNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
+ const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
+ auto tag = param.getTag();
+
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ RETURN_IF(mContext->setEngineArchitecture(
+ param.get<DynamicsProcessing::engineArchitecture>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setEngineArchitectureFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEq: {
+ RETURN_IF(
+ mContext->setPreEq(param.get<DynamicsProcessing::preEq>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEq: {
+ RETURN_IF(mContext->setPostEq(param.get<DynamicsProcessing::postEq>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEqBand: {
+ RETURN_IF(mContext->setPreEqBand(param.get<DynamicsProcessing::preEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPreEqBandFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEqBand: {
+ RETURN_IF(mContext->setPostEqBand(param.get<DynamicsProcessing::postEqBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPostEqBandFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbc: {
+ RETURN_IF(mContext->setMbc(param.get<DynamicsProcessing::mbc>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbcBand: {
+ RETURN_IF(mContext->setMbcBand(param.get<DynamicsProcessing::mbcBand>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMbcBandFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::limiter: {
+ RETURN_IF(mContext->setLimiter(param.get<DynamicsProcessing::limiter>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setLimiterFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::inputGain: {
+ RETURN_IF(mContext->setInputGain(param.get<DynamicsProcessing::inputGain>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setInputGainFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::dynamicsProcessingTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto dpId = id.get<Parameter::Id::dynamicsProcessingTag>();
+ auto dpIdTag = dpId.getTag();
+ switch (dpIdTag) {
+ case DynamicsProcessing::Id::commonTag:
+ return getParameterDynamicsProcessing(dpId.get<DynamicsProcessing::Id::commonTag>(),
+ specific);
+ case DynamicsProcessing::Id::vendorExtensionTag:
+ LOG(ERROR) << __func__ << " unsupported ID: " << toString(dpIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DPVendorExtensionIdNotSupported");
+ }
+}
+
+ndk::ScopedAStatus DynamicsProcessingImpl::getParameterDynamicsProcessing(
+ const DynamicsProcessing::Tag& tag, Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ switch (tag) {
+ case DynamicsProcessing::engineArchitecture: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::engineArchitecture>(
+ mContext->getEngineArchitecture()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEq: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::preEq>(mContext->getPreEq()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEq: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::postEq>(mContext->getPostEq()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::preEqBand: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
+ mContext->getPreEqBand()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::postEqBand: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
+ mContext->getPostEqBand()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbc: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::mbc>(mContext->getMbc()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::mbcBand: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::mbcBand>(mContext->getMbcBand()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::limiter: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::limiter>(mContext->getLimiter()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::inputGain: {
+ specific->set<Parameter::Specific::dynamicsProcessing>(
+ DynamicsProcessing::make<DynamicsProcessing::inputGain>(
+ mContext->getInputGain()));
+ return ndk::ScopedAStatus::ok();
+ }
+ case DynamicsProcessing::vendorExtension: {
+ LOG(ERROR) << __func__ << " wrong vendor tag in CommonTag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "DPVendorExtensionTagInWrongId");
+ }
+ }
+}
+
+std::shared_ptr<EffectContext> DynamicsProcessingImpl::createContext(
+ const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+
+ mContext = std::make_shared<DynamicsProcessingContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode DynamicsProcessingImpl::releaseContext() {
+ if (mContext) {
+ mContext->disable();
+ mContext->resetBuffer();
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status DynamicsProcessingImpl::effectProcessImpl(float* in, float* out, int samples) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ return mContext->lvmProcess(in, out, samples);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
new file mode 100644
index 0000000..824ebea
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -0,0 +1,60 @@
+/*
+ * 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 "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+#include "DynamicsProcessingContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class DynamicsProcessingImpl final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Descriptor kDescriptor;
+ static const DynamicsProcessing::Capability kCapability;
+
+ DynamicsProcessingImpl() { LOG(DEBUG) << __func__; }
+ ~DynamicsProcessingImpl() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus open(const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ OpenEffectReturn* ret) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) 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;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ std::shared_ptr<EffectContext> getContext() override { return mContext; }
+ std::string getEffectName() override { return kEffectName; }
+
+ private:
+ std::shared_ptr<DynamicsProcessingContext> mContext;
+ ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
new file mode 100644
index 0000000..57a2be9
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -0,0 +1,580 @@
+/*
+ * 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 "AHAL_DPLibEffectsContext"
+
+#include "DynamicsProcessing.h"
+#include "DynamicsProcessingContext.h"
+
+#include <functional>
+#include <sys/param.h>
+#include <unordered_set>
+
+namespace aidl::android::hardware::audio::effect {
+
+DynamicsProcessingContext::DynamicsProcessingContext(int statusDepth,
+ const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ init();
+}
+
+DynamicsProcessingContext::~DynamicsProcessingContext() {
+ LOG(DEBUG) << __func__;
+}
+
+RetCode DynamicsProcessingContext::enable() {
+ std::lock_guard lg(mMutex);
+ if (mState != DYNAMICS_PROCESSING_STATE_INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = DYNAMICS_PROCESSING_STATE_ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingContext::disable() {
+ std::lock_guard lg(mMutex);
+ if (mState != DYNAMICS_PROCESSING_STATE_ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+void DynamicsProcessingContext::reset() {
+ std::lock_guard lg(mMutex);
+ if (mDpFreq != nullptr) {
+ mDpFreq.reset();
+ }
+}
+
+RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
+ mCommon = common;
+ init();
+ return RetCode::SUCCESS;
+}
+
+void DynamicsProcessingContext::dpSetFreqDomainVariant_l(
+ const DynamicsProcessing::EngineArchitecture& engine) {
+ mDpFreq.reset(new dp_fx::DPFrequency());
+ mDpFreq->init(mChannelCount, engine.preEqStage.inUse, engine.preEqStage.bandCount,
+ engine.mbcStage.inUse, engine.mbcStage.bandCount, engine.postEqStage.inUse,
+ engine.postEqStage.bandCount, engine.limiterInUse);
+
+ int32_t sampleRate = mCommon.input.base.sampleRate;
+ int32_t minBlockSize = (int32_t)dp_fx::DPFrequency::getMinBockSize();
+ int32_t block = engine.preferredProcessingDurationMs * sampleRate / 1000.0f;
+ LOG(INFO) << __func__ << " sampleRate " << sampleRate << " block length "
+ << engine.preferredProcessingDurationMs << " ms (" << block << "samples)";
+ if (block < minBlockSize) {
+ block = minBlockSize;
+ } else if (!powerof2(block)) {
+ //find next highest power of 2.
+ block = 1 << (32 - __builtin_clz(block));
+ }
+ mDpFreq->configure(block, block >> 1, sampleRate);
+}
+
+RetCode DynamicsProcessingContext::setEngineArchitecture(
+ const DynamicsProcessing::EngineArchitecture& engineArchitecture) {
+ RETURN_VALUE_IF(!validateEngineConfig(engineArchitecture), RetCode::ERROR_ILLEGAL_PARAMETER,
+ "illegalEngineConfig");
+
+ std::lock_guard lg(mMutex);
+ if (!mEngineInited || mEngineArchitecture != engineArchitecture) {
+ if (engineArchitecture.resolutionPreference ==
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION) {
+ dpSetFreqDomainVariant_l(engineArchitecture);
+ } else {
+ LOG(WARNING) << __func__ << toString(engineArchitecture.resolutionPreference)
+ << " not available now";
+ }
+ mEngineInited = true;
+ mEngineArchitecture = engineArchitecture;
+ }
+ LOG(INFO) << __func__ << engineArchitecture.toString();
+ return RetCode::SUCCESS;
+}
+
+RetCode DynamicsProcessingContext::setPreEq(
+ const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+ std::lock_guard lg(mMutex);
+ return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.preEqStage.inUse,
+ StageType::PREEQ);
+}
+
+RetCode DynamicsProcessingContext::setPostEq(
+ const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+ std::lock_guard lg(mMutex);
+ return setDpChannels_l<dp_fx::DPEq>(channels, mEngineArchitecture.postEqStage.inUse,
+ StageType::POSTEQ);
+}
+
+RetCode DynamicsProcessingContext::setMbc(
+ const std::vector<DynamicsProcessing::ChannelConfig>& channels) {
+ std::lock_guard lg(mMutex);
+ return setDpChannels_l<dp_fx::DPMbc>(channels, mEngineArchitecture.mbcStage.inUse,
+ StageType::MBC);
+}
+
+RetCode DynamicsProcessingContext::setPreEqBand(
+ const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "postEqNotInUse");
+ return setBands_l<DynamicsProcessing::EqBandConfig>(
+ bands, mEngineArchitecture.preEqStage.bandCount, StageType::PREEQ);
+}
+
+RetCode DynamicsProcessingContext::setPostEqBand(
+ const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "postEqNotInUse");
+ return setBands_l<DynamicsProcessing::EqBandConfig>(
+ bands, mEngineArchitecture.postEqStage.bandCount, StageType::POSTEQ);
+}
+
+RetCode DynamicsProcessingContext::setMbcBand(
+ const std::vector<DynamicsProcessing::MbcBandConfig>& bands) {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(!mEngineArchitecture.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "mbcNotInUse");
+ return setBands_l<DynamicsProcessing::MbcBandConfig>(
+ bands, mEngineArchitecture.preEqStage.bandCount, StageType::MBC);
+}
+
+RetCode DynamicsProcessingContext::setLimiter(
+ const std::vector<DynamicsProcessing::LimiterConfig>& limiters) {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(!mEngineArchitecture.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "limiterNotInUse");
+ return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, -1, StageType::LIMITER);
+}
+
+RetCode DynamicsProcessingContext::setInputGain(
+ const std::vector<DynamicsProcessing::InputGain>& inputGains) {
+ std::lock_guard lg(mMutex);
+ return setBands_l<DynamicsProcessing::InputGain>(inputGains, -1, StageType::INPUTGAIN);
+}
+
+DynamicsProcessing::EngineArchitecture DynamicsProcessingContext::getEngineArchitecture() {
+ std::lock_guard lg(mMutex);
+ LOG(INFO) << __func__ << mEngineArchitecture.toString();
+ return mEngineArchitecture;
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPreEq() {
+ return getChannelConfig(StageType::PREEQ);
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getPostEq() {
+ return getChannelConfig(StageType::POSTEQ);
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPreEqBand() {
+ return getEqBandConfigs(StageType::PREEQ);
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getPostEqBand() {
+ return getEqBandConfigs(StageType::POSTEQ);
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getMbc() {
+ return getChannelConfig(StageType::MBC);
+}
+
+std::vector<DynamicsProcessing::MbcBandConfig> DynamicsProcessingContext::getMbcBand() {
+ std::vector<DynamicsProcessing::MbcBandConfig> bands;
+
+ std::lock_guard lg(mMutex);
+ auto maxBand = mEngineArchitecture.mbcStage.bandCount;
+ for (int32_t ch = 0; ch < mChannelCount; ch++) {
+ auto mbc = getMbc_l(ch);
+ if (!mbc) {
+ continue;
+ }
+ for (int32_t bandId = 0; bandId < maxBand; bandId++) {
+ auto band = mbc->getBand(bandId);
+ if (!band) {
+ continue;
+ }
+ bands.push_back({.channel = ch,
+ .band = bandId,
+ .enable = band->isEnabled(),
+ .cutoffFrequencyHz = band->getCutoffFrequency(),
+ .attackTimeMs = band->getAttackTime(),
+ .releaseTimeMs = band->getReleaseTime(),
+ .ratio = band->getRatio(),
+ .thresholdDb = band->getThreshold(),
+ .kneeWidthDb = band->getKneeWidth(),
+ .noiseGateThresholdDb = band->getNoiseGateThreshold(),
+ .expanderRatio = band->getExpanderRatio(),
+ .preGainDb = band->getPreGain(),
+ .postGainDb = band->getPostGain()});
+ }
+ }
+ return bands;
+}
+
+std::vector<DynamicsProcessing::LimiterConfig> DynamicsProcessingContext::getLimiter() {
+ std::vector<DynamicsProcessing::LimiterConfig> ret;
+
+ std::lock_guard lg(mMutex);
+ for (int32_t ch = 0; ch < mChannelCount; ch++) {
+ auto limiter = getLimiter_l(ch);
+ if (!limiter) {
+ continue;
+ }
+ ret.push_back({.channel = ch,
+ .enable = limiter->isEnabled(),
+ .linkGroup = static_cast<int32_t>(limiter->getLinkGroup()),
+ .attackTimeMs = limiter->getAttackTime(),
+ .releaseTimeMs = limiter->getReleaseTime(),
+ .ratio = limiter->getRatio(),
+ .thresholdDb = limiter->getThreshold(),
+ .postGainDb = limiter->getPostGain()});
+ }
+ return ret;
+}
+
+std::vector<DynamicsProcessing::InputGain> DynamicsProcessingContext::getInputGain() {
+ std::vector<DynamicsProcessing::InputGain> ret;
+
+ std::lock_guard lg(mMutex);
+ for (int32_t ch = 0; ch < mChannelCount; ch++) {
+ auto channel = getChannel_l(ch);
+ if (!channel) {
+ continue;
+ }
+ ret.push_back({.channel = ch, .gainDb = channel->getInputGain()});
+ }
+ return ret;
+}
+
+IEffect::Status DynamicsProcessingContext::lvmProcess(float* in, float* out, int samples) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << 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};
+
+ LOG(DEBUG) << __func__ << " start processing";
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(mState != DynamicsProcessingState::DYNAMICS_PROCESSING_STATE_ACTIVE, status,
+ "notInActiveState");
+ RETURN_VALUE_IF(!mDpFreq, status, "engineNotInited");
+ mDpFreq->processSamples(in, out, samples);
+ }
+ return {STATUS_OK, samples, samples};
+}
+
+void DynamicsProcessingContext::init() {
+ std::lock_guard lg(mMutex);
+ mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ mChannelCount =
+ ::android::hardware::audio::common::getChannelCount(mCommon.input.base.channelMask);
+}
+
+dp_fx::DPChannel* DynamicsProcessingContext::getChannel_l(int channel) {
+ RETURN_VALUE_IF(mDpFreq == nullptr, nullptr, "DPFreqNotInited");
+
+ return mDpFreq->getChannel(channel);
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getPreEq_l(int ch) {
+ auto channel = getChannel_l(ch);
+ RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+ return channel->getPreEq();
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getPostEq_l(int ch) {
+ auto channel = getChannel_l(ch);
+ RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+ return channel->getPostEq();
+}
+
+dp_fx::DPMbc* DynamicsProcessingContext::getMbc_l(int ch) {
+ auto channel = getChannel_l(ch);
+ RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+ return channel->getMbc();
+}
+
+dp_fx::DPLimiter* DynamicsProcessingContext::getLimiter_l(int ch) {
+ auto channel = getChannel_l(ch);
+ RETURN_VALUE_IF(channel == nullptr, nullptr, "ChannelNotExist");
+
+ return channel->getLimiter();
+}
+
+dp_fx::DPBandStage* DynamicsProcessingContext::getStageWithType_l(
+ DynamicsProcessingContext::StageType type, int ch) {
+ switch (type) {
+ case StageType::PREEQ: {
+ return getEqWithType_l(type, ch);
+ }
+ case StageType::POSTEQ: {
+ return getEqWithType_l(type, ch);
+ }
+ case StageType::MBC: {
+ return getMbc_l(ch);
+ }
+ case StageType::LIMITER:
+ FALLTHROUGH_INTENDED;
+ case StageType::INPUTGAIN: {
+ return nullptr;
+ }
+ }
+}
+
+dp_fx::DPEq* DynamicsProcessingContext::getEqWithType_l(DynamicsProcessingContext::StageType type,
+ int ch) {
+ switch (type) {
+ case StageType::PREEQ: {
+ return getPreEq_l(ch);
+ }
+ case StageType::POSTEQ: {
+ return getPostEq_l(ch);
+ }
+ case StageType::MBC:
+ FALLTHROUGH_INTENDED;
+ case StageType::LIMITER:
+ FALLTHROUGH_INTENDED;
+ case StageType::INPUTGAIN: {
+ return nullptr;
+ }
+ }
+}
+
+std::vector<DynamicsProcessing::ChannelConfig> DynamicsProcessingContext::getChannelConfig(
+ StageType type) {
+ std::vector<DynamicsProcessing::ChannelConfig> ret;
+
+ std::lock_guard lg(mMutex);
+ for (int32_t ch = 0; ch < mChannelCount; ch++) {
+ auto stage = getStageWithType_l(type, ch);
+ if (!stage) {
+ continue;
+ }
+ ret.push_back({.channel = ch, .enable = stage->isEnabled()});
+ }
+ return ret;
+}
+
+std::vector<DynamicsProcessing::EqBandConfig> DynamicsProcessingContext::getEqBandConfigs(
+ StageType type) {
+ std::vector<DynamicsProcessing::EqBandConfig> eqBands;
+
+ std::lock_guard lg(mMutex);
+ auto maxBand = mEngineArchitecture.preEqStage.bandCount;
+ for (int32_t ch = 0; ch < mChannelCount; ch++) {
+ auto eq = getEqWithType_l(type, ch);
+ if (!eq) {
+ continue;
+ }
+ for (int32_t bandId = 0; bandId < maxBand; bandId++) {
+ auto band = eq->getBand(bandId);
+ if (!band) {
+ continue;
+ }
+ eqBands.push_back({.channel = ch,
+ .band = bandId,
+ .enable = band->isEnabled(),
+ .cutoffFrequencyHz = band->getCutoffFrequency(),
+ .gainDb = band->getGain()});
+ }
+ }
+ return eqBands;
+}
+
+/**
+ * When StageEnablement is in use, bandCount needs to be positive.
+ */
+bool DynamicsProcessingContext::validateStageEnablement(
+ const DynamicsProcessing::StageEnablement& enablement) {
+ return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
+}
+
+bool DynamicsProcessingContext::validateEngineConfig(
+ const DynamicsProcessing::EngineArchitecture& engine) {
+ return engine.preferredProcessingDurationMs >= 0 &&
+ validateStageEnablement(engine.preEqStage) &&
+ validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
+}
+
+inline bool DynamicsProcessingContext::validateCutoffFrequency(float freq) {
+ return freq >= DynamicsProcessingImpl::kCapability.minCutOffFreq &&
+ freq <= DynamicsProcessingImpl::kCapability.maxCutOffFreq;
+}
+
+bool DynamicsProcessingContext::validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band,
+ int maxChannel, int maxBand) {
+ return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
+ validateCutoffFrequency(band.cutoffFrequencyHz);
+}
+
+bool DynamicsProcessingContext::validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band,
+ int maxChannel, int maxBand) {
+ return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
+ validateCutoffFrequency(band.cutoffFrequencyHz) && validateTime(band.attackTimeMs) &&
+ validateTime(band.releaseTimeMs) && validateRatio(band.ratio) &&
+ validateBandDb(band.thresholdDb) && validateBandDb(band.kneeWidthDb) &&
+ validateBandDb(band.noiseGateThresholdDb) && validateRatio(band.expanderRatio);
+}
+
+bool DynamicsProcessingContext::validateLimiterConfig(
+ const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
+ return validateChannel(limiter.channel, maxChannel) && validateTime(limiter.attackTimeMs) &&
+ validateTime(limiter.releaseTimeMs) && validateRatio(limiter.ratio) &&
+ validateBandDb(limiter.thresholdDb);
+}
+
+bool DynamicsProcessingContext::validateInputGainConfig(const DynamicsProcessing::InputGain& gain,
+ int maxChannel) {
+ return validateChannel(gain.channel, maxChannel);
+}
+
+template <typename D>
+RetCode DynamicsProcessingContext::setDpChannels_l(
+ const std::vector<DynamicsProcessing::ChannelConfig>& channels, bool stageInUse,
+ StageType type) {
+ RetCode ret = RetCode::SUCCESS;
+ std::unordered_set<int> channelSet;
+
+ RETURN_VALUE_IF(!stageInUse, RetCode::ERROR_ILLEGAL_PARAMETER, "stageNotInUse");
+ for (auto& it : channels) {
+ if (0 != channelSet.count(it.channel)) {
+ LOG(WARNING) << __func__ << " duplicated channel " << it.channel;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ } else {
+ channelSet.insert(it.channel);
+ }
+ if (it.channel < 0 || it.channel >= mChannelCount) {
+ LOG(WARNING) << __func__ << " skip illegal ChannelConfig " << it.toString() << " max "
+ << mChannelCount;
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ auto dp = getStageWithType_l(type, it.channel);
+ if (!dp) {
+ LOG(WARNING) << __func__ << " channel " << it.channel << " not exist";
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ if (dp->isEnabled() != it.enable) {
+ LOG(INFO) << __func__ << it.toString();
+ dp->setEnabled(it.enable);
+ }
+ }
+ return ret;
+}
+
+RetCode DynamicsProcessingContext::setDpChannelBand_l(const std::any& anyConfig, StageType type,
+ int maxCh, int maxBand,
+ std::set<std::pair<int, int>>& chBandSet) {
+ RETURN_VALUE_IF(!anyConfig.has_value(), RetCode::ERROR_ILLEGAL_PARAMETER, "bandInvalid");
+ RetCode ret = RetCode::SUCCESS;
+ std::pair<int, int> chBandKey;
+ switch (type) {
+ case StageType::PREEQ:
+ FALLTHROUGH_INTENDED;
+ case StageType::POSTEQ: {
+ dp_fx::DPEq* dp;
+ const auto& config = std::any_cast<DynamicsProcessing::EqBandConfig>(anyConfig);
+ RETURN_VALUE_IF(!validateEqBandConfig(config, maxCh, maxBand),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
+ RETURN_VALUE_IF(
+ nullptr == (dp = getEqWithType_l(type, config.channel)) || !dp->isEnabled(),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "dpEqNotExist");
+ dp_fx::DPEqBand band;
+ band.init(config.enable, config.cutoffFrequencyHz, config.gainDb);
+ dp->setBand(config.band, band);
+ chBandKey = {config.channel, config.band};
+ break;
+ }
+ case StageType::MBC: {
+ dp_fx::DPMbc* dp;
+ const auto& config = std::any_cast<DynamicsProcessing::MbcBandConfig>(anyConfig);
+ RETURN_VALUE_IF(!validateMbcBandConfig(config, maxCh, maxBand),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "mbcBandNotValid");
+ RETURN_VALUE_IF(nullptr == (dp = getMbc_l(config.channel)) || !dp->isEnabled(),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "dpMbcNotExist");
+ dp_fx::DPMbcBand band;
+ band.init(config.enable, config.cutoffFrequencyHz, config.attackTimeMs,
+ config.releaseTimeMs, config.ratio, config.thresholdDb, config.kneeWidthDb,
+ config.noiseGateThresholdDb, config.expanderRatio, config.preGainDb,
+ config.postGainDb);
+ dp->setBand(config.band, band);
+ chBandKey = {config.channel, config.band};
+ break;
+ }
+ case StageType::LIMITER: {
+ dp_fx::DPChannel* dp;
+ const auto& config = std::any_cast<DynamicsProcessing::LimiterConfig>(anyConfig);
+ RETURN_VALUE_IF(!validateLimiterConfig(config, maxCh),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "limiterBandNotValid");
+ RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
+ dp_fx::DPLimiter limiter;
+ limiter.init(mEngineArchitecture.limiterInUse, config.enable, config.linkGroup,
+ config.attackTimeMs, config.releaseTimeMs, config.ratio,
+ config.thresholdDb, config.postGainDb);
+ dp->setLimiter(limiter);
+ chBandKey = {config.channel, 0};
+ break;
+ }
+ case StageType::INPUTGAIN: {
+ dp_fx::DPChannel* dp;
+ const auto& config = std::any_cast<DynamicsProcessing::InputGain>(anyConfig);
+ RETURN_VALUE_IF(!validateInputGainConfig(config, maxCh),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "inputGainNotValid");
+ RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
+ dp->setInputGain(config.gainDb);
+ chBandKey = {config.channel, 0};
+ break;
+ }
+ }
+ RETURN_VALUE_IF(0 != chBandSet.count(chBandKey), RetCode::ERROR_ILLEGAL_PARAMETER,
+ "duplicatedBand");
+ chBandSet.insert(chBandKey);
+ return ret;
+}
+
+template <typename T /* BandConfig */>
+RetCode DynamicsProcessingContext::setBands_l(
+ const std::vector<T>& bands, int maxBand, StageType type) {
+ RetCode ret = RetCode::SUCCESS;
+ std::set<std::pair<int /* channel */, int /* band */>> bandSet;
+
+ for (const auto& it : bands) {
+ if (RetCode::SUCCESS !=
+ setDpChannelBand_l(std::make_any<T>(it), type, mChannelCount, maxBand, bandSet)) {
+ LOG(WARNING) << __func__ << " skipping band " << it.toString();
+ ret = RetCode::ERROR_ILLEGAL_PARAMETER;
+ continue;
+ }
+ LOG(INFO) << __func__ << it.toString();
+ }
+ return ret;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
new file mode 100644
index 0000000..8be784e
--- /dev/null
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -0,0 +1,130 @@
+/*
+ * 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/thread_annotations.h>
+#include <audio_effects/effect_dynamicsprocessing.h>
+
+#include "effect-impl/EffectContext.h"
+
+#include <any>
+#include <cstddef>
+#include <dsp/DPBase.h>
+#include <dsp/DPFrequency.h>
+
+namespace aidl::android::hardware::audio::effect {
+
+enum DynamicsProcessingState {
+ DYNAMICS_PROCESSING_STATE_UNINITIALIZED,
+ DYNAMICS_PROCESSING_STATE_INITIALIZED,
+ DYNAMICS_PROCESSING_STATE_ACTIVE,
+};
+
+class DynamicsProcessingContext final : public EffectContext {
+ public:
+ DynamicsProcessingContext(int statusDepth, const Parameter::Common& common);
+ ~DynamicsProcessingContext();
+
+ RetCode enable();
+ RetCode disable();
+ void reset();
+
+ // override EffectContext::setCommon to update mChannelCount
+ RetCode setCommon(const Parameter::Common& common) override;
+
+ RetCode setEngineArchitecture(const DynamicsProcessing::EngineArchitecture& engineArchitecture);
+ RetCode setPreEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
+ RetCode setPostEq(const std::vector<DynamicsProcessing::ChannelConfig>& eqChannels);
+ RetCode setPreEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
+ RetCode setPostEqBand(const std::vector<DynamicsProcessing::EqBandConfig>& eqBands);
+ RetCode setMbc(const std::vector<DynamicsProcessing::ChannelConfig>& mbcChannels);
+ RetCode setMbcBand(const std::vector<DynamicsProcessing::MbcBandConfig>& eqBands);
+ RetCode setLimiter(const std::vector<DynamicsProcessing::LimiterConfig>& limiters);
+ RetCode setInputGain(const std::vector<DynamicsProcessing::InputGain>& gain);
+
+ DynamicsProcessing::EngineArchitecture getEngineArchitecture();
+ std::vector<DynamicsProcessing::ChannelConfig> getPreEq();
+ std::vector<DynamicsProcessing::ChannelConfig> getPostEq();
+ std::vector<DynamicsProcessing::EqBandConfig> getPreEqBand();
+ std::vector<DynamicsProcessing::EqBandConfig> getPostEqBand();
+ std::vector<DynamicsProcessing::ChannelConfig> getMbc();
+ std::vector<DynamicsProcessing::MbcBandConfig> getMbcBand();
+ std::vector<DynamicsProcessing::LimiterConfig> getLimiter();
+ std::vector<DynamicsProcessing::InputGain> getInputGain();
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ static constexpr float kPreferredProcessingDurationMs = 10.0f;
+ static constexpr int kBandCount = 5;
+ std::mutex mMutex;
+ size_t mChannelCount GUARDED_BY(mMutex) = 0;
+ DynamicsProcessingState mState GUARDED_BY(mMutex) = DYNAMICS_PROCESSING_STATE_UNINITIALIZED;
+ std::unique_ptr<dp_fx::DPFrequency> mDpFreq GUARDED_BY(mMutex) = nullptr;
+ bool mEngineInited GUARDED_BY(mMutex) = false;
+ DynamicsProcessing::EngineArchitecture mEngineArchitecture GUARDED_BY(mMutex) = {
+ .resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = kPreferredProcessingDurationMs,
+ .preEqStage = {.inUse = true, .bandCount = kBandCount},
+ .postEqStage = {.inUse = true, .bandCount = kBandCount},
+ .mbcStage = {.inUse = true, .bandCount = kBandCount},
+ .limiterInUse = true,
+ };
+
+ enum class StageType { PREEQ, POSTEQ, MBC, LIMITER, INPUTGAIN };
+
+ void init();
+
+ void dpSetFreqDomainVariant_l(const DynamicsProcessing::EngineArchitecture& engine)
+ REQUIRES(mMutex);
+ dp_fx::DPChannel* getChannel_l(int ch) REQUIRES(mMutex);
+ dp_fx::DPEq* getPreEq_l(int ch) REQUIRES(mMutex);
+ dp_fx::DPEq* getPostEq_l(int ch) REQUIRES(mMutex);
+ dp_fx::DPMbc* getMbc_l(int ch) REQUIRES(mMutex);
+ dp_fx::DPLimiter* getLimiter_l(int ch) REQUIRES(mMutex);
+ dp_fx::DPBandStage* getStageWithType_l(StageType type, int ch) REQUIRES(mMutex);
+ dp_fx::DPEq* getEqWithType_l(StageType type, int ch) REQUIRES(mMutex);
+ template <typename D>
+ RetCode setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig>& channels,
+ bool stageInUse, StageType type) REQUIRES(mMutex);
+ template <typename T /* BandConfig */>
+ RetCode setBands_l(const std::vector<T>& bands, int maxBand, StageType type) REQUIRES(mMutex);
+ RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type, int maxCh, int maxBand,
+ std::set<std::pair<int, int>>& chBandSet) REQUIRES(mMutex);
+
+ std::vector<DynamicsProcessing::EqBandConfig> getEqBandConfigs(StageType type);
+ std::vector<DynamicsProcessing::ChannelConfig> getChannelConfig(StageType type);
+
+ bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
+ bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
+ bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
+ int maxBand);
+ bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
+ int maxBand);
+ bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
+ bool validateInputGainConfig(const DynamicsProcessing::InputGain& gain, int maxChannel);
+
+ inline bool validateCutoffFrequency(float freq);
+ inline bool validateChannel(int ch, int maxCh) { return ch >= 0 && ch < maxCh; }
+ inline bool validateBand(int band, int maxBand) { return band >= 0 && band < maxBand; }
+ inline bool validateTime(int time) { return time >= 0; }
+ inline bool validateRatio(int ratio) { return ratio >= 0; }
+ inline bool validateBandDb(int db) { return db <= 0; }
+};
+
+} // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index ba511fe..fc80211 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -22,6 +22,24 @@
default_applicable_licenses: ["frameworks_av_license"],
}
+cc_defaults {
+ name : "hapticgeneratordefaults",
+ srcs: [
+ "Processors.cpp",
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "libbase",
+ "liblog",
+ "libutils",
+ "libvibratorutils",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ ],
+ relative_install_path: "soundfx",
+}
+
cc_library_shared {
name: "libhapticgenerator",
@@ -29,7 +47,10 @@
srcs: [
"EffectHapticGenerator.cpp",
- "Processors.cpp",
+ ],
+
+ defaults: [
+ "hapticgeneratordefaults",
],
cflags: [
@@ -42,18 +63,29 @@
// with/without `-ffast-math` for more context.
"-fvisibility=hidden",
],
+}
- shared_libs: [
- "libaudioutils",
- "libbase",
- "liblog",
- "libutils",
- "libvibratorutils",
+cc_library_shared {
+ name: "libhapticgeneratoraidl",
+
+ srcs: [
+ "aidl/EffectHapticGenerator.cpp",
+ "aidl/HapticGeneratorContext.cpp",
+ ":effectCommonFile",
],
- relative_install_path: "soundfx",
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "hapticgeneratordefaults",
+ ],
- header_libs: [
- "libaudioeffects",
+ cflags: [
+ "-Wthread-safety",
+ ],
+
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
],
}
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
new file mode 100644
index 0000000..7e22482
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_HapticGeneratorImpl"
+
+#include "EffectHapticGenerator.h"
+
+#include <android-base/logging.h>
+#include <audio_effects/effect_hapticgenerator.h>
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::HapticGeneratorImpl;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kHapticGeneratorImplUUID;
+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 != kHapticGeneratorImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<HapticGeneratorImpl>();
+ 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 != kHapticGeneratorImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = HapticGeneratorImpl::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string HapticGeneratorImpl::kEffectName = "Haptic Generator";
+const Descriptor HapticGeneratorImpl::kDescriptor = {
+ .common = {.id = {.type = kHapticGeneratorTypeUUID,
+ .uuid = kHapticGeneratorImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
+ .name = HapticGeneratorImpl::kEffectName,
+ .implementor = "The Android Open Source Project"}};
+
+ndk::ScopedAStatus HapticGeneratorImpl::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::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->reset();
+ break;
+ default:
+ LOG(ERROR) << __func__ << " commandId " << toString(command) << " not supported";
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "commandIdNotSupported");
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::hapticGenerator != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+ auto tag = hgParam.getTag();
+
+ switch (tag) {
+ case HapticGenerator::hapticScales: {
+ RETURN_IF(mContext->setHgHapticScales(hgParam.get<HapticGenerator::hapticScales>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setHapticScaleFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case HapticGenerator::vibratorInfo: {
+ RETURN_IF(mContext->setHgVibratorInformation(
+ hgParam.get<HapticGenerator::vibratorInfo>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setVibratorInfoFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::hapticGeneratorTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto hgId = id.get<Parameter::Id::hapticGeneratorTag>();
+ auto hgIdTag = hgId.getTag();
+ switch (hgIdTag) {
+ case HapticGenerator::Id::commonTag:
+ return getParameterHapticGenerator(hgId.get<HapticGenerator::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(hgIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus HapticGeneratorImpl::getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ HapticGenerator hgParam;
+ switch (tag) {
+ case HapticGenerator::hapticScales: {
+ hgParam.set<HapticGenerator::hapticScales>(mContext->getHgHapticScales());
+ break;
+ }
+ case HapticGenerator::vibratorInfo: {
+ hgParam.set<HapticGenerator::vibratorInfo>(mContext->getHgVibratorInformation());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "HapticGeneratorTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::hapticGenerator>(hgParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> HapticGeneratorImpl::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+
+ mContext = std::make_shared<HapticGeneratorContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode HapticGeneratorImpl::releaseContext() {
+ if (mContext) {
+ mContext->reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status HapticGeneratorImpl::effectProcessImpl(float* in, float* out, int samples) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ return mContext->lvmProcess(in, out, samples);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
new file mode 100644
index 0000000..02ca392
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -0,0 +1,55 @@
+/*
+ * 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 "HapticGeneratorContext.h"
+#include "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class HapticGeneratorImpl final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Descriptor kDescriptor;
+ HapticGeneratorImpl() { LOG(DEBUG) << __func__; }
+ ~HapticGeneratorImpl() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus commandImpl(CommandId command) 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;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ std::shared_ptr<EffectContext> getContext() override { return mContext; }
+ std::string getEffectName() override { return kEffectName; }
+
+ private:
+ std::shared_ptr<HapticGeneratorContext> mContext;
+ ndk::ScopedAStatus getParameterHapticGenerator(const HapticGenerator::Tag& tag,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
new file mode 100644
index 0000000..8ed579b
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_HapticGeneratorContext"
+
+#include <Utils.h>
+#include <android-base/parsedouble.h>
+#include <android-base/properties.h>
+
+#include "HapticGeneratorContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+HapticGeneratorContext::HapticGeneratorContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ mState = HAPTIC_GENERATOR_STATE_UNINITIALIZED;
+ mSampleRate = common.input.base.sampleRate;
+ mFrameCount = common.input.frameCount;
+ init_params(common.input.base.channelMask, common.output.base.channelMask);
+}
+
+HapticGeneratorContext::~HapticGeneratorContext() {
+ LOG(DEBUG) << __func__;
+ mState = HAPTIC_GENERATOR_STATE_UNINITIALIZED;
+}
+
+RetCode HapticGeneratorContext::enable() {
+ if (mState != HAPTIC_GENERATOR_STATE_INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = HAPTIC_GENERATOR_STATE_ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode HapticGeneratorContext::disable() {
+ if (mState != HAPTIC_GENERATOR_STATE_ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = HAPTIC_GENERATOR_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+void HapticGeneratorContext::reset() {
+ for (auto& filter : mProcessorsRecord.filters) {
+ filter->clear();
+ }
+ for (auto& slowEnv : mProcessorsRecord.slowEnvs) {
+ slowEnv->clear();
+ }
+ for (auto& distortion : mProcessorsRecord.distortions) {
+ distortion->clear();
+ }
+}
+
+RetCode HapticGeneratorContext::setHgHapticScales(
+ const std::vector<HapticGenerator::HapticScale>& hapticScales) {
+ std::lock_guard lg(mMutex);
+ for (auto hapticScale : hapticScales) {
+ mParams.mHapticScales.insert_or_assign(hapticScale.id, hapticScale.scale);
+ }
+ mParams.mMaxVibratorScale = HapticGenerator::VibratorScale::MUTE;
+ for (const auto& [id, vibratorScale] : mParams.mHapticScales) {
+ mParams.mMaxVibratorScale = std::max(mParams.mMaxVibratorScale, vibratorScale);
+ }
+ return RetCode::SUCCESS;
+}
+
+HapticGenerator::VibratorInformation HapticGeneratorContext::getHgVibratorInformation() {
+ std::lock_guard lg(mMutex);
+ return mParams.mVibratorInfo;
+}
+
+std::vector<HapticGenerator::HapticScale> HapticGeneratorContext::getHgHapticScales() {
+ std::vector<HapticGenerator::HapticScale> result;
+ std::lock_guard lg(mMutex);
+ for (const auto& [id, vibratorScale] : mParams.mHapticScales) {
+ result.push_back({id, vibratorScale});
+ }
+ return result;
+}
+
+RetCode HapticGeneratorContext::setHgVibratorInformation(
+ const HapticGenerator::VibratorInformation& vibratorInfo) {
+ {
+ std::lock_guard lg(mMutex);
+ mParams.mVibratorInfo = vibratorInfo;
+
+ if (mProcessorsRecord.bpf != nullptr) {
+ mProcessorsRecord.bpf->setCoefficients(
+ ::android::audio_effect::haptic_generator::bpfCoefs(
+ mParams.mVibratorInfo.resonantFrequencyHz, DEFAULT_BPF_Q, mSampleRate));
+ }
+ if (mProcessorsRecord.bsf != nullptr) {
+ mProcessorsRecord.bsf->setCoefficients(
+ ::android::audio_effect::haptic_generator::bsfCoefs(
+ mParams.mVibratorInfo.resonantFrequencyHz,
+ mParams.mVibratorInfo.qFactor, mParams.mVibratorInfo.qFactor / 2.0f,
+ mSampleRate));
+ }
+ }
+ configure();
+ return RetCode::SUCCESS;
+}
+
+IEffect::Status HapticGeneratorContext::lvmProcess(float* in, float* out, int samples) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << 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};
+ RETURN_VALUE_IF(getInputFrameSize() != getOutputFrameSize(), status, "FrameSizeMismatch");
+ auto frameSize = getInputFrameSize();
+ RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize");
+
+ LOG(DEBUG) << __func__ << " start processing";
+ // The audio data must not be modified but just written to
+ // output buffer according the access mode.
+ bool accumulate = false;
+ if (in != out) {
+ for (int i = 0; i < samples; i++) {
+ if (accumulate) {
+ out[i] += in[i];
+ } else {
+ out[i] = in[i];
+ }
+ }
+ }
+
+ if (mState != HAPTIC_GENERATOR_STATE_ACTIVE) {
+ return status;
+ }
+
+ std::lock_guard lg(mMutex);
+ if (mParams.mMaxVibratorScale == HapticGenerator::VibratorScale::MUTE) {
+ // Haptic channels are muted, not need to generate haptic data.
+ return {STATUS_OK, samples, samples};
+ }
+
+ // Resize buffer if the haptic sample count is greater than buffer size.
+ size_t hapticSampleCount = mFrameCount * mParams.mHapticChannelCount;
+ if (hapticSampleCount > mInputBuffer.size()) {
+ // The inputBuffer and outputBuffer must have the same size, which must be at least
+ // the haptic sample count.
+ mInputBuffer.resize(hapticSampleCount);
+ mOutputBuffer.resize(hapticSampleCount);
+ }
+
+ // Construct input buffer according to haptic channel source
+ for (size_t i = 0; i < mFrameCount; ++i) {
+ for (size_t j = 0; j < mParams.mHapticChannelCount; ++j) {
+ mInputBuffer[i * mParams.mHapticChannelCount + j] =
+ in[i * mParams.mAudioChannelCount + mParams.mHapticChannelSource[j]];
+ }
+ }
+
+ float* hapticOutBuffer =
+ runProcessingChain(mInputBuffer.data(), mOutputBuffer.data(), mFrameCount);
+ ::android::os::scaleHapticData(
+ hapticOutBuffer, hapticSampleCount,
+ static_cast<::android::os::HapticScale>(mParams.mMaxVibratorScale),
+ mParams.mVibratorInfo.qFactor);
+
+ // For haptic data, the haptic playback thread will copy the data from effect input
+ // buffer, which contains haptic data at the end of the buffer, directly to sink buffer.
+ // In that case, copy haptic data to input buffer instead of output buffer.
+ // Note: this may not work with rpc/binder calls
+ int offset = samples;
+ for (int i = 0; i < hapticSampleCount; ++i) {
+ in[samples + i] = hapticOutBuffer[i];
+ }
+ return {STATUS_OK, samples, static_cast<int32_t>(samples + hapticSampleCount)};
+}
+
+void HapticGeneratorContext::init_params(media::audio::common::AudioChannelLayout inputChMask,
+ media::audio::common::AudioChannelLayout outputChMask) {
+ std::lock_guard lg(mMutex);
+ mParams.mMaxVibratorScale = HapticGenerator::VibratorScale::MUTE;
+ mParams.mVibratorInfo.resonantFrequencyHz = DEFAULT_RESONANT_FREQUENCY;
+ mParams.mVibratorInfo.qFactor = DEFAULT_BSF_ZERO_Q;
+
+ mParams.mAudioChannelCount = ::android::hardware::audio::common::getChannelCount(
+ inputChMask, ~media::audio::common::AudioChannelLayout::LAYOUT_HAPTIC_AB);
+ mParams.mHapticChannelCount = ::android::hardware::audio::common::getChannelCount(
+ outputChMask, media::audio::common::AudioChannelLayout::LAYOUT_HAPTIC_AB);
+ LOG_ALWAYS_FATAL_IF(mParams.mHapticChannelCount > 2, "haptic channel count is too large");
+ for (size_t i = 0; i < mParams.mHapticChannelCount; ++i) {
+ // By default, use the first audio channel to generate haptic channels.
+ mParams.mHapticChannelSource[i] = 0;
+ }
+
+ mState = HAPTIC_GENERATOR_STATE_INITIALIZED;
+}
+
+float HapticGeneratorContext::getDistortionOutputGain() {
+ float distortionOutputGain = getFloatProperty(
+ "vendor.audio.hapticgenerator.distortion.output.gain", DEFAULT_DISTORTION_OUTPUT_GAIN);
+ LOG(DEBUG) << "Using distortion output gain as " << distortionOutputGain;
+ return distortionOutputGain;
+}
+
+float HapticGeneratorContext::getFloatProperty(const std::string& key, float defaultValue) {
+ float result;
+ std::string value = ::android::base::GetProperty(key, "");
+ if (!value.empty() && ::android::base::ParseFloat(value, &result)) {
+ return result;
+ }
+ return defaultValue;
+}
+
+void HapticGeneratorContext::addBiquadFilter(std::shared_ptr<HapticBiquadFilter> filter) {
+ // The process chain captures the shared pointer of the filter in lambda.
+ // The process record will keep a shared pointer to the filter so that it is possible to
+ // access the filter outside of the process chain.
+ mProcessorsRecord.filters.push_back(filter);
+ mProcessingChain.push_back([filter](float* out, const float* in, size_t frameCount) {
+ filter->process(out, in, frameCount);
+ });
+}
+
+/**
+ * Build haptic generator processing chain.
+ */
+void HapticGeneratorContext::buildProcessingChain() {
+ std::lock_guard lg(mMutex);
+ const size_t channelCount = mParams.mHapticChannelCount;
+ float highPassCornerFrequency = 50.0f;
+ auto hpf = ::android::audio_effect::haptic_generator::createHPF2(highPassCornerFrequency,
+ mSampleRate, channelCount);
+ addBiquadFilter(hpf);
+ float lowPassCornerFrequency = 9000.0f;
+ auto lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency,
+ mSampleRate, channelCount);
+ addBiquadFilter(lpf);
+
+ auto ramp = std::make_shared<::android::audio_effect::haptic_generator::Ramp>(
+ channelCount); // ramp = half-wave rectifier.
+ // The process chain captures the shared pointer of the ramp in lambda. It will be the only
+ // reference to the ramp.
+ // The process record will keep a weak pointer to the ramp so that it is possible to access
+ // the ramp outside of the process chain.
+ mProcessorsRecord.ramps.push_back(ramp);
+ mProcessingChain.push_back([ramp](float* out, const float* in, size_t frameCount) {
+ ramp->process(out, in, frameCount);
+ });
+
+ highPassCornerFrequency = 60.0f;
+ hpf = ::android::audio_effect::haptic_generator::createHPF2(highPassCornerFrequency,
+ mSampleRate, channelCount);
+ addBiquadFilter(hpf);
+ lowPassCornerFrequency = 700.0f;
+ lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+ channelCount);
+ addBiquadFilter(lpf);
+
+ lowPassCornerFrequency = 400.0f;
+ lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+ channelCount);
+ addBiquadFilter(lpf);
+ lowPassCornerFrequency = 500.0f;
+ lpf = ::android::audio_effect::haptic_generator::createLPF2(lowPassCornerFrequency, mSampleRate,
+ channelCount);
+ addBiquadFilter(lpf);
+
+ auto bpf = ::android::audio_effect::haptic_generator::createBPF(
+ mParams.mVibratorInfo.resonantFrequencyHz, DEFAULT_BPF_Q, mSampleRate, channelCount);
+ mProcessorsRecord.bpf = bpf;
+ addBiquadFilter(bpf);
+
+ float normalizationPower = DEFAULT_SLOW_ENV_NORMALIZATION_POWER;
+ // The process chain captures the shared pointer of the slow envelope in lambda. It will
+ // be the only reference to the slow envelope.
+ // The process record will keep a weak pointer to the slow envelope so that it is possible
+ // to access the slow envelope outside of the process chain.
+ // SlowEnvelope = partial normalizer, or AGC.
+ auto slowEnv = std::make_shared<::android::audio_effect::haptic_generator::SlowEnvelope>(
+ 5.0f /*envCornerFrequency*/, mSampleRate, normalizationPower, 0.01f /*envOffset*/,
+ channelCount);
+ mProcessorsRecord.slowEnvs.push_back(slowEnv);
+ mProcessingChain.push_back([slowEnv](float* out, const float* in, size_t frameCount) {
+ slowEnv->process(out, in, frameCount);
+ });
+
+ auto bsf = ::android::audio_effect::haptic_generator::createBSF(
+ mParams.mVibratorInfo.resonantFrequencyHz, mParams.mVibratorInfo.qFactor,
+ mParams.mVibratorInfo.qFactor / 2.0f, mSampleRate, channelCount);
+ mProcessorsRecord.bsf = bsf;
+ addBiquadFilter(bsf);
+
+ // The process chain captures the shared pointer of the Distortion in lambda. It will
+ // be the only reference to the Distortion.
+ // The process record will keep a weak pointer to the Distortion so that it is possible
+ // to access the Distortion outside of the process chain.
+ auto distortion = std::make_shared<::android::audio_effect::haptic_generator::Distortion>(
+ DEFAULT_DISTORTION_CORNER_FREQUENCY, mSampleRate, DEFAULT_DISTORTION_INPUT_GAIN,
+ DEFAULT_DISTORTION_CUBE_THRESHOLD, getDistortionOutputGain(), channelCount);
+ mProcessorsRecord.distortions.push_back(distortion);
+ mProcessingChain.push_back([distortion](float* out, const float* in, size_t frameCount) {
+ distortion->process(out, in, frameCount);
+ });
+}
+
+void HapticGeneratorContext::configure() {
+ mProcessingChain.clear();
+ mProcessorsRecord.filters.clear();
+ mProcessorsRecord.ramps.clear();
+ mProcessorsRecord.slowEnvs.clear();
+ mProcessorsRecord.distortions.clear();
+
+ buildProcessingChain();
+}
+
+/**
+ * Run the processing chain to generate haptic data from audio data
+ *
+ * @param buf1 a buffer contains raw audio data
+ * @param buf2 a buffer that is large enough to keep all the data
+ * @param frameCount frame count of the data
+ *
+ * @return a pointer to the output buffer
+ */
+float* HapticGeneratorContext::runProcessingChain(float* buf1, float* buf2, size_t frameCount) {
+ float* in = buf1;
+ float* out = buf2;
+ for (const auto processingFunc : mProcessingChain) {
+ processingFunc(out, in, frameCount);
+ std::swap(in, out);
+ }
+ return in;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
new file mode 100644
index 0000000..a0a0a4c
--- /dev/null
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <vibrator/ExternalVibrationUtils.h>
+#include <map>
+
+#include "Processors.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum HapticGeneratorState {
+ HAPTIC_GENERATOR_STATE_UNINITIALIZED,
+ HAPTIC_GENERATOR_STATE_INITIALIZED,
+ HAPTIC_GENERATOR_STATE_ACTIVE,
+};
+
+struct HapticGeneratorParam {
+ // The audio channels used to generate haptic channels. The first channel will be used to
+ // generate HAPTIC_A, The second channel will be used to generate HAPTIC_B.
+ // The value will be offset of audio channel
+ int mHapticChannelSource[2];
+
+ int mHapticChannelCount;
+ int mAudioChannelCount;
+
+ HapticGenerator::HapticScale mHapticScale;
+ std::map<int, HapticGenerator::VibratorScale> mHapticScales;
+ // max intensity will be used to scale haptic data.
+ HapticGenerator::VibratorScale mMaxVibratorScale;
+
+ HapticGenerator::VibratorInformation mVibratorInfo;
+};
+
+// A structure to keep all shared pointers for all processors in HapticGenerator.
+struct HapticGeneratorProcessorsRecord {
+ std::vector<std::shared_ptr<HapticBiquadFilter>> filters;
+ std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::Ramp>> ramps;
+ std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::SlowEnvelope>> slowEnvs;
+ std::vector<std::shared_ptr<::android::audio_effect::haptic_generator::Distortion>> distortions;
+
+ // Cache band-pass filter and band-stop filter for updating parameters
+ // according to vibrator info
+ std::shared_ptr<HapticBiquadFilter> bpf;
+ std::shared_ptr<HapticBiquadFilter> bsf;
+};
+
+class HapticGeneratorContext final : public EffectContext {
+ public:
+ HapticGeneratorContext(int statusDepth, const Parameter::Common& common);
+ ~HapticGeneratorContext();
+ RetCode enable();
+ RetCode disable();
+ void reset();
+
+ RetCode setHgHapticScales(const std::vector<HapticGenerator::HapticScale>& hapticScales);
+ std::vector<HapticGenerator::HapticScale> getHgHapticScales();
+
+ RetCode setHgVibratorInformation(const HapticGenerator::VibratorInformation& vibratorInfo);
+ HapticGenerator::VibratorInformation getHgVibratorInformation();
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ static constexpr float DEFAULT_RESONANT_FREQUENCY = 150.0f;
+ static constexpr float DEFAULT_BSF_ZERO_Q = 8.0f;
+ static constexpr float DEFAULT_BSF_POLE_Q = 4.0f;
+ static constexpr float DEFAULT_DISTORTION_OUTPUT_GAIN = 1.5f;
+ static constexpr float DEFAULT_BPF_Q = 1.0f;
+ static constexpr float DEFAULT_SLOW_ENV_NORMALIZATION_POWER = -0.8f;
+ static constexpr float DEFAULT_DISTORTION_CORNER_FREQUENCY = 300.0f;
+ static constexpr float DEFAULT_DISTORTION_INPUT_GAIN = 0.3f;
+ static constexpr float DEFAULT_DISTORTION_CUBE_THRESHOLD = 0.1f;
+
+ std::mutex mMutex;
+ HapticGeneratorState mState;
+ HapticGeneratorParam mParams GUARDED_BY(mMutex);
+ int mSampleRate;
+ int mFrameCount = 0;
+
+ // A cache for all shared pointers of the HapticGenerator
+ struct HapticGeneratorProcessorsRecord mProcessorsRecord;
+
+ // Using a vector of functions to record the processing chain for haptic-generating algorithm.
+ // The three parameters of the processing functions are pointer to output buffer, pointer to
+ // input buffer and frame count.
+ std::vector<std::function<void(float*, const float*, size_t)>> mProcessingChain;
+
+ // inputBuffer is where to keep input buffer for the generating algorithm. It will be
+ // constructed according to hapticChannelSource.
+ std::vector<float> mInputBuffer;
+
+ // outputBuffer is a buffer having the same length as inputBuffer. It can be used as
+ // intermediate buffer in the generating algorithm.
+ std::vector<float> mOutputBuffer;
+
+ void init_params(media::audio::common::AudioChannelLayout inputChMask,
+ media::audio::common::AudioChannelLayout outputChMask);
+ void configure();
+
+ float getDistortionOutputGain();
+ float getFloatProperty(const std::string& key, float defaultValue);
+ void addBiquadFilter(std::shared_ptr<HapticBiquadFilter> filter);
+ void buildProcessingChain();
+ float* runProcessingChain(float* buf1, float* buf2, size_t frameCount);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index bcd6947..7acba11 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -44,3 +44,33 @@
header_libs: ["libaudioeffects"],
}
+
+cc_library_shared {
+ name: "libloudnessenhanceraidl",
+ srcs: [
+ "aidl/EffectLoudnessEnhancer.cpp",
+ "aidl/LoudnessEnhancerContext.cpp",
+ "dsp/core/dynamic_range_compression.cpp",
+ ":effectCommonFile",
+ ],
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+ cflags: [
+ "-Wthread-safety",
+ ],
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ ],
+ relative_install_path: "soundfx",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
new file mode 100644
index 0000000..9d8bc80
--- /dev/null
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_LoudnessEnhancerImpl"
+
+#include <android-base/logging.h>
+
+#include "EffectLoudnessEnhancer.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kLoudnessEnhancerImplUUID;
+using aidl::android::hardware::audio::effect::LoudnessEnhancerImpl;
+using aidl::android::hardware::audio::effect::State;
+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 != kLoudnessEnhancerImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<LoudnessEnhancerImpl>();
+ 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 != kLoudnessEnhancerImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = LoudnessEnhancerImpl::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string LoudnessEnhancerImpl::kEffectName = "Loudness Enhancer";
+const Descriptor LoudnessEnhancerImpl::kDescriptor = {
+ .common = {.id = {.type = kLoudnessEnhancerTypeUUID,
+ .uuid = kLoudnessEnhancerImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
+ .name = LoudnessEnhancerImpl::kEffectName,
+ .implementor = "The Android Open Source Project"}};
+
+ndk::ScopedAStatus LoudnessEnhancerImpl::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus LoudnessEnhancerImpl::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();
+}
+
+ndk::ScopedAStatus LoudnessEnhancerImpl::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::loudnessEnhancer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& leParam = specific.get<Parameter::Specific::loudnessEnhancer>();
+ auto tag = leParam.getTag();
+
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ RETURN_IF(mContext->setLeGain(leParam.get<LoudnessEnhancer::gainMb>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setGainMbFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::loudnessEnhancerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto leId = id.get<Parameter::Id::loudnessEnhancerTag>();
+ auto leIdTag = leId.getTag();
+ switch (leIdTag) {
+ case LoudnessEnhancer::Id::commonTag:
+ return getParameterLoudnessEnhancer(leId.get<LoudnessEnhancer::Id::commonTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(leIdTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus LoudnessEnhancerImpl::getParameterLoudnessEnhancer(
+ const LoudnessEnhancer::Tag& tag, Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ LoudnessEnhancer leParam;
+ switch (tag) {
+ case LoudnessEnhancer::gainMb: {
+ leParam.set<LoudnessEnhancer::gainMb>(mContext->getLeGain());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "LoudnessEnhancerTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::loudnessEnhancer>(leParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> LoudnessEnhancerImpl::createContext(
+ const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+
+ mContext = std::make_shared<LoudnessEnhancerContext>(1 /* statusFmqDepth */, common);
+ return mContext;
+}
+
+RetCode LoudnessEnhancerImpl::releaseContext() {
+ if (mContext) {
+ mContext->disable();
+ mContext->resetBuffer();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status LoudnessEnhancerImpl::effectProcessImpl(float* in, float* out, int samples) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ return mContext->lvmProcess(in, out, samples);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
new file mode 100644
index 0000000..6402fd2
--- /dev/null
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
@@ -0,0 +1,55 @@
+/*
+ * 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 "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+#include "LoudnessEnhancerContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class LoudnessEnhancerImpl final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Descriptor kDescriptor;
+ LoudnessEnhancerImpl() { LOG(DEBUG) << __func__; }
+ ~LoudnessEnhancerImpl() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus commandImpl(CommandId command) 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;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ std::shared_ptr<EffectContext> getContext() override { return mContext; }
+ std::string getEffectName() override { return kEffectName; }
+
+ private:
+ std::shared_ptr<LoudnessEnhancerContext> mContext;
+ ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
new file mode 100644
index 0000000..033b222
--- /dev/null
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.cpp
@@ -0,0 +1,130 @@
+/*
+ * 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 "LoudnessEnhancerContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+LoudnessEnhancerContext::LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+ LOG(DEBUG) << __func__;
+ mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
+ mSampleRate = common.input.base.sampleRate;
+ init_params();
+}
+
+LoudnessEnhancerContext::~LoudnessEnhancerContext() {
+ LOG(DEBUG) << __func__;
+ mState = LOUDNESS_ENHANCER_STATE_UNINITIALIZED;
+}
+
+RetCode LoudnessEnhancerContext::enable() {
+ if (mState != LOUDNESS_ENHANCER_STATE_INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = LOUDNESS_ENHANCER_STATE_ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode LoudnessEnhancerContext::disable() {
+ if (mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+void LoudnessEnhancerContext::reset() {
+ float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification
+ {
+ std::lock_guard lg(mMutex);
+ if (mCompressor != nullptr) {
+ // Get samplingRate from input
+ mCompressor->Initialize(targetAmp, mSampleRate);
+ }
+ }
+}
+
+RetCode LoudnessEnhancerContext::setLeGain(int gainMb) {
+ mGain = gainMb;
+ reset(); // apply parameter update
+ return RetCode::SUCCESS;
+}
+
+IEffect::Status LoudnessEnhancerContext::lvmProcess(float* in, float* out, int samples) {
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << 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};
+ RETURN_VALUE_IF(getInputFrameSize() != getOutputFrameSize(), status, "FrameSizeMismatch");
+ auto frameSize = getInputFrameSize();
+ RETURN_VALUE_IF(0 == frameSize, status, "zeroFrameSize");
+
+ LOG(DEBUG) << __func__ << " start processing";
+ {
+ std::lock_guard lg(mMutex);
+ // PcmType is always expected to be Float 32 bit.
+ constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
+ constexpr float inverseScale = 1.f / scale;
+ const float inputAmp = pow(10, mGain / 2000.0f) * scale;
+ float leftSample, rightSample;
+ if (mCompressor != nullptr) {
+ for (int inIdx = 0; inIdx < samples; inIdx += 2) {
+ // makeup gain is applied on the input of the compressor
+ leftSample = inputAmp * in[inIdx];
+ rightSample = inputAmp * in[inIdx + 1];
+ mCompressor->Compress(&leftSample, &rightSample);
+ in[inIdx] = leftSample * inverseScale;
+ in[inIdx + 1] = rightSample * inverseScale;
+ }
+ } else {
+ for (int inIdx = 0; inIdx < samples; inIdx += 2) {
+ leftSample = inputAmp * in[inIdx];
+ rightSample = inputAmp * in[inIdx + 1];
+ in[inIdx] = leftSample * inverseScale;
+ in[inIdx + 1] = rightSample * inverseScale;
+ }
+ }
+ bool accumulate = false;
+ if (in != out) {
+ for (int i = 0; i < samples; i++) {
+ if (accumulate) {
+ out[i] += in[i];
+ } else {
+ out[i] = in[i];
+ }
+ }
+ }
+ }
+ return {STATUS_OK, samples, samples};
+}
+
+void LoudnessEnhancerContext::init_params() {
+ mGain = LOUDNESS_ENHANCER_DEFAULT_TARGET_GAIN_MB;
+ float targetAmp = pow(10, mGain / 2000.0f); // mB to linear amplification
+ LOG(DEBUG) << __func__ << "Target gain = " << mGain << "mB <=> factor = " << targetAmp;
+
+ {
+ std::lock_guard lg(mMutex);
+ mCompressor = std::make_unique<le_fx::AdaptiveDynamicRangeCompression>();
+ mCompressor->Initialize(targetAmp, mSampleRate);
+ }
+ mState = LOUDNESS_ENHANCER_STATE_INITIALIZED;
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
new file mode 100644
index 0000000..b478b27
--- /dev/null
+++ b/media/libeffects/loudness/aidl/LoudnessEnhancerContext.h
@@ -0,0 +1,58 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <audio_effects/effect_loudnessenhancer.h>
+
+#include "dsp/core/dynamic_range_compression.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum LoudnessEnhancerState {
+ LOUDNESS_ENHANCER_STATE_UNINITIALIZED,
+ LOUDNESS_ENHANCER_STATE_INITIALIZED,
+ LOUDNESS_ENHANCER_STATE_ACTIVE,
+};
+
+class LoudnessEnhancerContext final : public EffectContext {
+ public:
+ LoudnessEnhancerContext(int statusDepth, const Parameter::Common& common);
+ ~LoudnessEnhancerContext();
+
+ RetCode enable();
+ RetCode disable();
+ void reset();
+
+ RetCode setLeGain(int gainMb);
+ int getLeGain() const { return mGain; }
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ std::mutex mMutex;
+ LoudnessEnhancerState mState;
+ int mSampleRate;
+ int mGain;
+ // In this implementation, there is no coupling between the compression on the left and right
+ // channels
+ std::unique_ptr<le_fx::AdaptiveDynamicRangeCompression> mCompressor GUARDED_BY(mMutex);
+
+ void init_params();
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index fcf538d..e303efd 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -24,6 +24,10 @@
namespace aidl::android::hardware::audio::effect {
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::aidl::android::media::audio::common::AudioDeviceDescription;
+using ::aidl::android::media::audio::common::AudioDeviceType;
+
RetCode BundleContext::init() {
std::lock_guard lg(mMutex);
// init with pre-defined preset NORMAL
@@ -69,6 +73,9 @@
RetCode BundleContext::enable() {
if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
+ // Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due to
+ // their nature.
+ bool tempDisabled = false;
switch (mType) {
case lvm::BundleEffectType::EQUALIZER:
LOG(DEBUG) << __func__ << " enable bundle EQ";
@@ -76,12 +83,29 @@
mSamplesToExitCountEq = (mSamplesPerSecond * 0.1);
mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::EQUALIZER));
break;
- default:
- // Add handling for other effects
+ case lvm::BundleEffectType::BASS_BOOST:
+ LOG(DEBUG) << __func__ << " enable bundle BB";
+ if (mSamplesToExitCountBb <= 0) mNumberEffectsEnabled++;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST));
+ mSamplesToExitCountBb = (mSamplesPerSecond * 0.1);
+ tempDisabled = mBassTempDisabled;
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ LOG(DEBUG) << __func__ << " enable bundle VR";
+ if (mSamplesToExitCountVirt <= 0) mNumberEffectsEnabled++;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER));
+ mSamplesToExitCountVirt = (mSamplesPerSecond * 0.1);
+ tempDisabled = mVirtualizerTempDisabled;
+ break;
+ case lvm::BundleEffectType::VOLUME:
+ LOG(DEBUG) << __func__ << " enable bundle VOL";
+ if ((mEffectInDrain & (1 << int(lvm::BundleEffectType::VOLUME))) == 0)
+ mNumberEffectsEnabled++;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
break;
}
mEnabled = true;
- return enableOperatingMode();
+ return (tempDisabled ? RetCode::SUCCESS : enableOperatingMode());
}
RetCode BundleContext::enableOperatingMode() {
@@ -95,8 +119,16 @@
LOG(DEBUG) << __func__ << " enable bundle EQ";
params.EQNB_OperatingMode = LVM_EQNB_ON;
break;
- default:
- // Add handling for other effects
+ case lvm::BundleEffectType::BASS_BOOST:
+ LOG(DEBUG) << __func__ << " enable bundle BB";
+ params.BE_OperatingMode = LVM_BE_ON;
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ LOG(DEBUG) << __func__ << " enable bundle VR";
+ params.VirtualizerOperatingMode = LVM_MODE_ON;
+ break;
+ case lvm::BundleEffectType::VOLUME:
+ LOG(DEBUG) << __func__ << " enable bundle VOL";
break;
}
RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
@@ -112,8 +144,17 @@
LOG(DEBUG) << __func__ << " disable bundle EQ";
mEffectInDrain |= 1 << int(lvm::BundleEffectType::EQUALIZER);
break;
- default:
- // Add handling for other effects
+ case lvm::BundleEffectType::BASS_BOOST:
+ LOG(DEBUG) << __func__ << " disable bundle BB";
+ mEffectInDrain |= 1 << int(lvm::BundleEffectType::BASS_BOOST);
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ LOG(DEBUG) << __func__ << " disable bundle VR";
+ mEffectInDrain |= 1 << int(lvm::BundleEffectType::VIRTUALIZER);
+ break;
+ case lvm::BundleEffectType::VOLUME:
+ LOG(DEBUG) << __func__ << " disable bundle VOL";
+ mEffectInDrain |= 1 << int(lvm::BundleEffectType::VOLUME);
break;
}
mEnabled = false;
@@ -131,8 +172,16 @@
LOG(DEBUG) << __func__ << " disable bundle EQ";
params.EQNB_OperatingMode = LVM_EQNB_OFF;
break;
- default:
- // Add handling for other effects
+ case lvm::BundleEffectType::BASS_BOOST:
+ LOG(DEBUG) << __func__ << " disable bundle BB";
+ params.BE_OperatingMode = LVM_BE_OFF;
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ LOG(DEBUG) << __func__ << " disable bundle VR";
+ params.VirtualizerOperatingMode = LVM_MODE_OFF;
+ break;
+ case lvm::BundleEffectType::VOLUME:
+ LOG(DEBUG) << __func__ << " disable bundle VOL";
break;
}
RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
@@ -156,6 +205,8 @@
RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
bool eqEnabled = params.EQNB_OperatingMode == LVM_EQNB_ON;
+ bool bbEnabled = params.BE_OperatingMode == LVM_BE_ON;
+ bool viEnabled = params.VirtualizerOperatingMode == LVM_MODE_ON;
if (eqEnabled) {
for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
@@ -182,6 +233,26 @@
bandFactorSum -= 1.0;
if (bandFactorSum > 0) crossCorrection = bandFactorSum * 0.7;
}
+ // BassBoost contribution
+ if (bbEnabled) {
+ float boostFactor = mBassStrengthSaved / 1000.0;
+ float boostCoefficient = lvm::kBassBoostEnergyCoefficient;
+
+ energyContribution += boostFactor * boostCoefficient * boostCoefficient;
+
+ if (eqEnabled) {
+ for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ float bandFactor = mBandGaindB[i] / 15.0;
+ float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i];
+ float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient;
+ if (bandEnergy > 0) energyBassBoost += bandEnergy;
+ }
+ }
+ }
+ // Virtualizer contribution
+ if (viEnabled) {
+ energyContribution += lvm::kVirtualizerContribution * lvm::kVirtualizerContribution;
+ }
double totalEnergyEstimation =
sqrt(energyContribution + energyCross + energyBassBoost) - crossCorrection;
@@ -189,15 +260,15 @@
// roundoff
int maxLevelRound = (int)(totalEnergyEstimation + 0.99);
- if (maxLevelRound + mLevelSaved > 0) {
- gainCorrection = maxLevelRound + mLevelSaved;
+ if (maxLevelRound + mVolume > 0) {
+ gainCorrection = maxLevelRound + mVolume;
}
- params.VC_EffectLevel = mLevelSaved - gainCorrection;
+ params.VC_EffectLevel = mVolume - gainCorrection;
if (params.VC_EffectLevel < -96) {
params.VC_EffectLevel = -96;
}
- LOG(INFO) << "\tVol: " << mLevelSaved << ", GainCorrection: " << gainCorrection
+ LOG(INFO) << "\tVol: " << mVolume << ", GainCorrection: " << gainCorrection
<< ", Actual vol: " << params.VC_EffectLevel;
/* Activate the initial settings */
@@ -216,6 +287,83 @@
return RetCode::SUCCESS;
}
+bool BundleContext::isDeviceSupportedBassBoost(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& devices) {
+ for (const auto& device : devices) {
+ if (device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER, ""} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_CARKIT,
+ AudioDeviceDescription::CONNECTION_BT_SCO} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER,
+ AudioDeviceDescription::CONNECTION_BT_A2DP}) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BundleContext::isDeviceSupportedVirtualizer(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& devices) {
+ for (const auto& device : devices) {
+ if (device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_ANALOG} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE,
+ AudioDeviceDescription::CONNECTION_ANALOG} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE,
+ AudioDeviceDescription::CONNECTION_BT_A2DP} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_USB}) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BundleContext::isConfigSupportedVirtualizer(size_t channelCount,
+ const AudioDeviceDescription& device) {
+ return (channelCount >= 1 && channelCount <= FCC_2) && isDeviceSupportedVirtualizer({device});
+}
+
+RetCode BundleContext::setOutputDevice(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& devices) {
+ mOutputDevice = devices;
+ switch (mType) {
+ case lvm::BundleEffectType::BASS_BOOST:
+ if (!isDeviceSupportedBassBoost(devices)) {
+ // If a device doesn't support bass boost, the effect must be temporarily disabled.
+ // The effect must still report its original state as this can only be changed by
+ // the start/stop commands.
+ if (mEnabled) {
+ disableOperatingMode();
+ }
+ mBassTempDisabled = true;
+ } else {
+ // If a device supports bass boost and the effect has been temporarily disabled
+ // previously then re-enable it
+ if (!mEnabled) {
+ enableOperatingMode();
+ }
+ mBassTempDisabled = false;
+ }
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ if (!isDeviceSupportedVirtualizer(devices)) {
+ if (mEnabled) {
+ disableOperatingMode();
+ }
+ mVirtualizerTempDisabled = true;
+ } else {
+ if (!mEnabled) {
+ enableOperatingMode();
+ }
+ mVirtualizerTempDisabled = false;
+ }
+ break;
+ default:
+ break;
+ }
+ return RetCode::SUCCESS;
+}
+
LVM_INT16 BundleContext::LVC_ToDB_s32Tos16(LVM_INT32 Lin_fix) const {
LVM_INT16 db_fix;
LVM_INT16 Shift;
@@ -267,8 +415,7 @@
int rightdB = VolToDb(volume.right);
int maxdB = std::max(leftdB, rightdB);
int pandB = rightdB - leftdB;
- // TODO: add volume effect implementation here:
- // android::VolumeSetVolumeLevel(pContext, (int16_t)(maxdB * 100));
+ setVolumeLevel(maxdB * 100);
LOG(DEBUG) << __func__ << " pandB: " << pandB << " maxdB " << maxdB;
{
@@ -328,6 +475,23 @@
return bandLevels;
}
+std::vector<int32_t> BundleContext::getEqualizerCenterFreqs() {
+ std::vector<int32_t> freqs;
+
+ LVM_ControlParams_t params;
+ {
+ std::lock_guard lg(mMutex);
+ /* Get the current settings */
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms), freqs,
+ " getControlParamFailed");
+ for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ freqs.push_back((int32_t)params.pEQNB_BandDefinition[i].Frequency * 1000);
+ }
+ }
+
+ return freqs;
+}
+
bool BundleContext::isBandLevelIndexInRange(
const std::vector<Equalizer::BandLevel>& bandLevels) const {
const auto [min, max] =
@@ -366,6 +530,91 @@
return RetCode::SUCCESS;
}
+RetCode BundleContext::setBassBoostStrength(int strength) {
+ if (strength < 0 || strength > lvm::kBassBoostCap.maxStrengthPm) {
+ LOG(ERROR) << __func__ << " invalid strength: " << strength;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVM_ControlParams_t params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.BE_EffectLevel = (LVM_INT16)((15 * strength) / 1000);
+ params.BE_CentreFreq = LVM_BE_CENTRE_90Hz;
+
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mBassStrengthSaved = strength;
+ LOG(INFO) << __func__ << " success with strength " << strength;
+ return limitLevel();
+}
+
+RetCode BundleContext::setVolumeLevel(int level) {
+ if (level < lvm::kVolumeCap.minLevelDb || level > lvm::kVolumeCap.maxLevelDb) {
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ if (mMuteEnabled) {
+ mLevelSaved = level / 100;
+ } else {
+ mVolume = level / 100;
+ }
+ LOG(INFO) << __func__ << " success with level " << level;
+ return limitLevel();
+}
+
+int BundleContext::getVolumeLevel() const {
+ return (mMuteEnabled ? mLevelSaved * 100 : mVolume * 100);
+}
+
+RetCode BundleContext::setVolumeMute(bool mute) {
+ mMuteEnabled = mute;
+ if (mMuteEnabled) {
+ mLevelSaved = mVolume;
+ mVolume = -96;
+ } else {
+ mVolume = mLevelSaved;
+ }
+ return limitLevel();
+}
+
+RetCode BundleContext::setVirtualizerStrength(int strength) {
+ if (strength < 0 || strength > lvm::kVirtualizerCap.maxStrengthPm) {
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVM_ControlParams_t params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.CS_EffectLevel = ((strength * 32767) / 1000);
+
+ RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+
+ mVirtStrengthSaved = strength;
+ LOG(INFO) << __func__ << " success with strength " << strength;
+ return limitLevel();
+}
+
+
+RetCode BundleContext::setForcedDevice(
+ const ::aidl::android::media::audio::common::AudioDeviceDescription& device) {
+ RETURN_VALUE_IF(true != isDeviceSupportedVirtualizer({device}), RetCode::ERROR_EFFECT_LIB_ERROR,
+ " deviceNotSupportVirtualizer");
+ mForceDevice = device;
+ return RetCode::SUCCESS;
+}
+
void BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
/* General parameters */
params.OperatingMode = LVM_MODE_ON;
@@ -451,6 +700,28 @@
return HeadroomBandDef;
}
+std::vector<Virtualizer::ChannelAngle> BundleContext::getSpeakerAngles(
+ const Virtualizer::SpeakerAnglesPayload payload) {
+ std::vector<Virtualizer::ChannelAngle> angles;
+ auto chCount = ::android::hardware::audio::common::getChannelCount(payload.layout);
+ RETURN_VALUE_IF(!isConfigSupportedVirtualizer(chCount, payload.device), angles,
+ "payloadNotSupported");
+
+ if (chCount == 1) {
+ angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
+ .azimuthDegree = 0,
+ .elevationDegree = 0}};
+ } else {
+ angles = {{.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_LEFT,
+ .azimuthDegree = -90,
+ .elevationDegree = 0},
+ {.channel = (int32_t)AudioChannelLayout::CHANNEL_FRONT_RIGHT,
+ .azimuthDegree = 90,
+ .elevationDegree = 0}};
+ }
+ return angles;
+}
+
IEffect::Status BundleContext::lvmProcess(float* in, float* out, int samples) {
IEffect::Status status = {EX_NULL_POINTER, 0, 0};
RETURN_VALUE_IF(!in, status, "nullInput");
@@ -473,6 +744,23 @@
--mNumberEffectsEnabled;
mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::EQUALIZER));
}
+ if ((undrainedEffects & 1 << int(lvm::BundleEffectType::BASS_BOOST)) != 0) {
+ LOG(DEBUG) << "Draining BASS_BOOST";
+ mSamplesToExitCountBb = 0;
+ --mNumberEffectsEnabled;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST));
+ }
+ if ((undrainedEffects & 1 << int(lvm::BundleEffectType::VIRTUALIZER)) != 0) {
+ LOG(DEBUG) << "Draining VIRTUALIZER";
+ mSamplesToExitCountVirt = 0;
+ --mNumberEffectsEnabled;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER));
+ }
+ if ((undrainedEffects & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) {
+ LOG(DEBUG) << "Draining VOLUME";
+ --mNumberEffectsEnabled;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
+ }
}
mEffectProcessCalled |= 1 << int(mType);
if (!mEnabled) {
@@ -490,8 +778,39 @@
LOG(DEBUG) << "Effect_process() this is the last frame for EQUALIZER";
}
break;
- default:
- // Add handling for other effects
+ case lvm::BundleEffectType::BASS_BOOST:
+ if (mSamplesToExitCountBb > 0) {
+ mSamplesToExitCountBb -= samples;
+ }
+ if (mSamplesToExitCountBb <= 0) {
+ isDataAvailable = false;
+ if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::BASS_BOOST)) != 0) {
+ mNumberEffectsEnabled--;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::BASS_BOOST));
+ }
+ LOG(DEBUG) << "Effect_process() this is the last frame for BASS_BOOST";
+ }
+ break;
+ case lvm::BundleEffectType::VIRTUALIZER:
+ if (mSamplesToExitCountVirt > 0) {
+ mSamplesToExitCountVirt -= samples;
+ }
+ if (mSamplesToExitCountVirt <= 0) {
+ isDataAvailable = false;
+ if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::VIRTUALIZER)) != 0) {
+ mNumberEffectsEnabled--;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VIRTUALIZER));
+ }
+ LOG(DEBUG) << "Effect_process() this is the last frame for VIRTUALIZER";
+ }
+ break;
+ case lvm::BundleEffectType::VOLUME:
+ isDataAvailable = false;
+ if ((mEffectInDrain & 1 << int(lvm::BundleEffectType::VOLUME)) != 0) {
+ mNumberEffectsEnabled--;
+ mEffectInDrain &= ~(1 << int(lvm::BundleEffectType::VOLUME));
+ }
+ LOG(DEBUG) << "Effect_process() LVM_VOLUME Effect is not enabled";
break;
}
}
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index c944bd1..47d5e5a 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -47,7 +47,7 @@
RetCode disable();
RetCode disableOperatingMode();
- void setSampleRate (const int sampleRate) { mSampleRate = sampleRate; }
+ void setSampleRate(const int sampleRate) { mSampleRate = sampleRate; }
int getSampleRate() const { return mSampleRate; }
void setChannelMask(const aidl::android::media::audio::common::AudioChannelLayout& chMask) {
@@ -56,12 +56,47 @@
aidl::android::media::audio::common::AudioChannelLayout getChannelMask() const {
return mChMask;
}
+ bool isDeviceSupportedBassBoost(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
+ devices);
+ bool isDeviceSupportedVirtualizer(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
+ devices);
+ bool isConfigSupportedVirtualizer(
+ size_t channelCount,
+ const aidl::android::media::audio::common::AudioDeviceDescription& device);
+
+ RetCode setOutputDevice(
+ const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>& devices)
+ override;
RetCode setEqualizerPreset(const std::size_t presetIdx);
int getEqualizerPreset() const { return mCurPresetIdx; }
RetCode setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels);
std::vector<Equalizer::BandLevel> getEqualizerBandLevels() const;
+ std::vector<int32_t> getEqualizerCenterFreqs();
+
+ RetCode setBassBoostStrength(int strength);
+ int getBassBoostStrength() const { return mBassStrengthSaved; }
+
+ RetCode setVolumeLevel(int level);
+ int getVolumeLevel() const;
+
+ RetCode setVolumeMute(bool mute);
+ int getVolumeMute() const { return mMuteEnabled; }
+
+ RetCode setVirtualizerStrength(int strength);
+ int getVirtualizerStrength() const { return mVirtStrengthSaved; }
+
+ RetCode setForcedDevice(
+ const ::aidl::android::media::audio::common::AudioDeviceDescription& device);
+ aidl::android::media::audio::common::AudioDeviceDescription getForcedDevice() const {
+ return mForceDevice;
+ }
+ std::vector<Virtualizer::ChannelAngle> getSpeakerAngles(
+ const Virtualizer::SpeakerAnglesPayload payload);
+
RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) override;
Parameter::VolumeStereo getVolumeStereo() override { return mVolumeStereo; }
@@ -94,7 +129,7 @@
int mEffectProcessCalled = 0;
int mNumberEffectsEnabled = 0;
int mNumberEffectsCalled = 0;
- bool mFirstVolume = false;
+ bool mFirstVolume = true;
// Bass
bool mBassTempDisabled = false;
int mBassStrengthSaved = 0;
@@ -104,8 +139,10 @@
// Virtualizer
int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
bool mVirtualizerTempDisabled = false;
+ ::aidl::android::media::audio::common::AudioDeviceDescription mForceDevice;
// Volume
int mLevelSaved = 0; /* for when mute is set, level must be saved */
+ int mVolume = 0;
bool mMuteEnabled = false; /* Must store as mute = -96dB level */
void initControlParameter(LVM_ControlParams_t& params) const;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index e1495a3..1996240 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -83,10 +83,62 @@
.implementor = "NXP Software Ltd."},
.capability = Capability::make<Capability::equalizer>(kEqCap)};
-// TODO: add descriptors for other bundle effect types here.
-static const Descriptor kVirtualizerDesc;
-static const Descriptor kBassBoostDesc;
-static const Descriptor kVolumeDesc;
+static const bool mStrengthSupported = true;
+
+static const BassBoost::Capability kBassBoostCap = {.maxStrengthPm = 1000,
+ .strengthSupported = mStrengthSupported};
+
+static const std::string kBassBoostEffectName = "Dynamic Bass Boost";
+
+static const Descriptor kBassBoostDesc = {
+ .common = {.id = {.type = kBassBoostTypeUUID,
+ .uuid = kBassBoostBundleImplUUID,
+ .proxy = kBassBoostProxyUUID},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL,
+ .deviceIndication = true},
+ .cpuLoad = BASS_BOOST_CUP_LOAD_ARM9E,
+ .memoryUsage = BUNDLE_MEM_USAGE,
+ .name = kBassBoostEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::bassBoost>(kBassBoostCap)};
+
+static const Virtualizer::Capability kVirtualizerCap = {.maxStrengthPm = 1000,
+ .strengthSupported = mStrengthSupported};
+
+static const std::string kVirtualizerEffectName = "Virtualizer";
+
+static const Descriptor kVirtualizerDesc = {
+ .common = {.id = {.type = kVirtualizerTypeUUID,
+ .uuid = kVirtualizerBundleImplUUID,
+ .proxy = kVirtualizerProxyUUID},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::LAST,
+ .volume = Flags::Volume::CTRL,
+ .deviceIndication = true},
+ .cpuLoad = VIRTUALIZER_CUP_LOAD_ARM9E,
+ .memoryUsage = BUNDLE_MEM_USAGE,
+ .name = kVirtualizerEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::virtualizer>(kVirtualizerCap)};
+
+static const Volume::Capability kVolumeCap = {.minLevelDb = -9600, .maxLevelDb = 0};
+
+static const std::string kVolumeEffectName = "Volume";
+
+static const Descriptor kVolumeDesc = {
+ .common = {.id = {.type = kVolumeTypeUUID,
+ .uuid = kVolumeBundleImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::LAST,
+ .volume = Flags::Volume::CTRL},
+ .cpuLoad = VOLUME_CUP_LOAD_ARM9E,
+ .memoryUsage = BUNDLE_MEM_USAGE,
+ .name = kVolumeEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::volume>(kVolumeCap)};
/* The following tables have been computed using the actual levels measured by the output of
* white noise or pink noise (IEC268-1) for the EQ and BassBoost Effects. These are estimates of
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index f16458c..fd9f3dc 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -32,12 +32,16 @@
using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::EffectBundleAidl;
using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kBassBoostBundleImplUUID;
using aidl::android::hardware::audio::effect::kEqualizerBundleImplUUID;
+using aidl::android::hardware::audio::effect::kVirtualizerBundleImplUUID;
+using aidl::android::hardware::audio::effect::kVolumeBundleImplUUID;
using aidl::android::hardware::audio::effect::State;
using aidl::android::media::audio::common::AudioUuid;
bool isUuidSupported(const AudioUuid* uuid) {
- return *uuid == kEqualizerBundleImplUUID;
+ return (*uuid == kEqualizerBundleImplUUID || *uuid == kBassBoostBundleImplUUID ||
+ *uuid == kVirtualizerBundleImplUUID || *uuid == kVolumeBundleImplUUID);
}
extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
@@ -57,11 +61,19 @@
}
extern "C" binder_exception_t queryEffect(const AudioUuid* in_impl_uuid, Descriptor* _aidl_return) {
- if (!in_impl_uuid || *in_impl_uuid != kEqualizerBundleImplUUID) {
+ if (!in_impl_uuid || !isUuidSupported(in_impl_uuid)) {
LOG(ERROR) << __func__ << "uuid not supported";
return EX_ILLEGAL_ARGUMENT;
}
- *_aidl_return = aidl::android::hardware::audio::effect::lvm::kEqualizerDesc;
+ if (*in_impl_uuid == kEqualizerBundleImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kEqualizerDesc;
+ } else if (*in_impl_uuid == kBassBoostBundleImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm:: kBassBoostDesc;
+ } else if (*in_impl_uuid == kVirtualizerBundleImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVirtualizerDesc;
+ } else if (*in_impl_uuid == kVolumeBundleImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kVolumeDesc;
+ }
return EX_NONE;
}
@@ -73,9 +85,20 @@
mType = lvm::BundleEffectType::EQUALIZER;
mDescriptor = &lvm::kEqualizerDesc;
mEffectName = &lvm::kEqualizerEffectName;
+ } else if (uuid == kBassBoostBundleImplUUID) {
+ mType = lvm::BundleEffectType::BASS_BOOST;
+ mDescriptor = &lvm::kBassBoostDesc;
+ mEffectName = &lvm::kBassBoostEffectName;
+ } else if (uuid == kVirtualizerBundleImplUUID) {
+ mType = lvm::BundleEffectType::VIRTUALIZER;
+ mDescriptor = &lvm::kVirtualizerDesc;
+ mEffectName = &lvm::kVirtualizerEffectName;
+ } else if (uuid == kVolumeBundleImplUUID) {
+ mType = lvm::BundleEffectType::VOLUME;
+ mDescriptor = &lvm::kVolumeDesc;
+ mEffectName = &lvm::kVolumeEffectName;
} else {
- // TODO: add other bundle effect types here.
- LOG(ERROR) << __func__ << uuid.toString() << " not supported yet!";
+ LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
}
}
@@ -135,6 +158,12 @@
switch (tag) {
case Parameter::Specific::equalizer:
return setParameterEqualizer(specific);
+ case Parameter::Specific::bassBoost:
+ return setParameterBassBoost(specific);
+ case Parameter::Specific::virtualizer:
+ return setParameterVirtualizer(specific);
+ case Parameter::Specific::volume:
+ return setParameterVolume(specific);
default:
LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -162,6 +191,68 @@
}
}
+ndk::ScopedAStatus EffectBundleAidl::setParameterBassBoost(const Parameter::Specific& specific) {
+ auto& bb = specific.get<Parameter::Specific::bassBoost>();
+ auto bbTag = bb.getTag();
+ switch (bbTag) {
+ case BassBoost::strengthPm: {
+ RETURN_IF(mContext->setBassBoostStrength(bb.get<BassBoost::strengthPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setStrengthFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default:
+ LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "bbTagNotSupported");
+ }
+}
+
+ndk::ScopedAStatus EffectBundleAidl::setParameterVirtualizer(const Parameter::Specific& specific) {
+ auto& vr = specific.get<Parameter::Specific::virtualizer>();
+ auto vrTag = vr.getTag();
+ switch (vrTag) {
+ case Virtualizer::strengthPm: {
+ RETURN_IF(mContext->setVirtualizerStrength(vr.get<Virtualizer::strengthPm>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setStrengthFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Virtualizer::device: {
+ RETURN_IF(mContext->setForcedDevice(vr.get<Virtualizer::device>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDeviceFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Virtualizer::speakerAngles:
+ FALLTHROUGH_INTENDED;
+ case Virtualizer::vendor: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(vrTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VirtualizerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectBundleAidl::setParameterVolume(const Parameter::Specific& specific) {
+ auto& vol = specific.get<Parameter::Specific::volume>();
+ auto volTag = vol.getTag();
+ switch (volTag) {
+ case Volume::levelDb: {
+ RETURN_IF(mContext->setVolumeLevel(vol.get<Volume::levelDb>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Volume::mute:
+ RETURN_IF(mContext->setVolumeMute(vol.get<Volume::mute>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMuteFailed");
+ return ndk::ScopedAStatus::ok();
+ default:
+ LOG(ERROR) << __func__ << " unsupported parameter " << specific.toString();
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "volTagNotSupported");
+ }
+}
+
ndk::ScopedAStatus EffectBundleAidl::getParameterSpecific(const Parameter::Id& id,
Parameter::Specific* specific) {
RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
@@ -170,6 +261,12 @@
switch (tag) {
case Parameter::Id::equalizerTag:
return getParameterEqualizer(id.get<Parameter::Id::equalizerTag>(), specific);
+ case Parameter::Id::bassBoostTag:
+ return getParameterBassBoost(id.get<Parameter::Id::bassBoostTag>(), specific);
+ case Parameter::Id::virtualizerTag:
+ return getParameterVirtualizer(id.get<Parameter::Id::virtualizerTag>(), specific);
+ case Parameter::Id::volumeTag:
+ return getParameterVolume(id.get<Parameter::Id::volumeTag>(), specific);
default:
LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
@@ -194,6 +291,10 @@
eqParam.set<Equalizer::preset>(mContext->getEqualizerPreset());
break;
}
+ case Equalizer::centerFreqMh: {
+ eqParam.set<Equalizer::centerFreqMh>(mContext->getEqualizerCenterFreqs());
+ break;
+ }
default: {
LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
@@ -205,6 +306,96 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus EffectBundleAidl::getParameterBassBoost(const BassBoost::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != BassBoost::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ BassBoost bbParam;
+
+ auto tag = id.get<BassBoost::Id::commonTag>();
+ switch (tag) {
+ case BassBoost::strengthPm: {
+ bbParam.set<BassBoost::strengthPm>(mContext->getBassBoostStrength());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "BassBoostTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::bassBoost>(bbParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectBundleAidl::getParameterVolume(const Volume::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != Volume::Id::commonTag, EX_ILLEGAL_ARGUMENT, "VolumeTagNotSupported");
+
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ Volume volParam;
+
+ auto tag = id.get<Volume::Id::commonTag>();
+ switch (tag) {
+ case Volume::levelDb: {
+ volParam.set<Volume::levelDb>(mContext->getVolumeLevel());
+ break;
+ }
+ case Volume::mute: {
+ volParam.set<Volume::mute>(mContext->getVolumeMute());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " not handled tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VolumeTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::volume>(volParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectBundleAidl::getParameterVirtualizer(const Virtualizer::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != Virtualizer::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "VirtualizerTagNotSupported");
+
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ Virtualizer vrParam;
+
+ if (id.getTag() == Virtualizer::Id::speakerAnglesPayload) {
+ auto angles = mContext->getSpeakerAngles(id.get<Virtualizer::Id::speakerAnglesPayload>());
+ Virtualizer param = Virtualizer::make<Virtualizer::speakerAngles>(angles);
+ specific->set<Parameter::Specific::virtualizer>(param);
+ return ndk::ScopedAStatus::ok();
+ }
+
+ auto tag = id.get<Virtualizer::Id::commonTag>();
+ switch (tag) {
+ case Virtualizer::strengthPm: {
+ vrParam.set<Virtualizer::strengthPm>(mContext->getVirtualizerStrength());
+ break;
+ }
+ case Virtualizer::device: {
+ vrParam.set<Virtualizer::device>(mContext->getForcedDevice());
+ break;
+ }
+ case Virtualizer::speakerAngles:
+ FALLTHROUGH_INTENDED;
+ case Virtualizer::vendor: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VirtualizerTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::virtualizer>(vrParam);
+ return ndk::ScopedAStatus::ok();
+}
+
std::shared_ptr<EffectContext> EffectBundleAidl::createContext(const Parameter::Common& common) {
if (mContext) {
LOG(DEBUG) << __func__ << " context already exist";
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index 0d7d17c..0330e5a 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -60,9 +60,18 @@
IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+ ndk::ScopedAStatus setParameterBassBoost(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id,
+ Parameter::Specific* specific);
+
ndk::ScopedAStatus setParameterEqualizer(const Parameter::Specific& specific);
ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id,
Parameter::Specific* specific);
+ ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific);
+ ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Id& id,
+ Parameter::Specific* specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index aef9295..fa300d2 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -125,7 +125,41 @@
cflags: [
"-Wthread-safety",
],
+ relative_install_path: "soundfx",
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
-}
\ No newline at end of file
+}
+
+cc_library_shared {
+ name: "libreverbaidl",
+ srcs: [
+ "Reverb/aidl/ReverbContext.cpp",
+ "Reverb/aidl/EffectReverb.cpp",
+ ":effectCommonFile",
+ ],
+ static_libs: ["libreverb"],
+ defaults: [
+ "aidlaudioservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ ],
+ local_include_dirs: ["Reverb/aidl"],
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+ shared_libs: [
+ "libbase",
+ "libaudioutils",
+ "libcutils",
+ "liblog",
+ ],
+ cflags: [
+ "-Wthread-safety",
+ ],
+ relative_install_path: "soundfx",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
new file mode 100644
index 0000000..51825ca
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -0,0 +1,373 @@
+/*
+ * 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 "EffectReverb"
+#include <Utils.h>
+#include <algorithm>
+#include <unordered_set>
+
+#include <android-base/logging.h>
+#include <fmq/AidlMessageQueue.h>
+#include <audio_effects/effect_bassboost.h>
+#include <audio_effects/effect_equalizer.h>
+#include <audio_effects/effect_virtualizer.h>
+
+#include "EffectReverb.h"
+#include <limits.h>
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::EffectReverb;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::kAuxEnvReverbImplUUID;
+using aidl::android::hardware::audio::effect::kAuxPresetReverbImplUUID;
+using aidl::android::hardware::audio::effect::kInsertEnvReverbImplUUID;
+using aidl::android::hardware::audio::effect::kInsertPresetReverbImplUUID;
+using aidl::android::hardware::audio::effect::State;
+using aidl::android::media::audio::common::AudioUuid;
+
+bool isReverbUuidSupported(const AudioUuid* uuid) {
+ return (*uuid == kAuxEnvReverbImplUUID || *uuid == kInsertEnvReverbImplUUID ||
+ *uuid == kAuxPresetReverbImplUUID || *uuid == kInsertPresetReverbImplUUID);
+}
+
+extern "C" binder_exception_t createEffect(const AudioUuid* uuid,
+ std::shared_ptr<IEffect>* instanceSpp) {
+ if (uuid == nullptr || !isReverbUuidSupported(uuid)) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<EffectReverb>(*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 || !isReverbUuidSupported(in_impl_uuid)) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (*in_impl_uuid == kAuxEnvReverbImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kAuxEnvReverbDesc;
+ } else if (*in_impl_uuid == kInsertEnvReverbImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kInsertEnvReverbDesc;
+ } else if (*in_impl_uuid == kAuxPresetReverbImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kAuxPresetReverbDesc;
+ } else if (*in_impl_uuid == kInsertPresetReverbImplUUID) {
+ *_aidl_return = aidl::android::hardware::audio::effect::lvm::kInsertPresetReverbDesc;
+ }
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+EffectReverb::EffectReverb(const AudioUuid& uuid) {
+ LOG(DEBUG) << __func__ << uuid.toString();
+ if (uuid == kAuxEnvReverbImplUUID) {
+ mType = lvm::ReverbEffectType::AUX_ENV;
+ mDescriptor = &lvm::kAuxEnvReverbDesc;
+ mEffectName = &lvm::kAuxEnvReverbEffectName;
+ } else if (uuid == kInsertEnvReverbImplUUID) {
+ mType = lvm::ReverbEffectType::INSERT_ENV;
+ mDescriptor = &lvm::kInsertEnvReverbDesc;
+ mEffectName = &lvm::kInsertEnvReverbEffectName;
+ } else if (uuid == kAuxPresetReverbImplUUID) {
+ mType = lvm::ReverbEffectType::AUX_PRESET;
+ mDescriptor = &lvm::kAuxPresetReverbDesc;
+ mEffectName = &lvm::kAuxPresetReverbEffectName;
+ } else if (uuid == kInsertPresetReverbImplUUID) {
+ mType = lvm::ReverbEffectType::INSERT_PRESET;
+ mDescriptor = &lvm::kInsertPresetReverbDesc;
+ mEffectName = &lvm::kInsertPresetReverbEffectName;
+ } else {
+ LOG(ERROR) << __func__ << uuid.toString() << " not supported!";
+ }
+}
+
+EffectReverb::~EffectReverb() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+}
+
+ndk::ScopedAStatus EffectReverb::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 EffectReverb::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::presetReverb:
+ return setParameterPresetReverb(specific);
+ case Parameter::Specific::environmentalReverb:
+ return setParameterEnvironmentalReverb(specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "specificParamNotSupported");
+ }
+}
+
+ndk::ScopedAStatus EffectReverb::setParameterPresetReverb(const Parameter::Specific& specific) {
+ auto& prParam = specific.get<Parameter::Specific::presetReverb>();
+ auto tag = prParam.getTag();
+
+ switch (tag) {
+ case PresetReverb::preset: {
+ RETURN_IF(mContext->setPresetReverbPreset(prParam.get<PresetReverb::preset>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setPresetFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectReverb::setParameterEnvironmentalReverb(
+ const Parameter::Specific& specific) {
+ auto& erParam = specific.get<Parameter::Specific::environmentalReverb>();
+ auto tag = erParam.getTag();
+
+ switch (tag) {
+ case EnvironmentalReverb::roomLevelMb: {
+ RETURN_IF(mContext->setEnvironmentalReverbRoomLevel(
+ erParam.get<EnvironmentalReverb::roomLevelMb>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setRoomLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::roomHfLevelMb: {
+ RETURN_IF(
+ mContext->setEnvironmentalReverbRoomHfLevel(
+ erParam.get<EnvironmentalReverb::roomHfLevelMb>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setRoomHfLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::decayTimeMs: {
+ RETURN_IF(mContext->setEnvironmentalReverbDecayTime(
+ erParam.get<EnvironmentalReverb::decayTimeMs>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDecayTimeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::decayHfRatioPm: {
+ RETURN_IF(
+ mContext->setEnvironmentalReverbDecayHfRatio(
+ erParam.get<EnvironmentalReverb::decayHfRatioPm>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDecayHfRatioFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::levelMb: {
+ RETURN_IF(mContext->setEnvironmentalReverbLevel(
+ erParam.get<EnvironmentalReverb::levelMb>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setLevelFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::delayMs: {
+ RETURN_IF(mContext->setEnvironmentalReverbDelay(
+ erParam.get<EnvironmentalReverb::delayMs>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDelayFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::diffusionPm: {
+ RETURN_IF(mContext->setEnvironmentalReverbDiffusion(
+ erParam.get<EnvironmentalReverb::diffusionPm>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDiffusionFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::densityPm: {
+ RETURN_IF(mContext->setEnvironmentalReverbDensity(
+ erParam.get<EnvironmentalReverb::densityPm>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setDensityFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case EnvironmentalReverb::bypass: {
+ RETURN_IF(mContext->setEnvironmentalReverbBypass(
+ erParam.get<EnvironmentalReverb::bypass>()) != RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setBypassFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus EffectReverb::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+
+ switch (tag) {
+ case Parameter::Id::presetReverbTag:
+ return getParameterPresetReverb(id.get<Parameter::Id::presetReverbTag>(), specific);
+ case Parameter::Id::environmentalReverbTag:
+ return getParameterEnvironmentalReverb(id.get<Parameter::Id::environmentalReverbTag>(),
+ specific);
+ default:
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "wrongIdTag");
+ }
+}
+
+ndk::ScopedAStatus EffectReverb::getParameterPresetReverb(const PresetReverb::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != PresetReverb::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ PresetReverb prParam;
+ auto tag = id.get<PresetReverb::Id::commonTag>();
+ switch (tag) {
+ case PresetReverb::preset: {
+ prParam.set<PresetReverb::preset>(mContext->getPresetReverbPreset());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "PresetReverbTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::presetReverb>(prParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectReverb::getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(id.getTag() != EnvironmentalReverb::Id::commonTag, EX_ILLEGAL_ARGUMENT,
+ "EnvironmentalReverbTagNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ EnvironmentalReverb erParam;
+
+ auto tag = id.get<EnvironmentalReverb::Id::commonTag>();
+ switch (tag) {
+ case EnvironmentalReverb::roomLevelMb: {
+ erParam.set<EnvironmentalReverb::roomLevelMb>(
+ mContext->getEnvironmentalReverbRoomLevel());
+ break;
+ }
+ case EnvironmentalReverb::roomHfLevelMb: {
+ erParam.set<EnvironmentalReverb::roomHfLevelMb>(
+ mContext->getEnvironmentalReverbRoomHfLevel());
+ break;
+ }
+ case EnvironmentalReverb::decayTimeMs: {
+ erParam.set<EnvironmentalReverb::decayTimeMs>(
+ mContext->getEnvironmentalReverbDecayTime());
+ break;
+ }
+ case EnvironmentalReverb::decayHfRatioPm: {
+ erParam.set<EnvironmentalReverb::decayHfRatioPm>(
+ mContext->getEnvironmentalReverbDecayHfRatio());
+ break;
+ }
+ case EnvironmentalReverb::levelMb: {
+ erParam.set<EnvironmentalReverb::levelMb>(mContext->getEnvironmentalReverbLevel());
+ break;
+ }
+ case EnvironmentalReverb::delayMs: {
+ erParam.set<EnvironmentalReverb::delayMs>(mContext->getEnvironmentalReverbDelay());
+ break;
+ }
+ case EnvironmentalReverb::diffusionPm: {
+ erParam.set<EnvironmentalReverb::diffusionPm>(
+ mContext->getEnvironmentalReverbDiffusion());
+ break;
+ }
+ case EnvironmentalReverb::densityPm: {
+ erParam.set<EnvironmentalReverb::densityPm>(mContext->getEnvironmentalReverbDensity());
+ break;
+ }
+ case EnvironmentalReverb::bypass: {
+ erParam.set<EnvironmentalReverb::bypass>(mContext->getEnvironmentalReverbBypass());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "EnvironmentalReverbTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::environmentalReverb>(erParam);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> EffectReverb::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ } else {
+ mContext = std::make_shared<ReverbContext>(1 /* statusFmqDepth */, common, mType);
+ }
+
+ return mContext;
+}
+
+std::shared_ptr<EffectContext> EffectReverb::getContext() {
+ return mContext;
+}
+
+RetCode EffectReverb::releaseContext() {
+ if (mContext) {
+ mContext.reset();
+ }
+ return RetCode::SUCCESS;
+}
+
+ndk::ScopedAStatus EffectReverb::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 EffectReverb::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/lvm/wrapper/Reverb/aidl/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
new file mode 100644
index 0000000..d7d2bbd
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
@@ -0,0 +1,64 @@
+/*
+ * 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 "effect-impl/EffectImpl.h"
+#include "ReverbContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class EffectReverb final : public EffectImpl {
+ public:
+ explicit EffectReverb(const AudioUuid& uuid);
+ ~EffectReverb() 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<ReverbContext> mContext;
+ const Descriptor* mDescriptor;
+ const std::string* mEffectName;
+ lvm::ReverbEffectType mType;
+
+ IEffect::Status status(binder_status_t status, size_t consumed, size_t produced);
+
+ ndk::ScopedAStatus setParameterPresetReverb(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Id& id,
+ Parameter::Specific* specific);
+
+ ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific);
+ ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
new file mode 100644
index 0000000..d35c22b
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
@@ -0,0 +1,560 @@
+/*
+ * 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 "ReverbContext"
+#include <Utils.h>
+
+#include "ReverbContext.h"
+#include "VectorArithmetic.h"
+#include "math.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+using aidl::android::media::audio::common::AudioDeviceDescription;
+using aidl::android::media::audio::common::AudioDeviceType;
+
+#define GOTO_IF_LVREV_ERROR(status, tag, log) \
+ do { \
+ LVREV_ReturnStatus_en temp = (status); \
+ if (temp != LVREV_SUCCESS) { \
+ LOG(ERROR) << __func__ << " return status: " << temp << " " << (log); \
+ goto tag; \
+ } \
+ } while (0)
+
+RetCode ReverbContext::init() {
+ if (isPreset()) {
+ // force reloading preset at first call to process()
+ mPreset = PresetReverb::Presets::NONE;
+ mNextPreset = PresetReverb::Presets::NONE;
+ }
+
+ mVolume.left = kUnitVolume;
+ mVolume.right = kUnitVolume;
+ mPrevVolume.left = kUnitVolume;
+ mPrevVolume.right = kUnitVolume;
+ volumeMode = VOLUME_FLAT;
+
+ mSamplesToExitCount = kDefaultDecayTime * mCommon.input.base.sampleRate / 1000;
+
+ /* Saved strength is used to return the exact strength that was used in the set to the get
+ * because we map the original strength range of 0:1000 to 1:15, and this will avoid
+ * quantisation like effect when returning
+ */
+ mRoomLevel = lvm::kMinLevel;
+ mRoomHfLevel = 0;
+ mEnabled = LVM_FALSE;
+ mDecayTime = kDefaultDecayTime;
+ mDecayHfRatio = kDefaultDamping * 20;
+ mDensity = kDefaultRoomSize * 10;
+ mDiffusion = kDefaultDensity * 10;
+ mLevel = lvm::kMinLevel;
+
+ // allocate lvm reverb instance
+ LVREV_ReturnStatus_en status = LVREV_SUCCESS;
+ {
+ std::lock_guard lg(mMutex);
+ LVREV_InstanceParams_st params = {
+ .MaxBlockSize = lvm::kMaxCallSize,
+ // Max format, could be mono during process
+ .SourceFormat = LVM_STEREO,
+ .NumDelays = LVREV_DELAYLINES_4,
+ };
+ /* Init sets the instance handle */
+ status = LVREV_GetInstanceHandle(&mInstance, ¶ms);
+ GOTO_IF_LVREV_ERROR(status, deinit, "LVREV_GetInstanceHandleFailed");
+
+ // set control
+ LVREV_ControlParams_st controlParams;
+ initControlParameter(controlParams);
+ status = LVREV_SetControlParameters(mInstance, &controlParams);
+ GOTO_IF_LVREV_ERROR(status, deinit, "LVREV_SetControlParametersFailed");
+ }
+
+ return RetCode::SUCCESS;
+
+deinit:
+ deInit();
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+}
+
+void ReverbContext::deInit() {
+ std::lock_guard lg(mMutex);
+ if (mInstance) {
+ LVREV_FreeInstance(mInstance);
+ mInstance = nullptr;
+ }
+}
+
+RetCode ReverbContext::enable() {
+ if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
+ mEnabled = true;
+ mSamplesToExitCount = (mDecayTime * mCommon.input.base.sampleRate) / 1000;
+ // force no volume ramp for first buffer processed after enabling the effect
+ volumeMode = VOLUME_FLAT;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::disable() {
+ if (!mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
+ mEnabled = false;
+ return RetCode::SUCCESS;
+}
+
+bool ReverbContext::isAuxiliary() {
+ return (mType == lvm::ReverbEffectType::AUX_ENV || mType == lvm::ReverbEffectType::AUX_PRESET);
+}
+
+bool ReverbContext::isPreset() {
+ return (mType == lvm::ReverbEffectType::AUX_PRESET ||
+ mType == lvm::ReverbEffectType::INSERT_PRESET);
+}
+
+RetCode ReverbContext::setVolumeStereo(const Parameter::VolumeStereo& volume) {
+ if (volumeMode == VOLUME_OFF) {
+ // force no volume ramp for first buffer processed after getting volume control
+ volumeMode = VOLUME_FLAT;
+ }
+ mVolumeStereo = volume;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setPresetReverbPreset(const PresetReverb::Presets& preset) {
+ mNextPreset = preset;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbRoomLevel(int roomLevel) {
+ if (roomLevel < lvm::kEnvReverbCap.minRoomLevelMb ||
+ roomLevel > lvm::kEnvReverbCap.maxRoomLevelMb) {
+ LOG(ERROR) << __func__ << " invalid roomLevel: " << roomLevel;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ // Sum of room and reverb level controls
+ // needs to subtract max levels for both room level and reverb level
+ int combinedLevel = (roomLevel + mLevel) - lvm::kMaxReverbLevel;
+ params.Level = convertLevel(combinedLevel);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mRoomLevel = roomLevel;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbRoomHfLevel(int roomHfLevel) {
+ if (roomHfLevel < lvm::kEnvReverbCap.minRoomHfLevelMb ||
+ roomHfLevel > lvm::kEnvReverbCap.maxRoomHfLevelMb) {
+ LOG(ERROR) << __func__ << " invalid roomHfLevel: " << roomHfLevel;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.LPF = convertHfLevel(roomHfLevel);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mRoomHfLevel = roomHfLevel;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbDecayTime(int decayTime) {
+ if (decayTime < 0 || decayTime > lvm::kEnvReverbCap.maxDecayTimeMs) {
+ LOG(ERROR) << __func__ << " invalid decayTime: " << decayTime;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ int time = decayTime;
+ if (time > lvm::kMaxT60) {
+ time = lvm::kMaxT60;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.T60 = (LVM_UINT16)time;
+ mSamplesToExitCount = (params.T60 * mCommon.input.base.sampleRate) / 1000;
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mDecayTime = time;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbDecayHfRatio(int decayHfRatio) {
+ if (decayHfRatio < lvm::kEnvReverbCap.minDecayHfRatioPm ||
+ decayHfRatio > lvm::kEnvReverbCap.maxDecayHfRatioPm) {
+ LOG(ERROR) << __func__ << " invalid decayHfRatio: " << decayHfRatio;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.Damping = (LVM_INT16)(decayHfRatio / 20);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mDecayHfRatio = decayHfRatio;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbLevel(int level) {
+ if (level < lvm::kEnvReverbCap.minLevelMb || level > lvm::kEnvReverbCap.maxLevelMb) {
+ LOG(ERROR) << __func__ << " invalid level: " << level;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ // Sum of room and reverb level controls
+ // needs to subtract max levels for both room level and level
+ int combinedLevel = (level + mRoomLevel) - lvm::kMaxReverbLevel;
+ params.Level = convertLevel(combinedLevel);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mLevel = level;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbDelay(int delay) {
+ if (delay < 0 || delay > lvm::kEnvReverbCap.maxDelayMs) {
+ LOG(ERROR) << __func__ << " invalid delay: " << delay;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mDelay = delay;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbDiffusion(int diffusion) {
+ if (diffusion < 0 || diffusion > lvm::kEnvReverbCap.maxDiffusionPm) {
+ LOG(ERROR) << __func__ << " invalid diffusion: " << diffusion;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.Density = (LVM_INT16)(diffusion / 10);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mDiffusion = diffusion;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbDensity(int density) {
+ if (density < 0 || density > lvm::kEnvReverbCap.maxDensityPm) {
+ LOG(ERROR) << __func__ << " invalid density: " << density;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ // Update Control Parameter
+ LVREV_ControlParams_st params;
+ {
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_GetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " getControlParamFailed");
+
+ params.RoomSize = (LVM_INT16)(((density * 99) / 1000) + 1);
+
+ RETURN_VALUE_IF(LVREV_SUCCESS != LVREV_SetControlParameters(mInstance, ¶ms),
+ RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
+ }
+ mDensity = density;
+ return RetCode::SUCCESS;
+}
+
+RetCode ReverbContext::setEnvironmentalReverbBypass(bool bypass) {
+ mBypass = bypass;
+ return RetCode::SUCCESS;
+}
+
+void ReverbContext::loadPreset() {
+ // TODO: add delay when early reflections are implemented
+ mPreset = mNextPreset;
+
+ if (mPreset != PresetReverb::Presets::NONE) {
+ const t_reverb_settings preset = mReverbPresets[mPreset];
+ setEnvironmentalReverbRoomLevel(preset.roomLevel);
+ setEnvironmentalReverbRoomHfLevel(preset.roomHFLevel);
+ setEnvironmentalReverbDecayTime(preset.decayTime);
+ setEnvironmentalReverbDecayHfRatio(preset.decayHFRatio);
+ setEnvironmentalReverbLevel(preset.reverbLevel);
+ // reverbDelay
+ setEnvironmentalReverbDiffusion(preset.diffusion);
+ setEnvironmentalReverbDensity(preset.density);
+ }
+}
+
+void ReverbContext::initControlParameter(LVREV_ControlParams_st& params) {
+ /* Set the initial process parameters */
+ /* General parameters */
+ params.OperatingMode = LVM_MODE_ON;
+ params.SampleRate = LVM_FS_44100;
+ params.SourceFormat = (::android::hardware::audio::common::getChannelCount(
+ mCommon.input.base.channelMask) == 1
+ ? LVM_MONO
+ : LVM_STEREO);
+
+ if (!isAuxiliary() && params.SourceFormat == LVM_MONO) {
+ params.SourceFormat = LVM_STEREO;
+ }
+
+ /* Reverb parameters */
+ params.Level = kDefaultLevel;
+ params.LPF = kDefaultLPF;
+ params.HPF = kDefaultHPF;
+ params.T60 = kDefaultDecayTime;
+ params.Density = kDefaultDensity;
+ params.Damping = kDefaultDamping;
+ params.RoomSize = kDefaultRoomSize;
+}
+
+/*
+ * Convert level from OpenSL ES format to LVM format
+ *
+ * @param level : level to be applied
+ */
+
+int ReverbContext::convertLevel(int level) {
+ for (int i = 0; i < kLevelMapping.size(); i++) {
+ if (level <= kLevelMapping[i]) {
+ return i;
+ }
+ }
+ return kDefaultLevel;
+}
+
+/*
+ * Convert level HF from OpenSL ES format to LVM format
+ *
+ * @param hfLevel : level to be applied
+ */
+
+int16_t ReverbContext::convertHfLevel(int hfLevel) {
+ for (auto lpfPair : kLPFMapping) {
+ if (hfLevel <= lpfPair.roomHf) {
+ return lpfPair.lpf;
+ }
+ }
+ return kDefaultLPF;
+}
+
+IEffect::Status ReverbContext::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);
+
+ int channels =
+ ::android::hardware::audio::common::getChannelCount(mCommon.input.base.channelMask);
+ int outChannels =
+ ::android::hardware::audio::common::getChannelCount(mCommon.output.base.channelMask);
+ int frameCount = mCommon.input.frameCount;
+
+ // Reverb only effects the stereo channels in multichannel source.
+ if (channels < 1 || channels > LVM_MAX_CHANNELS) {
+ LOG(ERROR) << __func__ << " process invalid PCM channels " << channels;
+ return status;
+ }
+
+ std::vector<float> inFrames(samples);
+ std::vector<float> outFrames(frameCount * FCC_2);
+
+ if (isPreset() && mNextPreset != mPreset) {
+ loadPreset();
+ }
+
+ if (isAuxiliary()) {
+ inFrames.assign(in, in + samples);
+ } else {
+ // mono input is duplicated
+ if (channels >= FCC_2) {
+ for (int i = 0; i < frameCount; i++) {
+ inFrames[FCC_2 * i] = in[channels * i] * kSendLevel;
+ inFrames[FCC_2 * i + 1] = in[channels * i + 1] * kSendLevel;
+ }
+ } else {
+ for (int i = 0; i < frameCount; i++) {
+ inFrames[FCC_2 * i] = inFrames[FCC_2 * i + 1] = in[i] * kSendLevel;
+ }
+ }
+ }
+
+ if (isPreset() && mPreset == PresetReverb::Presets::NONE) {
+ std::fill(outFrames.begin(), outFrames.end(), 0); // always stereo here
+ } else {
+ if (!mEnabled && mSamplesToExitCount > 0) {
+ std::fill(outFrames.begin(), outFrames.end(), 0);
+ LOG(VERBOSE) << "Zeroing " << channels << " samples per frame at the end of call ";
+ }
+
+ /* Process the samples, producing a stereo output */
+ LVREV_ReturnStatus_en lvrevStatus =
+ LVREV_Process(mInstance, /* Instance handle */
+ inFrames.data(), /* Input buffer */
+ outFrames.data(), /* Output buffer */
+ frameCount); /* Number of samples to read */
+ if (lvrevStatus != LVREV_SUCCESS) {
+ LOG(ERROR) << __func__ << lvrevStatus;
+ return {EX_UNSUPPORTED_OPERATION, 0, 0};
+ }
+ }
+ // Convert to 16 bits
+ if (isAuxiliary()) {
+ // nothing to do here
+ } else {
+ if (channels >= FCC_2) {
+ for (int i = 0; i < frameCount; i++) {
+ // Mix with dry input
+ outFrames[FCC_2 * i] += in[channels * i];
+ outFrames[FCC_2 * i + 1] += in[channels * i + 1];
+ }
+ } else {
+ for (int i = 0; i < frameCount; i++) {
+ // Mix with dry input
+ outFrames[FCC_2 * i] += in[i];
+ outFrames[FCC_2 * i + 1] += in[i];
+ }
+ }
+
+ // apply volume with ramp if needed
+ if (mVolume != mPrevVolume && volumeMode == VOLUME_RAMP) {
+ float vl = mPrevVolume.left;
+ float incl = (mVolume.left - vl) / frameCount;
+ float vr = mPrevVolume.right;
+ float incr = (mVolume.right - vr) / frameCount;
+
+ for (int i = 0; i < frameCount; i++) {
+ outFrames[FCC_2 * i] *= vl;
+ outFrames[FCC_2 * i + 1] *= vr;
+
+ vl += incl;
+ vr += incr;
+ }
+ mPrevVolume = mVolume;
+ } else if (volumeMode != VOLUME_OFF) {
+ if (mVolume.left != kUnitVolume || mVolume.right != kUnitVolume) {
+ for (int i = 0; i < frameCount; i++) {
+ outFrames[FCC_2 * i] *= mVolume.left;
+ outFrames[FCC_2 * i + 1] *= mVolume.right;
+ }
+ }
+ mPrevVolume = mVolume;
+ volumeMode = VOLUME_RAMP;
+ }
+ }
+
+ bool accumulate = false;
+ if (outChannels > 2) {
+ // Accumulate if required
+ if (accumulate) {
+ for (int i = 0; i < frameCount; i++) {
+ out[outChannels * i] += outFrames[FCC_2 * i];
+ out[outChannels * i + 1] += outFrames[FCC_2 * i + 1];
+ }
+ } else {
+ for (int i = 0; i < frameCount; i++) {
+ out[outChannels * i] = outFrames[FCC_2 * i];
+ out[outChannels * i + 1] = outFrames[FCC_2 * i + 1];
+ }
+ }
+ if (!isAuxiliary()) {
+ for (int i = 0; i < frameCount; i++) {
+ // channels and outChannels are expected to be same.
+ for (int j = FCC_2; j < outChannels; j++) {
+ out[outChannels * i + j] = in[outChannels * i + j];
+ }
+ }
+ }
+ } else {
+ if (accumulate) {
+ if (outChannels == FCC_1) {
+ for (int i = 0; i < frameCount; i++) {
+ out[i] += ((outFrames[i * FCC_2] + outFrames[i * FCC_2 + 1]) * 0.5f);
+ }
+ } else {
+ for (int i = 0; i < frameCount * FCC_2; i++) {
+ out[i] += outFrames[i];
+ }
+ }
+ } else {
+ if (outChannels == FCC_1) {
+ From2iToMono_Float(outFrames.data(), out, frameCount);
+ } else {
+ for (int i = 0; i < frameCount * FCC_2; i++) {
+ out[i] = outFrames[i];
+ }
+ }
+ }
+ }
+
+ LOG(DEBUG) << __func__ << " done processing";
+
+ if (!mEnabled && mSamplesToExitCount > 0) {
+ // signed - unsigned will trigger integer overflow if result becomes negative.
+ mSamplesToExitCount -= samples;
+ }
+
+ return {STATUS_OK, samples, outChannels * frameCount};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
new file mode 100644
index 0000000..af49a25
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.h
@@ -0,0 +1,174 @@
+/*
+ * 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 <unordered_map>
+
+#include "ReverbTypes.h"
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+enum VolumeMode {
+ VOLUME_OFF,
+ VOLUME_FLAT,
+ VOLUME_RAMP,
+};
+
+struct LPFPair {
+ int roomHf;
+ int lpf;
+};
+
+class ReverbContext final : public EffectContext {
+ public:
+ ReverbContext(int statusDepth, const Parameter::Common& common,
+ const lvm::ReverbEffectType& type)
+ : EffectContext(statusDepth, common), mType(type) {
+ LOG(DEBUG) << __func__ << type;
+ init();
+ }
+ ~ReverbContext() override {
+ LOG(DEBUG) << __func__;
+ deInit();
+ }
+
+ RetCode init();
+ void deInit();
+
+ RetCode enable();
+ RetCode disable();
+
+ bool isAuxiliary();
+ bool isPreset();
+
+ RetCode setPresetReverbPreset(const PresetReverb::Presets& preset);
+ PresetReverb::Presets getPresetReverbPreset() const { return mNextPreset; }
+
+ RetCode setEnvironmentalReverbRoomLevel(int roomLevel);
+ int getEnvironmentalReverbRoomLevel() const { return mRoomLevel; }
+ RetCode setEnvironmentalReverbRoomHfLevel(int roomHfLevel);
+ int getEnvironmentalReverbRoomHfLevel() const { return mRoomHfLevel; }
+ RetCode setEnvironmentalReverbDecayTime(int decayTime);
+ int getEnvironmentalReverbDecayTime() const { return mDecayTime; }
+ RetCode setEnvironmentalReverbDecayHfRatio(int decayHfRatio);
+ int getEnvironmentalReverbDecayHfRatio() const { return mDecayHfRatio; }
+ RetCode setEnvironmentalReverbLevel(int level);
+ int getEnvironmentalReverbLevel() const { return mLevel; }
+ RetCode setEnvironmentalReverbDelay(int delay);
+ int getEnvironmentalReverbDelay() const { return mDelay; }
+ RetCode setEnvironmentalReverbDiffusion(int diffusion);
+ int getEnvironmentalReverbDiffusion() const { return mDiffusion; }
+ RetCode setEnvironmentalReverbDensity(int density);
+ int getEnvironmentalReverbDensity() const { return mDensity; }
+ RetCode setEnvironmentalReverbBypass(bool bypass);
+ bool getEnvironmentalReverbBypass() const { return mBypass; }
+
+ RetCode setVolumeStereo(const Parameter::VolumeStereo& volumeStereo) override;
+ Parameter::VolumeStereo getVolumeStereo() override { return mVolumeStereo; }
+
+ IEffect::Status lvmProcess(float* in, float* out, int samples);
+
+ private:
+ static constexpr inline float kUnitVolume = 1;
+ static constexpr inline float kSendLevel = 0.75f;
+ static constexpr inline int kDefaultLevel = 0;
+ static constexpr inline int kDefaultLPF = 23999; /* Default low pass filter, in Hz */
+ static constexpr inline int kDefaultHPF = 50; /* Default high pass filter, in Hz */
+ static constexpr inline int kDefaultDecayTime = 1490; /* Default Decay time, in ms */
+ static constexpr inline int kDefaultDensity = 100; /* Default Echo density */
+ static constexpr inline int kDefaultDamping = 21;
+ static constexpr inline int kDefaultRoomSize = 100;
+
+ static inline const std::vector<LPFPair> kLPFMapping = {
+ // Limit range to 50 for LVREV parameter range
+ {-10000, 50}, {-5000, 50}, {-4000, 50}, {-3000, 158}, {-2000, 502}, {-1000, 1666},
+ {-900, 1897}, {-800, 2169}, {-700, 2496}, {-600, 2895}, {-500, 3400}, {-400, 4066},
+ {-300, 5011}, {-200, 6537}, {-100, 9826}, {-99, 9881}, {-98, 9937}, {-97, 9994},
+ {-96, 10052}, {-95, 10111}, {-94, 10171}, {-93, 10231}, {-92, 10293}, {-91, 10356},
+ {-90, 10419}, {-89, 10484}, {-88, 10549}, {-87, 10616}, {-86, 10684}, {-85, 10753},
+ {-84, 10823}, {-83, 10895}, {-82, 10968}, {-81, 11042}, {-80, 11117}, {-79, 11194},
+ {-78, 11272}, {-77, 11352}, {-76, 11433}, {-75, 11516}, {-74, 11600}, {-73, 11686},
+ {-72, 11774}, {-71, 11864}, {-70, 11955}, {-69, 12049}, {-68, 12144}, {-67, 12242},
+ {-66, 12341}, {-65, 12443}, {-64, 12548}, {-63, 12654}, {-62, 12763}, {-61, 12875},
+ {-60, 12990}, {-59, 13107}, {-58, 13227}, {-57, 13351}, {-56, 13477}, {-55, 13607},
+ {-54, 13741}, {-53, 13878}, {-52, 14019}, {-51, 14164}, {-50, 14313}, {-49, 14467},
+ {-48, 14626}, {-47, 14789}, {-46, 14958}, {-45, 15132}, {-44, 15312}, {-43, 15498},
+ {-42, 15691}, {-41, 15890}, {-40, 16097}, {-39, 16311}, {-38, 16534}, {-37, 16766},
+ {-36, 17007}, {-35, 17259}, {-34, 17521}, {-33, 17795}, {-32, 18081}, {-31, 18381},
+ {-30, 18696}, {-29, 19027}, {-28, 19375}, {-27, 19742}, {-26, 20129}, {-25, 20540},
+ {-24, 20976}, {-23, 21439}, {-22, 21934}, {-21, 22463}, {-20, 23031}, {-19, 23643},
+ {-18, 23999}};
+
+ static inline const std::vector<int> kLevelMapping = {
+ -12000, -4000, -3398, -3046, -2796, -2603, -2444, -2310, -2194, -2092, -2000, -1918,
+ -1842, -1773, -1708, -1648, -1592, -1540, -1490, -1443, -1398, -1356, -1316, -1277,
+ -1240, -1205, -1171, -1138, -1106, -1076, -1046, -1018, -990, -963, -938, -912,
+ -888, -864, -841, -818, -796, -775, -754, -734, -714, -694, -675, -656,
+ -638, -620, -603, -585, -568, -552, -536, -520, -504, -489, -474, -459,
+ -444, -430, -416, -402, -388, -375, -361, -348, -335, -323, -310, -298,
+ -286, -274, -262, -250, -239, -228, -216, -205, -194, -184, -173, -162,
+ -152, -142, -132, -121, -112, -102, -92, -82, -73, -64, -54, -45,
+ -36, -27, -18, -9, 0};
+
+ static inline std::unordered_map<PresetReverb::Presets, t_reverb_settings> mReverbPresets = {
+ {PresetReverb::Presets::NONE, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+ {PresetReverb::Presets::SMALLROOM,
+ {-400, -600, 1100, 830, -400, 5, 500, 10, 1000, 1000}},
+ {PresetReverb::Presets::MEDIUMROOM,
+ {-400, -600, 1300, 830, -1000, 20, -200, 20, 1000, 1000}},
+ {PresetReverb::Presets::LARGEROOM,
+ {-400, -600, 1500, 830, -1600, 5, -1000, 40, 1000, 1000}},
+ {PresetReverb::Presets::MEDIUMHALL,
+ {-400, -600, 1800, 700, -1300, 15, -800, 30, 1000, 1000}},
+ {PresetReverb::Presets::LARGEHALL,
+ {-400, -600, 1800, 700, -2000, 30, -1400, 60, 1000, 1000}},
+ {PresetReverb::Presets::PLATE, {-400, -200, 1300, 900, 0, 2, 0, 10, 1000, 750}}};
+
+ std::mutex mMutex;
+ const lvm::ReverbEffectType mType;
+ bool mEnabled = false;
+ LVREV_Handle_t mInstance GUARDED_BY(mMutex);
+
+ int mRoomLevel;
+ int mRoomHfLevel;
+ int mDecayTime;
+ int mDecayHfRatio;
+ int mLevel;
+ int mDelay;
+ int mDiffusion;
+ int mDensity;
+ bool mBypass;
+
+ PresetReverb::Presets mPreset;
+ PresetReverb::Presets mNextPreset;
+
+ int mSamplesToExitCount;
+
+ Parameter::VolumeStereo mVolume;
+ Parameter::VolumeStereo mPrevVolume;
+ VolumeMode volumeMode;
+
+ void initControlParameter(LVREV_ControlParams_st& params);
+ int16_t convertHfLevel(int hfLevel);
+ int convertLevel(int level);
+ void loadPreset();
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h
new file mode 100644
index 0000000..e37602c
--- /dev/null
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbTypes.h
@@ -0,0 +1,150 @@
+/*
+ * 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 <android/binder_enums.h>
+#include <audio_effects/effect_environmentalreverb.h>
+#include <audio_effects/effect_presetreverb.h>
+#include "effect-impl/EffectUUID.h"
+// from Reverb/lib
+#include "LVREV.h"
+
+namespace aidl::android::hardware::audio::effect {
+namespace lvm {
+
+constexpr inline int kMaxCallSize = 256;
+constexpr inline int kMinLevel = -6000;
+constexpr inline int kMaxT60 = 7000; /* Maximum decay time */
+constexpr inline int kMaxReverbLevel = 2000;
+constexpr inline int kMaxFrameSize = 2560;
+constexpr inline int kCpuLoadARM9E = 470; // Expressed in 0.1 MIPS
+constexpr inline int kMemUsage = (71 + (kMaxFrameSize >> 7)); // Expressed in kB
+
+static const EnvironmentalReverb::Capability kEnvReverbCap = {.minRoomLevelMb = lvm::kMinLevel,
+ .maxRoomLevelMb = 0,
+ .minRoomHfLevelMb = -4000,
+ .maxRoomHfLevelMb = 0,
+ .maxDecayTimeMs = lvm::kMaxT60,
+ .minDecayHfRatioPm = 100,
+ .maxDecayHfRatioPm = 2000,
+ .minLevelMb = lvm::kMinLevel,
+ .maxLevelMb = 0,
+ .maxDelayMs = 65,
+ .maxDiffusionPm = 1000,
+ .maxDensityPm = 1000};
+
+// NXP SW auxiliary environmental reverb
+static const std::string kAuxEnvReverbEffectName = "Auxiliary Environmental Reverb";
+static const Descriptor kAuxEnvReverbDesc = {
+ .common = {.id = {.type = kEnvReverbTypeUUID,
+ .uuid = kAuxEnvReverbImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::AUXILIARY},
+ .cpuLoad = kCpuLoadARM9E,
+ .memoryUsage = kMemUsage,
+ .name = kAuxEnvReverbEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::environmentalReverb>(kEnvReverbCap)};
+
+// NXP SW insert environmental reverb
+static const std::string kInsertEnvReverbEffectName = "Insert Environmental Reverb";
+static const Descriptor kInsertEnvReverbDesc = {
+ .common = {.id = {.type = kEnvReverbTypeUUID,
+ .uuid = kInsertEnvReverbImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .cpuLoad = kCpuLoadARM9E,
+ .memoryUsage = kMemUsage,
+ .name = kInsertEnvReverbEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::environmentalReverb>(kEnvReverbCap)};
+
+static const std::vector<PresetReverb::Presets> kSupportedPresets{
+ ndk::enum_range<PresetReverb::Presets>().begin(),
+ ndk::enum_range<PresetReverb::Presets>().end()};
+static const PresetReverb::Capability kPresetReverbCap = {.supportedPresets = kSupportedPresets};
+
+// NXP SW auxiliary preset reverb
+static const std::string kAuxPresetReverbEffectName = "Auxiliary Preset Reverb";
+static const Descriptor kAuxPresetReverbDesc = {
+ .common = {.id = {.type = kPresetReverbTypeUUID,
+ .uuid = kAuxPresetReverbImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::AUXILIARY},
+ .cpuLoad = kCpuLoadARM9E,
+ .memoryUsage = kMemUsage,
+ .name = kAuxPresetReverbEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::presetReverb>(kPresetReverbCap)};
+
+// NXP SW insert preset reverb
+static const std::string kInsertPresetReverbEffectName = "Insert Preset Reverb";
+static const Descriptor kInsertPresetReverbDesc = {
+ .common = {.id = {.type = kPresetReverbTypeUUID,
+ .uuid = kInsertPresetReverbImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::FIRST,
+ .volume = Flags::Volume::CTRL},
+ .cpuLoad = kCpuLoadARM9E,
+ .memoryUsage = kMemUsage,
+ .name = kInsertPresetReverbEffectName,
+ .implementor = "NXP Software Ltd."},
+ .capability = Capability::make<Capability::presetReverb>(kPresetReverbCap)};
+
+enum class ReverbEffectType {
+ AUX_ENV,
+ INSERT_ENV,
+ AUX_PRESET,
+ INSERT_PRESET,
+};
+
+inline std::ostream& operator<<(std::ostream& out, const ReverbEffectType& type) {
+ switch (type) {
+ case ReverbEffectType::AUX_ENV:
+ return out << kAuxEnvReverbEffectName;
+ case ReverbEffectType::INSERT_ENV:
+ return out << kInsertEnvReverbEffectName;
+ case ReverbEffectType::AUX_PRESET:
+ return out << kAuxPresetReverbEffectName;
+ case ReverbEffectType::INSERT_PRESET:
+ return out << kInsertPresetReverbEffectName;
+ }
+ return out << "EnumReverbEffectTypeError";
+}
+
+inline std::ostream& operator<<(std::ostream& out, const LVREV_ReturnStatus_en& status) {
+ switch (status) {
+ case LVREV_SUCCESS:
+ return out << "LVREV_SUCCESS";
+ case LVREV_NULLADDRESS:
+ return out << "LVREV_NULLADDRESS";
+ case LVREV_OUTOFRANGE:
+ return out << "LVREV_OUTOFRANGE";
+ case LVREV_INVALIDNUMSAMPLES:
+ return out << "LVREV_INVALIDNUMSAMPLES";
+ case LVREV_RETURNSTATUS_DUMMY:
+ return out << "LVREV_RETURNSTATUS_DUMMY";
+ }
+ return out << "EnumLvrevRetStatusError";
+}
+
+} // namespace lvm
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 61a2bf5..59f1fc3 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -102,7 +102,8 @@
uint32_t state; // current state (enum preproc_session_state)
int id; // audio session ID
int io; // handle of input stream this session is on
- webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
+ rtc::scoped_refptr<webrtc::AudioProcessing>
+ apm; // handle on webRTC audio processing module (APM)
// Audio Processing module builder
webrtc::AudioProcessingBuilder ap_builder;
// frameCount represents the size of the buffers used for processing, and must represent 10ms.
@@ -260,9 +261,6 @@
ALOGV("Agc2Init");
effect->session->config = effect->session->apm->GetConfig();
effect->session->config.gain_controller2.fixed_digital.gain_db = 0.f;
- effect->session->config.gain_controller2.adaptive_digital.level_estimator =
- effect->session->config.gain_controller2.kRms;
- effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db = 2.f;
effect->session->apm->ApplyConfig(effect->session->config);
return 0;
}
@@ -332,24 +330,19 @@
ALOGV("Agc2GetParameter() target level %f dB", *(float*)pValue);
break;
case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
- *(uint32_t*)pValue = (uint32_t)(
- effect->session->config.gain_controller2.adaptive_digital.level_estimator);
- ALOGV("Agc2GetParameter() level estimator %d",
- *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
+ // WebRTC only supports RMS level estimator now
+ *(uint32_t*)pValue = (uint32_t)(0);
+ ALOGV("Agc2GetParameter() level estimator RMS");
break;
case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
- *(float*)pValue = (float)(effect->session->config.gain_controller2.adaptive_digital
- .extra_saturation_margin_db);
+ *(float*)pValue = (float)(2.0);
ALOGV("Agc2GetParameter() extra saturation margin %f dB", *(float*)pValue);
break;
case AGC2_PARAM_PROPERTIES:
pProperties->fixedDigitalGain =
(float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
- pProperties->level_estimator = (uint32_t)(
- effect->session->config.gain_controller2.adaptive_digital.level_estimator);
- pProperties->extraSaturationMargin =
- (float)(effect->session->config.gain_controller2.adaptive_digital
- .extra_saturation_margin_db);
+ pProperties->level_estimator = 0;
+ pProperties->extraSaturationMargin = 2.0;
break;
default:
ALOGW("Agc2GetParameter() unknown param %d", param);
@@ -438,16 +431,19 @@
effect->session->config.gain_controller2.fixed_digital.gain_db = valueFloat;
break;
case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
- ALOGV("Agc2SetParameter() level estimator %d",
- *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
- effect->session->config.gain_controller2.adaptive_digital.level_estimator =
- (*(webrtc::AudioProcessing::Config::GainController2::LevelEstimator*)pValue);
+ ALOGV("Agc2SetParameter() level estimator %d", *(uint32_t*)pValue);
+ if (*(uint32_t*)pValue != 0) {
+ // only RMS is supported
+ status = -EINVAL;
+ }
break;
case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
valueFloat = (float)(*(int32_t*)pValue);
ALOGV("Agc2SetParameter() extra saturation margin %f dB", valueFloat);
- effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
- valueFloat;
+ if (valueFloat != 2.0) {
+ // extra_staturation_margin_db is no longer configurable in webrtc
+ status = -EINVAL;
+ }
break;
case AGC2_PARAM_PROPERTIES:
ALOGV("Agc2SetParameter() properties gain %f, level %d margin %f",
@@ -455,11 +451,9 @@
pProperties->extraSaturationMargin);
effect->session->config.gain_controller2.fixed_digital.gain_db =
pProperties->fixedDigitalGain;
- effect->session->config.gain_controller2.adaptive_digital.level_estimator =
- (webrtc::AudioProcessing::Config::GainController2::LevelEstimator)
- pProperties->level_estimator;
- effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
- pProperties->extraSaturationMargin;
+ if (pProperties->level_estimator != 0 || pProperties->extraSaturationMargin != 2.0) {
+ status = -EINVAL;
+ }
break;
default:
ALOGW("Agc2SetParameter() unknown param %08x value %08x", param, *(uint32_t*)pValue);
@@ -879,8 +873,8 @@
error:
if (session->createdMsk == 0) {
- delete session->apm;
- session->apm = NULL;
+ // Scoped_refptr will handle reference counting here
+ session->apm = nullptr;
}
return status;
}
@@ -889,8 +883,8 @@
ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
session->createdMsk &= ~(1 << fx->procId);
if (session->createdMsk == 0) {
- delete session->apm;
- session->apm = NULL;
+ // Scoped_refptr will handle reference counting here
+ session->apm = nullptr;
session->id = 0;
}
diff --git a/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp b/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
index 07006a1..8fdb864 100644
--- a/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/EffectPreprocessingTest.cpp
@@ -143,10 +143,6 @@
const AGC2Params* agc2Params = ¶ms->agc2Params;
ASSERT_NO_FATAL_FAILURE(
effect.setParam(AGC2_PARAM_FIXED_DIGITAL_GAIN, agc2Params->fixedDigitalGain));
- ASSERT_NO_FATAL_FAILURE(effect.setParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
- agc2Params->adaptDigiLevelEstimator));
- ASSERT_NO_FATAL_FAILURE(effect.setParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
- agc2Params->extraSaturationMargin));
} else if (isAECEffect(uuid)) {
const AECParams* aecParams = ¶ms->aecParams;
ASSERT_NO_FATAL_FAILURE(effect.setParam(AEC_PARAM_ECHO_DELAY, aecParams->echoDelay));
diff --git a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
index 3bd93f8..03400d7 100644
--- a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
@@ -400,20 +400,6 @@
ALOGE("Invalid AGC2 Fixed Digital Gain. Error %d\n", status);
return EXIT_FAILURE;
}
- if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
- (uint32_t)preProcCfgParams.agc2Level,
- effectHandle[PREPROC_AGC2]);
- status != 0) {
- ALOGE("Invalid AGC2 Level Estimator. Error %d\n", status);
- return EXIT_FAILURE;
- }
- if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
- (float)preProcCfgParams.agc2SaturationMargin,
- effectHandle[PREPROC_AGC2]);
- status != 0) {
- ALOGE("Invalid AGC2 Saturation Margin. Error %d\n", status);
- return EXIT_FAILURE;
- }
}
if (effectEn[PREPROC_NS]) {
if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index 8dd6789..cf782f7 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -18,34 +18,60 @@
],
}
-cc_library_shared {
- name: "libvisualizer",
-
+cc_defaults {
+ name: "visualizer_defaults",
vendor: true,
-
- srcs: [
- "EffectVisualizer.cpp",
- ],
-
cflags: [
- "-O2",
- "-fvisibility=hidden",
-
- "-DBUILD_FLOAT",
+ "-DBUILD_FLOAT", // TODO: remove BUILD_FLOAT and SUPPORT_MC in lvm libs
"-DSUPPORT_MC",
-
"-Wall",
"-Werror",
],
-
shared_libs: [
"liblog",
],
-
- relative_install_path: "soundfx",
-
header_libs: [
"libaudioeffects",
"libaudioutils_headers",
],
}
+
+cc_library_shared {
+ name: "libvisualizer",
+ defaults: [
+ "visualizer_defaults",
+ ],
+ srcs: [
+ "EffectVisualizer.cpp",
+ ],
+ relative_install_path: "soundfx",
+ cflags: [
+ "-O2",
+ "-fvisibility=hidden",
+ ],
+}
+
+cc_library_shared {
+ name: "libvisualizeraidl",
+ srcs: [
+ "aidl/Visualizer.cpp",
+ "aidl/VisualizerContext.cpp",
+ ":effectCommonFile",
+ ],
+ defaults: [
+ "aidlaudioeffectservice_defaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "latest_android_media_audio_common_types_ndk_shared",
+ "visualizer_defaults",
+ ],
+ cflags: [
+ "-Wthread-safety",
+ ],
+ shared_libs: [
+ "libcutils",
+ ],
+ relative_install_path: "soundfx",
+ visibility: [
+ "//hardware/interfaces/audio/aidl/default",
+ ],
+}
diff --git a/media/libeffects/visualizer/aidl/Visualizer.cpp b/media/libeffects/visualizer/aidl/Visualizer.cpp
new file mode 100644
index 0000000..28a7287
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/Visualizer.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AHAL_VisualizerLibEffects"
+
+#include <android-base/logging.h>
+#include "Visualizer.h"
+
+using aidl::android::hardware::audio::effect::Descriptor;
+using aidl::android::hardware::audio::effect::IEffect;
+using aidl::android::hardware::audio::effect::VisualizerImpl;
+using aidl::android::hardware::audio::effect::kVisualizerImplUUID;
+using aidl::android::hardware::audio::effect::State;
+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 != kVisualizerImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ if (instanceSpp) {
+ *instanceSpp = ndk::SharedRefBase::make<VisualizerImpl>();
+ 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 != kVisualizerImplUUID) {
+ LOG(ERROR) << __func__ << "uuid not supported";
+ return EX_ILLEGAL_ARGUMENT;
+ }
+ *_aidl_return = VisualizerImpl::kDescriptor;
+ return EX_NONE;
+}
+
+namespace aidl::android::hardware::audio::effect {
+
+const std::string VisualizerImpl::kEffectName = "Visualizer";
+const Visualizer::Capability VisualizerImpl::kCapability = {
+ .maxLatencyMs = VisualizerContext::kMaxLatencyMs,
+ .captureSampleRange = {.min = 0, .max = VisualizerContext::kMaxCaptureBufSize}};
+const Descriptor VisualizerImpl::kDescriptor = {
+ .common = {.id = {.type = kVisualizerTypeUUID,
+ .uuid = kVisualizerImplUUID,
+ .proxy = std::nullopt},
+ .flags = {.type = Flags::Type::INSERT,
+ .insert = Flags::Insert::LAST,
+ .volume = Flags::Volume::CTRL},
+ .name = VisualizerImpl::kEffectName,
+ .implementor = "The Android Open Source Project"},
+ .capability = Capability::make<Capability::visualizer>(VisualizerImpl::kCapability)};
+
+ndk::ScopedAStatus VisualizerImpl::getDescriptor(Descriptor* _aidl_return) {
+ RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
+ LOG(DEBUG) << __func__ << kDescriptor.toString();
+ *_aidl_return = kDescriptor;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::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();
+}
+
+ndk::ScopedAStatus VisualizerImpl::setOnlyParameter(
+ const Visualizer::SetOnlyParameters& param) {
+ auto tag = param.getTag();
+ switch (tag) {
+ case Visualizer::SetOnlyParameters::latencyMs: {
+ RETURN_IF(mContext->setDownstreamLatency(
+ param.get<Visualizer::SetOnlyParameters::latencyMs>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setLatencyFailed");
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::setParameterSpecific(const Parameter::Specific& specific) {
+ RETURN_IF(Parameter::Specific::visualizer != specific.getTag(), EX_ILLEGAL_ARGUMENT,
+ "EffectNotSupported");
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ auto& param = specific.get<Parameter::Specific::visualizer>();
+ const auto tag = param.getTag();
+ switch (tag) {
+ case Visualizer::captureSamples: {
+ RETURN_IF(mContext->setCaptureSamples(param.get<Visualizer::captureSamples>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setCaptureSizeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::scalingMode: {
+ RETURN_IF(mContext->setScalingMode(param.get<Visualizer::scalingMode>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setScalingModeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::measurementMode: {
+ RETURN_IF(mContext->setMeasurementMode(param.get<Visualizer::measurementMode>()) !=
+ RetCode::SUCCESS,
+ EX_ILLEGAL_ARGUMENT, "setMeasurementModeFailed");
+ return ndk::ScopedAStatus::ok();
+ }
+ case Visualizer::setOnlyParameters: {
+ return setOnlyParameter(param.get<Visualizer::setOnlyParameters>());
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
+ }
+ }
+}
+
+ndk::ScopedAStatus VisualizerImpl::getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
+ Parameter::Specific* specific) {
+ Visualizer visualizer;
+ Visualizer::GetOnlyParameters param;
+ switch (tag) {
+ case Visualizer::GetOnlyParameters::measurement: {
+ param.set<Visualizer::GetOnlyParameters::measurement>(mContext->getMeasure());
+ break;
+ }
+ case Visualizer::GetOnlyParameters::captureSampleBuffer: {
+ param.set<Visualizer::GetOnlyParameters::captureSampleBuffer>(mContext->capture());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "setOnlyParameterTagNotSupported");
+ }
+ }
+ visualizer.set<Visualizer::getOnlyParameters>(param);
+ specific->set<Parameter::Specific::visualizer>(visualizer);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::getParameterSpecific(const Parameter::Id& id,
+ Parameter::Specific* specific) {
+ RETURN_IF(!specific, EX_NULL_POINTER, "nullPtr");
+ auto tag = id.getTag();
+ RETURN_IF(Parameter::Id::visualizerTag != tag, EX_ILLEGAL_ARGUMENT, "wrongIdTag");
+ auto specificId = id.get<Parameter::Id::visualizerTag>();
+ auto specificTag = specificId.getTag();
+ switch (specificTag) {
+ case Visualizer::Id::commonTag: {
+ return getParameterVisualizer(specificId.get<Visualizer::Id::commonTag>(), specific);
+ }
+ case Visualizer::Id::getOnlyParamTag: {
+ return getOnlyParameter(specificId.get<Visualizer::Id::getOnlyParamTag>(), specific);
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(specificTag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "VisualizerTagNotSupported");
+ }
+ }
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus VisualizerImpl::getParameterVisualizer(const Visualizer::Tag& tag,
+ Parameter::Specific* specific) {
+ RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+
+ Visualizer param;
+ switch (tag) {
+ case Visualizer::captureSamples: {
+ param.set<Visualizer::captureSamples>(mContext->getCaptureSamples());
+ break;
+ }
+ case Visualizer::scalingMode: {
+ param.set<Visualizer::scalingMode>(mContext->getScalingMode());
+ break;
+ }
+ case Visualizer::measurementMode: {
+ param.set<Visualizer::measurementMode>(mContext->getMeasurementMode());
+ break;
+ }
+ default: {
+ LOG(ERROR) << __func__ << " unsupported tag: " << toString(tag);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "VisualizerTagNotSupported");
+ }
+ }
+
+ specific->set<Parameter::Specific::visualizer>(param);
+ return ndk::ScopedAStatus::ok();
+}
+
+std::shared_ptr<EffectContext> VisualizerImpl::createContext(const Parameter::Common& common) {
+ if (mContext) {
+ LOG(DEBUG) << __func__ << " context already exist";
+ return mContext;
+ }
+
+ mContext = std::make_shared<VisualizerContext>(1 /* statusFmqDepth */, common);
+ mContext->initParams(common);
+ return mContext;
+}
+
+RetCode VisualizerImpl::releaseContext() {
+ if (mContext) {
+ mContext->disable();
+ mContext->resetBuffer();
+ }
+ return RetCode::SUCCESS;
+}
+
+// Processing method running in EffectWorker thread.
+IEffect::Status VisualizerImpl::effectProcessImpl(float* in, float* out, int samples) {
+ IEffect::Status status = {EX_NULL_POINTER, 0, 0};
+ RETURN_VALUE_IF(!mContext, status, "nullContext");
+ return mContext->process(in, out, samples);
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
new file mode 100644
index 0000000..5908d9a
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -0,0 +1,60 @@
+/*
+ * 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 "effect-impl/EffectImpl.h"
+#include "effect-impl/EffectUUID.h"
+
+#include "VisualizerContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VisualizerImpl final : public EffectImpl {
+ public:
+ static const std::string kEffectName;
+ static const Visualizer::Capability kCapability;
+ static const Descriptor kDescriptor;
+ VisualizerImpl() { LOG(DEBUG) << __func__; }
+ ~VisualizerImpl() {
+ cleanUp();
+ LOG(DEBUG) << __func__;
+ }
+
+ ndk::ScopedAStatus commandImpl(CommandId command) 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;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
+ RetCode releaseContext() override;
+
+ std::shared_ptr<EffectContext> getContext() override { return mContext; }
+ std::string getEffectName() override { return kEffectName; }
+
+ private:
+ std::shared_ptr<VisualizerContext> mContext;
+ ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
+ Parameter::Specific* specific);
+ ndk::ScopedAStatus setOnlyParameter(const Visualizer::SetOnlyParameters& param);
+ ndk::ScopedAStatus getOnlyParameter(const Visualizer::GetOnlyParameters::Tag tag,
+ Parameter::Specific* specific);
+};
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.cpp b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
new file mode 100644
index 0000000..1965e0e
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.cpp
@@ -0,0 +1,331 @@
+/*
+ * 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 "VisualizerContext.h"
+
+#include <algorithm>
+#include <android/binder_status.h>
+#include <audio_utils/primitives.h>
+#include <math.h>
+#include <system/audio.h>
+#include <time.h>
+#include <Utils.h>
+
+#ifndef BUILD_FLOAT
+ #error AIDL Visualizer only support float 32bits, make sure add cflags -DBUILD_FLOAT,
+#endif
+
+using android::hardware::audio::common::getChannelCount;
+
+namespace aidl::android::hardware::audio::effect {
+
+VisualizerContext::VisualizerContext(int statusDepth, const Parameter::Common& common)
+ : EffectContext(statusDepth, common) {
+}
+
+VisualizerContext::~VisualizerContext() {
+ std::lock_guard lg(mMutex);
+ LOG(DEBUG) << __func__;
+ mState = State::UNINITIALIZED;
+}
+
+RetCode VisualizerContext::initParams(const Parameter::Common& common) {
+ std::lock_guard lg(mMutex);
+ LOG(DEBUG) << __func__;
+ if (common.input != common.output) {
+ LOG(ERROR) << __func__ << " mismatch input: " << common.input.toString()
+ << " and output: " << common.output.toString();
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+
+ mState = State::INITIALIZED;
+ auto channelCount = getChannelCount(common.input.base.channelMask);
+#ifdef SUPPORT_MC
+ if (channelCount < 1 || channelCount > FCC_LIMIT) return RetCode::ERROR_ILLEGAL_PARAMETER;
+#else
+ if (channelCount != FCC_2) return RetCode::ERROR_ILLEGAL_PARAMETER;
+#endif
+ mChannelCount = channelCount;
+ mCommon = common;
+ return RetCode::SUCCESS;
+}
+
+RetCode VisualizerContext::enable() {
+ std::lock_guard lg(mMutex);
+ if (mState != State::INITIALIZED) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = State::ACTIVE;
+ return RetCode::SUCCESS;
+}
+
+RetCode VisualizerContext::disable() {
+ std::lock_guard lg(mMutex);
+ if (mState != State::ACTIVE) {
+ return RetCode::ERROR_EFFECT_LIB_ERROR;
+ }
+ mState = State::INITIALIZED;
+ return RetCode::SUCCESS;
+}
+
+void VisualizerContext::reset() {
+ std::lock_guard lg(mMutex);
+ std::fill_n(mCaptureBuf.begin(), kMaxCaptureBufSize, 0x80);
+}
+
+RetCode VisualizerContext::setCaptureSamples(int samples) {
+ std::lock_guard lg(mMutex);
+ if (samples < 0 || (unsigned)samples > kMaxCaptureBufSize) {
+ LOG(ERROR) << __func__ << " captureSamples " << samples << " exceed valid range: 0 - "
+ << kMaxCaptureBufSize;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ mCaptureSamples = samples;
+ return RetCode::SUCCESS;
+}
+int VisualizerContext::getCaptureSamples() {
+ std::lock_guard lg(mMutex);
+ return mCaptureSamples;
+}
+
+RetCode VisualizerContext::setMeasurementMode(Visualizer::MeasurementMode mode) {
+ std::lock_guard lg(mMutex);
+ mMeasurementMode = mode;
+ return RetCode::SUCCESS;
+}
+Visualizer::MeasurementMode VisualizerContext::getMeasurementMode() {
+ std::lock_guard lg(mMutex);
+ return mMeasurementMode;
+}
+
+RetCode VisualizerContext::setScalingMode(Visualizer::ScalingMode mode) {
+ std::lock_guard lg(mMutex);
+ mScalingMode = mode;
+ return RetCode::SUCCESS;
+}
+Visualizer::ScalingMode VisualizerContext::getScalingMode() {
+ std::lock_guard lg(mMutex);
+ return mScalingMode;
+}
+
+RetCode VisualizerContext::setDownstreamLatency(int latency) {
+ if (latency < 0 || (unsigned)latency > kMaxLatencyMs) {
+ LOG(ERROR) << __func__ << " latency " << latency << " exceed valid range: 0 - "
+ << kMaxLatencyMs;
+ return RetCode::ERROR_ILLEGAL_PARAMETER;
+ }
+ std::lock_guard lg(mMutex);
+ mDownstreamLatency = latency;
+ return RetCode::SUCCESS;
+}
+
+uint32_t VisualizerContext::getDeltaTimeMsFromUpdatedTime_l() {
+ uint32_t deltaMs = 0;
+ if (mBufferUpdateTime.tv_sec != 0) {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
+ time_t secs = ts.tv_sec - mBufferUpdateTime.tv_sec;
+ long nsec = ts.tv_nsec - mBufferUpdateTime.tv_nsec;
+ if (nsec < 0) {
+ --secs;
+ nsec += 1000000000;
+ }
+ deltaMs = secs * 1000 + nsec / 1000000;
+ }
+ }
+ return deltaMs;
+}
+
+Visualizer::GetOnlyParameters::Measurement VisualizerContext::getMeasure() {
+ uint16_t peakU16 = 0;
+ float sumRmsSquared = 0.0f;
+ uint8_t nbValidMeasurements = 0;
+
+ {
+ std::lock_guard lg(mMutex);
+ // reset measurements if last measurement was too long ago (which implies stored
+ // measurements aren't relevant anymore and shouldn't bias the new one)
+ const uint32_t delayMs = getDeltaTimeMsFromUpdatedTime_l();
+ if (delayMs > kDiscardMeasurementsTimeMs) {
+ LOG(INFO) << __func__ << " Discarding " << delayMs << " ms old measurements";
+ for (uint32_t i = 0; i < mMeasurementWindowSizeInBuffers; i++) {
+ mPastMeasurements[i].mIsValid = false;
+ mPastMeasurements[i].mPeakU16 = 0;
+ mPastMeasurements[i].mRmsSquared = 0;
+ }
+ mMeasurementBufferIdx = 0;
+ } else {
+ // only use actual measurements, otherwise the first RMS measure happening before
+ // MEASUREMENT_WINDOW_MAX_SIZE_IN_BUFFERS have been played will always be artificially
+ // low
+ for (uint32_t i = 0; i < mMeasurementWindowSizeInBuffers; i++) {
+ if (mPastMeasurements[i].mIsValid) {
+ if (mPastMeasurements[i].mPeakU16 > peakU16) {
+ peakU16 = mPastMeasurements[i].mPeakU16;
+ }
+ sumRmsSquared += mPastMeasurements[i].mRmsSquared;
+ nbValidMeasurements++;
+ }
+ }
+ }
+ }
+
+ float rms = nbValidMeasurements == 0 ? 0.0f : sqrtf(sumRmsSquared / nbValidMeasurements);
+ Visualizer::GetOnlyParameters::Measurement measure;
+ // convert from I16 sample values to mB and write results
+ measure.rms = (rms < 0.000016f) ? -9600 : (int32_t)(2000 * log10(rms / 32767.0f));
+ measure.peak = (peakU16 == 0) ? -9600 : (int32_t)(2000 * log10(peakU16 / 32767.0f));
+ LOG(INFO) << __func__ << " peak " << peakU16 << " (" << measure.peak << "mB), rms " << rms
+ << " (" << measure.rms << "mB)";
+ return measure;
+}
+
+std::vector<uint8_t> VisualizerContext::capture() {
+ std::vector<uint8_t> result;
+ std::lock_guard lg(mMutex);
+ RETURN_VALUE_IF(mState != State::ACTIVE, result, "illegalState");
+ const uint32_t deltaMs = getDeltaTimeMsFromUpdatedTime_l();
+
+ // if audio framework has stopped playing audio although the effect is still active we must
+ // clear the capture buffer to return silence
+ if ((mLastCaptureIdx == mCaptureIdx) && (mBufferUpdateTime.tv_sec != 0) &&
+ (deltaMs > kMaxStallTimeMs)) {
+ LOG(INFO) << __func__ << " capture going to idle";
+ mBufferUpdateTime.tv_sec = 0;
+ return result;
+ }
+ int32_t latencyMs = mDownstreamLatency;
+ latencyMs -= deltaMs;
+ if (latencyMs < 0) {
+ latencyMs = 0;
+ }
+ uint32_t deltaSamples = mCaptureSamples + mCommon.input.base.sampleRate * latencyMs / 1000;
+
+ // large sample rate, latency, or capture size, could cause overflow.
+ // do not offset more than the size of buffer.
+ if (deltaSamples > kMaxCaptureBufSize) {
+ android_errorWriteLog(0x534e4554, "31781965");
+ deltaSamples = kMaxCaptureBufSize;
+ }
+
+ int32_t capturePoint;
+ //capturePoint = (int32_t)mCaptureIdx - deltaSamples;
+ __builtin_sub_overflow((int32_t) mCaptureIdx, deltaSamples, &capturePoint);
+ // a negative capturePoint means we wrap the buffer.
+ if (capturePoint < 0) {
+ uint32_t size = -capturePoint;
+ if (size > mCaptureSamples) {
+ size = mCaptureSamples;
+ }
+ result.insert(result.end(), &mCaptureBuf[kMaxCaptureBufSize + capturePoint],
+ &mCaptureBuf[kMaxCaptureBufSize + capturePoint + size]);
+ mCaptureSamples -= size;
+ capturePoint = 0;
+ }
+ result.insert(result.end(), &mCaptureBuf[capturePoint],
+ &mCaptureBuf[capturePoint + mCaptureSamples]);
+ mLastCaptureIdx = mCaptureIdx;
+ return result;
+}
+
+IEffect::Status VisualizerContext::process(float* in, float* out, int samples) {
+ IEffect::Status result = {STATUS_NOT_ENOUGH_DATA, 0, 0};
+ RETURN_VALUE_IF(in == nullptr || out == nullptr || samples == 0, result, "dataBufferError");
+
+ std::lock_guard lg(mMutex);
+ result.status = STATUS_INVALID_OPERATION;
+ RETURN_VALUE_IF(mState != State::ACTIVE, result, "stateNotActive");
+ LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
+ // perform measurements if needed
+ if (mMeasurementMode == Visualizer::MeasurementMode::PEAK_RMS) {
+ // find the peak and RMS squared for the new buffer
+ float rmsSqAcc = 0;
+ float maxSample = 0.f;
+ for (size_t inIdx = 0; inIdx < (unsigned)samples; ++inIdx) {
+ maxSample = fmax(maxSample, fabs(in[inIdx]));
+ rmsSqAcc += in[inIdx] * in[inIdx];
+ }
+ maxSample *= 1 << 15; // scale to int16_t, with exactly 1 << 15 representing positive num.
+ rmsSqAcc *= 1 << 30; // scale to int16_t * 2
+ mPastMeasurements[mMeasurementBufferIdx] = {
+ .mPeakU16 = (uint16_t)maxSample,
+ .mRmsSquared = rmsSqAcc / samples,
+ .mIsValid = true };
+ if (++mMeasurementBufferIdx >= mMeasurementWindowSizeInBuffers) {
+ mMeasurementBufferIdx = 0;
+ }
+ }
+
+ float fscale; // multiplicative scale
+ if (mScalingMode == Visualizer::ScalingMode::NORMALIZED) {
+ // derive capture scaling factor from peak value in current buffer
+ // this gives more interesting captures for display.
+ float maxSample = 0.f;
+ for (size_t inIdx = 0; inIdx < (unsigned)samples; ) {
+ // we reconstruct the actual summed value to ensure proper normalization
+ // for multichannel outputs (channels > 2 may often be 0).
+ float smp = 0.f;
+ for (int i = 0; i < mChannelCount; ++i) {
+ smp += in[inIdx++];
+ }
+ maxSample = fmax(maxSample, fabs(smp));
+ }
+ if (maxSample > 0.f) {
+ fscale = 0.99f / maxSample;
+ int exp; // unused
+ const float significand = frexp(fscale, &exp);
+ if (significand == 0.5f) {
+ fscale *= 255.f / 256.f; // avoid returning unaltered PCM signal
+ }
+ } else {
+ // scale doesn't matter, the values are all 0.
+ fscale = 1.f;
+ }
+ } else {
+ assert(mScalingMode == Visualizer::ScalingMode::AS_PLAYED);
+ // Note: if channels are uncorrelated, 1/sqrt(N) could be used at the risk of clipping.
+ fscale = 1.f / mChannelCount; // account for summing all the channels together.
+ }
+
+ uint32_t captIdx;
+ uint32_t inIdx;
+ for (inIdx = 0, captIdx = mCaptureIdx; inIdx < (unsigned)samples; captIdx++) {
+ // wrap
+ if (captIdx >= kMaxCaptureBufSize) {
+ captIdx = 0;
+ }
+
+ float smp = 0.f;
+ for (uint32_t i = 0; i < mChannelCount; ++i) {
+ smp += in[inIdx++];
+ }
+ mCaptureBuf[captIdx] = clamp8_from_float(smp * fscale);
+ }
+
+ // the following two should really be atomic, though it probably doesn't
+ // matter much for visualization purposes
+ mCaptureIdx = captIdx;
+ // update last buffer update time stamp
+ if (clock_gettime(CLOCK_MONOTONIC, &mBufferUpdateTime) < 0) {
+ mBufferUpdateTime.tv_sec = 0;
+ }
+
+ // TODO: handle access_mode
+ memcpy(out, in, samples * sizeof(float));
+ return {STATUS_OK, samples, samples};
+}
+
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/visualizer/aidl/VisualizerContext.h b/media/libeffects/visualizer/aidl/VisualizerContext.h
new file mode 100644
index 0000000..bfda0b9
--- /dev/null
+++ b/media/libeffects/visualizer/aidl/VisualizerContext.h
@@ -0,0 +1,101 @@
+/*
+ * 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 <android-base/thread_annotations.h>
+#include <audio_effects/effect_dynamicsprocessing.h>
+
+#include "effect-impl/EffectContext.h"
+
+namespace aidl::android::hardware::audio::effect {
+
+class VisualizerContext final : public EffectContext {
+ public:
+ static const uint32_t kMaxCaptureBufSize = 65536;
+ static const uint32_t kMaxLatencyMs = 3000; // 3 seconds of latency for audio pipeline
+
+ VisualizerContext(int statusDepth, const Parameter::Common& common);
+ ~VisualizerContext();
+
+ RetCode initParams(const Parameter::Common& common);
+
+ RetCode enable();
+ RetCode disable();
+ // keep all parameters and reset buffer.
+ void reset();
+
+ RetCode setCaptureSamples(int captureSize);
+ int getCaptureSamples();
+ RetCode setMeasurementMode(Visualizer::MeasurementMode mode);
+ Visualizer::MeasurementMode getMeasurementMode();
+ RetCode setScalingMode(Visualizer::ScalingMode mode);
+ Visualizer::ScalingMode getScalingMode();
+ RetCode setDownstreamLatency(int latency);
+
+ IEffect::Status process(float* in, float* out, int samples);
+ // Gets the current measurements, measured by process() and consumed by getParameter()
+ Visualizer::GetOnlyParameters::Measurement getMeasure();
+ // Gets the latest PCM capture, data captured by process() and consumed by getParameter()
+ std::vector<uint8_t> capture();
+
+ struct BufferStats {
+ bool mIsValid;
+ uint16_t mPeakU16; // the positive peak of the absolute value of the samples in a buffer
+ float mRmsSquared; // the average square of the samples in a buffer
+ };
+
+ enum State {
+ UNINITIALIZED,
+ INITIALIZED,
+ ACTIVE,
+ };
+
+ private:
+ // maximum time since last capture buffer update before resetting capture buffer. This means
+ // that the framework has stopped playing audio and we must start returning silence
+ static const uint32_t kMaxStallTimeMs = 1000;
+ // discard measurements older than this number of ms
+ static const uint32_t kDiscardMeasurementsTimeMs = 2000;
+ // maximum number of buffers for which we keep track of the measurements
+ // note: buffer index is stored in uint8_t
+ static const uint32_t kMeasurementWindowMaxSizeInBuffers = 25;
+
+ // serialize process() and parameter setting
+ std::mutex mMutex;
+ Parameter::Common mCommon GUARDED_BY(mMutex);
+ State mState GUARDED_BY(mMutex) = State::UNINITIALIZED;
+ uint32_t mCaptureIdx GUARDED_BY(mMutex) = 0;
+ uint32_t mLastCaptureIdx GUARDED_BY(mMutex) = 0;
+ Visualizer::ScalingMode mScalingMode GUARDED_BY(mMutex) = Visualizer::ScalingMode::NORMALIZED;
+ struct timespec mBufferUpdateTime GUARDED_BY(mMutex);
+ // capture buf with 8 bits PCM
+ std::array<uint8_t, kMaxCaptureBufSize> mCaptureBuf GUARDED_BY(mMutex);
+ uint32_t mDownstreamLatency GUARDED_BY(mMutex) = 0;
+ uint32_t mCaptureSamples GUARDED_BY(mMutex) = kMaxCaptureBufSize;
+
+ // to avoid recomputing it every time a buffer is processed
+ uint8_t mChannelCount GUARDED_BY(mMutex) = 0;
+ Visualizer::MeasurementMode mMeasurementMode GUARDED_BY(mMutex) =
+ Visualizer::MeasurementMode::NONE;
+ uint8_t mMeasurementWindowSizeInBuffers = kMeasurementWindowMaxSizeInBuffers;
+ uint8_t mMeasurementBufferIdx GUARDED_BY(mMutex) = 0;
+ std::array<BufferStats, kMeasurementWindowMaxSizeInBuffers> mPastMeasurements;
+ void init_params();
+
+ uint32_t getDeltaTimeMsFromUpdatedTime_l() REQUIRES(mMutex);
+};
+} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libheadtracking/HeadTrackingProcessor.cpp b/media/libheadtracking/HeadTrackingProcessor.cpp
index 101b825..6b62004 100644
--- a/media/libheadtracking/HeadTrackingProcessor.cpp
+++ b/media/libheadtracking/HeadTrackingProcessor.cpp
@@ -97,7 +97,7 @@
mModeSelector.setScreenStable(mWorldToScreenTimestamp.value(), screenStable);
// Whenever the screen is unstable, recenter the head pose.
if (!screenStable) {
- recenter(true, false);
+ recenter(true, false, "calculate: screen movement");
}
mScreenHeadFusion.setWorldToScreenPose(mWorldToScreenTimestamp.value(),
worldToLogicalScreen);
@@ -109,7 +109,7 @@
// Auto-recenter.
bool headStable = mHeadStillnessDetector.calculate(timestamp);
if (headStable || !screenStable) {
- recenter(true, false);
+ recenter(true, false, "calculate: head movement");
worldToHead = mHeadPoseBias.getOutput();
}
@@ -139,16 +139,16 @@
HeadTrackingMode getActualMode() const override { return mModeSelector.getActualMode(); }
- void recenter(bool recenterHead, bool recenterScreen) override {
+ void recenter(bool recenterHead, bool recenterScreen, std::string source) override {
if (recenterHead) {
mHeadPoseBias.recenter();
mHeadStillnessDetector.reset();
- mLocalLog.log("recenter Head");
+ mLocalLog.log("recenter Head from %s", source.c_str());
}
if (recenterScreen) {
mScreenPoseBias.recenter();
mScreenStillnessDetector.reset();
- mLocalLog.log("recenter Screen");
+ mLocalLog.log("recenter Screen from %s", source.c_str());
}
// If a sensor being recentered is included in the current mode, apply rate limiting to
diff --git a/media/libheadtracking/include/media/HeadTrackingProcessor.h b/media/libheadtracking/include/media/HeadTrackingProcessor.h
index 8ef8ab0..b4c78a0 100644
--- a/media/libheadtracking/include/media/HeadTrackingProcessor.h
+++ b/media/libheadtracking/include/media/HeadTrackingProcessor.h
@@ -95,7 +95,8 @@
/**
* This causes the current poses for both the head and/or screen to be considered "center".
*/
- virtual void recenter(bool recenterHead = true, bool recenterScreen = true) = 0;
+ virtual void recenter(
+ bool recenterHead = true, bool recenterScreen = true, std::string source = "") = 0;
/**
* Dump HeadTrackingProcessor parameters under caller lock.
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index ab1cf69..590a7b7 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -384,7 +384,6 @@
export_shared_lib_headers: [
"libaudioclient",
"libbinder",
- "libandroidicu",
//"libsonivox",
"libmedia_omx",
"framework-permission-aidl-cpp",
diff --git a/media/libmedia/include/media/CharacterEncodingDetector.h b/media/libmedia/include/media/CharacterEncodingDetector.h
index 62564b1..2acc868 100644
--- a/media/libmedia/include/media/CharacterEncodingDetector.h
+++ b/media/libmedia/include/media/CharacterEncodingDetector.h
@@ -21,9 +21,12 @@
#include "StringArray.h"
-#include "unicode/ucnv.h"
-#include "unicode/ucsdet.h"
-#include "unicode/ustring.h"
+/** Declare opaque structures from ICU4C. */
+struct UConverter;
+typedef struct UConverter UConverter;
+
+struct UCharsetMatch;
+typedef struct UCharsetMatch UCharsetMatch;
namespace android {
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index b45dae5..2f9b85e 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -214,7 +214,8 @@
{
public:
explicit MediaPlayer(const android::content::AttributionSourceState& mAttributionSource =
- android::content::AttributionSourceState());
+ android::content::AttributionSourceState(),
+ audio_session_t sessionId = AUDIO_SESSION_ALLOCATE);
~MediaPlayer();
void died();
void disconnect();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 5215c1b..b5c75b3 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -42,8 +42,8 @@
using media::VolumeShaper;
using content::AttributionSourceState;
-MediaPlayer::MediaPlayer(const AttributionSourceState& attributionSource)
- : mAttributionSource(attributionSource)
+MediaPlayer::MediaPlayer(const AttributionSourceState& attributionSource,
+ const audio_session_t sessionId) : mAttributionSource(attributionSource)
{
ALOGV("constructor");
mListener = NULL;
@@ -61,7 +61,12 @@
mLeftVolume = mRightVolume = 1.0;
mVideoWidth = mVideoHeight = 0;
mLockThreadId = 0;
- mAudioSessionId = (audio_session_t) AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
+ if (sessionId == AUDIO_SESSION_ALLOCATE) {
+ mAudioSessionId = static_cast<audio_session_t>(
+ AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION));
+ } else {
+ mAudioSessionId = sessionId;
+ }
AudioSystem::acquireAudioSessionId(mAudioSessionId, (pid_t)-1, (uid_t)-1); // always in client.
mSendLevel = 0;
mRetransmitEndpointValid = false;
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index ba3df59..f80a467 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -122,6 +122,7 @@
#define AMEDIAMETRICS_PROP_BURSTFRAMES "burstFrames" // int32
#define AMEDIAMETRICS_PROP_CALLERNAME "callerName" // string, eg. "aaudio"
#define AMEDIAMETRICS_PROP_CHANNELCOUNT "channelCount" // int32
+#define AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE "channelCountHardware" // int32
#define AMEDIAMETRICS_PROP_CHANNELMASK "channelMask" // int32
#define AMEDIAMETRICS_PROP_CHANNELMASKS "channelMasks" // string with channelMask values
// separated by |.
@@ -147,6 +148,7 @@
#define AMEDIAMETRICS_PROP_DURATIONNS "durationNs" // int64 duration time span
#define AMEDIAMETRICS_PROP_ENABLED "enabled" // string true/false.
#define AMEDIAMETRICS_PROP_ENCODING "encoding" // string value of format
+#define AMEDIAMETRICS_PROP_ENCODINGHARDWARE "encodingHardware" // string value of hardware format
#define AMEDIAMETRICS_PROP_EVENT "event#" // string value (often func name)
#define AMEDIAMETRICS_PROP_EXECUTIONTIMENS "executionTimeNs" // time to execute the event
@@ -182,6 +184,7 @@
#define AMEDIAMETRICS_PROP_PLAYERIID "playerIId" // int32 (-1 invalid/unset IID)
#define AMEDIAMETRICS_PROP_ROUTEDDEVICEID "routedDeviceId" // int32
#define AMEDIAMETRICS_PROP_SAMPLERATE "sampleRate" // int32
+#define AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE "sampleRateHardware" // int32
#define AMEDIAMETRICS_PROP_SELECTEDDEVICEID "selectedDeviceId" // int32
#define AMEDIAMETRICS_PROP_SELECTEDMICDIRECTION "selectedMicDirection" // int32
#define AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION "selectedMicFieldDimension" // double
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 727d68d..5c6c5fd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1227,7 +1227,11 @@
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
} else {
// Only audio track has error. Video track could be still good to play.
- notifyListener(MEDIA_INFO, MEDIA_INFO_PLAY_AUDIO_ERROR, err);
+ if (mVideoEOS) {
+ notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
+ } else {
+ notifyListener(MEDIA_INFO, MEDIA_INFO_PLAY_AUDIO_ERROR, err);
+ }
}
mAudioDecoderError = true;
} else {
@@ -1238,7 +1242,11 @@
notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
} else {
// Only video track has error. Audio track could be still good to play.
- notifyListener(MEDIA_INFO, MEDIA_INFO_PLAY_VIDEO_ERROR, err);
+ if (mAudioEOS) {
+ notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0);
+ } else {
+ notifyListener(MEDIA_INFO, MEDIA_INFO_PLAY_VIDEO_ERROR, err);
+ }
}
mVideoDecoderError = true;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index 6788b56..a964d4f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -22,14 +22,13 @@
#include <mediadrm/DrmUtils.h>
#include <utils/Log.h>
-
namespace android {
// static helpers - internal
sp<IDrm> NuPlayerDrm::CreateDrm(status_t *pstatus)
{
- return DrmUtils::MakeDrm(pstatus);
+ return DrmUtils::MakeDrm(IDRM_NUPLAYER, pstatus);
}
sp<ICrypto> NuPlayerDrm::createCrypto(status_t *pstatus)
@@ -191,8 +190,8 @@
uint8_t key[kBlockSize],
uint8_t iv[kBlockSize],
CryptoPlugin::Mode mode,
- size_t *clearbytes,
- size_t *encryptedbytes)
+ uint32_t *clearbytes,
+ uint32_t *encryptedbytes)
{
// size needed to store all the crypto data
size_t cryptosize;
@@ -236,7 +235,7 @@
if (!meta.findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) {
return NULL;
}
- size_t numSubSamples = cryptedsize / sizeof(size_t);
+ size_t numSubSamples = cryptedsize / sizeof(uint32_t);
if (numSubSamples <= 0) {
ALOGE("getSampleCryptoInfo INVALID numSubSamples: %zu", numSubSamples);
@@ -285,8 +284,8 @@
(uint8_t*) key,
(uint8_t*) iv,
(CryptoPlugin::Mode)mode,
- (size_t*) cleardata,
- (size_t*) crypteddata);
+ (uint32_t*) cleardata,
+ (uint32_t*) crypteddata);
}
} // namespace android
diff --git a/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
index 4360656..232638c 100644
--- a/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
+++ b/media/libmediaplayerservice/nuplayer/include/nuplayer/NuPlayerDrm.h
@@ -106,8 +106,8 @@
uint8_t key[kBlockSize],
uint8_t iv[kBlockSize],
CryptoPlugin::Mode mode,
- size_t *clearbytes,
- size_t *encryptedbytes);
+ uint32_t *clearbytes,
+ uint32_t *encryptedbytes);
static CryptoInfo *getSampleCryptoInfo(MetaDataBase &meta);
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index d6028d9..4a5524d 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -6315,6 +6315,11 @@
flags |= OMX_BUFFERFLAG_EOS;
}
+ int32_t isDecodeOnly = 0;
+ if (buffer->meta()->findInt32("decode-only", &isDecodeOnly) && isDecodeOnly != 0) {
+ flags |= OMX_BUFFERFLAG_DECODEONLY;
+ mCodec->mDecodeOnlyTimesUs.emplace(timeUs);
+ }
size_t size = buffer->size();
size_t offset = buffer->offset();
if (buffer->base() != info->mCodecData->base()) {
@@ -6344,6 +6349,10 @@
ALOGV("[%s] calling emptyBuffer %u w/ EOS",
mCodec->mComponentName.c_str(), bufferID);
} else {
+ if (flags & OMX_BUFFERFLAG_DECODEONLY) {
+ ALOGV("[%s] calling emptyBuffer %u w/ decode only flag",
+ mCodec->mComponentName.c_str(), bufferID);
+ }
#if TRACK_BUFFER_TIMING
ALOGI("[%s] calling emptyBuffer %u w/ time %lld us",
mCodec->mComponentName.c_str(), bufferID, (long long)timeUs);
@@ -6634,6 +6643,39 @@
info->mData.clear();
+ // Workaround: if OMX_BUFFERFLAG_DECODEONLY is not implemented in
+ // HAL, the flag is then removed in the corresponding output buffer.
+
+ // for all buffers that were marked as DECODE_ONLY, remove their timestamp
+ // if it is smaller than the timestamp of the buffer that was
+ // just received
+ while (!mCodec->mDecodeOnlyTimesUs.empty() &&
+ *mCodec->mDecodeOnlyTimesUs.begin() < timeUs) {
+ mCodec->mDecodeOnlyTimesUs.erase(mCodec->mDecodeOnlyTimesUs.begin());
+ }
+ // if OMX_BUFFERFLAG_DECODEONLY is not implemented in HAL, we need to restore the
+ // OMX_BUFFERFLAG_DECODEONLY flag to the frames we had saved in the set, the set
+ // contains the timestamps of buffers that were marked as DECODE_ONLY by the app
+ if (!mCodec->mDecodeOnlyTimesUs.empty() &&
+ *mCodec->mDecodeOnlyTimesUs.begin() == timeUs) {
+ mCodec->mDecodeOnlyTimesUs.erase(timeUs);
+ // If the app queued the last valid buffer as DECODE_ONLY and queued an additional
+ // empty buffer as EOS, it's possible that HAL sets the last valid frame as EOS
+ // instead and drops the empty buffer. In such a case, we should not add back
+ // the OMX_BUFFERFLAG_DECODEONLY flag to it, as doing so will make it so that the
+ // app does not receive the EOS buffer, which breaks the contract of EOS buffers
+ if (flags & OMX_BUFFERFLAG_EOS) {
+ // Set buffer size to 0, as described by
+ // https://developer.android.com/reference/android/media/MediaCodec.BufferInfo?hl=en#size
+ // a buffer of size 0 should only be used to carry the EOS flag and should
+ // be discarded by the app as it has no data
+ buffer->setRange(0, 0);
+ } else {
+ // re-add the OMX_BUFFERFLAG_DECODEONLY flag to the buffer in case it is
+ // not the end of stream buffer
+ flags |= OMX_BUFFERFLAG_DECODEONLY;
+ }
+ }
mCodec->mBufferChannel->drainThisBuffer(info->mBufferID, flags);
info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM;
@@ -6854,6 +6896,7 @@
mCodec->mConverter[0].clear();
mCodec->mConverter[1].clear();
mCodec->mComponentName.clear();
+ mCodec->mDecodeOnlyTimesUs.clear();
}
bool ACodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) {
@@ -8839,6 +8882,7 @@
ALOGV("[%s] Now Flushing", mCodec->mComponentName.c_str());
mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false;
+ mCodec->mDecodeOnlyTimesUs.clear();
// If we haven't transitioned after 3 seconds, we're probably stuck.
sp<AMessage> msg = new AMessage(ACodec::kWhatCheckIfStuck, mCodec);
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 88b15ae..c5a59ff 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -114,6 +114,10 @@
if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
it->mCodecBuffer->meta()->setInt32("csd", csd);
}
+ int32_t decodeOnly;
+ if (it->mClientBuffer->meta()->findInt32("decode-only", &decodeOnly)) {
+ it->mCodecBuffer->meta()->setInt32("decode-only", decodeOnly);
+ }
}
ALOGV("queueInputBuffer #%d", it->mBufferId);
sp<AMessage> msg = mInputBufferFilled->dup();
@@ -263,6 +267,10 @@
if (it->mClientBuffer->meta()->findInt32("csd", &csd)) {
it->mCodecBuffer->meta()->setInt32("csd", csd);
}
+ int32_t decodeOnly;
+ if (it->mClientBuffer->meta()->findInt32("decode-only", &decodeOnly)) {
+ it->mCodecBuffer->meta()->setInt32("decode-only", decodeOnly);
+ }
ALOGV("queueSecureInputBuffer #%d", it->mBufferId);
sp<AMessage> msg = mInputBufferFilled->dup();
@@ -634,6 +642,9 @@
if (omxFlags & OMX_BUFFERFLAG_EOS) {
flags |= MediaCodec::BUFFER_FLAG_EOS;
}
+ if (omxFlags & OMX_BUFFERFLAG_DECODEONLY) {
+ flags |= MediaCodec::BUFFER_FLAG_DECODE_ONLY;
+ }
it->mClientBuffer->meta()->setInt32("flags", flags);
mCallback->onOutputBufferAvailable(
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 8c469df..32e40c3 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -155,6 +155,7 @@
"libEGL",
"libGLESv1_CM",
"libGLESv2",
+ "libvulkan",
"libgui",
"liblog",
"libprocessgroup",
@@ -300,7 +301,6 @@
"libstagefright_codecbase",
"libstagefright_foundation",
"libstagefright_omx_utils",
- "libRScpp",
"libhidlallocatorutils",
"libhidlbase",
"libhidlmemory",
@@ -317,7 +317,6 @@
"libstagefright_esds",
"libstagefright_color_conversion",
"libyuv_static",
- "libstagefright_mediafilter",
"libstagefright_webm",
"libstagefright_timedtext",
"libogg",
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f3ef39e..7237bb2 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -75,7 +75,6 @@
#include <media/stagefright/MediaCodecConstants.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaFilter.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/PersistentSurface.h>
#include <media/stagefright/SurfaceUtils.h>
@@ -1512,6 +1511,21 @@
}
}
+bool MediaCodec::discardDecodeOnlyOutputBuffer(size_t index) {
+ Mutex::Autolock al(mBufferLock);
+ BufferInfo *info = &mPortBuffers[kPortIndexOutput][index];
+ sp<MediaCodecBuffer> buffer = info->mData;
+ int32_t flags;
+ CHECK(buffer->meta()->findInt32("flags", &flags));
+ if (flags & BUFFER_FLAG_DECODE_ONLY) {
+ info->mOwnedByClient = false;
+ info->mData.clear();
+ mBufferChannel->discardBuffer(buffer);
+ return true;
+ }
+ return false;
+}
+
// static
status_t MediaCodec::PostAndAwaitResponse(
const sp<AMessage> &msg, sp<AMessage> *response) {
@@ -1565,8 +1579,6 @@
} else if (name.startsWithIgnoreCase("omx.")) {
// at this time only ACodec specifies a mime type.
return new ACodec;
- } else if (name.startsWithIgnoreCase("android.filter.")) {
- return new MediaFilter;
} else {
return NULL;
}
@@ -3201,7 +3213,8 @@
return true;
}
-bool MediaCodec::handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest) {
+MediaCodec::DequeueOutputResult MediaCodec::handleDequeueOutputBuffer(
+ const sp<AReplyToken> &replyID, bool newRequest) {
if (!isExecuting() || (mFlags & kFlagIsAsync)
|| (newRequest && (mFlags & kFlagDequeueOutputPending))) {
PostReplyWithError(replyID, INVALID_OPERATION);
@@ -3214,7 +3227,7 @@
sp<AMessage> response = new AMessage;
BufferInfo *info = peekNextPortBuffer(kPortIndexOutput);
if (!info) {
- return false;
+ return DequeueOutputResult::kNoBuffer;
}
// In synchronous mode, output format change should be handled
@@ -3225,10 +3238,13 @@
if (mFlags & kFlagOutputFormatChanged) {
PostReplyWithError(replyID, INFO_FORMAT_CHANGED);
mFlags &= ~kFlagOutputFormatChanged;
- return true;
+ return DequeueOutputResult::kRepliedWithError;
}
ssize_t index = dequeuePortBuffer(kPortIndexOutput);
+ if (discardDecodeOnlyOutputBuffer(index)) {
+ return DequeueOutputResult::kDiscardedBuffer;
+ }
response->setSize("index", index);
response->setSize("offset", buffer->offset());
@@ -3247,9 +3263,10 @@
statsBufferReceived(timeUs, buffer);
response->postReply(replyID);
+ return DequeueOutputResult::kSuccess;
}
- return true;
+ return DequeueOutputResult::kRepliedWithError;
}
void MediaCodec::onMessageReceived(const sp<AMessage> &msg) {
@@ -3844,11 +3861,26 @@
handleOutputFormatChangeIfNeeded(buffer);
onOutputBufferAvailable();
} else if (mFlags & kFlagDequeueOutputPending) {
- CHECK(handleDequeueOutputBuffer(mDequeueOutputReplyID));
-
- ++mDequeueOutputTimeoutGeneration;
- mFlags &= ~kFlagDequeueOutputPending;
- mDequeueOutputReplyID = 0;
+ DequeueOutputResult dequeueResult =
+ handleDequeueOutputBuffer(mDequeueOutputReplyID);
+ switch (dequeueResult) {
+ case DequeueOutputResult::kNoBuffer:
+ TRESPASS();
+ break;
+ case DequeueOutputResult::kDiscardedBuffer:
+ break;
+ case DequeueOutputResult::kRepliedWithError:
+ [[fallthrough]];
+ case DequeueOutputResult::kSuccess:
+ {
+ ++mDequeueOutputTimeoutGeneration;
+ mFlags &= ~kFlagDequeueOutputPending;
+ mDequeueOutputReplyID = 0;
+ break;
+ }
+ default:
+ TRESPASS();
+ }
} else {
postActivityNotificationIfPossible();
}
@@ -4547,27 +4579,39 @@
break;
}
- if (handleDequeueOutputBuffer(replyID, true /* new request */)) {
- break;
- }
+ DequeueOutputResult dequeueResult =
+ handleDequeueOutputBuffer(replyID, true /* new request */);
+ switch (dequeueResult) {
+ case DequeueOutputResult::kNoBuffer:
+ [[fallthrough]];
+ case DequeueOutputResult::kDiscardedBuffer:
+ {
+ int64_t timeoutUs;
+ CHECK(msg->findInt64("timeoutUs", &timeoutUs));
- int64_t timeoutUs;
- CHECK(msg->findInt64("timeoutUs", &timeoutUs));
+ if (timeoutUs == 0LL) {
+ PostReplyWithError(replyID, -EAGAIN);
+ break;
+ }
- if (timeoutUs == 0LL) {
- PostReplyWithError(replyID, -EAGAIN);
- break;
- }
+ mFlags |= kFlagDequeueOutputPending;
+ mDequeueOutputReplyID = replyID;
- mFlags |= kFlagDequeueOutputPending;
- mDequeueOutputReplyID = replyID;
-
- if (timeoutUs > 0LL) {
- sp<AMessage> timeoutMsg =
- new AMessage(kWhatDequeueOutputTimedOut, this);
- timeoutMsg->setInt32(
- "generation", ++mDequeueOutputTimeoutGeneration);
- timeoutMsg->post(timeoutUs);
+ if (timeoutUs > 0LL) {
+ sp<AMessage> timeoutMsg =
+ new AMessage(kWhatDequeueOutputTimedOut, this);
+ timeoutMsg->setInt32(
+ "generation", ++mDequeueOutputTimeoutGeneration);
+ timeoutMsg->post(timeoutUs);
+ }
+ break;
+ }
+ case DequeueOutputResult::kRepliedWithError:
+ [[fallthrough]];
+ case DequeueOutputResult::kSuccess:
+ break;
+ default:
+ TRESPASS();
}
break;
}
@@ -5229,6 +5273,7 @@
buffer->setRange(offset, size);
buffer->meta()->setInt64("timeUs", timeUs);
+
if (flags & BUFFER_FLAG_EOS) {
buffer->meta()->setInt32("eos", true);
}
@@ -5237,7 +5282,12 @@
buffer->meta()->setInt32("csd", true);
}
- if (mTunneled) {
+ bool isBufferDecodeOnly = ((flags & BUFFER_FLAG_DECODE_ONLY) != 0);
+ if (isBufferDecodeOnly) {
+ buffer->meta()->setInt32("decode-only", true);
+ }
+
+ if (mTunneled && !isBufferDecodeOnly) {
TunnelPeekState previousState = mTunnelPeekState;
switch(mTunnelPeekState){
case TunnelPeekState::kEnabledNoBuffer:
@@ -5550,6 +5600,9 @@
void MediaCodec::onOutputBufferAvailable() {
int32_t index;
while ((index = dequeuePortBuffer(kPortIndexOutput)) >= 0) {
+ if (discardDecodeOnlyOutputBuffer(index)) {
+ continue;
+ }
const sp<MediaCodecBuffer> &buffer =
mPortBuffers[kPortIndexOutput][index].mData;
sp<AMessage> msg = mCallback->dup();
diff --git a/media/libstagefright/OggWriter.cpp b/media/libstagefright/OggWriter.cpp
index d2a65d0..cff37a3 100644
--- a/media/libstagefright/OggWriter.cpp
+++ b/media/libstagefright/OggWriter.cpp
@@ -96,6 +96,7 @@
return ERROR_UNSUPPORTED;
}
+ // NOLINTNEXTLINE(clang-analyzer-unix.MallocSizeof)
mOs = (OggStreamState*) malloc(sizeof(ogg_stream_state));
if (ogg_stream_init((ogg_stream_state*)mOs, rand()) == -1) {
ALOGE("ogg stream init failed");
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index 1f569ef..f526e05 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -222,6 +222,11 @@
static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
+ // In nonblocking mode(timetout = 0), native_window_dequeue_buffer_and_wait()
+ // can fail with timeout. Changing to blocking mode will ensure that dequeue
+ // does not timeout.
+ static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->setDequeueTimeout(-1);
+
err = nativeWindow->query(nativeWindow,
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
if (err != NO_ERROR) {
diff --git a/media/libstagefright/filters/Android.bp b/media/libstagefright/filters/Android.bp
deleted file mode 100644
index e6d59ad..0000000
--- a/media/libstagefright/filters/Android.bp
+++ /dev/null
@@ -1,52 +0,0 @@
-package {
- // See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "frameworks_av_media_libstagefright_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- default_applicable_licenses: ["frameworks_av_media_libstagefright_license"],
-}
-
-cc_library_static {
- name: "libstagefright_mediafilter",
-
- srcs: [
- "ColorConvert.cpp",
- "GraphicBufferListener.cpp",
- "IntrinsicBlurFilter.cpp",
- "MediaFilter.cpp",
- "RSFilter.cpp",
- "SaturationFilter.cpp",
- "saturationARGB.rscript",
- "SimpleFilter.cpp",
- "ZeroFilter.cpp",
- ],
-
- export_include_dirs: [
- "include",
- ],
-
- local_include_dirs: [
- "include/filters",
- ],
-
- cflags: [
- "-Wno-multichar",
- "-Werror",
- "-Wall",
- ],
-
- header_libs: [
- "libmediadrm_headers",
- ],
-
- shared_libs: [
- "libgui",
- "libmedia",
- "libhidlmemory",
- ],
-
- sanitize: {
- cfi: true,
- },
-}
diff --git a/media/libstagefright/filters/ColorConvert.cpp b/media/libstagefright/filters/ColorConvert.cpp
deleted file mode 100644
index a8d5dd2..0000000
--- a/media/libstagefright/filters/ColorConvert.cpp
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2014 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 "ColorConvert.h"
-
-#ifndef max
-#define max(a,b) ((a) > (b) ? (a) : (b))
-#endif
-#ifndef min
-#define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-namespace android {
-
-void YUVToRGB(
- int32_t y, int32_t u, int32_t v,
- int32_t* r, int32_t* g, int32_t* b) {
- y -= 16;
- u -= 128;
- v -= 128;
-
- *b = 1192 * y + 2066 * u;
- *g = 1192 * y - 833 * v - 400 * u;
- *r = 1192 * y + 1634 * v;
-
- *r = min(262143, max(0, *r));
- *g = min(262143, max(0, *g));
- *b = min(262143, max(0, *b));
-
- *r >>= 10;
- *g >>= 10;
- *b >>= 10;
-}
-
-void convertYUV420spToARGB(
- uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
- uint8_t *dest) {
- const int32_t bytes_per_pixel = 2;
-
- for (int32_t i = 0; i < height; i++) {
- for (int32_t j = 0; j < width; j++) {
- int32_t y = *(pY + i * width + j);
- int32_t u = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
- int32_t v = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
-
- int32_t r, g, b;
- YUVToRGB(y, u, v, &r, &g, &b);
-
- *dest++ = 0xFF;
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- }
- }
-}
-
-void convertYUV420spToRGB888(
- uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
- uint8_t *dest) {
- const int32_t bytes_per_pixel = 2;
-
- for (int32_t i = 0; i < height; i++) {
- for (int32_t j = 0; j < width; j++) {
- int32_t y = *(pY + i * width + j);
- int32_t u = *(pUV + (i/2) * width + bytes_per_pixel * (j/2));
- int32_t v = *(pUV + (i/2) * width + bytes_per_pixel * (j/2) + 1);
-
- int32_t r, g, b;
- YUVToRGB(y, u, v, &r, &g, &b);
-
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- }
- }
-}
-
-// HACK - not even slightly optimized
-// TODO: remove when RGBA support is added to SoftwareRenderer
-void convertRGBAToARGB(
- uint8_t *src, int32_t width, int32_t height, uint32_t stride,
- uint8_t *dest) {
- for (int32_t i = 0; i < height; ++i) {
- for (int32_t j = 0; j < width; ++j) {
- uint8_t r = *src++;
- uint8_t g = *src++;
- uint8_t b = *src++;
- uint8_t a = *src++;
- *dest++ = a;
- *dest++ = r;
- *dest++ = g;
- *dest++ = b;
- }
- src += (stride - width) * 4;
- }
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
deleted file mode 100644
index db061c1..0000000
--- a/media/libstagefright/filters/GraphicBufferListener.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "GraphicBufferListener"
-
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <media/stagefright/MediaErrors.h>
-
-#include <gui/BufferItem.h>
-#include <utils/String8.h>
-
-#include "GraphicBufferListener.h"
-
-namespace android {
-
-status_t GraphicBufferListener::init(
- const sp<AMessage> ¬ify,
- size_t bufferWidth, size_t bufferHeight, size_t bufferCount) {
- mNotify = notify;
-
- String8 name("GraphicBufferListener");
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
- mConsumer->setConsumerName(name);
- mConsumer->setDefaultBufferSize(bufferWidth, bufferHeight);
- mConsumer->setConsumerUsageBits(GRALLOC_USAGE_SW_READ_OFTEN);
-
- status_t err = mConsumer->setMaxAcquiredBufferCount(bufferCount);
- if (err != NO_ERROR) {
- ALOGE("Unable to set BQ max acquired buffer count to %zu: %d",
- bufferCount, err);
- return err;
- }
-
- wp<BufferQueue::ConsumerListener> listener =
- static_cast<BufferQueue::ConsumerListener*>(this);
- sp<BufferQueue::ProxyConsumerListener> proxy =
- new BufferQueue::ProxyConsumerListener(listener);
-
- err = mConsumer->consumerConnect(proxy, false);
- if (err != NO_ERROR) {
- ALOGE("Error connecting to BufferQueue: %s (%d)",
- strerror(-err), err);
- return err;
- }
-
- ALOGV("init() successful.");
-
- return OK;
-}
-
-void GraphicBufferListener::onFrameAvailable(const BufferItem& /* item */) {
- ALOGV("onFrameAvailable() called");
-
- {
- Mutex::Autolock autoLock(mMutex);
- mNumFramesAvailable++;
- }
-
- sp<AMessage> notify = mNotify->dup();
- mNotify->setWhat(kWhatFrameAvailable);
- mNotify->post();
-}
-
-void GraphicBufferListener::onBuffersReleased() {
- ALOGV("onBuffersReleased() called");
- // nothing to do
-}
-
-void GraphicBufferListener::onSidebandStreamChanged() {
- ALOGW("GraphicBufferListener cannot consume sideband streams.");
- // nothing to do
-}
-
-BufferItem GraphicBufferListener::getBufferItem() {
- BufferItem item;
-
- {
- Mutex::Autolock autoLock(mMutex);
- if (mNumFramesAvailable <= 0) {
- ALOGE("getBuffer() called with no frames available");
- return item;
- }
- mNumFramesAvailable--;
- }
-
- status_t err = mConsumer->acquireBuffer(&item, 0);
- if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
- // shouldn't happen, since we track num frames available
- ALOGE("frame was not available");
- item.mSlot = -1;
- return item;
- } else if (err != OK) {
- ALOGE("acquireBuffer returned err=%d", err);
- item.mSlot = -1;
- return item;
- }
-
- // Wait for it to become available.
- err = item.mFence->waitForever("GraphicBufferListener::getBufferItem");
- if (err != OK) {
- ALOGW("failed to wait for buffer fence: %d", err);
- // keep going
- }
-
- // If this is the first time we're seeing this buffer, add it to our
- // slot table.
- if (item.mGraphicBuffer != NULL) {
- ALOGV("setting mBufferSlot %d", item.mSlot);
- mBufferSlot[item.mSlot] = item.mGraphicBuffer;
- }
-
- return item;
-}
-
-sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) {
- sp<GraphicBuffer> buf;
- if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
- return buf;
- }
-
- buf = mBufferSlot[item.mSlot];
- CHECK(buf.get() != NULL);
-
- return buf;
-}
-
-status_t GraphicBufferListener::releaseBuffer(BufferItem item) {
- if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
- return ERROR_OUT_OF_RANGE;
- }
-
- mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/IntrinsicBlurFilter.cpp b/media/libstagefright/filters/IntrinsicBlurFilter.cpp
deleted file mode 100644
index e00afd9..0000000
--- a/media/libstagefright/filters/IntrinsicBlurFilter.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "IntrinsicBlurFilter"
-
-#include <utils/Log.h>
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include "IntrinsicBlurFilter.h"
-
-namespace android {
-
-status_t IntrinsicBlurFilter::configure(const sp<AMessage> &msg) {
- status_t err = SimpleFilter::configure(msg);
- if (err != OK) {
- return err;
- }
-
- if (!msg->findString("cacheDir", &mCacheDir)) {
- ALOGE("Failed to find cache directory in config message.");
- return NAME_NOT_FOUND;
- }
-
- return OK;
-}
-
-status_t IntrinsicBlurFilter::start() {
- // TODO: use a single RS context object for entire application
- mRS = new RSC::RS();
-
- if (!mRS->init(mCacheDir.c_str())) {
- ALOGE("Failed to initialize RenderScript context.");
- return NO_INIT;
- }
-
- // 32-bit elements for ARGB8888
- RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
-
- RSC::Type::Builder tb(mRS, e);
- tb.setX(mWidth);
- tb.setY(mHeight);
- RSC::sp<const RSC::Type> t = tb.create();
-
- mAllocIn = RSC::Allocation::createTyped(mRS, t);
- mAllocOut = RSC::Allocation::createTyped(mRS, t);
-
- mBlur = RSC::ScriptIntrinsicBlur::create(mRS, e);
- mBlur->setRadius(mBlurRadius);
- mBlur->setInput(mAllocIn);
-
- return OK;
-}
-
-void IntrinsicBlurFilter::reset() {
- mBlur.clear();
- mAllocOut.clear();
- mAllocIn.clear();
- mRS.clear();
-}
-
-status_t IntrinsicBlurFilter::setParameters(const sp<AMessage> &msg) {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
-
- float blurRadius;
- if (params->findFloat("blur-radius", &blurRadius)) {
- mBlurRadius = blurRadius;
- }
-
- return OK;
-}
-
-status_t IntrinsicBlurFilter::processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
- mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
- mBlur->forEach(mAllocOut);
- mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
deleted file mode 100644
index c7baa73..0000000
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "MediaFilter"
-
-#include <inttypes.h>
-#include <utils/Trace.h>
-
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include <media/stagefright/BufferProducerWrapper.h>
-#include <media/stagefright/MediaCodecConstants.h>
-#include <media/stagefright/MediaDefs.h>
-#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MediaFilter.h>
-
-#include <media/MediaCodecBuffer.h>
-
-#include <gui/BufferItem.h>
-
-#include "ColorConvert.h"
-#include "GraphicBufferListener.h"
-#include "IntrinsicBlurFilter.h"
-#include "RSFilter.h"
-#include "SaturationFilter.h"
-#include "ZeroFilter.h"
-
-namespace android {
-
-class MediaFilter::BufferChannel : public BufferChannelBase {
-public:
- BufferChannel(const sp<AMessage> &in, const sp<AMessage> &out)
- : mInputBufferFilled(in), mOutputBufferDrained(out) {
- }
-
- ~BufferChannel() override = default;
-
- // BufferChannelBase
-
- status_t queueInputBuffer(const sp<MediaCodecBuffer> &buffer) override {
- sp<AMessage> msg = mInputBufferFilled->dup();
- msg->setObject("buffer", buffer);
- msg->post();
- return OK;
- }
-
- status_t queueSecureInputBuffer(
- const sp<MediaCodecBuffer> &,
- bool,
- const uint8_t *,
- const uint8_t *,
- CryptoPlugin::Mode,
- CryptoPlugin::Pattern,
- const CryptoPlugin::SubSample *,
- size_t,
- AString *) override {
- return INVALID_OPERATION;
- }
-
- status_t renderOutputBuffer(
- const sp<MediaCodecBuffer> &buffer, int64_t /* timestampNs */) override {
- sp<AMessage> msg = mOutputBufferDrained->dup();
- msg->setObject("buffer", buffer);
- msg->post();
- return OK;
- }
-
- status_t discardBuffer(const sp<MediaCodecBuffer> &buffer) override {
- if (FindBufferIndex(&mInputBuffers, buffer) >= 0) {
- sp<AMessage> msg = mInputBufferFilled->dup();
- msg->setObject("buffer", buffer);
- msg->post();
- return OK;
- }
- sp<AMessage> msg = mOutputBufferDrained->dup();
- msg->setObject("buffer", buffer);
- msg->post();
- return OK;
- }
-
- void getInputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- if (!array) {
- return;
- }
- array->clear();
- array->appendVector(mInputBuffers);
- }
-
- void getOutputBufferArray(Vector<sp<MediaCodecBuffer>> *array) {
- if (!array) {
- return;
- }
- array->clear();
- array->appendVector(mOutputBuffers);
- }
-
- // For MediaFilter
-
- void fillThisBuffer(const sp<MediaCodecBuffer> &buffer) {
- ssize_t index = FindBufferIndex(&mInputBuffers, buffer);
- mCallback->onInputBufferAvailable(index, buffer);
- }
-
- void drainThisBuffer(const sp<MediaCodecBuffer> &buffer, int flags) {
- ssize_t index = FindBufferIndex(&mOutputBuffers, buffer);
- buffer->meta()->setInt32("flags", flags);
- mCallback->onOutputBufferAvailable(index, buffer);
- }
-
- template <class T>
- void setInputBuffers(T begin, T end) {
- mInputBuffers.clear();
- for (T it = begin; it != end; ++it) {
- mInputBuffers.push_back(it->mData);
- }
- }
-
- template <class T>
- void setOutputBuffers(T begin, T end) {
- mOutputBuffers.clear();
- for (T it = begin; it != end; ++it) {
- mOutputBuffers.push_back(it->mData);
- }
- }
-
-private:
- sp<AMessage> mInputBufferFilled;
- sp<AMessage> mOutputBufferDrained;
- Vector<sp<MediaCodecBuffer>> mInputBuffers;
- Vector<sp<MediaCodecBuffer>> mOutputBuffers;
-
- static ssize_t FindBufferIndex(
- Vector<sp<MediaCodecBuffer>> *array, const sp<MediaCodecBuffer> &buffer) {
- for (size_t i = 0; i < array->size(); ++i) {
- if (array->itemAt(i) == buffer) {
- return i;
- }
- }
- return -1;
- }
-};
-
-// parameter: number of input and output buffers
-static const size_t kBufferCountActual = 4;
-
-MediaFilter::MediaFilter()
- : mState(UNINITIALIZED),
- mGeneration(0),
- mGraphicBufferListener(NULL) {
-}
-
-MediaFilter::~MediaFilter() {
-}
-
-//////////////////// PUBLIC FUNCTIONS //////////////////////////////////////////
-
-std::shared_ptr<BufferChannelBase> MediaFilter::getBufferChannel() {
- if (!mBufferChannel) {
- mBufferChannel = std::make_shared<BufferChannel>(
- new AMessage(kWhatInputBufferFilled, this),
- new AMessage(kWhatOutputBufferDrained, this));
- }
- return mBufferChannel;
-}
-
-void MediaFilter::initiateAllocateComponent(const sp<AMessage> &msg) {
- msg->setWhat(kWhatAllocateComponent);
- msg->setTarget(this);
- msg->post();
-}
-
-void MediaFilter::initiateConfigureComponent(const sp<AMessage> &msg) {
- msg->setWhat(kWhatConfigureComponent);
- msg->setTarget(this);
- msg->post();
-}
-
-void MediaFilter::initiateCreateInputSurface() {
- (new AMessage(kWhatCreateInputSurface, this))->post();
-}
-
-void MediaFilter::initiateSetInputSurface(
- const sp<PersistentSurface> & /* surface */) {
- ALOGW("initiateSetInputSurface() unsupported");
-}
-
-void MediaFilter::initiateStart() {
- (new AMessage(kWhatStart, this))->post();
-}
-
-void MediaFilter::initiateShutdown(bool keepComponentAllocated) {
- sp<AMessage> msg = new AMessage(kWhatShutdown, this);
- msg->setInt32("keepComponentAllocated", keepComponentAllocated);
- msg->post();
-}
-
-void MediaFilter::signalFlush() {
- (new AMessage(kWhatFlush, this))->post();
-}
-
-void MediaFilter::signalResume() {
- (new AMessage(kWhatResume, this))->post();
-}
-
-// nothing to do
-void MediaFilter::signalRequestIDRFrame() {
- return;
-}
-
-void MediaFilter::signalSetParameters(const sp<AMessage> ¶ms) {
- sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
- msg->setMessage("params", params);
- msg->post();
-}
-
-void MediaFilter::signalEndOfInputStream() {
- (new AMessage(kWhatSignalEndOfInputStream, this))->post();
-}
-
-void MediaFilter::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- case kWhatAllocateComponent:
- {
- onAllocateComponent(msg);
- break;
- }
- case kWhatConfigureComponent:
- {
- onConfigureComponent(msg);
- break;
- }
- case kWhatStart:
- {
- onStart();
- break;
- }
- case kWhatProcessBuffers:
- {
- processBuffers();
- break;
- }
- case kWhatInputBufferFilled:
- {
- onInputBufferFilled(msg);
- break;
- }
- case kWhatOutputBufferDrained:
- {
- onOutputBufferDrained(msg);
- break;
- }
- case kWhatShutdown:
- {
- onShutdown(msg);
- break;
- }
- case kWhatFlush:
- {
- onFlush();
- break;
- }
- case kWhatResume:
- {
- // nothing to do
- break;
- }
- case kWhatSetParameters:
- {
- onSetParameters(msg);
- break;
- }
- case kWhatCreateInputSurface:
- {
- onCreateInputSurface();
- break;
- }
- case GraphicBufferListener::kWhatFrameAvailable:
- {
- onInputFrameAvailable();
- break;
- }
- case kWhatSignalEndOfInputStream:
- {
- onSignalEndOfInputStream();
- break;
- }
- default:
- {
- ALOGE("Message not handled:\n%s", msg->debugString().c_str());
- break;
- }
- }
-}
-
-//////////////////// HELPER FUNCTIONS //////////////////////////////////////////
-
-void MediaFilter::signalProcessBuffers() {
- (new AMessage(kWhatProcessBuffers, this))->post();
-}
-
-void MediaFilter::signalError(status_t error) {
- mCallback->onError(error, ACTION_CODE_FATAL);
-}
-
-status_t MediaFilter::allocateBuffersOnPort(OMX_U32 portIndex) {
- CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput);
- const bool isInput = portIndex == kPortIndexInput;
- const size_t bufferSize = isInput ? mMaxInputSize : mMaxOutputSize;
-
- CHECK(mBuffers[portIndex].isEmpty());
-
- ALOGV("Allocating %zu buffers of size %zu on %s port",
- kBufferCountActual, bufferSize,
- isInput ? "input" : "output");
-
- // trigger output format change
- sp<AMessage> outputFormat = mOutputFormat->dup();
- for (size_t i = 0; i < kBufferCountActual; ++i) {
- BufferInfo info;
- info.mStatus = BufferInfo::OWNED_BY_US;
- info.mBufferID = i;
- info.mGeneration = mGeneration;
- info.mOutputFlags = 0;
- info.mData = new MediaCodecBuffer(
- isInput ? mInputFormat : outputFormat,
- new ABuffer(bufferSize));
- info.mData->meta()->setInt64("timeUs", 0);
-
- mBuffers[portIndex].push_back(info);
-
- if (!isInput) {
- mAvailableOutputBuffers.push(
- &mBuffers[portIndex].editItemAt(i));
- }
- }
- if (isInput) {
- mBufferChannel->setInputBuffers(
- mBuffers[portIndex].begin(), mBuffers[portIndex].end());
- } else {
- mBufferChannel->setOutputBuffers(
- mBuffers[portIndex].begin(), mBuffers[portIndex].end());
- }
-
- return OK;
-}
-
-MediaFilter::BufferInfo* MediaFilter::findBuffer(
- uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
- ssize_t *index) {
- for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) {
- BufferInfo *info = &mBuffers[portIndex].editItemAt(i);
-
- if (info->mData == buffer) {
- if (index != NULL) {
- *index = i;
- }
- return info;
- }
- }
-
- TRESPASS();
-
- return NULL;
-}
-
-void MediaFilter::postFillThisBuffer(BufferInfo *info) {
- ALOGV("postFillThisBuffer on buffer %d", info->mBufferID);
- if (mPortEOS[kPortIndexInput]) {
- return;
- }
-
- CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
-
- info->mGeneration = mGeneration;
-
- info->mData->meta()->clear();
-
- sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this);
- reply->setInt32("buffer-id", info->mBufferID);
-
- info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
-
- mBufferChannel->fillThisBuffer(info->mData);
-}
-
-void MediaFilter::postDrainThisBuffer(BufferInfo *info) {
- CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US);
-
- info->mGeneration = mGeneration;
-
- sp<AMessage> reply = new AMessage(kWhatOutputBufferDrained, this);
- reply->setInt32("buffer-id", info->mBufferID);
-
- mBufferChannel->drainThisBuffer(info->mData, info->mOutputFlags);
-
- info->mStatus = BufferInfo::OWNED_BY_UPSTREAM;
-}
-
-void MediaFilter::postEOS() {
- mCallback->onEos(ERROR_END_OF_STREAM);
-
- ALOGV("Sent kWhatEOS.");
-}
-
-void MediaFilter::requestFillEmptyInput() {
- if (mPortEOS[kPortIndexInput]) {
- return;
- }
-
- for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
- BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
-
- if (info->mStatus == BufferInfo::OWNED_BY_US) {
- postFillThisBuffer(info);
- }
- }
-}
-
-void MediaFilter::processBuffers() {
- if (mAvailableInputBuffers.empty() || mAvailableOutputBuffers.empty()) {
- ALOGV("Skipping process (buffers unavailable)");
- return;
- }
-
- if (mPortEOS[kPortIndexOutput]) {
- // TODO notify caller of queueInput error when it is supported
- // in MediaCodec
- ALOGW("Tried to process a buffer after EOS.");
- return;
- }
-
- BufferInfo *inputInfo = mAvailableInputBuffers[0];
- mAvailableInputBuffers.removeAt(0);
- BufferInfo *outputInfo = mAvailableOutputBuffers[0];
- mAvailableOutputBuffers.removeAt(0);
-
- status_t err;
- err = mFilter->processBuffers(inputInfo->mData, outputInfo->mData);
- if (err != (status_t)OK) {
- outputInfo->mData->meta()->setInt32("err", err);
- }
-
- int64_t timeUs;
- CHECK(inputInfo->mData->meta()->findInt64("timeUs", &timeUs));
- outputInfo->mData->meta()->setInt64("timeUs", timeUs);
- outputInfo->mOutputFlags = 0;
- int32_t eos = 0;
- if (inputInfo->mData->meta()->findInt32("eos", &eos) && eos != 0) {
- outputInfo->mOutputFlags |= BUFFER_FLAG_END_OF_STREAM;
- mPortEOS[kPortIndexOutput] = true;
- outputInfo->mData->meta()->setInt32("eos", eos);
- postEOS();
- ALOGV("Output stream saw EOS.");
- }
-
- ALOGV("Processed input buffer %u [%zu], output buffer %u [%zu]",
- inputInfo->mBufferID, inputInfo->mData->size(),
- outputInfo->mBufferID, outputInfo->mData->size());
-
- if (mGraphicBufferListener != NULL) {
- delete inputInfo;
- } else {
- postFillThisBuffer(inputInfo);
- }
- postDrainThisBuffer(outputInfo);
-
- // prevent any corner case where buffers could get stuck in queue
- signalProcessBuffers();
-}
-
-void MediaFilter::onAllocateComponent(const sp<AMessage> &msg) {
- CHECK_EQ(mState, UNINITIALIZED);
-
- CHECK(msg->findString("componentName", &mComponentName));
- const char* name = mComponentName.c_str();
- if (!strcasecmp(name, "android.filter.zerofilter")) {
- mFilter = new ZeroFilter;
- } else if (!strcasecmp(name, "android.filter.saturation")) {
- mFilter = new SaturationFilter;
- } else if (!strcasecmp(name, "android.filter.intrinsicblur")) {
- mFilter = new IntrinsicBlurFilter;
- } else if (!strcasecmp(name, "android.filter.RenderScript")) {
- mFilter = new RSFilter;
- } else {
- ALOGE("Unrecognized filter name: %s", name);
- signalError(NAME_NOT_FOUND);
- return;
- }
-
- mCallback->onComponentAllocated(mComponentName.c_str());
- mState = INITIALIZED;
- ALOGV("Handled kWhatAllocateComponent.");
-}
-
-void MediaFilter::onConfigureComponent(const sp<AMessage> &msg) {
- // TODO: generalize to allow audio filters as well as video
-
- CHECK_EQ(mState, INITIALIZED);
-
- // get params - at least mime, width & height
- AString mime;
- CHECK(msg->findString("mime", &mime));
- if (strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) {
- ALOGE("Bad mime: %s", mime.c_str());
- signalError(BAD_VALUE);
- return;
- }
-
- CHECK(msg->findInt32("width", &mWidth));
- CHECK(msg->findInt32("height", &mHeight));
- if (!msg->findInt32("stride", &mStride)) {
- mStride = mWidth;
- }
- if (!msg->findInt32("slice-height", &mSliceHeight)) {
- mSliceHeight = mHeight;
- }
-
- mMaxInputSize = mWidth * mHeight * 4; // room for ARGB8888
- int32_t maxInputSize;
- if (msg->findInt32("max-input-size", &maxInputSize)
- && (size_t)maxInputSize > mMaxInputSize) {
- mMaxInputSize = maxInputSize;
- }
-
- if (!msg->findInt32("color-format", &mColorFormatIn)) {
- // default to OMX_COLOR_Format32bitARGB8888
- mColorFormatIn = OMX_COLOR_Format32bitARGB8888;
- msg->setInt32("color-format", mColorFormatIn);
- }
- mColorFormatOut = mColorFormatIn;
-
- mMaxOutputSize = mWidth * mHeight * 4; // room for ARGB8888
-
- AString cacheDir;
- if (!msg->findString("cacheDir", &cacheDir)) {
- ALOGE("Failed to find cache directory in config message.");
- signalError(NAME_NOT_FOUND);
- return;
- }
-
- status_t err;
- err = mFilter->configure(msg);
- if (err != (status_t)OK) {
- ALOGE("Failed to configure filter component, err %d", err);
- signalError(err);
- return;
- }
-
- mInputFormat = new AMessage();
- mInputFormat->setString("mime", mime.c_str());
- mInputFormat->setInt32("stride", mStride);
- mInputFormat->setInt32("slice-height", mSliceHeight);
- mInputFormat->setInt32("color-format", mColorFormatIn);
- mInputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
- mInputFormat->setInt32("width", mWidth);
- mInputFormat->setInt32("height", mHeight);
-
- mOutputFormat = new AMessage();
- mOutputFormat->setString("mime", mime.c_str());
- mOutputFormat->setInt32("stride", mStride);
- mOutputFormat->setInt32("slice-height", mSliceHeight);
- mOutputFormat->setInt32("color-format", mColorFormatOut);
- mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight);
- mOutputFormat->setInt32("width", mWidth);
- mOutputFormat->setInt32("height", mHeight);
- mOutputFormat->setInt32("using-sw-renderer", 1);
-
- mCallback->onComponentConfigured(mInputFormat, mOutputFormat);
- mState = CONFIGURED;
- ALOGV("Handled kWhatConfigureComponent.");
-}
-
-void MediaFilter::onStart() {
- CHECK_EQ(mState, CONFIGURED);
-
- allocateBuffersOnPort(kPortIndexInput);
-
- allocateBuffersOnPort(kPortIndexOutput);
-
- mCallback->onStartCompleted();
-
- status_t err = mFilter->start();
- if (err != (status_t)OK) {
- ALOGE("Failed to start filter component, err %d", err);
- signalError(err);
- return;
- }
-
- mPortEOS[kPortIndexInput] = false;
- mPortEOS[kPortIndexOutput] = false;
- mInputEOSResult = OK;
- mState = STARTED;
-
- requestFillEmptyInput();
- ALOGV("Handled kWhatStart.");
-}
-
-void MediaFilter::onInputBufferFilled(const sp<AMessage> &msg) {
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
- ssize_t index = -1;
- BufferInfo *info = findBuffer(kPortIndexInput, buffer, &index);
-
- if (mState != STARTED) {
- // we're not running, so we'll just keep that buffer...
- info->mStatus = BufferInfo::OWNED_BY_US;
- return;
- }
-
- if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale input buffer [index %zd]", index);
- // buffer is stale (taken before a flush/shutdown) - repost it
- CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
- postFillThisBuffer(info);
- return;
- }
-
- CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
- info->mStatus = BufferInfo::OWNED_BY_US;
-
- int32_t err = OK;
- bool eos = false;
-
- int32_t isCSD;
- if (buffer != NULL && buffer->meta()->findInt32("csd", &isCSD)
- && isCSD != 0) {
- // ignore codec-specific data buffers
- ALOGW("MediaFilter received a codec-specific data buffer");
- postFillThisBuffer(info);
- return;
- }
-
- int32_t tmp;
- if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) {
- eos = true;
- err = ERROR_END_OF_STREAM;
- }
-
- mAvailableInputBuffers.push_back(info);
- processBuffers();
-
- if (eos) {
- mPortEOS[kPortIndexInput] = true;
- mInputEOSResult = err;
- }
-
- ALOGV("Handled kWhatInputBufferFilled. [index %zd]", index);
-}
-
-void MediaFilter::onOutputBufferDrained(const sp<AMessage> &msg) {
- sp<RefBase> obj;
- CHECK(msg->findObject("buffer", &obj));
- sp<MediaCodecBuffer> buffer = static_cast<MediaCodecBuffer *>(obj.get());
- ssize_t index = -1;
- BufferInfo *info = findBuffer(kPortIndexOutput, buffer, &index);
-
- if (mState != STARTED) {
- // we're not running, so we'll just keep that buffer...
- info->mStatus = BufferInfo::OWNED_BY_US;
- return;
- }
-
- if (info->mGeneration != mGeneration) {
- ALOGV("Caught a stale output buffer [index %zd]", index);
- // buffer is stale (taken before a flush/shutdown) - keep it
- CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_US);
- return;
- }
-
- CHECK_EQ(info->mStatus, BufferInfo::OWNED_BY_UPSTREAM);
- info->mStatus = BufferInfo::OWNED_BY_US;
-
- mAvailableOutputBuffers.push_back(info);
-
- processBuffers();
-
- ALOGV("Handled kWhatOutputBufferDrained. [index %zd]", index);
-}
-
-void MediaFilter::onShutdown(const sp<AMessage> &msg) {
- mGeneration++;
-
- if (mState != UNINITIALIZED) {
- mFilter->reset();
- }
-
- int32_t keepComponentAllocated;
- CHECK(msg->findInt32("keepComponentAllocated", &keepComponentAllocated));
- if (!keepComponentAllocated || mState == UNINITIALIZED) {
- mState = UNINITIALIZED;
- } else {
- mState = INITIALIZED;
- }
-
- if (keepComponentAllocated) {
- mCallback->onStopCompleted();
- } else {
- mCallback->onReleaseCompleted();
- }
-}
-
-void MediaFilter::onFlush() {
- mGeneration++;
-
- mAvailableInputBuffers.clear();
- for (size_t i = 0; i < mBuffers[kPortIndexInput].size(); ++i) {
- BufferInfo *info = &mBuffers[kPortIndexInput].editItemAt(i);
- info->mStatus = BufferInfo::OWNED_BY_US;
- }
- mAvailableOutputBuffers.clear();
- for (size_t i = 0; i < mBuffers[kPortIndexOutput].size(); ++i) {
- BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i);
- info->mStatus = BufferInfo::OWNED_BY_US;
- mAvailableOutputBuffers.push_back(info);
- }
-
- mPortEOS[kPortIndexInput] = false;
- mPortEOS[kPortIndexOutput] = false;
- mInputEOSResult = OK;
-
- mCallback->onFlushCompleted();
- ALOGV("Posted kWhatFlushCompleted");
-
- // MediaCodec returns all input buffers after flush, so in
- // onInputBufferFilled we call postFillThisBuffer on them
-}
-
-void MediaFilter::onSetParameters(const sp<AMessage> &msg) {
- CHECK(mState != STARTED);
-
- status_t err = mFilter->setParameters(msg);
- if (err != (status_t)OK) {
- ALOGE("setParameters returned err %d", err);
- }
-}
-
-void MediaFilter::onCreateInputSurface() {
- CHECK(mState == CONFIGURED);
-
- mGraphicBufferListener = new GraphicBufferListener;
-
- sp<AMessage> notify = new AMessage();
- notify->setTarget(this);
- status_t err = mGraphicBufferListener->init(
- notify, mStride, mSliceHeight, kBufferCountActual);
-
- if (err != OK) {
- ALOGE("Failed to init mGraphicBufferListener: %d", err);
- signalError(err);
- return;
- }
-
- mCallback->onInputSurfaceCreated(
- nullptr, nullptr,
- new BufferProducerWrapper(
- mGraphicBufferListener->getIGraphicBufferProducer()));
-}
-
-void MediaFilter::onInputFrameAvailable() {
- BufferItem item = mGraphicBufferListener->getBufferItem();
- sp<GraphicBuffer> buf = mGraphicBufferListener->getBuffer(item);
-
- // get pointer to graphic buffer
- void* bufPtr;
- buf->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &bufPtr);
-
- // HACK - there is no OMX_COLOR_FORMATTYPE value for RGBA, so the format
- // conversion is hardcoded until we add this.
- // TODO: check input format and convert only if necessary
- // copy RGBA graphic buffer into temporary ARGB input buffer
- BufferInfo *inputInfo = new BufferInfo;
- inputInfo->mData = new MediaCodecBuffer(
- mInputFormat, new ABuffer(buf->getWidth() * buf->getHeight() * 4));
- ALOGV("Copying surface data into temp buffer.");
- convertRGBAToARGB(
- (uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
- buf->getStride(), inputInfo->mData->data());
- inputInfo->mBufferID = item.mSlot;
- inputInfo->mGeneration = mGeneration;
- inputInfo->mOutputFlags = 0;
- inputInfo->mStatus = BufferInfo::OWNED_BY_US;
- inputInfo->mData->meta()->setInt64("timeUs", item.mTimestamp / 1000);
-
- mAvailableInputBuffers.push_back(inputInfo);
-
- mGraphicBufferListener->releaseBuffer(item);
-
- signalProcessBuffers();
-}
-
-void MediaFilter::onSignalEndOfInputStream() {
- // if using input surface, need to send an EOS output buffer
- if (mGraphicBufferListener != NULL) {
- Vector<BufferInfo> *outputBufs = &mBuffers[kPortIndexOutput];
- BufferInfo* eosBuf;
- bool foundBuf = false;
- for (size_t i = 0; i < kBufferCountActual; i++) {
- eosBuf = &outputBufs->editItemAt(i);
- if (eosBuf->mStatus == BufferInfo::OWNED_BY_US) {
- foundBuf = true;
- break;
- }
- }
-
- if (!foundBuf) {
- ALOGE("onSignalEndOfInputStream failed to find an output buffer");
- return;
- }
-
- eosBuf->mOutputFlags = BUFFER_FLAG_END_OF_STREAM;
- eosBuf->mGeneration = mGeneration;
- eosBuf->mData->setRange(0, 0);
- postDrainThisBuffer(eosBuf);
- ALOGV("Posted EOS on output buffer %u", eosBuf->mBufferID);
- }
-
- mPortEOS[kPortIndexOutput] = true;
- mCallback->onSignaledInputEOS(OK);
-
- ALOGV("Output stream saw EOS.");
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/RSFilter.cpp b/media/libstagefright/filters/RSFilter.cpp
deleted file mode 100644
index 225a375..0000000
--- a/media/libstagefright/filters/RSFilter.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "RSFilter"
-
-#include <utils/Log.h>
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include "RSFilter.h"
-
-namespace android {
-
-RSFilter::RSFilter() {
-
-}
-
-RSFilter::~RSFilter() {
-
-}
-
-status_t RSFilter::configure(const sp<AMessage> &msg) {
- status_t err = SimpleFilter::configure(msg);
- if (err != OK) {
- return err;
- }
-
- if (!msg->findString("cacheDir", &mCacheDir)) {
- ALOGE("Failed to find cache directory in config message.");
- return NAME_NOT_FOUND;
- }
-
- sp<RenderScriptWrapper> wrapper;
- if (!msg->findObject("rs-wrapper", (sp<RefBase>*)&wrapper)) {
- ALOGE("Failed to find RenderScriptWrapper in config message.");
- return NAME_NOT_FOUND;
- }
-
- mRS = wrapper->mContext;
- mCallback = wrapper->mCallback;
-
- return OK;
-}
-
-status_t RSFilter::start() {
- // 32-bit elements for ARGB8888
- RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
-
- RSC::Type::Builder tb(mRS, e);
- tb.setX(mWidth);
- tb.setY(mHeight);
- RSC::sp<const RSC::Type> t = tb.create();
-
- mAllocIn = RSC::Allocation::createTyped(mRS, t);
- mAllocOut = RSC::Allocation::createTyped(mRS, t);
-
- return OK;
-}
-
-void RSFilter::reset() {
- mCallback.clear();
- mAllocOut.clear();
- mAllocIn.clear();
- mRS.clear();
-}
-
-status_t RSFilter::setParameters(const sp<AMessage> &msg) {
- return mCallback->handleSetParameters(msg);
-}
-
-status_t RSFilter::processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
- mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
- mCallback->processBuffers(mAllocIn.get(), mAllocOut.get());
- mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/SaturationFilter.cpp b/media/libstagefright/filters/SaturationFilter.cpp
deleted file mode 100644
index 0a1df05..0000000
--- a/media/libstagefright/filters/SaturationFilter.cpp
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "SaturationFilter"
-
-#include <utils/Log.h>
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include "SaturationFilter.h"
-
-namespace android {
-
-status_t SaturationFilter::configure(const sp<AMessage> &msg) {
- status_t err = SimpleFilter::configure(msg);
- if (err != OK) {
- return err;
- }
-
- if (!msg->findString("cacheDir", &mCacheDir)) {
- ALOGE("Failed to find cache directory in config message.");
- return NAME_NOT_FOUND;
- }
-
- return OK;
-}
-
-status_t SaturationFilter::start() {
- // TODO: use a single RS context object for entire application
- mRS = new RSC::RS();
-
- if (!mRS->init(mCacheDir.c_str())) {
- ALOGE("Failed to initialize RenderScript context.");
- return NO_INIT;
- }
-
- // 32-bit elements for ARGB8888
- RSC::sp<const RSC::Element> e = RSC::Element::U8_4(mRS);
-
- RSC::Type::Builder tb(mRS, e);
- tb.setX(mWidth);
- tb.setY(mHeight);
- RSC::sp<const RSC::Type> t = tb.create();
-
- mAllocIn = RSC::Allocation::createTyped(mRS, t);
- mAllocOut = RSC::Allocation::createTyped(mRS, t);
-
- mScript = new ScriptC_saturationARGB(mRS);
-
- mScript->set_gSaturation(mSaturation);
-
- return OK;
-}
-
-void SaturationFilter::reset() {
- mScript.clear();
- mAllocOut.clear();
- mAllocIn.clear();
- mRS.clear();
-}
-
-status_t SaturationFilter::setParameters(const sp<AMessage> &msg) {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
-
- float saturation;
- if (params->findFloat("saturation", &saturation)) {
- mSaturation = saturation;
- }
-
- return OK;
-}
-
-status_t SaturationFilter::processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
- mAllocIn->copy1DRangeFrom(0, mWidth * mHeight, srcBuffer->data());
- mScript->forEach_root(mAllocIn, mAllocOut);
- mAllocOut->copy1DRangeTo(0, mWidth * mHeight, outBuffer->data());
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/SimpleFilter.cpp b/media/libstagefright/filters/SimpleFilter.cpp
deleted file mode 100644
index 6c1ca2c..0000000
--- a/media/libstagefright/filters/SimpleFilter.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2014 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 <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include "SimpleFilter.h"
-
-namespace android {
-
-status_t SimpleFilter::configure(const sp<AMessage> &msg) {
- CHECK(msg->findInt32("width", &mWidth));
- CHECK(msg->findInt32("height", &mHeight));
- if (!msg->findInt32("stride", &mStride)) {
- mStride = mWidth;
- }
- if (!msg->findInt32("slice-height", &mSliceHeight)) {
- mSliceHeight = mHeight;
- }
- CHECK(msg->findInt32("color-format", &mColorFormatIn));
- mColorFormatOut = mColorFormatIn;
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/ZeroFilter.cpp b/media/libstagefright/filters/ZeroFilter.cpp
deleted file mode 100644
index 74b94b7..0000000
--- a/media/libstagefright/filters/ZeroFilter.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 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_NDEBUG 0
-#define LOG_TAG "ZeroFilter"
-
-#include <media/MediaCodecBuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-
-#include "ZeroFilter.h"
-
-namespace android {
-
-status_t ZeroFilter::setParameters(const sp<AMessage> &msg) {
- sp<AMessage> params;
- CHECK(msg->findMessage("params", ¶ms));
-
- int32_t invert;
- if (params->findInt32("invert", &invert)) {
- mInvertData = (invert != 0);
- }
-
- return OK;
-}
-
-status_t ZeroFilter::processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) {
- // assuming identical input & output buffers, since we're a copy filter
- if (mInvertData) {
- uint32_t* src = (uint32_t*)srcBuffer->data();
- uint32_t* dest = (uint32_t*)outBuffer->data();
- for (size_t i = 0; i < srcBuffer->size() / 4; ++i) {
- *(dest++) = *(src++) ^ 0xFFFFFFFF;
- }
- } else {
- memcpy(outBuffer->data(), srcBuffer->data(), srcBuffer->size());
- }
- outBuffer->setRange(0, srcBuffer->size());
-
- return OK;
-}
-
-} // namespace android
diff --git a/media/libstagefright/filters/include/filters/ColorConvert.h b/media/libstagefright/filters/include/filters/ColorConvert.h
deleted file mode 100644
index 13faa02..0000000
--- a/media/libstagefright/filters/include/filters/ColorConvert.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef COLOR_CONVERT_H_
-#define COLOR_CONVERT_H_
-
-#include <inttypes.h>
-
-namespace android {
-
-void YUVToRGB(
- int32_t y, int32_t u, int32_t v,
- int32_t* r, int32_t* g, int32_t* b);
-
-void convertYUV420spToARGB(
- uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
- uint8_t *dest);
-
-void convertYUV420spToRGB888(
- uint8_t *pY, uint8_t *pUV, int32_t width, int32_t height,
- uint8_t *dest);
-
-// TODO: remove when RGBA support is added to SoftwareRenderer
-void convertRGBAToARGB(
- uint8_t *src, int32_t width, int32_t height, uint32_t stride,
- uint8_t *dest);
-
-} // namespace android
-
-#endif // COLOR_CONVERT_H_
diff --git a/media/libstagefright/filters/include/filters/GraphicBufferListener.h b/media/libstagefright/filters/include/filters/GraphicBufferListener.h
deleted file mode 100644
index 586bf65..0000000
--- a/media/libstagefright/filters/include/filters/GraphicBufferListener.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef GRAPHIC_BUFFER_LISTENER_H_
-#define GRAPHIC_BUFFER_LISTENER_H_
-
-#include <gui/BufferQueue.h>
-
-namespace android {
-
-struct AMessage;
-
-struct GraphicBufferListener : public BufferQueue::ConsumerListener {
-public:
- GraphicBufferListener() {};
-
- status_t init(
- const sp<AMessage> ¬ify,
- size_t bufferWidth, size_t bufferHeight, size_t bufferCount);
-
- virtual void onFrameAvailable(const BufferItem& item);
- virtual void onBuffersReleased();
- virtual void onSidebandStreamChanged();
-
- // Returns the handle to the producer side of the BufferQueue. Buffers
- // queued on this will be received by GraphicBufferListener.
- sp<IGraphicBufferProducer> getIGraphicBufferProducer() const {
- return mProducer;
- }
-
- BufferItem getBufferItem();
- sp<GraphicBuffer> getBuffer(BufferItem item);
- status_t releaseBuffer(BufferItem item);
-
- enum {
- kWhatFrameAvailable = 'frav',
- };
-
-private:
- sp<AMessage> mNotify;
- size_t mNumFramesAvailable;
-
- mutable Mutex mMutex;
-
- // Our BufferQueue interfaces. mProducer is passed to the producer through
- // getIGraphicBufferProducer, and mConsumer is used internally to retrieve
- // the buffers queued by the producer.
- sp<IGraphicBufferProducer> mProducer;
- sp<IGraphicBufferConsumer> mConsumer;
-
- // Cache of GraphicBuffers from the buffer queue.
- sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];
-};
-
-} // namespace android
-
-#endif // GRAPHIC_BUFFER_LISTENER_H
diff --git a/media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h b/media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
deleted file mode 100644
index a2aabfa..0000000
--- a/media/libstagefright/filters/include/filters/IntrinsicBlurFilter.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef INTRINSIC_BLUR_FILTER_H_
-#define INTRINSIC_BLUR_FILTER_H_
-
-#include "RenderScript.h"
-#include "SimpleFilter.h"
-
-namespace android {
-
-struct IntrinsicBlurFilter : public SimpleFilter {
-public:
- IntrinsicBlurFilter() : mBlurRadius(1.f) {};
-
- virtual status_t configure(const sp<AMessage> &msg);
- virtual status_t start();
- virtual void reset();
- virtual status_t setParameters(const sp<AMessage> &msg);
- virtual status_t processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
-
-protected:
- virtual ~IntrinsicBlurFilter() {};
-
-private:
- AString mCacheDir;
- RSC::sp<RSC::RS> mRS;
- RSC::sp<RSC::Allocation> mAllocIn;
- RSC::sp<RSC::Allocation> mAllocOut;
- RSC::sp<RSC::ScriptIntrinsicBlur> mBlur;
- float mBlurRadius;
-};
-
-} // namespace android
-
-#endif // INTRINSIC_BLUR_FILTER_H_
diff --git a/media/libstagefright/filters/include/filters/RSFilter.h b/media/libstagefright/filters/include/filters/RSFilter.h
deleted file mode 100644
index 3326284..0000000
--- a/media/libstagefright/filters/include/filters/RSFilter.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef RS_FILTER_H_
-#define RS_FILTER_H_
-
-#include <media/stagefright/RenderScriptWrapper.h>
-#include <RenderScript.h>
-
-#include "SimpleFilter.h"
-
-namespace android {
-
-struct AString;
-
-struct RSFilter : public SimpleFilter {
-public:
- RSFilter();
-
- virtual status_t configure(const sp<AMessage> &msg);
- virtual status_t start();
- virtual void reset();
- virtual status_t setParameters(const sp<AMessage> &msg);
- virtual status_t processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
-
-protected:
- virtual ~RSFilter();
-
-private:
- AString mCacheDir;
- sp<RenderScriptWrapper::RSFilterCallback> mCallback;
- RSC::sp<RSC::RS> mRS;
- RSC::sp<RSC::Allocation> mAllocIn;
- RSC::sp<RSC::Allocation> mAllocOut;
-};
-
-} // namespace android
-
-#endif // RS_FILTER_H_
diff --git a/media/libstagefright/filters/include/filters/SaturationFilter.h b/media/libstagefright/filters/include/filters/SaturationFilter.h
deleted file mode 100644
index 317e469..0000000
--- a/media/libstagefright/filters/include/filters/SaturationFilter.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef SATURATION_FILTER_H_
-#define SATURATION_FILTER_H_
-
-#include <RenderScript.h>
-
-#include "ScriptC_saturationARGB.h"
-#include "SimpleFilter.h"
-
-namespace android {
-
-struct SaturationFilter : public SimpleFilter {
-public:
- SaturationFilter() : mSaturation(1.f) {};
-
- virtual status_t configure(const sp<AMessage> &msg);
- virtual status_t start();
- virtual void reset();
- virtual status_t setParameters(const sp<AMessage> &msg);
- virtual status_t processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
-
-protected:
- virtual ~SaturationFilter() {};
-
-private:
- AString mCacheDir;
- RSC::sp<RSC::RS> mRS;
- RSC::sp<RSC::Allocation> mAllocIn;
- RSC::sp<RSC::Allocation> mAllocOut;
- RSC::sp<ScriptC_saturationARGB> mScript;
- float mSaturation;
-};
-
-} // namespace android
-
-#endif // SATURATION_FILTER_H_
diff --git a/media/libstagefright/filters/include/filters/SimpleFilter.h b/media/libstagefright/filters/include/filters/SimpleFilter.h
deleted file mode 100644
index a3c2d76..0000000
--- a/media/libstagefright/filters/include/filters/SimpleFilter.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef SIMPLE_FILTER_H_
-#define SIMPLE_FILTER_H_
-
-#include <stdint.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-
-namespace android {
-
-struct AMessage;
-class MediaCodecBuffer;
-
-struct SimpleFilter : public RefBase {
-public:
- SimpleFilter() : mWidth(0), mHeight(0), mStride(0), mSliceHeight(0),
- mColorFormatIn(0), mColorFormatOut(0) {};
-
- virtual status_t configure(const sp<AMessage> &msg);
-
- virtual status_t start() = 0;
- virtual void reset() = 0;
- virtual status_t setParameters(const sp<AMessage> &msg) = 0;
- virtual status_t processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer) = 0;
-
-protected:
- int32_t mWidth, mHeight;
- int32_t mStride, mSliceHeight;
- int32_t mColorFormatIn, mColorFormatOut;
-
- virtual ~SimpleFilter() {};
-};
-
-} // namespace android
-
-#endif // SIMPLE_FILTER_H_
diff --git a/media/libstagefright/filters/include/filters/ZeroFilter.h b/media/libstagefright/filters/include/filters/ZeroFilter.h
deleted file mode 100644
index f941cc8..0000000
--- a/media/libstagefright/filters/include/filters/ZeroFilter.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef ZERO_FILTER_H_
-#define ZERO_FILTER_H_
-
-#include "SimpleFilter.h"
-
-namespace android {
-
-struct ZeroFilter : public SimpleFilter {
-public:
- ZeroFilter() : mInvertData(false) {};
-
- virtual status_t start() { return OK; };
- virtual void reset() {};
- virtual status_t setParameters(const sp<AMessage> &msg);
- virtual status_t processBuffers(
- const sp<MediaCodecBuffer> &srcBuffer, const sp<MediaCodecBuffer> &outBuffer);
-
-protected:
- virtual ~ZeroFilter() {};
-
-private:
- bool mInvertData;
-};
-
-} // namespace android
-
-#endif // ZERO_FILTER_H_
diff --git a/media/libstagefright/filters/saturation.rscript b/media/libstagefright/filters/saturation.rscript
deleted file mode 100644
index 2c867ac..0000000
--- a/media/libstagefright/filters/saturation.rscript
+++ /dev/null
@@ -1,40 +0,0 @@
-// Sample script for RGB888 support (compare to saturationARGB.rs)
-/*
- * Copyright (C) 2014 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 version(1)
-#pragma rs java_package_name(com.android.rs.cppbasic)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-// global variables (parameters accessible to application code)
-float gSaturation = 1.0f;
-
-void root(const uchar3 *v_in, uchar3 *v_out) {
- // scale 0-255 uchar to 0-1.0 float
- float3 in = {v_in->r * 0.003921569f, v_in->g * 0.003921569f,
- v_in->b * 0.003921569f};
-
- // apply saturation filter
- float3 result = dot(in, gMonoMult);
- result = mix(result, in, gSaturation);
-
- // convert to uchar, copied from rsPackColorTo8888
- v_out->x = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
- v_out->y = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
- v_out->z = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
-}
diff --git a/media/libstagefright/filters/saturationARGB.rscript b/media/libstagefright/filters/saturationARGB.rscript
deleted file mode 100644
index 1de9dd8..0000000
--- a/media/libstagefright/filters/saturationARGB.rscript
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2014 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 version(1)
-#pragma rs java_package_name(com.android.rs.cppbasic)
-#pragma rs_fp_relaxed
-
-const static float3 gMonoMult = {0.299f, 0.587f, 0.114f};
-
-// global variables (parameters accessible to application code)
-float gSaturation = 1.0f;
-
-void root(const uchar4 *v_in, uchar4 *v_out) {
- v_out->x = v_in->x; // don't modify A
-
- // get RGB, scale 0-255 uchar to 0-1.0 float
- float3 rgb = {v_in->y * 0.003921569f, v_in->z * 0.003921569f,
- v_in->w * 0.003921569f};
-
- // apply saturation filter
- float3 result = dot(rgb, gMonoMult);
- result = mix(result, rgb, gSaturation);
-
- v_out->y = (uchar)clamp((result.r * 255.f + 0.5f), 0.f, 255.f);
- v_out->z = (uchar)clamp((result.g * 255.f + 0.5f), 0.f, 255.f);
- v_out->w = (uchar)clamp((result.b * 255.f + 0.5f), 0.f, 255.f);
-}
diff --git a/media/libstagefright/include/media/stagefright/ACodec.h b/media/libstagefright/include/media/stagefright/ACodec.h
index 38a4c1e..08c7917 100644
--- a/media/libstagefright/include/media/stagefright/ACodec.h
+++ b/media/libstagefright/include/media/stagefright/ACodec.h
@@ -17,6 +17,7 @@
#ifndef A_CODEC_H_
#define A_CODEC_H_
+#include <set>
#include <stdint.h>
#include <list>
#include <vector>
@@ -270,6 +271,7 @@
std::vector<BufferInfo> mBuffers[2];
bool mPortEOS[2];
status_t mInputEOSResult;
+ std::set<int64_t> mDecodeOnlyTimesUs;
std::list<sp<AMessage>> mDeferredQueue;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index edb3786..dbc97db 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -90,6 +90,7 @@
BUFFER_FLAG_EOS = 4,
BUFFER_FLAG_PARTIAL_FRAME = 8,
BUFFER_FLAG_MUXER_DATA = 16,
+ BUFFER_FLAG_DECODE_ONLY = 32,
};
enum CVODegree {
@@ -409,6 +410,13 @@
kBufferRendered,
};
+ enum class DequeueOutputResult {
+ kNoBuffer,
+ kDiscardedBuffer,
+ kRepliedWithError,
+ kSuccess,
+ };
+
struct ResourceManagerServiceProxy;
State mState;
@@ -555,7 +563,9 @@
sp<MediaCodecBuffer> *buffer, sp<AMessage> *format);
bool handleDequeueInputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
- bool handleDequeueOutputBuffer(const sp<AReplyToken> &replyID, bool newRequest = false);
+ DequeueOutputResult handleDequeueOutputBuffer(
+ const sp<AReplyToken> &replyID,
+ bool newRequest = false);
void cancelPendingDequeueOperations();
void extractCSD(const sp<AMessage> &format);
@@ -639,6 +649,7 @@
void statsBufferSent(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
void statsBufferReceived(int64_t presentationUs, const sp<MediaCodecBuffer> &buffer);
+ bool discardDecodeOnlyOutputBuffer(size_t index);
enum {
// the default shape of our latency histogram buckets
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 78792c5..4e9623b 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -869,6 +869,7 @@
constexpr int32_t BUFFER_FLAG_END_OF_STREAM = 4;
constexpr int32_t BUFFER_FLAG_KEY_FRAME = 1;
constexpr int32_t BUFFER_FLAG_PARTIAL_FRAME = 8;
+constexpr int32_t BUFFER_FLAG_DECODE_ONLY = 32;
constexpr int32_t BUFFER_FLAG_SYNC_FRAME = 1;
constexpr int32_t CONFIGURE_FLAG_ENCODE = 1;
constexpr int32_t CONFIGURE_FLAG_USE_BLOCK_MODEL = 2;
diff --git a/media/libstagefright/include/media/stagefright/MediaFilter.h b/media/libstagefright/include/media/stagefright/MediaFilter.h
deleted file mode 100644
index 1255e0f..0000000
--- a/media/libstagefright/include/media/stagefright/MediaFilter.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef MEDIA_FILTER_H_
-#define MEDIA_FILTER_H_
-
-#include <media/stagefright/CodecBase.h>
-
-namespace android {
-
-struct GraphicBufferListener;
-struct SimpleFilter;
-
-struct MediaFilter : public CodecBase {
- MediaFilter();
-
- virtual std::shared_ptr<BufferChannelBase> getBufferChannel() override;
- virtual void initiateAllocateComponent(const sp<AMessage> &msg);
- virtual void initiateConfigureComponent(const sp<AMessage> &msg);
- virtual void initiateCreateInputSurface();
- virtual void initiateSetInputSurface(const sp<PersistentSurface> &surface);
-
- virtual void initiateStart();
- virtual void initiateShutdown(bool keepComponentAllocated = false);
-
- virtual void signalFlush();
- virtual void signalResume();
-
- virtual void signalRequestIDRFrame();
- virtual void signalSetParameters(const sp<AMessage> &msg);
- virtual void signalEndOfInputStream();
-
- virtual void onMessageReceived(const sp<AMessage> &msg);
-
-protected:
- virtual ~MediaFilter();
-
-private:
- struct BufferInfo {
- enum Status {
- OWNED_BY_US,
- OWNED_BY_UPSTREAM,
- };
-
- uint32_t mBufferID;
- int32_t mGeneration;
- int32_t mOutputFlags;
- Status mStatus;
-
- sp<MediaCodecBuffer> mData;
- };
-
- class BufferChannel;
-
- enum State {
- UNINITIALIZED,
- INITIALIZED,
- CONFIGURED,
- STARTED,
- };
-
- enum {
- kWhatInputBufferFilled = 'inpF',
- kWhatOutputBufferDrained = 'outD',
- kWhatShutdown = 'shut',
- kWhatFlush = 'flus',
- kWhatResume = 'resm',
- kWhatAllocateComponent = 'allo',
- kWhatConfigureComponent = 'conf',
- kWhatCreateInputSurface = 'cisf',
- kWhatSignalEndOfInputStream = 'eois',
- kWhatStart = 'star',
- kWhatSetParameters = 'setP',
- kWhatProcessBuffers = 'proc',
- };
-
- enum {
- kPortIndexInput = 0,
- kPortIndexOutput = 1
- };
-
- // member variables
- AString mComponentName;
- State mState;
- status_t mInputEOSResult;
- int32_t mWidth, mHeight;
- int32_t mStride, mSliceHeight;
- int32_t mColorFormatIn, mColorFormatOut;
- size_t mMaxInputSize, mMaxOutputSize;
- int32_t mGeneration;
- sp<AMessage> mInputFormat;
- sp<AMessage> mOutputFormat;
-
- Vector<BufferInfo> mBuffers[2];
- Vector<BufferInfo*> mAvailableInputBuffers;
- Vector<BufferInfo*> mAvailableOutputBuffers;
- bool mPortEOS[2];
-
- sp<SimpleFilter> mFilter;
- sp<GraphicBufferListener> mGraphicBufferListener;
-
- std::shared_ptr<BufferChannel> mBufferChannel;
-
- // helper functions
- void signalProcessBuffers();
- void signalError(status_t error);
-
- status_t allocateBuffersOnPort(OMX_U32 portIndex);
- BufferInfo *findBuffer(
- uint32_t portIndex, const sp<MediaCodecBuffer> &buffer,
- ssize_t *index = NULL);
- void postFillThisBuffer(BufferInfo *info);
- void postDrainThisBuffer(BufferInfo *info);
- void postEOS();
- void requestFillEmptyInput();
- void processBuffers();
-
- void onAllocateComponent(const sp<AMessage> &msg);
- void onConfigureComponent(const sp<AMessage> &msg);
- void onStart();
- void onInputBufferFilled(const sp<AMessage> &msg);
- void onOutputBufferDrained(const sp<AMessage> &msg);
- void onShutdown(const sp<AMessage> &msg);
- void onFlush();
- void onSetParameters(const sp<AMessage> &msg);
- void onCreateInputSurface();
- void onInputFrameAvailable();
- void onSignalEndOfInputStream();
-
- DISALLOW_EVIL_CONSTRUCTORS(MediaFilter);
-};
-
-} // namespace android
-
-#endif // MEDIA_FILTER_H_
diff --git a/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h b/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
deleted file mode 100644
index b42649e..0000000
--- a/media/libstagefright/include/media/stagefright/RenderScriptWrapper.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2014 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.
- */
-
-#ifndef RENDERSCRIPT_WRAPPER_H_
-#define RENDERSCRIPT_WRAPPER_H_
-
-#include <RenderScript.h>
-
-namespace android {
-
-struct RenderScriptWrapper : public RefBase {
-public:
- struct RSFilterCallback : public RefBase {
- public:
- // called by RSFilter to process each input buffer
- virtual status_t processBuffers(
- RSC::Allocation* inBuffer,
- RSC::Allocation* outBuffer) = 0;
-
- virtual status_t handleSetParameters(const sp<AMessage> &msg) = 0;
- };
-
- sp<RSFilterCallback> mCallback;
- RSC::sp<RSC::RS> mContext;
-};
-
-} // namespace android
-
-#endif // RENDERSCRIPT_WRAPPER_H_
diff --git a/media/libstagefright/renderfright/Android.bp b/media/libstagefright/renderfright/Android.bp
index 3c00a1c..3598e8d 100644
--- a/media/libstagefright/renderfright/Android.bp
+++ b/media/libstagefright/renderfright/Android.bp
@@ -32,6 +32,7 @@
"libEGL",
"libGLESv1_CM",
"libGLESv2",
+ "libvulkan",
"liblog",
"libnativewindow",
"libprocessgroup",
diff --git a/media/module/extractors/aac/AACExtractor.cpp b/media/module/extractors/aac/AACExtractor.cpp
index 2fc4584..a44fb61 100644
--- a/media/module/extractors/aac/AACExtractor.cpp
+++ b/media/module/extractors/aac/AACExtractor.cpp
@@ -310,9 +310,9 @@
return AMEDIA_ERROR_END_OF_STREAM;
}
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
status_t err = mBufferGroup->acquire_buffer(&buffer);
- if (err != OK) {
+ if (err != OK || buffer == nullptr) {
return AMEDIA_ERROR_UNKNOWN;
}
diff --git a/media/module/extractors/amr/AMRExtractor.cpp b/media/module/extractors/amr/AMRExtractor.cpp
index e26ff0a..b0f69ce 100644
--- a/media/module/extractors/amr/AMRExtractor.cpp
+++ b/media/module/extractors/amr/AMRExtractor.cpp
@@ -341,9 +341,9 @@
return AMEDIA_ERROR_MALFORMED;
}
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
status_t err = mBufferGroup->acquire_buffer(&buffer);
- if (err != OK) {
+ if (err != OK || buffer == nullptr) {
return AMEDIA_ERROR_UNKNOWN;
}
diff --git a/media/module/extractors/flac/FLACExtractor.cpp b/media/module/extractors/flac/FLACExtractor.cpp
index ec7cb24..2434e41 100644
--- a/media/module/extractors/flac/FLACExtractor.cpp
+++ b/media/module/extractors/flac/FLACExtractor.cpp
@@ -614,9 +614,9 @@
}
// acquire a media buffer
CHECK(mGroup != NULL);
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
status_t err = mGroup->acquire_buffer(&buffer);
- if (err != OK) {
+ if (err != OK || buffer == nullptr) {
return NULL;
}
const size_t bufferSize = blocksize * getChannels() * getOutputSampleSize();
diff --git a/media/module/extractors/midi/MidiExtractor.cpp b/media/module/extractors/midi/MidiExtractor.cpp
index 984c76a..167cc40 100644
--- a/media/module/extractors/midi/MidiExtractor.cpp
+++ b/media/module/extractors/midi/MidiExtractor.cpp
@@ -240,9 +240,9 @@
if ((state == EAS_STATE_STOPPED) || (state == EAS_STATE_ERROR)) {
return NULL;
}
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
status_t err = mGroup->acquire_buffer(&buffer);
- if (err != OK) {
+ if (err != OK || buffer == nullptr) {
ALOGE("readBuffer: no buffer");
return NULL;
}
@@ -327,29 +327,12 @@
bool SniffMidi(CDataSource *source, float *confidence)
{
- // look for standard prefix / magic number info in the files.
- // "MThd" for midi
- // "XMF_"
- // this will be very fast.
- //
- char hdr_magic[4];
- if (source->readAt(source->handle, 0, hdr_magic, sizeof(hdr_magic)) == sizeof(hdr_magic)) {
- if (memcmp(hdr_magic,"MThd", sizeof(hdr_magic)) == 0) {
- *confidence = 0.85;
- ALOGV("SniffMidi: yes, MThd");
- return true;
- }
- if (memcmp(hdr_magic,"XMF_", sizeof(hdr_magic)) == 0) {
- *confidence = 0.85;
- ALOGV("SniffMidi: yes, XMF_");
- return true;
- }
+ MidiEngine p(source, NULL, NULL);
+ if (p.initCheck() == OK) {
+ *confidence = 0.8;
+ ALOGV("SniffMidi: yes");
+ return true;
}
-
- // alternatives:
- // instantiate MidiEngine, (expensively) parsing the entire file to decide.
-
-
ALOGV("SniffMidi: no");
return false;
diff --git a/media/module/extractors/mkv/MatroskaExtractor.cpp b/media/module/extractors/mkv/MatroskaExtractor.cpp
index 443e26c..2b72387 100644
--- a/media/module/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/module/extractors/mkv/MatroskaExtractor.cpp
@@ -790,6 +790,7 @@
int64_t timeUs = mBlockIter.blockTimeUs();
for (int i = 0; i < block->GetFrameCount(); ++i) {
+ status_t err;
MatroskaExtractor::TrackInfo *trackInfo = &mExtractor->mTracks.editItemAt(mTrackIndex);
const mkvparser::Block::Frame &frame = block->GetFrame(i);
size_t len = frame.len;
@@ -798,8 +799,13 @@
}
len += trackInfo->mHeaderLen;
- MediaBufferHelper *mbuf;
- mBufferGroup->acquire_buffer(&mbuf, false /* nonblocking */, len /* requested size */);
+ MediaBufferHelper *mbuf = nullptr;
+ err = mBufferGroup->acquire_buffer(&mbuf, false /* nonblocking */,
+ len /* requested size */);
+ if (err != OK || mbuf == nullptr) {
+ ALOGE("readBlock: no buffer");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
mbuf->set_range(0, len);
uint8_t *data = static_cast<uint8_t *>(mbuf->data());
if (trackInfo->mHeader) {
@@ -832,7 +838,7 @@
}
}
- status_t err = frame.Read(mExtractor->mReader, data + trackInfo->mHeaderLen);
+ err = frame.Read(mExtractor->mReader, data + trackInfo->mHeaderLen);
if (err == OK
&& mExtractor->mIsWebm
&& trackInfo->mEncrypted) {
diff --git a/media/module/extractors/mp3/MP3Extractor.cpp b/media/module/extractors/mp3/MP3Extractor.cpp
index 248a39c..328b790 100644
--- a/media/module/extractors/mp3/MP3Extractor.cpp
+++ b/media/module/extractors/mp3/MP3Extractor.cpp
@@ -521,9 +521,9 @@
mSamplesRead = 0;
}
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
status_t err = mBufferGroup->acquire_buffer(&buffer);
- if (err != OK) {
+ if (err != OK || buffer == nullptr) {
return AMEDIA_ERROR_UNKNOWN;
}
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index 8f8fc1b..1d88785 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -394,6 +394,15 @@
return MEDIA_MIMETYPE_AUDIO_MPEGH_MHA1;
case FOURCC("mhm1"):
return MEDIA_MIMETYPE_AUDIO_MPEGH_MHM1;
+ case FOURCC("dtsc"):
+ return MEDIA_MIMETYPE_AUDIO_DTS;
+ case FOURCC("dtse"):
+ case FOURCC("dtsh"):
+ return MEDIA_MIMETYPE_AUDIO_DTS_HD;
+ case FOURCC("dtsl"):
+ return MEDIA_MIMETYPE_AUDIO_DTS_HD_MA;
+ case FOURCC("dtsx"):
+ return MEDIA_MIMETYPE_AUDIO_DTS_UHD_P2;
default:
ALOGW("Unknown fourcc: %c%c%c%c",
(fourcc >> 24) & 0xff,
@@ -1804,6 +1813,11 @@
case 0x6D730055: // "ms U" mp3 audio
case FOURCC("mha1"):
case FOURCC("mhm1"):
+ case FOURCC("dtsc"):
+ case FOURCC("dtse"):
+ case FOURCC("dtsh"):
+ case FOURCC("dtsl"):
+ case FOURCC("dtsx"):
{
if (mIsQT && depth >= 1 && mPath[depth - 1] == FOURCC("wave")) {
@@ -6323,7 +6337,7 @@
err = mBufferGroup->acquire_buffer(&mBuffer);
- if (err != OK) {
+ if (err != OK || mBuffer == nullptr) {
CHECK(mBuffer == NULL);
return AMEDIA_ERROR_UNKNOWN;
}
diff --git a/media/module/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/module/extractors/mpeg2/MPEG2PSExtractor.cpp
index afd28ef..44c8937 100644
--- a/media/module/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/module/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -699,11 +699,26 @@
}
}
- MediaBufferBase *mbuf;
- mSource->read(&mbuf, (MediaTrack::ReadOptions*) options);
+ MediaBufferBase *mbuf = nullptr;
+ status_t err_read = mSource->read(&mbuf, (MediaTrack::ReadOptions*) options);
+ if (mbuf == nullptr) {
+ ALOGE("Track::read: null buffer read from source");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (err_read != OK) {
+ ALOGE("Track::read: no buffer read from source");
+ mbuf->release();
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
size_t length = mbuf->range_length();
- MediaBufferHelper *outbuf;
- mBufferGroup->acquire_buffer(&outbuf, false, length);
+ MediaBufferHelper *outbuf = nullptr;
+ status_t err = mBufferGroup->acquire_buffer(&outbuf, false, length);
+ if (err != OK || outbuf == nullptr) {
+ ALOGE("Track::read: no buffer");
+ mbuf->release();
+ return AMEDIA_ERROR_UNKNOWN;
+ }
memcpy(outbuf->data(), mbuf->data(), length);
outbuf->set_range(0, length);
*buffer = outbuf;
diff --git a/media/module/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/module/extractors/mpeg2/MPEG2TSExtractor.cpp
index 9a3cd92..736b817 100644
--- a/media/module/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/module/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -182,11 +182,26 @@
return AMEDIA_ERROR_END_OF_STREAM;
}
- MediaBufferBase *mbuf;
- mImpl->read(&mbuf, (MediaTrack::ReadOptions*) options);
+ MediaBufferBase *mbuf = nullptr;
+ status_t err_read = mImpl->read(&mbuf, (MediaTrack::ReadOptions*) options);
+ if (mbuf == nullptr) {
+ ALOGE("Track::read: null buffer read from source");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+ if (err_read != OK) {
+ ALOGE("Track::read: no buffer read from source");
+ mbuf->release();
+ return AMEDIA_ERROR_UNKNOWN;
+ }
+
size_t length = mbuf->range_length();
- MediaBufferHelper *outbuf;
- mBufferGroup->acquire_buffer(&outbuf, false, length);
+ MediaBufferHelper *outbuf = nullptr;
+ status_t err = mBufferGroup->acquire_buffer(&outbuf, false, length);
+ if (err != OK || outbuf == nullptr) {
+ ALOGE("read: no buffer");
+ mbuf->release();
+ return AMEDIA_ERROR_UNKNOWN;
+ }
memcpy(outbuf->data(), mbuf->data(), length);
outbuf->set_range(0, length);
*out = outbuf;
diff --git a/media/module/extractors/ogg/OggExtractor.cpp b/media/module/extractors/ogg/OggExtractor.cpp
index eb2246d..1c6f516 100644
--- a/media/module/extractors/ogg/OggExtractor.cpp
+++ b/media/module/extractors/ogg/OggExtractor.cpp
@@ -790,7 +790,8 @@
}
MediaBufferHelper *tmp;
if (mBufferGroup) {
- mBufferGroup->acquire_buffer(&tmp, false, fullSize);
+ // ignore return code here. instead, check tmp below.
+ (void) mBufferGroup->acquire_buffer(&tmp, false, fullSize);
ALOGV("acquired buffer %p from group", tmp);
} else {
tmp = new StandAloneMediaBuffer(fullSize);
@@ -924,13 +925,16 @@
status_t MyOggExtractor::init() {
AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME, mMimeType);
- media_status_t err;
- MediaBufferHelper *packet;
for (size_t i = 0; i < mNumHeaders; ++i) {
+ media_status_t err;
+ MediaBufferHelper *packet = nullptr;
// ignore timestamp for configuration packets
if ((err = _readNextPacket(&packet, /* calcVorbisTimestamp = */ false)) != AMEDIA_OK) {
return err;
}
+ if (packet == nullptr) {
+ return AMEDIA_ERROR_UNKNOWN;
+ }
ALOGV("read packet of size %zu\n", packet->range_length());
err = verifyHeader(packet, /* type = */ i * 2 + 1);
packet->release();
diff --git a/media/module/extractors/wav/WAVExtractor.cpp b/media/module/extractors/wav/WAVExtractor.cpp
index 9e94587..9c3bac6 100644
--- a/media/module/extractors/wav/WAVExtractor.cpp
+++ b/media/module/extractors/wav/WAVExtractor.cpp
@@ -459,11 +459,15 @@
mCurrentPos = pos + mOffset;
}
- MediaBufferHelper *buffer;
+ MediaBufferHelper *buffer = nullptr;
media_status_t err = mBufferGroup->acquire_buffer(&buffer);
if (err != OK) {
return err;
}
+ if (buffer == nullptr) {
+ ALOGE("acquire_buffer OK, but no buffer");
+ return AMEDIA_ERROR_UNKNOWN;
+ }
// maxBytesToRead may be reduced so that in-place data conversion will fit in buffer size.
const size_t bufferSize = std::min(buffer->size(), kMaxFrameSize);
diff --git a/media/module/libmediatranscoding/tests/TranscodingSessionController_tests.cpp b/media/module/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
index ef9c4f8..fdd327f 100644
--- a/media/module/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
+++ b/media/module/libmediatranscoding/tests/TranscodingSessionController_tests.cpp
@@ -337,6 +337,8 @@
// Should have created new transcoder.
EXPECT_EQ(mTranscoder->getGeneration(), generation);
EXPECT_EQ(mTranscoder.use_count(), 2);
+ // b/240537336: Allow extra time to finish onError call
+ sleep(1);
}
void testPacerHelper(int numSubmits, int sessionDurationMs, int expectedSuccess) {
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index f4674de..5005365 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -253,7 +253,7 @@
}
static sp<IDrm> CreateDrm() {
- return DrmUtils::MakeDrm();
+ return DrmUtils::MakeDrm(IDRM_NDK);
}
diff --git a/media/ndk/include/media/NdkMediaDrm.h b/media/ndk/include/media/NdkMediaDrm.h
index 4eca3d7..8044140 100644
--- a/media/ndk/include/media/NdkMediaDrm.h
+++ b/media/ndk/include/media/NdkMediaDrm.h
@@ -261,8 +261,8 @@
/**
* Open a new session with the MediaDrm object. A session ID is returned.
*
- * Returns MEDIADRM_NOT_PROVISIONED_ERROR if provisioning is needed.
- * Returns MEDIADRM_RESOURCE_BUSY_ERROR if required resources are in use.
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if provisioning is needed.
+ * Returns AMEDIA_DRM_RESOURCE_BUSY if required resources are in use.
*
* Available since API level 21.
*/
@@ -327,7 +327,7 @@
* 2. keyRequestSize will be set to the size of the request
* If this does not return AMEDIA_OK, value of these parameters should not be used.
*
- * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if reprovisioning is needed, due to a
* problem with the device certificate.
*
* Available since API level 21.
@@ -390,7 +390,7 @@
* 4. keyRequestType will be set to the key request type. Passing in NULL means
* you don't need it to be reported.
*
- * Returns MEDIADRM_NOT_PROVISIONED_ERROR if reprovisioning is needed, due to a
+ * Returns AMEDIA_DRM_NOT_PROVISIONED if reprovisioning is needed, due to a
* problem with the device certificate.
*
* Available since API level 33.
@@ -457,7 +457,7 @@
* On entry, numPairs should be set by the caller to the maximum number of pairs
* that can be returned (the size of the array). On exit, numPairs will be set
* to the number of entries written to the array. If the number of {key, value} pairs
- * to be returned is greater than *numPairs, MEDIADRM_SHORT_BUFFER will be returned
+ * to be returned is greater than *numPairs, AMEDIA_DRM_SHORT_BUFFER will be returned
* and numPairs will be set to the number of pairs available.
*
* Available since API level 21.
@@ -495,7 +495,7 @@
* DRM engine plugin.
* responseSize is the length of the provisioning response in bytes.
*
- * Returns MEDIADRM_DEVICE_REVOKED_ERROR if the response indicates that the
+ * Returns AMEDIA_DRM_DEVICE_REVOKED if the response indicates that the
* server rejected the request
*
* Available since API level 21.
@@ -522,7 +522,7 @@
* numSecureStops is set by the caller to the maximum number of secure stops to
* return. On exit, *numSecureStops will be set to the number actually returned.
* If *numSecureStops is too small for the number of secure stops available,
- * MEDIADRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
+ * AMEDIA_DRM_SHORT_BUFFER will be returned and *numSecureStops will be set to the
* number required.
*
* Available since API level 21.
@@ -657,7 +657,7 @@
* Generate a signature using the specified macAlgorithm over the message data
* referenced by message of size messageSize and store the signature in the
* buffer referenced signature of max size *signatureSize. If the buffer is not
- * large enough to hold the signature, MEDIADRM_SHORT_BUFFER is returned and
+ * large enough to hold the signature, AMEDIA_DRM_SHORT_BUFFER is returned and
* *signatureSize is set to the buffer size required. The key to use is identified
* by the 16 byte keyId. The key must have been loaded into the session using
* provideKeyResponse.
@@ -670,7 +670,7 @@
/*
* Perform a signature verification using the specified macAlgorithm over the message
- * data referenced by the message parameter of size messageSize. Returns MEDIADRM_OK
+ * data referenced by the message parameter of size messageSize. Returns AMEDIA_OK
* if the signature matches, otherwise MEDAIDRM_VERIFY_FAILED is returned. The key to
* use is identified by the 16 byte keyId. The key must have been loaded into the
* session using provideKeyResponse.
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bac4b22..2b5bacf 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -183,11 +183,11 @@
AMediaCodecCryptoInfo_setPattern; # introduced=24
AMediaCodec_configure;
AMediaCodec_createCodecByName;
- AMediaCodec_createCodecByNameForClient; # apex # introduced=31
+ AMediaCodec_createCodecByNameForClient; # systemapi # introduced=31
AMediaCodec_createDecoderByType;
- AMediaCodec_createDecoderByTypeForClient; # apex # introduced=31
+ AMediaCodec_createDecoderByTypeForClient; # systemapi # introduced=31
AMediaCodec_createEncoderByType;
- AMediaCodec_createEncoderByTypeForClient; # apex # introduced=31
+ AMediaCodec_createEncoderByTypeForClient; # systemapi # introduced=31
AMediaCodec_delete;
AMediaCodec_dequeueInputBuffer;
AMediaCodec_dequeueOutputBuffer;
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 0cf5bd9..a5378e6 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -312,7 +312,7 @@
}
// Automatically create a TimeCheck class for a class and method.
-// This is used for Audio HIDL support.
+// This is used for Audio HAL support.
mediautils::TimeCheck makeTimeCheckStatsForClassMethod(
std::string_view className, std::string_view methodName) {
std::shared_ptr<MethodStatistics<std::string>> statistics =
diff --git a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
index 51e8d7a..15f043a 100644
--- a/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
+++ b/media/utils/fuzzers/ServiceUtilitiesFuzz.cpp
@@ -25,6 +25,7 @@
static constexpr int kMaxOperations = 50;
static constexpr int kMaxStringLen = 256;
+static constexpr int kMaxSpaces = 1000;
using android::content::AttributionSourceState;
@@ -35,7 +36,9 @@
pm.allowPlaybackCapture(uid);
},
[](FuzzedDataProvider* data_provider, android::MediaPackageManager pm) -> void {
- int spaces = data_provider->ConsumeIntegral<int>();
+ /* The large value of spaces was taking time in file write operation.
+ * Limited spaces values in range to avoid timeout.*/
+ int spaces = data_provider->ConsumeIntegralInRange<int>(0, kMaxSpaces);
// Dump everything into /dev/null
int fd = open("/dev/null", O_WRONLY);
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index f9ea50c..f1d572f 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -147,4 +147,9 @@
TimeCheck makeTimeCheckStatsForClassMethod(
std::string_view className, std::string_view methodName);
+// A handy statement-like macro to put at the beginning of almost every method
+// which calls into HAL. Note that it requires the class to implement 'getClassName'.
+#define TIME_CHECK() auto timeCheck = \
+ mediautils::makeTimeCheckStatsForClassMethod(getClassName(), __func__)
+
} // namespace android::mediautils
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 41d4e16..43ef311 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -24,6 +24,7 @@
defaults: [
"latest_android_media_audio_common_types_cpp_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
],
srcs: [
@@ -76,6 +77,7 @@
"libutils",
"liblog",
"libbinder",
+ "libbinder_ndk",
"libaudioclient",
"libaudiomanager",
"libmedialogservice",
@@ -105,11 +107,11 @@
"libaudiohal_headers",
"libaudioutils_headers",
"libmedia_headers",
- "libsounddose_headers",
],
export_shared_lib_headers: [
"libpermission",
+ "android.hardware.audio.core.sounddose-V1-ndk",
],
cflags: [
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index cf7e135..7bb0fd3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -194,7 +194,6 @@
BINDER_METHOD_ENTRY(restoreOutput) \
BINDER_METHOD_ENTRY(openInput) \
BINDER_METHOD_ENTRY(closeInput) \
-BINDER_METHOD_ENTRY(invalidateStream) \
BINDER_METHOD_ENTRY(setVoiceVolume) \
BINDER_METHOD_ENTRY(getRenderPosition) \
BINDER_METHOD_ENTRY(getInputFramesLost) \
@@ -232,6 +231,9 @@
BINDER_METHOD_ENTRY(setDeviceConnectedState) \
BINDER_METHOD_ENTRY(setRequestedLatencyMode) \
BINDER_METHOD_ENTRY(getSupportedLatencyModes) \
+BINDER_METHOD_ENTRY(setBluetoothVariableLatencyEnabled) \
+BINDER_METHOD_ENTRY(isBluetoothVariableLatencyEnabled) \
+BINDER_METHOD_ENTRY(supportsBluetoothVariableLatency) \
BINDER_METHOD_ENTRY(getSoundDoseInterface) \
// singleton for Binder Method Statistics for IAudioFlinger
@@ -328,7 +330,8 @@
mPatchCommandThread(sp<PatchCommandThread>::make()),
mDeviceEffectManager(sp<DeviceEffectManager>::make(*this)),
mMelReporter(sp<MelReporter>::make(*this)),
- mSystemReady(false)
+ mSystemReady(false),
+ mBluetoothLatencyModesEnabled(true)
{
// Move the audio session unique ID generator start base as time passes to limit risk of
// generating the same ID again after an audioserver restart.
@@ -1667,6 +1670,44 @@
return thread->getSupportedLatencyModes(modes);
}
+status_t AudioFlinger::setBluetoothVariableLatencyEnabled(bool enabled) {
+ Mutex::Autolock _l(mLock);
+ status_t status = INVALID_OPERATION;
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ // Success if at least one PlaybackThread supports Bluetooth latency modes
+ if (mPlaybackThreads.valueAt(i)->setBluetoothVariableLatencyEnabled(enabled) == NO_ERROR) {
+ status = NO_ERROR;
+ }
+ }
+ if (status == NO_ERROR) {
+ mBluetoothLatencyModesEnabled.store(enabled);
+ }
+ return status;
+}
+
+status_t AudioFlinger::isBluetoothVariableLatencyEnabled(bool *enabled) {
+ if (enabled == nullptr) {
+ return BAD_VALUE;
+ }
+ *enabled = mBluetoothLatencyModesEnabled.load();
+ return NO_ERROR;
+}
+
+status_t AudioFlinger::supportsBluetoothVariableLatency(bool* support) {
+ if (support == nullptr) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mLock);
+ *support = false;
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ if (mAudioHwDevs.valueAt(i)->supportsBluetoothVariableLatency()) {
+ *support = true;
+ break;
+ }
+ }
+ return NO_ERROR;
+}
+
status_t AudioFlinger::getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose) {
if (soundDose == nullptr) {
@@ -2179,9 +2220,9 @@
void AudioFlinger::onSupportedLatencyModesChanged(
audio_io_handle_t output, const std::vector<audio_latency_mode_t>& modes) {
int32_t outputAidl = VALUE_OR_FATAL(legacy2aidl_audio_io_handle_t_int32_t(output));
- std::vector<media::LatencyMode> modesAidl = VALUE_OR_FATAL(
- convertContainer<std::vector<media::LatencyMode>>(modes,
- legacy2aidl_audio_latency_mode_t_LatencyMode));
+ std::vector<media::audio::common::AudioLatencyMode> modesAidl = VALUE_OR_FATAL(
+ convertContainer<std::vector<media::audio::common::AudioLatencyMode>>(
+ modes, legacy2aidl_audio_latency_mode_t_AudioLatencyMode));
Mutex::Autolock _l(mClientLock);
size_t size = mNotificationClients.size();
@@ -2532,6 +2573,9 @@
ALOGE("loadHwModule() error %d loading module %s", rc, name);
return AUDIO_MODULE_HANDLE_NONE;
}
+ if (!mMelReporter->activateHalSoundDoseComputation(name, dev)) {
+ ALOGW("loadHwModule() sound dose reporting is not available");
+ }
mHardwareStatus = AUDIO_HW_INIT;
rc = dev->initCheck();
@@ -2580,6 +2624,13 @@
flags = static_cast<AudioHwDevice::Flags>(flags | AudioHwDevice::AHWD_IS_INSERT);
}
+
+ if (bool supports = false;
+ dev->supportsBluetoothVariableLatency(&supports) == NO_ERROR && supports) {
+ flags = static_cast<AudioHwDevice::Flags>(flags |
+ AudioHwDevice::AHWD_SUPPORTS_BT_LATENCY_MODES);
+ }
+
audio_module_handle_t handle = (audio_module_handle_t) nextUniqueId(AUDIO_UNIQUE_ID_USE_MODULE);
AudioHwDevice *audioDevice = new AudioHwDevice(handle, name, dev, flags);
if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
@@ -2812,14 +2863,15 @@
status_t status = INVALID_OPERATION;
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- std::vector<media::MicrophoneInfo> mics;
+ std::vector<audio_microphone_characteristic_t> mics;
AudioHwDevice *dev = mAudioHwDevs.valueAt(i);
mHardwareStatus = AUDIO_HW_GET_MICROPHONES;
status_t devStatus = dev->hwDevice()->getMicrophones(&mics);
mHardwareStatus = AUDIO_HW_IDLE;
if (devStatus == NO_ERROR) {
- microphones->insert(microphones->begin(), mics.begin(), mics.end());
// report success if at least one HW module supports the function.
+ std::transform(mics.begin(), mics.end(), std::back_inserter(*microphones),
+ [](auto& mic) { return media::MicrophoneInfo(mic); });
status = NO_ERROR;
}
}
@@ -2953,6 +3005,7 @@
if (thread->isMsdDevice()) {
thread->setDownStreamPatch(&patch);
}
+ thread->setBluetoothVariableLatencyEnabled(mBluetoothLatencyModesEnabled.load());
return thread;
}
}
@@ -3398,17 +3451,23 @@
closeInputFinish(thread);
}
-status_t AudioFlinger::invalidateStream(audio_stream_type_t stream)
-{
+status_t AudioFlinger::invalidateTracks(const std::vector<audio_port_handle_t> &portIds) {
Mutex::Autolock _l(mLock);
- ALOGV("invalidateStream() stream %d", stream);
+ ALOGV("%s", __func__);
+ std::set<audio_port_handle_t> portIdSet(portIds.begin(), portIds.end());
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
- thread->invalidateTracks(stream);
+ thread->invalidateTracks(portIdSet);
+ if (portIdSet.empty()) {
+ return NO_ERROR;
+ }
}
for (size_t i = 0; i < mMmapThreads.size(); i++) {
- mMmapThreads[i]->invalidateTracks(stream);
+ mMmapThreads[i]->invalidateTracks(portIdSet);
+ if (portIdSet.empty()) {
+ return NO_ERROR;
+ }
}
return NO_ERROR;
}
@@ -4607,7 +4666,6 @@
case TransactionCode::RESTORE_OUTPUT:
case TransactionCode::OPEN_INPUT:
case TransactionCode::CLOSE_INPUT:
- case TransactionCode::INVALIDATE_STREAM:
case TransactionCode::SET_VOICE_VOLUME:
case TransactionCode::MOVE_EFFECTS:
case TransactionCode::SET_EFFECT_SUSPENDED:
@@ -4622,6 +4680,7 @@
case TransactionCode::SET_DEVICE_CONNECTED_STATE:
case TransactionCode::SET_REQUESTED_LATENCY_MODE:
case TransactionCode::GET_SUPPORTED_LATENCY_MODES:
+ case TransactionCode::INVALIDATE_TRACKS:
ALOGW("%s: transaction %d received from PID %d",
__func__, code, IPCThreadState::self()->getCallingPid());
// return status only for non void methods
@@ -4650,7 +4709,10 @@
case TransactionCode::SYSTEM_READY:
case TransactionCode::SET_AUDIO_HAL_PIDS:
case TransactionCode::SET_VIBRATOR_INFOS:
- case TransactionCode::UPDATE_SECONDARY_OUTPUTS: {
+ case TransactionCode::UPDATE_SECONDARY_OUTPUTS:
+ case TransactionCode::SET_BLUETOOTH_VARIABLE_LATENCY_ENABLED:
+ case TransactionCode::IS_BLUETOOTH_VARIABLE_LATENCY_ENABLED:
+ case TransactionCode::SUPPORTS_BLUETOOTH_VARIABLE_LATENCY: {
if (!isServiceUid(IPCThreadState::self()->getCallingUid())) {
ALOGW("%s: transaction %d received from PID %d unauthorized UID %d",
__func__, code, IPCThreadState::self()->getCallingPid(),
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 360ad36..e8133d9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -139,6 +139,7 @@
class AudioFlinger : public AudioFlingerServerAdapter::Delegate
{
+ friend class sp<AudioFlinger>;
public:
static void instantiate() ANDROID_API;
@@ -210,8 +211,6 @@
virtual status_t closeInput(audio_io_handle_t input);
- virtual status_t invalidateStream(audio_stream_type_t stream);
-
virtual status_t setVoiceVolume(float volume);
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames,
@@ -307,9 +306,17 @@
virtual status_t getSupportedLatencyModes(audio_io_handle_t output,
std::vector<audio_latency_mode_t>* modes);
+ virtual status_t setBluetoothVariableLatencyEnabled(bool enabled);
+
+ virtual status_t isBluetoothVariableLatencyEnabled(bool* enabled);
+
+ virtual status_t supportsBluetoothVariableLatency(bool* support);
+
virtual status_t getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback,
sp<media::ISoundDose>* soundDose);
+ status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
+
status_t onTransactWrapper(TransactionCode code, const Parcel& data, uint32_t flags,
const std::function<status_t()>& delegate) override;
@@ -695,14 +702,16 @@
binder::Status getVolumeShaperState(
int32_t id,
std::optional<media::VolumeShaperState>* _aidl_return) override;
- binder::Status getDualMonoMode(media::AudioDualMonoMode* _aidl_return) override;
- binder::Status setDualMonoMode(media::AudioDualMonoMode mode) override;
+ binder::Status getDualMonoMode(
+ media::audio::common::AudioDualMonoMode* _aidl_return) override;
+ binder::Status setDualMonoMode(
+ media::audio::common::AudioDualMonoMode mode) override;
binder::Status getAudioDescriptionMixLevel(float* _aidl_return) override;
binder::Status setAudioDescriptionMixLevel(float leveldB) override;
binder::Status getPlaybackRateParameters(
- media::AudioPlaybackRate* _aidl_return) override;
+ media::audio::common::AudioPlaybackRate* _aidl_return) override;
binder::Status setPlaybackRateParameters(
- const media::AudioPlaybackRate& playbackRate) override;
+ const media::audio::common::AudioPlaybackRate& playbackRate) override;
private:
const sp<PlaybackThread::Track> mTrack;
@@ -1053,6 +1062,9 @@
/** Interface for interacting with the AudioService. */
mediautils::atomic_sp<IAudioManager> mAudioManager;
+
+ // Bluetooth Variable latency control logic is enabled or disabled
+ std::atomic_bool mBluetoothLatencyModesEnabled;
};
#undef INCLUDING_FROM_AUDIOFLINGER_H
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index 8c5d239..1749f3f 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -40,6 +40,8 @@
// Means that this isn't a terminal module, and software patches
// are used to transport audio data further.
AHWD_IS_INSERT = 0x4,
+ // This Module supports BT Latency mode control
+ AHWD_SUPPORTS_BT_LATENCY_MODES = 0x8,
};
AudioHwDevice(audio_module_handle_t handle,
@@ -64,6 +66,10 @@
return (0 != (mFlags & AHWD_IS_INSERT));
}
+ bool supportsBluetoothVariableLatency() const {
+ return (0 != (mFlags & AHWD_SUPPORTS_BT_LATENCY_MODES));
+ }
+
audio_module_handle_t handle() const { return mHandle; }
const char *moduleName() const { return mModuleName; }
sp<DeviceHalInterface> hwDevice() const { return mHwDevice; }
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index 8cc7eab..5dbcb33 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -24,9 +24,67 @@
#include <audio_utils/power.h>
#include <utils/Log.h>
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+
namespace android {
+bool AudioFlinger::MelReporter::activateHalSoundDoseComputation(const std::string& module,
+ const sp<DeviceHalInterface>& device) {
+ if (mSoundDoseManager->forceUseFrameworkMel()) {
+ ALOGD("%s: Forcing use of internal MEL computation.", __func__);
+ activateInternalSoundDoseComputation();
+ return false;
+ }
+
+ ndk::SpAIBinder soundDoseBinder;
+ if (device->getSoundDoseInterface(module, &soundDoseBinder) != OK) {
+ ALOGW("%s: HAL cannot provide sound dose interface for module %s, use internal MEL",
+ __func__, module.c_str());
+ activateInternalSoundDoseComputation();
+ return false;
+ }
+
+ if (soundDoseBinder == nullptr) {
+ ALOGW("%s: HAL doesn't implement a sound dose interface for module %s, use internal MEL",
+ __func__, module.c_str());
+ activateInternalSoundDoseComputation();
+ return false;
+ }
+
+ std::shared_ptr<ISoundDose> soundDoseInterface = ISoundDose::fromBinder(soundDoseBinder);
+
+ if (!mSoundDoseManager->setHalSoundDoseInterface(soundDoseInterface)) {
+ ALOGW("%s: cannot activate HAL MEL reporting for module %s", __func__, module.c_str());
+ activateInternalSoundDoseComputation();
+ return false;
+ }
+
+ stopInternalMelComputation();
+ return true;
+}
+
+void AudioFlinger::MelReporter::activateInternalSoundDoseComputation() {
+ {
+ std::lock_guard _l(mLock);
+ if (!mUseHalSoundDoseInterface) {
+ // no need to start internal MEL on active patches
+ return;
+ }
+ mUseHalSoundDoseInterface = false;
+ }
+
+ mSoundDoseManager->setHalSoundDoseInterface(nullptr);
+}
+
+void AudioFlinger::MelReporter::onFirstRef() {
+ mAudioFlinger.mPatchCommandThread->addListener(this);
+}
+
bool AudioFlinger::MelReporter::shouldComputeMelForDeviceType(audio_devices_t device) {
+ if (mSoundDoseManager->forceComputeCsdOnAllDevices()) {
+ return true;
+ }
+
switch (device) {
case AUDIO_DEVICE_OUT_WIRED_HEADSET:
case AUDIO_DEVICE_OUT_WIRED_HEADPHONE:
@@ -42,14 +100,50 @@
}
}
+void AudioFlinger::MelReporter::updateMetadataForCsd(audio_io_handle_t streamHandle,
+ const std::vector<playback_track_metadata_v7_t>& metadataVec) {
+ std::lock_guard _laf(mAudioFlinger.mLock);
+ std::lock_guard _l(mLock);
+ auto activeMelPatchId = activePatchStreamHandle_l(streamHandle);
+ if (!activeMelPatchId) {
+ ALOGV("%s stream handle %d does not have an active patch", __func__, streamHandle);
+ return;
+ }
+
+ bool shouldActivateCsd = false;
+ for (const auto& metadata : metadataVec) {
+ if (metadata.base.usage == AUDIO_USAGE_GAME || metadata.base.usage == AUDIO_USAGE_MEDIA) {
+ shouldActivateCsd = true;
+ }
+ }
+
+ auto activeMelPatchIt = mActiveMelPatches.find(activeMelPatchId.value());
+ if (activeMelPatchIt != mActiveMelPatches.end()
+ && shouldActivateCsd != activeMelPatchIt->second.csdActive) {
+ if (activeMelPatchIt->second.csdActive) {
+ ALOGV("%s should not compute CSD for stream handle %d", __func__, streamHandle);
+ stopMelComputationForPatch_l(activeMelPatchIt->second);
+ } else {
+ ALOGV("%s should compute CSD for stream handle %d", __func__, streamHandle);
+ startMelComputationForActivePatch_l(activeMelPatchIt->second);
+ }
+ activeMelPatchIt->second.csdActive = shouldActivateCsd;
+ }
+}
+
void AudioFlinger::MelReporter::onCreateAudioPatch(audio_patch_handle_t handle,
const PatchPanel::Patch& patch) {
+ if (useHalSoundDoseInterface()) {
+ ALOGV("%s using HAL sound dose, ignore new patch", __func__);
+ return;
+ }
+
ALOGV("%s: handle %d mHalHandle %d device sink %08x",
__func__, handle, patch.mHalHandle,
patch.mAudioPatch.num_sinks > 0 ? patch.mAudioPatch.sinks[0].ext.device.type : 0);
if (patch.mAudioPatch.num_sources == 0
|| patch.mAudioPatch.sources[0].type != AUDIO_PORT_TYPE_MIX) {
- ALOGW("%s: patch does not contain any mix sources", __func__);
+ ALOGV("%s: patch does not contain any mix sources", __func__);
return;
}
@@ -61,37 +155,49 @@
&& shouldComputeMelForDeviceType(patch.mAudioPatch.sinks[i].ext.device.type)) {
audio_port_handle_t deviceId = patch.mAudioPatch.sinks[i].id;
newPatch.deviceHandles.push_back(deviceId);
-
- // Start the MEL calculation in the PlaybackThread
- std::lock_guard _lAf(mAudioFlinger.mLock);
- auto thread = mAudioFlinger.checkPlaybackThread_l(streamHandle);
- if (thread != nullptr) {
- thread->startMelComputation(mSoundDoseManager.getOrCreateProcessorForDevice(
- deviceId,
- newPatch.streamHandle,
- thread->mSampleRate,
- thread->mChannelCount,
- thread->mFormat));
- }
+ AudioDeviceTypeAddr adt{patch.mAudioPatch.sinks[i].ext.device.type,
+ patch.mAudioPatch.sinks[i].ext.device.address};
+ mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
}
}
+ std::lock_guard _afl(mAudioFlinger.mLock);
std::lock_guard _l(mLock);
- mActiveMelPatches[patch.mAudioPatch.id] = newPatch;
+ ALOGV("%s add patch handle %d to active devices", __func__, handle);
+ startMelComputationForActivePatch_l(newPatch);
+ newPatch.csdActive = true;
+ mActiveMelPatches[handle] = newPatch;
+}
+
+void AudioFlinger::MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch) {
+ auto thread = mAudioFlinger.checkPlaybackThread_l(patch.streamHandle);
+ if (thread == nullptr) {
+ ALOGE("%s cannot find thread for stream handle %d", __func__, patch.streamHandle);
+ return;
+ }
+
+ for (const auto& deviceHandle : patch.deviceHandles) {
+ ++mActiveDevices[deviceHandle];
+ ALOGI("%s add stream %d that uses device %d for CSD, nr of streams: %d", __func__,
+ patch.streamHandle, deviceHandle, mActiveDevices[deviceHandle]);
+ thread->startMelComputation(mSoundDoseManager->getOrCreateProcessorForDevice(
+ deviceHandle,
+ patch.streamHandle,
+ thread->mSampleRate,
+ thread->mChannelCount,
+ thread->mFormat));
+ }
}
void AudioFlinger::MelReporter::onReleaseAudioPatch(audio_patch_handle_t handle) {
- ALOGV("%s", __func__);
-
ActiveMelPatch melPatch;
{
std::lock_guard _l(mLock);
auto patchIt = mActiveMelPatches.find(handle);
if (patchIt == mActiveMelPatches.end()) {
- ALOGW(
- "%s patch does not contain any mix sources with active MEL calculation",
- __func__);
+ ALOGV("%s patch handle %d does not contain any mix sources with active MEL calculation",
+ __func__, handle);
return;
}
@@ -99,25 +205,68 @@
mActiveMelPatches.erase(patchIt);
}
- // Stop MEL calculation for the PlaybackThread
- std::lock_guard _lAf(mAudioFlinger.mLock);
- mSoundDoseManager.removeStreamProcessor(melPatch.streamHandle);
- auto thread = mAudioFlinger.checkPlaybackThread_l(melPatch.streamHandle);
- if (thread != nullptr) {
- thread->stopMelComputation();
- }
+ std::lock_guard _afl(mAudioFlinger.mLock);
+ std::lock_guard _l(mLock);
+ stopMelComputationForPatch_l(melPatch);
}
sp<media::ISoundDose> AudioFlinger::MelReporter::getSoundDoseInterface(
const sp<media::ISoundDoseCallback>& callback) {
// no need to lock since getSoundDoseInterface is synchronized
- return mSoundDoseManager.getSoundDoseInterface(callback);
+ return mSoundDoseManager->getSoundDoseInterface(callback);
+}
+
+void AudioFlinger::MelReporter::stopInternalMelComputation() {
+ ALOGV("%s", __func__);
+ std::lock_guard _l(mLock);
+ mActiveMelPatches.clear();
+ mUseHalSoundDoseInterface = true;
+}
+
+void AudioFlinger::MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch) {
+ auto thread = mAudioFlinger.checkPlaybackThread_l(patch.streamHandle);
+ ALOGV("%s: stop MEL for stream id: %d", __func__, patch.streamHandle);
+ for (const auto& deviceId : patch.deviceHandles) {
+ if (mActiveDevices[deviceId] > 0) {
+ --mActiveDevices[deviceId];
+ if (mActiveDevices[deviceId] == 0) {
+ // no stream is using deviceId anymore
+ ALOGI("%s removing device %d from active CSD devices", __func__, deviceId);
+ mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
+ }
+ }
+ }
+
+ mSoundDoseManager->removeStreamProcessor(patch.streamHandle);
+ if (thread != nullptr) {
+ thread->stopMelComputation();
+ }
+}
+
+
+std::optional<audio_patch_handle_t> AudioFlinger::MelReporter::activePatchStreamHandle_l(
+ audio_io_handle_t streamHandle) {
+ for(const auto& patchIt : mActiveMelPatches) {
+ if (patchIt.second.streamHandle == streamHandle) {
+ return patchIt.first;
+ }
+ }
+ return std::nullopt;
+}
+
+bool AudioFlinger::MelReporter::useHalSoundDoseInterface() {
+ bool useHalSoundDoseInterface = !mSoundDoseManager->forceUseFrameworkMel();
+ {
+ std::lock_guard _l(mLock);
+ useHalSoundDoseInterface &= mUseHalSoundDoseInterface;
+ }
+ return useHalSoundDoseInterface;
}
std::string AudioFlinger::MelReporter::dump() {
std::lock_guard _l(mLock);
std::string output("\nSound Dose:\n");
- output.append(mSoundDoseManager.dump());
+ output.append(mSoundDoseManager->dump());
return output;
}
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index f73b3d6..c1b291f 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -32,17 +32,34 @@
class MelReporter : public PatchCommandThread::PatchCommandListener {
public:
explicit MelReporter(AudioFlinger& audioFlinger)
- : mAudioFlinger(audioFlinger) {}
+ : mAudioFlinger(audioFlinger),
+ mSoundDoseManager(sp<SoundDoseManager>::make()) {}
- void onFirstRef() override {
- mAudioFlinger.mPatchCommandThread->addListener(this);
- }
+ void onFirstRef() override;
- /** Returns true if we should compute MEL for the given device. */
- static bool shouldComputeMelForDeviceType(audio_devices_t device);
+ /**
+ * Activates the MEL reporting from the HAL sound dose interface. If the HAL
+ * does not support the sound dose interface for this module, the internal MEL
+ * calculation will be use.
+ *
+ * <p>If the device is using the audio AIDL HAL then this method will try to get the sound
+ * dose interface from IModule#getSoundDose(). Otherwise, if the legacy audio HIDL HAL is used
+ * this method will be looking for the standalone sound dose implementation. It falls back to
+ * the internal MEL computation if no valid sound dose interface can be retrieved.
+ *
+ * @return true if the MEL reporting will be done from any sound dose HAL interface
+ * implementation, false otherwise.
+ */
+ bool activateHalSoundDoseComputation(const std::string& module,
+ const sp<DeviceHalInterface>& device);
- // For now only support internal MelReporting
- [[nodiscard]] bool isHalReportingEnabled() const { return false; }
+ /**
+ * Activates the MEL reporting from internal framework values. These are used
+ * as a fallback when there is no sound dose interface implementation from HAL.
+ * Note: the internal CSD computation does not guarantee a certification with
+ * IEC62368-1 3rd edition or EN50332-3
+ */
+ void activateInternalSoundDoseComputation();
sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback);
@@ -53,16 +70,39 @@
const PatchPanel::Patch& patch) override;
void onReleaseAudioPatch(audio_patch_handle_t handle) override;
+ /**
+ * The new metadata can determine whether we should compute MEL for the given thread.
+ * This is the case only if one of the tracks in the thread mix is using MEDIA or GAME.
+ * Otherwise, this method will disable CSD.
+ **/
+ void updateMetadataForCsd(audio_io_handle_t streamHandle,
+ const std::vector<playback_track_metadata_v7_t>& metadataVec);
private:
- AudioFlinger& mAudioFlinger; // does not own the object
-
- SoundDoseManager mSoundDoseManager;
-
struct ActiveMelPatch {
audio_io_handle_t streamHandle{AUDIO_IO_HANDLE_NONE};
std::vector<audio_port_handle_t> deviceHandles;
+ bool csdActive;
};
+ /** Returns true if we should compute MEL for the given device. */
+ bool shouldComputeMelForDeviceType(audio_devices_t device);
+
+ void stopInternalMelComputation();
+
+ /** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
+ void stopMelComputationForPatch_l(const ActiveMelPatch& patch);
+
+ /** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
+ void startMelComputationForActivePatch_l(const ActiveMelPatch& patch);
+
+ std::optional<audio_patch_handle_t> activePatchStreamHandle_l(audio_io_handle_t streamHandle);
+
+ bool useHalSoundDoseInterface();
+
+ AudioFlinger& mAudioFlinger; // does not own the object
+
+ sp<SoundDoseManager> mSoundDoseManager;
+
/**
* Lock for protecting the active mel patches. Do not mix with the AudioFlinger lock.
* Locking order AudioFlinger::mLock -> PatchCommandThread::mLock -> MelReporter::mLock.
@@ -70,4 +110,7 @@
std::mutex mLock;
std::unordered_map<audio_patch_handle_t, ActiveMelPatch>
mActiveMelPatches GUARDED_BY(AudioFlinger::MelReporter::mLock);
+ std::unordered_map<audio_port_handle_t, int>
+ mActiveDevices GUARDED_BY(AudioFlinger::MelReporter::mLock);
+ bool mUseHalSoundDoseInterface GUARDED_BY(AudioFlinger::MelReporter::mLock) = false;
};
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index ebbdf56..9560609 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -148,8 +148,12 @@
sp<media::VolumeHandler> getVolumeHandler() { return mVolumeHandler; }
/** Set the computed normalized final volume of the track.
* !masterMute * masterVolume * streamVolume * averageLRVolume */
- void setFinalVolume(float volume);
+ void setFinalVolume(float volumeLeft, float volumeRight);
float getFinalVolume() const { return mFinalVolume; }
+ void getFinalVolume(float* left, float* right) const {
+ *left = mFinalVolumeLeft;
+ *right = mFinalVolumeRight;
+ }
using SourceMetadatas = std::vector<playback_track_metadata_v7_t>;
using MetadataInserter = std::back_insert_iterator<SourceMetadatas>;
@@ -355,6 +359,10 @@
// 'volatile' means accessed without lock or
// barrier, but is read/written atomically
float mFinalVolume; // combine master volume, stream type volume and track volume
+ float mFinalVolumeLeft; // combine master volume, stream type volume and track
+ // volume
+ float mFinalVolumeRight; // combine master volume, stream type volume and track
+ // volume
sp<AudioTrackServerProxy> mAudioTrackServerProxy;
bool mResumeToStopping; // track was paused in stopping state.
bool mFlushHwPending; // track requests for thread flush
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d8f12ec..4ca8a8e 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -273,8 +273,8 @@
static std::string toString(audio_latency_mode_t mode) {
// We convert to the AIDL type to print (eventually the legacy type will be removed).
- const auto result = legacy2aidl_audio_latency_mode_t_LatencyMode(mode);
- return result.has_value() ? media::toString(*result) : "UNKNOWN";
+ const auto result = legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode);
+ return result.has_value() ? media::audio::common::toString(*result) : "UNKNOWN";
}
// Could be made a template, but other toString overloads for std::vector are confused.
@@ -2970,7 +2970,14 @@
void AudioFlinger::PlaybackThread::onCodecFormatChanged(
const std::basic_string<uint8_t>& metadataBs)
{
- std::thread([this, metadataBs]() {
+ wp<AudioFlinger::PlaybackThread> weakPointerThis = this;
+ std::thread([this, metadataBs, weakPointerThis]() {
+ sp<AudioFlinger::PlaybackThread> playbackThread = weakPointerThis.promote();
+ if (playbackThread == nullptr) {
+ ALOGW("PlaybackThread was destroyed, skip codec format change event");
+ return;
+ }
+
audio_utils::metadata::Data metadata =
audio_utils::metadata::dataFromByteString(metadataBs);
if (metadata.empty()) {
@@ -3222,10 +3229,10 @@
item.record();
}
-void AudioFlinger::PlaybackThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::PlaybackThread::updateMetadata_l()
{
if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
- return; // nothing to do
+ return {}; // nothing to do
}
StreamOutHalInterface::SourceMetadata metadata;
auto backInserter = std::back_inserter(metadata.tracks);
@@ -3234,6 +3241,9 @@
track->copyMetadataTo(backInserter);
}
sendMetadataToBackend_l(metadata);
+ MetadataUpdate change;
+ change.playbackMetadataUpdate = metadata.tracks;
+ return change;
}
void AudioFlinger::PlaybackThread::sendMetadataToBackend_l(
@@ -3471,8 +3481,10 @@
}
void AudioFlinger::PlaybackThread::stopMelComputation() {
- ALOGV("%s: stopping mel processor for thread %d", __func__, id());
- mMelProcessor = nullptr;
+ if (mMelProcessor.load() != nullptr) {
+ ALOGV("%s: stopping mel processor for thread %d", __func__, id());
+ mMelProcessor = nullptr;
+ }
}
void AudioFlinger::PlaybackThread::threadLoop_drain()
@@ -3571,6 +3583,28 @@
invalidateTracks_l(streamType);
}
+void AudioFlinger::PlaybackThread::invalidateTracks(std::set<audio_port_handle_t>& portIds) {
+ Mutex::Autolock _l(mLock);
+ invalidateTracks_l(portIds);
+}
+
+bool AudioFlinger::PlaybackThread::invalidateTracks_l(std::set<audio_port_handle_t>& portIds) {
+ bool trackMatch = false;
+ const size_t size = mTracks.size();
+ for (size_t i = 0; i < size; i++) {
+ sp<Track> t = mTracks[i];
+ if (t->isExternalTrack() && portIds.find(t->portId()) != portIds.end()) {
+ t->invalidate();
+ portIds.erase(t->portId());
+ trackMatch = true;
+ }
+ if (portIds.empty()) {
+ break;
+ }
+ }
+ return trackMatch;
+}
+
// getTrackById_l must be called with holding thread lock
AudioFlinger::PlaybackThread::Track* AudioFlinger::PlaybackThread::getTrackById_l(
audio_port_handle_t trackPortId) {
@@ -3615,9 +3649,9 @@
if (result != OK) return result;
#ifdef FLOAT_EFFECT_CHAIN
- buffer = halInBuffer->audioBuffer()->f32;
+ buffer = halInBuffer ? halInBuffer->audioBuffer()->f32 : buffer;
#else
- buffer = halInBuffer->audioBuffer()->s16;
+ buffer = halInBuffer ? halInBuffer->audioBuffer()->s16 : buffer;
#endif
ALOGV("addEffectChain_l() creating new input buffer %p session %d",
buffer, session);
@@ -3646,7 +3680,8 @@
halOutBuffer = halInBuffer;
ALOGV("addEffectChain_l() %p on thread %p for session %d", chain.get(), this, session);
if (!audio_is_global_session(session)) {
- buffer = reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData());
+ buffer = halInBuffer ? reinterpret_cast<effect_buffer_t*>(halInBuffer->externalData())
+ : buffer;
// Only one effect chain can be present in direct output thread and it uses
// the sink buffer as input
if (mType != DIRECT) {
@@ -3658,9 +3693,9 @@
&halInBuffer);
if (result != OK) return result;
#ifdef FLOAT_EFFECT_CHAIN
- buffer = halInBuffer->audioBuffer()->f32;
+ buffer = halInBuffer ? halInBuffer->audioBuffer()->f32 : buffer;
#else
- buffer = halInBuffer->audioBuffer()->s16;
+ buffer = halInBuffer ? halInBuffer->audioBuffer()->s16 : buffer;
#endif
ALOGV("addEffectChain_l() creating new input buffer %p session %d",
buffer, session);
@@ -3903,6 +3938,7 @@
checkOutputStageEffects();
}
+ MetadataUpdate metadataUpdate;
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -4004,7 +4040,7 @@
mActiveTracks.updatePowerState(this);
- updateMetadata_l();
+ metadataUpdate = updateMetadata_l();
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
@@ -4234,6 +4270,11 @@
// enable changes in effect chain
unlockEffectChains(effectChains);
+ if (!metadataUpdate.playbackMetadataUpdate.empty()) {
+ mAudioFlinger->mMelReporter->updateMetadataForCsd(id(),
+ metadataUpdate.playbackMetadataUpdate);
+ }
+
if (!waitingAsyncCallback()) {
// mSleepTimeUs == 0 means we must write to audio hardware
if (mSleepTimeUs == 0) {
@@ -4670,6 +4711,8 @@
} else {
status = PlaybackThread::createAudioPatch_l(patch, handle);
}
+
+ updateHalSupportedLatencyModes_l();
return status;
}
@@ -4751,7 +4794,7 @@
if (configChanged) {
sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
}
- // Force meteadata update after a route change
+ // Force metadata update after a route change
mActiveTracks.setHasChanged();
return status;
@@ -4821,6 +4864,7 @@
: PlaybackThread(audioFlinger, output, id, type, systemReady, mixerConfig),
// mAudioMixer below
// mFastMixer below
+ mBluetoothLatencyModesEnabled(false),
mFastMixerFutex(0),
mMasterMono(false)
// mOutputSink below
@@ -5036,6 +5080,21 @@
delete mAudioMixer;
}
+void AudioFlinger::MixerThread::onFirstRef() {
+ PlaybackThread::onFirstRef();
+
+ Mutex::Autolock _l(mLock);
+ if (mOutput != nullptr && mOutput->stream != nullptr) {
+ status_t status = mOutput->stream->setLatencyModeCallback(this);
+ if (status != INVALID_OPERATION) {
+ updateHalSupportedLatencyModes_l();
+ }
+ // Default to enabled if the HAL supports it. This can be changed by Audioflinger after
+ // the thread construction according to AudioFlinger::mBluetoothLatencyModesEnabled
+ mBluetoothLatencyModesEnabled.store(
+ mOutput->audioHwDev->supportsBluetoothVariableLatency());
+ }
+}
uint32_t AudioFlinger::MixerThread::correctLatency_l(uint32_t latency) const
{
@@ -5513,7 +5572,7 @@
vlf *= volume;
vrf *= volume;
- track->setFinalVolume((vlf + vrf) / 2.f);
+ track->setFinalVolume(vlf, vrf);
++fastTracks;
} else {
// was it previously active?
@@ -5712,7 +5771,7 @@
vaf = v * sendLevel * (1. / MAX_GAIN_INT);
}
- track->setFinalVolume((vrf + vlf) / 2.f);
+ track->setFinalVolume(vrf, vlf);
// Delegate volume control to effect in track effect chain if needed
if (chain != 0 && chain->setVolume_l(&vl, &vr)) {
@@ -6245,6 +6304,100 @@
maxPeriod = seconds(mNormalFrameCount) / mSampleRate * 15;
}
+void AudioFlinger::MixerThread::onHalLatencyModesChanged_l() {
+ mAudioFlinger->onSupportedLatencyModesChanged(mId, mSupportedLatencyModes);
+}
+
+void AudioFlinger::MixerThread::setHalLatencyMode_l() {
+ // Only handle latency mode if:
+ // - mBluetoothLatencyModesEnabled is true
+ // - the HAL supports latency modes
+ // - the selected device is Bluetooth LE or A2DP
+ if (!mBluetoothLatencyModesEnabled.load() || mSupportedLatencyModes.empty()) {
+ return;
+ }
+ if (mOutDeviceTypeAddrs.size() != 1
+ || !(audio_is_a2dp_out_device(mOutDeviceTypeAddrs[0].mType)
+ || audio_is_ble_out_device(mOutDeviceTypeAddrs[0].mType))) {
+ return;
+ }
+
+ audio_latency_mode_t latencyMode = AUDIO_LATENCY_MODE_FREE;
+ if (mSupportedLatencyModes.size() == 1) {
+ // If the HAL only support one latency mode currently, confirm the choice
+ latencyMode = mSupportedLatencyModes[0];
+ } else if (mSupportedLatencyModes.size() > 1) {
+ // Request low latency if:
+ // - At least one active track is either:
+ // - a fast track with gaming usage or
+ // - a track with acessibility usage
+ for (const auto& track : mActiveTracks) {
+ if ((track->isFastTrack() && track->attributes().usage == AUDIO_USAGE_GAME)
+ || track->attributes().usage == AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY) {
+ latencyMode = AUDIO_LATENCY_MODE_LOW;
+ break;
+ }
+ }
+ }
+
+ if (latencyMode != mSetLatencyMode) {
+ status_t status = mOutput->stream->setLatencyMode(latencyMode);
+ ALOGD("%s: thread(%d) setLatencyMode(%s) returned %d",
+ __func__, mId, toString(latencyMode).c_str(), status);
+ if (status == NO_ERROR) {
+ mSetLatencyMode = latencyMode;
+ }
+ }
+}
+
+void AudioFlinger::MixerThread::updateHalSupportedLatencyModes_l() {
+
+ if (mOutput == nullptr || mOutput->stream == nullptr) {
+ return;
+ }
+ std::vector<audio_latency_mode_t> latencyModes;
+ const status_t status = mOutput->stream->getRecommendedLatencyModes(&latencyModes);
+ if (status != NO_ERROR) {
+ latencyModes.clear();
+ }
+ if (latencyModes != mSupportedLatencyModes) {
+ ALOGD("%s: thread(%d) status %d supported latency modes: %s",
+ __func__, mId, status, toString(latencyModes).c_str());
+ mSupportedLatencyModes.swap(latencyModes);
+ sendHalLatencyModesChangedEvent_l();
+ }
+}
+
+status_t AudioFlinger::MixerThread::getSupportedLatencyModes(
+ std::vector<audio_latency_mode_t>* modes) {
+ if (modes == nullptr) {
+ return BAD_VALUE;
+ }
+ Mutex::Autolock _l(mLock);
+ *modes = mSupportedLatencyModes;
+ return NO_ERROR;
+}
+
+void AudioFlinger::MixerThread::onRecommendedLatencyModeChanged(
+ std::vector<audio_latency_mode_t> modes) {
+ Mutex::Autolock _l(mLock);
+ if (modes != mSupportedLatencyModes) {
+ ALOGD("%s: thread(%d) supported latency modes: %s",
+ __func__, mId, toString(modes).c_str());
+ mSupportedLatencyModes.swap(modes);
+ sendHalLatencyModesChangedEvent_l();
+ }
+}
+
+status_t AudioFlinger::MixerThread::setBluetoothVariableLatencyEnabled(bool enabled) {
+ if (mOutput == nullptr || mOutput->audioHwDev == nullptr
+ || !mOutput->audioHwDev->supportsBluetoothVariableLatency()) {
+ return INVALID_OPERATION;
+ }
+ mBluetoothLatencyModesEnabled.store(enabled);
+ return NO_ERROR;
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
@@ -6329,7 +6482,7 @@
shaperVolume == 0.f});
if (lastTrack) {
- track->setFinalVolume((left + right) / 2.f);
+ track->setFinalVolume(left, right);
if (left != mLeftVolFloat || right != mRightVolFloat) {
mLeftVolFloat = left;
mRightVolFloat = right;
@@ -7218,6 +7371,13 @@
}
}
+void AudioFlinger::OffloadThread::invalidateTracks(std::set<audio_port_handle_t>& portIds) {
+ Mutex::Autolock _l(mLock);
+ if (PlaybackThread::invalidateTracks_l(portIds)) {
+ mFlushPending = true;
+ }
+}
+
// ----------------------------------------------------------------------------
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger,
@@ -7469,13 +7629,7 @@
}
void AudioFlinger::SpatializerThread::onFirstRef() {
- PlaybackThread::onFirstRef();
-
- Mutex::Autolock _l(mLock);
- status_t status = mOutput->stream->setLatencyModeCallback(this);
- if (status != INVALID_OPERATION) {
- updateHalSupportedLatencyModes_l();
- }
+ MixerThread::onFirstRef();
const pid_t tid = getTid();
if (tid == -1) {
@@ -7489,32 +7643,6 @@
}
}
-status_t AudioFlinger::SpatializerThread::createAudioPatch_l(const struct audio_patch *patch,
- audio_patch_handle_t *handle)
-{
- status_t status = MixerThread::createAudioPatch_l(patch, handle);
- updateHalSupportedLatencyModes_l();
- return status;
-}
-
-void AudioFlinger::SpatializerThread::updateHalSupportedLatencyModes_l() {
- std::vector<audio_latency_mode_t> latencyModes;
- const status_t status = mOutput->stream->getRecommendedLatencyModes(&latencyModes);
- if (status != NO_ERROR) {
- latencyModes.clear();
- }
- if (latencyModes != mSupportedLatencyModes) {
- ALOGD("%s: thread(%d) status %d supported latency modes: %s",
- __func__, mId, status, toString(latencyModes).c_str());
- mSupportedLatencyModes.swap(latencyModes);
- sendHalLatencyModesChangedEvent_l();
- }
-}
-
-void AudioFlinger::SpatializerThread::onHalLatencyModesChanged_l() {
- mAudioFlinger->onSupportedLatencyModesChanged(mId, mSupportedLatencyModes);
-}
-
void AudioFlinger::SpatializerThread::setHalLatencyMode_l() {
// if mSupportedLatencyModes is empty, the HAL stream does not support
// latency mode control and we can exit.
@@ -7562,16 +7690,6 @@
return NO_ERROR;
}
-status_t AudioFlinger::SpatializerThread::getSupportedLatencyModes(
- std::vector<audio_latency_mode_t>* modes) {
- if (modes == nullptr) {
- return BAD_VALUE;
- }
- Mutex::Autolock _l(mLock);
- *modes = mSupportedLatencyModes;
- return NO_ERROR;
-}
-
void AudioFlinger::SpatializerThread::checkOutputStageEffects()
{
bool hasVirtualizer = false;
@@ -7624,17 +7742,6 @@
}
}
-void AudioFlinger::SpatializerThread::onRecommendedLatencyModeChanged(
- std::vector<audio_latency_mode_t> modes) {
- Mutex::Autolock _l(mLock);
- if (modes != mSupportedLatencyModes) {
- ALOGD("%s: thread(%d) supported latency modes: %s",
- __func__, mId, toString(modes).c_str());
- mSupportedLatencyModes.swap(modes);
- sendHalLatencyModesChangedEvent_l();
- }
-}
-
// ----------------------------------------------------------------------------
// Record
// ----------------------------------------------------------------------------
@@ -7706,10 +7813,11 @@
ALOGV("%p kUseFastCapture = Always, initFastCapture = true", this);
break;
case FastCapture_Static:
- initFastCapture = (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
- ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d",
- this, (long long)mFrameCount, mSampleRate, kMinNormalCaptureBufferSizeMs,
- initFastCapture);
+ initFastCapture = !mIsMsdDevice // Disable fast capture for MSD BUS devices.
+ && (mFrameCount * 1000) / mSampleRate < kMinNormalCaptureBufferSizeMs;
+ ALOGV("%p kUseFastCapture = Static, (%lld * 1000) / %u vs %u, initFastCapture = %d "
+ "mIsMsdDevice = %d", this, (long long)mFrameCount, mSampleRate,
+ kMinNormalCaptureBufferSizeMs, initFastCapture, mIsMsdDevice);
break;
// case FastCapture_Dynamic:
}
@@ -8926,10 +9034,10 @@
mSharedAudioPackageName = "";
}
-void AudioFlinger::RecordThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::RecordThread::updateMetadata_l()
{
if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
- return; // nothing to do
+ return {}; // nothing to do
}
StreamInHalInterface::SinkMetadata metadata;
auto backInserter = std::back_inserter(metadata.tracks);
@@ -8937,6 +9045,9 @@
track->copyMetadataTo(backInserter);
}
mInput->stream->updateSinkMetadata(metadata);
+ MetadataUpdate change;
+ change.recordMetadataUpdate = metadata.tracks;
+ return change;
}
// destroyTrack_l() must be called with ThreadBase::mLock held
@@ -10562,6 +10673,25 @@
}
}
+void AudioFlinger::MmapPlaybackThread::invalidateTracks(std::set<audio_port_handle_t>& portIds)
+{
+ Mutex::Autolock _l(mLock);
+ bool trackMatch = false;
+ for (const sp<MmapTrack> &track : mActiveTracks) {
+ if (portIds.find(track->portId()) != portIds.end()) {
+ track->invalidate();
+ trackMatch = true;
+ portIds.erase(track->portId());
+ }
+ if (portIds.empty()) {
+ break;
+ }
+ }
+ if (trackMatch) {
+ broadcast_l();
+ }
+}
+
void AudioFlinger::MmapPlaybackThread::processVolume_l()
{
float volume;
@@ -10617,10 +10747,10 @@
}
}
-void AudioFlinger::MmapPlaybackThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::MmapPlaybackThread::updateMetadata_l()
{
if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
- return; // nothing to do
+ return {}; // nothing to do
}
StreamOutHalInterface::SourceMetadata metadata;
for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10636,7 +10766,11 @@
metadata.tracks.push_back(trackMetadata);
}
mOutput->stream->updateSourceMetadata(metadata);
-}
+
+ MetadataUpdate change;
+ change.playbackMetadataUpdate = metadata.tracks;
+ return change;
+};
void AudioFlinger::MmapPlaybackThread::checkSilentMode_l()
{
@@ -10744,10 +10878,10 @@
}
}
-void AudioFlinger::MmapCaptureThread::updateMetadata_l()
+AudioFlinger::ThreadBase::MetadataUpdate AudioFlinger::MmapCaptureThread::updateMetadata_l()
{
if (!isStreamInitialized() || !mActiveTracks.readAndClearHasChanged()) {
- return; // nothing to do
+ return {}; // nothing to do
}
StreamInHalInterface::SinkMetadata metadata;
for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10762,6 +10896,9 @@
metadata.tracks.push_back(trackMetadata);
}
mInput->stream->updateSinkMetadata(metadata);
+ MetadataUpdate change;
+ change.recordMetadataUpdate = metadata.tracks;
+ return change;
}
void AudioFlinger::MmapCaptureThread::setRecordSilenced(audio_port_handle_t portId, bool silenced)
@@ -10804,6 +10941,8 @@
Vector<sp<Track>> *tracksToRemove) {
mixer_state result = MixerThread::prepareTracks_l(tracksToRemove);
// If there is only one active track and it is bit-perfect, enable tee buffer.
+ float volumeLeft = 1.0f;
+ float volumeRight = 1.0f;
if (mActiveTracks.size() == 1 && mActiveTracks[0]->isBitPerfect()) {
const int trackId = mActiveTracks[0]->id();
mAudioMixer->setParameter(
@@ -10811,6 +10950,7 @@
mAudioMixer->setParameter(
trackId, AudioMixer::TRACK, AudioMixer::TEE_BUFFER_FRAME_COUNT,
(void *)(uintptr_t)mNormalFrameCount);
+ mActiveTracks[0]->getFinalVolume(&volumeLeft, &volumeRight);
mIsBitPerfect = true;
} else {
mIsBitPerfect = false;
@@ -10822,6 +10962,11 @@
trackId, AudioMixer::TRACK, AudioMixer::TEE_BUFFER, nullptr);
}
}
+ if (mVolumeLeft != volumeLeft || mVolumeRight != volumeRight) {
+ mVolumeLeft = volumeLeft;
+ mVolumeRight = volumeRight;
+ setVolumeForOutput_l(volumeLeft, volumeRight);
+ }
return result;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 23b48d8..f829efc 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -376,8 +376,6 @@
virtual void toAudioPortConfig(struct audio_port_config *config) = 0;
virtual void resizeInputBuffer_l(int32_t maxSharedAudioHistoryMs);
- virtual void onHalLatencyModesChanged_l() {}
-
// see note at declaration of mStandby, mOutDevice and mInDevice
bool standby() const { return mStandby; }
@@ -609,7 +607,11 @@
void checkSuspendOnAddEffectChain_l(const sp<EffectChain>& chain);
// sends the metadata of the active tracks to the HAL
- virtual void updateMetadata_l() = 0;
+ struct MetadataUpdate {
+ std::vector<playback_track_metadata_v7_t> playbackMetadataUpdate;
+ std::vector<record_track_metadata_v7_t> recordMetadataUpdate;
+ };
+ virtual MetadataUpdate updateMetadata_l() = 0;
String16 getWakeLockTag();
@@ -625,6 +627,8 @@
product_strategy_t getStrategyForStream(audio_stream_type_t stream) const;
+ virtual void onHalLatencyModesChanged_l() {}
+
virtual void dumpInternals_l(int fd __unused, const Vector<String16>& args __unused)
{ }
virtual void dumpTracks_l(int fd __unused, const Vector<String16>& args __unused) { }
@@ -1036,7 +1040,11 @@
// called with AudioFlinger lock held
bool invalidateTracks_l(audio_stream_type_t streamType);
+ bool invalidateTracks_l(std::set<audio_port_handle_t>& portIds);
virtual void invalidateTracks(audio_stream_type_t streamType);
+ // Invalidate tracks by a set of port ids. The port id will be removed from
+ // the given set if the corresponding track is found and invalidated.
+ virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds);
virtual size_t frameCount() const { return mNormalFrameCount; }
@@ -1098,6 +1106,10 @@
return INVALID_OPERATION;
}
+ virtual status_t setBluetoothVariableLatencyEnabled(bool enabled __unused) {
+ return INVALID_OPERATION;
+ }
+
void startMelComputation(const sp<audio_utils::MelProcessor>& processor);
void stopMelComputation();
@@ -1269,7 +1281,7 @@
void removeTrack_l(const sp<Track>& track);
void readOutputParameters_l();
- void updateMetadata_l() final;
+ MetadataUpdate updateMetadata_l() final;
virtual void sendMetadataToBackend_l(const StreamOutHalInterface::SourceMetadata& metadata);
void collectTimestamps_l();
@@ -1458,7 +1470,8 @@
}
};
-class MixerThread : public PlaybackThread {
+class MixerThread : public PlaybackThread,
+ public StreamOutHalInterfaceLatencyModeCallback {
public:
MixerThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
@@ -1468,6 +1481,13 @@
audio_config_base_t *mixerConfig = nullptr);
virtual ~MixerThread();
+ // RefBase
+ virtual void onFirstRef();
+
+ // StreamOutHalInterfaceLatencyModeCallback
+ void onRecommendedLatencyModeChanged(
+ std::vector<audio_latency_mode_t> modes) override;
+
// Thread virtuals
virtual bool checkForNewParameter_l(const String8& keyValuePair,
@@ -1504,6 +1524,17 @@
virtual status_t releaseAudioPatch_l(const audio_patch_handle_t handle);
AudioMixer* mAudioMixer; // normal mixer
+
+ // Support low latency mode by default as unless explicitly indicated by the audio HAL
+ // we assume the audio path is compatible with the head tracking latency requirements
+ std::vector<audio_latency_mode_t> mSupportedLatencyModes = {AUDIO_LATENCY_MODE_LOW};
+ // default to invalid value to force first update to the audio HAL
+ audio_latency_mode_t mSetLatencyMode =
+ (audio_latency_mode_t)AUDIO_LATENCY_MODE_INVALID;
+
+ // Bluetooth Variable latency control logic is enabled or disabled for this thread
+ std::atomic_bool mBluetoothLatencyModesEnabled;
+
private:
// one-time initialization, no locks required
sp<FastMixer> mFastMixer; // non-0 if there is also a fast mixer
@@ -1537,6 +1568,11 @@
return INVALID_OPERATION;
}
+ status_t getSupportedLatencyModes(
+ std::vector<audio_latency_mode_t>* modes) override;
+
+ status_t setBluetoothVariableLatencyEnabled(bool enabled) override;
+
protected:
virtual void setMasterMono_l(bool mono) {
mMasterMono.store(mono);
@@ -1555,6 +1591,10 @@
mFastMixer->setMasterBalance(balance);
}
}
+
+ void updateHalSupportedLatencyModes_l();
+ void onHalLatencyModesChanged_l() override;
+ void setHalLatencyMode_l() override;
};
class DirectOutputThread : public PlaybackThread {
@@ -1655,6 +1695,7 @@
virtual bool waitingAsyncCallback();
virtual bool waitingAsyncCallback_l();
virtual void invalidateTracks(audio_stream_type_t streamType);
+ void invalidateTracks(std::set<audio_port_handle_t>& portIds) override;
virtual bool keepWakeLock() const { return (mKeepWakeLock || (mDrainSequence & 1)); }
@@ -1757,8 +1798,7 @@
}
};
-class SpatializerThread : public MixerThread,
- public StreamOutHalInterfaceLatencyModeCallback {
+class SpatializerThread : public MixerThread {
public:
SpatializerThread(const sp<AudioFlinger>& audioFlinger,
AudioStreamOut* output,
@@ -1769,32 +1809,16 @@
bool hasFastMixer() const override { return false; }
- status_t createAudioPatch_l(const struct audio_patch *patch,
- audio_patch_handle_t *handle) override;
-
// RefBase
virtual void onFirstRef();
- // StreamOutHalInterfaceLatencyModeCallback
- void onRecommendedLatencyModeChanged(std::vector<audio_latency_mode_t> modes) override;
-
status_t setRequestedLatencyMode(audio_latency_mode_t mode) override;
- status_t getSupportedLatencyModes(std::vector<audio_latency_mode_t>* modes) override;
protected:
void checkOutputStageEffects() override;
- void onHalLatencyModesChanged_l() override;
void setHalLatencyMode_l() override;
private:
- void updateHalSupportedLatencyModes_l();
-
- // Support low latency mode by default as unless explicitly indicated by the audio HAL
- // we assume the audio path is compatible with the head tracking latency requirements
- std::vector<audio_latency_mode_t> mSupportedLatencyModes = {AUDIO_LATENCY_MODE_LOW};
- // default to invalid value to force first update to the audio HAL
- audio_latency_mode_t mSetLatencyMode =
- (audio_latency_mode_t)AUDIO_LATENCY_MODE_INVALID;
// Do not request a specific mode by default
audio_latency_mode_t mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
@@ -1963,7 +1987,7 @@
status_t setPreferredMicrophoneDirection(audio_microphone_direction_t direction);
status_t setPreferredMicrophoneFieldDimension(float zoom);
- void updateMetadata_l() override;
+ MetadataUpdate updateMetadata_l() override;
bool fastTrackAvailable() const { return mFastTrackAvail; }
@@ -2151,6 +2175,7 @@
virtual audio_stream_type_t streamType() { return AUDIO_STREAM_DEFAULT; }
virtual void invalidateTracks(audio_stream_type_t streamType __unused) {}
+ virtual void invalidateTracks(std::set<audio_port_handle_t>& portIds __unused) {}
// Sets the UID records silence
virtual void setRecordSilenced(audio_port_handle_t portId __unused,
@@ -2230,12 +2255,13 @@
void setMasterMute_l(bool muted) { mMasterMute = muted; }
virtual void invalidateTracks(audio_stream_type_t streamType);
+ void invalidateTracks(std::set<audio_port_handle_t>& portIds) override;
virtual audio_stream_type_t streamType() { return mStreamType; }
virtual void checkSilentMode_l();
void processVolume_l() override;
- void updateMetadata_l() override;
+ MetadataUpdate updateMetadata_l() override;
virtual void toAudioPortConfig(struct audio_port_config *config);
@@ -2268,7 +2294,7 @@
status_t exitStandby_l() REQUIRES(mLock) override;
- void updateMetadata_l() override;
+ MetadataUpdate updateMetadata_l() override;
void processVolume_l() override;
void setRecordSilenced(audio_port_handle_t portId,
bool silenced) override;
@@ -2297,4 +2323,6 @@
private:
bool mIsBitPerfect;
+ float mVolumeLeft = 0.f;
+ float mVolumeRight = 0.f;
};
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index beeb09c..382e4f9 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -440,7 +440,8 @@
return Status::ok();
}
-Status AudioFlinger::TrackHandle::getDualMonoMode(media::AudioDualMonoMode* _aidl_return)
+Status AudioFlinger::TrackHandle::getDualMonoMode(
+ media::audio::common::AudioDualMonoMode* _aidl_return)
{
audio_dual_mono_mode_t mode = AUDIO_DUAL_MONO_MODE_OFF;
const status_t status = mTrack->getDualMonoMode(&mode)
@@ -453,7 +454,7 @@
}
Status AudioFlinger::TrackHandle::setDualMonoMode(
- media::AudioDualMonoMode mode)
+ media::audio::common::AudioDualMonoMode mode)
{
const auto localMonoMode = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioDualMonoMode_audio_dual_mono_mode_t(mode));
@@ -477,7 +478,7 @@
}
Status AudioFlinger::TrackHandle::getPlaybackRateParameters(
- media::AudioPlaybackRate* _aidl_return)
+ media::audio::common::AudioPlaybackRate* _aidl_return)
{
audio_playback_rate_t localPlaybackRate{};
status_t status = mTrack->getPlaybackRateParameters(&localPlaybackRate)
@@ -490,7 +491,7 @@
}
Status AudioFlinger::TrackHandle::setPlaybackRateParameters(
- const media::AudioPlaybackRate& playbackRate)
+ const media::audio::common::AudioPlaybackRate& playbackRate)
{
const audio_playback_rate_t localPlaybackRate = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPlaybackRate_audio_playback_rate_t(playbackRate));
@@ -792,7 +793,7 @@
" Format Chn mask SRate "
"ST Usg CT "
" G db L dB R dB VS dB "
- " Server FrmCnt FrmRdy F Underruns Flushed"
+ " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect"
"%s\n",
isServerLatencySupported() ? " Latency" : "");
}
@@ -878,7 +879,7 @@
"%08X %08X %6u "
"%2u %3x %2x "
"%5.2g %5.2g %5.2g %5.2g%c "
- "%08X %6zu%c %6zu %c %9u%c %7u",
+ "%08X %6zu%c %6zu %c %9u%c %7u %10s",
active ? "yes" : "no",
(mClient == 0) ? getpid() : mClient->pid(),
mSessionId,
@@ -907,7 +908,8 @@
fillingStatus,
mAudioTrackServerProxy->getUnderrunFrames(),
nowInUnderrun,
- (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000
+ (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
+ isBitPerfect() ? "true" : "false"
);
if (isServerLatencySupported()) {
@@ -1160,6 +1162,23 @@
}
if (status == NO_ERROR) {
forEachTeePatchTrack([](auto patchTrack) { patchTrack->start(); });
+
+ // send format to AudioManager for playback activity monitoring
+ sp<IAudioManager> audioManager = thread->mAudioFlinger->getOrCreateAudioManager();
+ if (audioManager && mPortId != AUDIO_PORT_HANDLE_NONE) {
+ std::unique_ptr<os::PersistableBundle> bundle =
+ std::make_unique<os::PersistableBundle>();
+ bundle->putBoolean(String16(kExtraPlayerEventSpatializedKey),
+ isSpatialized());
+ bundle->putInt(String16(kExtraPlayerEventSampleRateKey), mSampleRate);
+ bundle->putInt(String16(kExtraPlayerEventChannelMaskKey), mChannelMask);
+ status_t result = audioManager->portEvent(mPortId,
+ PLAYER_UPDATE_FORMAT, bundle);
+ if (result != OK) {
+ ALOGE("%s: unable to send playback format for port ID %d, status error %d",
+ __func__, mPortId, result);
+ }
+ }
}
return status;
}
@@ -1383,8 +1402,11 @@
return mVolumeHandler->getVolumeShaperState(id);
}
-void AudioFlinger::PlaybackThread::Track::setFinalVolume(float volume)
+void AudioFlinger::PlaybackThread::Track::setFinalVolume(float volumeLeft, float volumeRight)
{
+ mFinalVolumeLeft = volumeLeft;
+ mFinalVolumeRight = volumeRight;
+ const float volume = (volumeLeft + volumeRight) * 0.5f;
if (mFinalVolume != volume) { // Compare to an epsilon if too many meaningless updates
mFinalVolume = volume;
setMetadataHasChanged();
diff --git a/services/audioflinger/sounddose/Android.bp b/services/audioflinger/sounddose/Android.bp
index 0e409d3..6d9a0cc 100644
--- a/services/audioflinger/sounddose/Android.bp
+++ b/services/audioflinger/sounddose/Android.bp
@@ -12,15 +12,24 @@
double_loadable: true,
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_shared",
+ "latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "latest_android_hardware_audio_sounddose_ndk_shared",
+ ],
+
srcs: [
"SoundDoseManager.cpp",
],
shared_libs: [
"audioflinger-aidl-cpp",
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudiofoundation",
"libaudioutils",
"libbase",
"libbinder",
+ "libbinder_ndk",
"liblog",
"libutils",
],
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 46f310c..6f9e11f 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -20,14 +20,22 @@
#include "SoundDoseManager.h"
+#if !defined(BACKEND_NDK)
+#define BACKEND_NDK
+#endif
+
+#include "android/media/SoundDoseRecord.h"
#include <android-base/stringprintf.h>
+#include <media/AidlConversionCppNdk.h>
+#include <cinttypes>
#include <time.h>
#include <utils/Log.h>
-#include <cinttypes>
-#include "android/media/SoundDoseRecord.h"
namespace android {
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+
namespace {
int64_t getMonotonicSecond() {
@@ -46,6 +54,11 @@
size_t channelCount, audio_format_t format) {
std::lock_guard _l(mLock);
+ if (mHalSoundDose != nullptr) {
+ ALOGW("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
+ return nullptr;
+ }
+
auto streamProcessor = mActiveProcessors.find(streamHandle);
sp<audio_utils::MelProcessor> processor;
if (streamProcessor != mActiveProcessors.end() &&
@@ -63,20 +76,66 @@
}
}
+bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
+ ALOGV("%s", __func__);
+
+ {
+ std::lock_guard _l(mLock);
+
+ mHalSoundDose = halSoundDose;
+ if (halSoundDose == nullptr) {
+ ALOGI("%s: passed ISoundDose object is null, switching to internal CSD", __func__);
+ return false;
+ }
+
+ if (!mHalSoundDose->setOutputRs2(mRs2Value).isOk()) {
+ ALOGW("%s: Cannot set RS2 value for momentary exposure %f",
+ __func__,
+ mRs2Value);
+ }
+
+ // initialize the HAL sound dose callback lazily
+ if (mHalSoundDoseCallback == nullptr) {
+ mHalSoundDoseCallback =
+ ndk::SharedRefBase::make<HalSoundDoseCallback>(this);
+ }
+ }
+
+ auto status = halSoundDose->registerSoundDoseCallback(mHalSoundDoseCallback);
+ if (!status.isOk()) {
+ // Not a warning since this can happen if the callback was registered before
+ ALOGI("%s: Cannot register HAL sound dose callback with status message: %s",
+ __func__,
+ status.getMessage());
+ }
+
+ return true;
+}
+
void SoundDoseManager::setOutputRs2(float rs2Value) {
ALOGV("%s", __func__);
std::lock_guard _l(mLock);
- mRs2Value = rs2Value;
+ if (mHalSoundDose != nullptr) {
+ // using the HAL sound dose interface
+ if (!mHalSoundDose->setOutputRs2(rs2Value).isOk()) {
+ ALOGE("%s: Cannot set RS2 value for momentary exposure %f", __func__, rs2Value);
+ return;
+ }
+ mRs2Value = rs2Value;
+ return;
+ }
for (auto& streamProcessor : mActiveProcessors) {
sp<audio_utils::MelProcessor> processor = streamProcessor.second.promote();
if (processor != nullptr) {
- status_t result = processor->setOutputRs2(mRs2Value);
+ status_t result = processor->setOutputRs2(rs2Value);
if (result != NO_ERROR) {
- ALOGW("%s: could not set RS2 value %f for stream %d", __func__, mRs2Value,
+ ALOGW("%s: could not set RS2 value %f for stream %d", __func__, rs2Value,
streamProcessor.first);
+ return;
}
+ mRs2Value = rs2Value;
}
}
}
@@ -89,6 +148,102 @@
}
}
+audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
+ std::lock_guard _l(mLock);
+
+ audio_devices_t type;
+ std::string address;
+ auto result = aidl::android::aidl2legacy_AudioDevice_audio_device(
+ audioDevice, &type, &address);
+ if (result != NO_ERROR) {
+ ALOGE("%s: could not convert from AudioDevice to AudioDeviceTypeAddr", __func__);
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+
+ auto adt = AudioDeviceTypeAddr(type, address);
+ auto deviceIt = mActiveDevices.find(adt);
+ if (deviceIt == mActiveDevices.end()) {
+ ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return deviceIt->second;
+}
+
+void SoundDoseManager::mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
+ const audio_port_handle_t deviceId) {
+ std::lock_guard _l(mLock);
+ ALOGI("%s: map address: %s to device id: %d", __func__, adt.toString().c_str(), deviceId);
+ mActiveDevices[adt] = deviceId;
+}
+
+void SoundDoseManager::clearMapDeviceIdEntries(audio_port_handle_t deviceId) {
+ std::lock_guard _l(mLock);
+ for (auto activeDevice = mActiveDevices.begin(); activeDevice != mActiveDevices.end();) {
+ if (activeDevice->second == deviceId) {
+ ALOGI("%s: clear mapping addr: %s to deviceId: %d",
+ __func__, activeDevice->first.toString().c_str(), deviceId);
+ activeDevice = mActiveDevices.erase(activeDevice);
+ continue;
+ }
+ ++activeDevice;
+ }
+}
+
+ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onMomentaryExposureWarning(
+ float in_currentDbA, const AudioDevice& in_audioDevice) {
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ std::shared_ptr<ISoundDose> halSoundDose;
+ soundDoseManager->getHalSoundDose(&halSoundDose);
+ if(halSoundDose == nullptr) {
+ ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
+ if (id == AUDIO_PORT_HANDLE_NONE) {
+ ALOGI("%s: no mapped id for audio device with type %d and address %s",
+ __func__, in_audioDevice.type.type,
+ in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ soundDoseManager->onMomentaryExposure(in_currentDbA, id);
+
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus SoundDoseManager::HalSoundDoseCallback::onNewMelValues(
+ const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+ const AudioDevice& in_audioDevice) {
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager == nullptr) {
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ std::shared_ptr<ISoundDose> halSoundDose;
+ soundDoseManager->getHalSoundDose(&halSoundDose);
+ if(halSoundDose == nullptr) {
+ ALOGW("%s: HAL sound dose interface deactivated. Ignoring", __func__);
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_STATE);
+ }
+
+ auto id = soundDoseManager->getIdForAudioDevice(in_audioDevice);
+ if (id == AUDIO_PORT_HANDLE_NONE) {
+ ALOGI("%s: no mapped id for audio device with type %d and address %s",
+ __func__, in_audioDevice.type.type,
+ in_audioDevice.address.get<AudioDeviceAddress::id>().c_str());
+ return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
+ }
+ // TODO: introduce timestamp in onNewMelValues callback
+ soundDoseManager->onNewMelValues(in_melRecord.melValues, 0,
+ in_melRecord.melValues.size(), id);
+
+ return ndk::ScopedAStatus::ok();
+}
+
void SoundDoseManager::SoundDose::binderDied(__unused const wp<IBinder>& who) {
ALOGV("%s", __func__);
@@ -117,6 +272,72 @@
return binder::Status::ok();
}
+binder::Status SoundDoseManager::SoundDose::getOutputRs2(float* value) {
+ ALOGV("%s", __func__);
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager != nullptr) {
+ std::lock_guard _l(soundDoseManager->mLock);
+ *value = soundDoseManager->mRs2Value;
+ }
+ return binder::Status::ok();
+}
+
+binder::Status SoundDoseManager::SoundDose::getCsd(float* value) {
+ ALOGV("%s", __func__);
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager != nullptr) {
+ *value = soundDoseManager->mMelAggregator->getCsd();
+ }
+ return binder::Status::ok();
+}
+
+binder::Status SoundDoseManager::SoundDose::forceUseFrameworkMel(bool useFrameworkMel) {
+ ALOGV("%s", __func__);
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager != nullptr) {
+ soundDoseManager->setUseFrameworkMel(useFrameworkMel);
+ }
+ return binder::Status::ok();
+}
+
+binder::Status SoundDoseManager::SoundDose::forceComputeCsdOnAllDevices(
+ bool computeCsdOnAllDevices) {
+ ALOGV("%s", __func__);
+ auto soundDoseManager = mSoundDoseManager.promote();
+ if (soundDoseManager != nullptr) {
+ soundDoseManager->setComputeCsdOnAllDevices(computeCsdOnAllDevices);
+ }
+ return binder::Status::ok();
+}
+
+void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
+ // invalidate any HAL sound dose interface used
+ setHalSoundDoseInterface(nullptr);
+
+ std::lock_guard _l(mLock);
+ mUseFrameworkMel = useFrameworkMel;
+}
+
+bool SoundDoseManager::forceUseFrameworkMel() const {
+ std::lock_guard _l(mLock);
+ return mUseFrameworkMel;
+}
+
+void SoundDoseManager::setComputeCsdOnAllDevices(bool computeCsdOnAllDevices) {
+ std::lock_guard _l(mLock);
+ mComputeCsdOnAllDevices = computeCsdOnAllDevices;
+}
+
+bool SoundDoseManager::forceComputeCsdOnAllDevices() const {
+ std::lock_guard _l(mLock);
+ return mComputeCsdOnAllDevices;
+}
+
+void SoundDoseManager::getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const {
+ std::lock_guard _l(mLock);
+ *halSoundDose = mHalSoundDose;
+}
+
void SoundDoseManager::resetSoundDose() {
std::lock_guard lock(mLock);
mSoundDose = nullptr;
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index b0aa5d6..c12efc3 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -17,8 +17,11 @@
#pragma once
+#include <aidl/android/hardware/audio/core/sounddose/ISoundDose.h>
+#include <aidl/android/media/audio/common/AudioDevice.h>
#include <android/media/BnSoundDose.h>
#include <android/media/ISoundDoseCallback.h>
+#include <media/AudioDeviceTypeAddr.h>
#include <audio_utils/MelAggregator.h>
#include <audio_utils/MelProcessor.h>
#include <binder/Status.h>
@@ -27,8 +30,10 @@
namespace android {
+using aidl::android::hardware::audio::core::sounddose::ISoundDose;
+
class SoundDoseManager : public audio_utils::MelProcessor::MelCallback {
- public:
+public:
/** CSD is computed with a rolling window of 7 days. */
static constexpr int64_t kCsdWindowSeconds = 604800; // 60s * 60m * 24h * 7d
/** Default RS2 value in dBA as defined in IEC 62368-1 3rd edition. */
@@ -36,13 +41,13 @@
SoundDoseManager()
: mMelAggregator(sp<audio_utils::MelAggregator>::make(kCsdWindowSeconds)),
- mRs2Value(kDefaultRs2Value){};
+ mRs2Value(kDefaultRs2Value) {};
/**
* \brief Creates or gets the MelProcessor assigned to the streamHandle
*
* \param deviceId id for the devices where the stream is active.
- * \param streanHandle handle to the stream
+ * \param streamHandle handle to the stream
* \param sampleRate sample rate for the processor
* \param channelCount number of channels to be processed.
* \param format format of the input samples.
@@ -58,7 +63,7 @@
/**
* \brief Removes stream processor when MEL computation is not needed anymore
*
- * \param streanHandle handle to the stream
+ * \param streamHandle handle to the stream
*/
void removeStreamProcessor(audio_io_handle_t streamHandle);
@@ -78,10 +83,31 @@
**/
sp<media::ISoundDose> getSoundDoseInterface(const sp<media::ISoundDoseCallback>& callback);
+ /**
+ * Sets the HAL sound dose interface to use for the MEL computation. Use nullptr
+ * for using the internal MEL computation.
+ *
+ * @return true if setting the HAL sound dose value was successful, false otherwise.
+ */
+ bool setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose);
+
+ /** Returns the cached audio port id from the active devices. */
+ audio_port_handle_t getIdForAudioDevice(
+ const aidl::android::media::audio::common::AudioDevice& audioDevice) const;
+
+ /** Caches mapping between address and device port id. */
+ void mapAddressToDeviceId(const AudioDeviceTypeAddr& adt,
+ const audio_port_handle_t deviceId);
+
+ /** Clear all map entries with passed audio_port_handle_t. */
+ void clearMapDeviceIdEntries(audio_port_handle_t deviceId);
+
std::string dump() const;
- // used for testing
+ // used for testing only
size_t getCachedMelRecordsSize() const;
+ bool forceUseFrameworkMel() const;
+ bool forceComputeCsdOnAllDevices() const;
/** Method for converting from audio_utils::CsdRecord to media::SoundDoseRecord. */
static media::SoundDoseRecord csdRecordToSoundDoseRecord(const audio_utils::CsdRecord& legacy);
@@ -98,7 +124,7 @@
public:
SoundDose(SoundDoseManager* manager, const sp<media::ISoundDoseCallback>& callback)
: mSoundDoseManager(manager),
- mSoundDoseCallback(callback) {};
+ mSoundDoseCallback(callback) {}
/** IBinder::DeathRecipient. Listen to the death of ISoundDoseCallback. */
virtual void binderDied(const wp<IBinder>& who);
@@ -107,17 +133,41 @@
binder::Status setOutputRs2(float value) override;
binder::Status resetCsd(float currentCsd,
const std::vector<media::SoundDoseRecord>& records) override;
+ binder::Status getOutputRs2(float* value);
+ binder::Status getCsd(float* value);
+ binder::Status forceUseFrameworkMel(bool useFrameworkMel);
+ binder::Status forceComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
wp<SoundDoseManager> mSoundDoseManager;
const sp<media::ISoundDoseCallback> mSoundDoseCallback;
};
+ class HalSoundDoseCallback : public ISoundDose::BnHalSoundDoseCallback {
+ public:
+ explicit HalSoundDoseCallback(SoundDoseManager* manager)
+ : mSoundDoseManager(manager) {}
+
+ ndk::ScopedAStatus onMomentaryExposureWarning(
+ float in_currentDbA,
+ const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;
+ ndk::ScopedAStatus onNewMelValues(
+ const ISoundDose::IHalSoundDoseCallback::MelRecord& in_melRecord,
+ const aidl::android::media::audio::common::AudioDevice& in_audioDevice) override;
+
+ wp<SoundDoseManager> mSoundDoseManager;
+ };
+
void resetSoundDose();
void resetCsd(float currentCsd, const std::vector<media::SoundDoseRecord>& records);
sp<media::ISoundDoseCallback> getSoundDoseCallback() const;
-
+
+ void setUseFrameworkMel(bool useFrameworkMel);
+ void setComputeCsdOnAllDevices(bool computeCsdOnAllDevices);
+ /** Returns the HAL sound dose interface or null if internal MEL computation is used. */
+ void getHalSoundDose(std::shared_ptr<ISoundDose>* halSoundDose) const;
+
mutable std::mutex mLock;
// no need for lock since MelAggregator is thread-safe
@@ -126,9 +176,20 @@
std::unordered_map<audio_io_handle_t, wp<audio_utils::MelProcessor>> mActiveProcessors
GUARDED_BY(mLock);
+ // map active device address and type to device id, used also for managing the pause/resume
+ // logic for deviceId's that should not report MEL values (e.g.: do not have an active MUSIC
+ // or GAME stream).
+ std::map<AudioDeviceTypeAddr, audio_port_handle_t> mActiveDevices GUARDED_BY(mLock);
+
float mRs2Value GUARDED_BY(mLock);
sp<SoundDose> mSoundDose GUARDED_BY(mLock);
+
+ std::shared_ptr<ISoundDose> mHalSoundDose GUARDED_BY(mLock);
+ std::shared_ptr<HalSoundDoseCallback> mHalSoundDoseCallback GUARDED_BY(mLock);
+
+ bool mUseFrameworkMel GUARDED_BY(mLock) = false;
+ bool mComputeCsdOnAllDevices GUARDED_BY(mLock) = false;
};
} // namespace android
diff --git a/services/audioflinger/sounddose/tests/Android.bp b/services/audioflinger/sounddose/tests/Android.bp
index a886663..fef73dc 100644
--- a/services/audioflinger/sounddose/tests/Android.bp
+++ b/services/audioflinger/sounddose/tests/Android.bp
@@ -14,15 +14,24 @@
"sounddosemanager_tests.cpp"
],
+ defaults: [
+ "latest_android_media_audio_common_types_ndk_static",
+ "latest_android_hardware_audio_core_sounddose_ndk_static",
+ "latest_android_hardware_audio_sounddose_ndk_static",
+ ],
+
shared_libs: [
"audioflinger-aidl-cpp",
+ "libaudiofoundation",
"libaudioutils",
"libbase",
+ "libbinder_ndk",
"liblog",
"libutils",
],
static_libs: [
+ "libaudio_aidl_conversion_common_ndk",
"libgmock",
"libsounddose",
],
@@ -37,4 +46,8 @@
"-Werror",
"-Wextra",
],
+
+ test_suites: [
+ "general-tests",
+ ],
}
\ No newline at end of file
diff --git a/services/audioflinger/sounddose/tests/TEST_MAPPING b/services/audioflinger/sounddose/tests/TEST_MAPPING
new file mode 100644
index 0000000..dd7fe4d
--- /dev/null
+++ b/services/audioflinger/sounddose/tests/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "presubmit": [
+ {
+ "name": "sounddosemanager_tests"
+ }
+ ]
+}
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 0aa5a20..4b1edf3 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -15,25 +15,55 @@
*/
// #define LOG_NDEBUG 0
-#define LOG_TAG "sounddosemanager_tests"
+#define LOG_TAG "SoundDoseManager_tests"
+
+#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
#include <SoundDoseManager.h>
-#include <gtest/gtest.h>
-
namespace android {
namespace {
-TEST(SoundDoseManagerTest, GetProcessorForExistingStream) {
- SoundDoseManager soundDoseManager;
+using aidl::android::hardware::audio::core::sounddose::BnSoundDose;
+using aidl::android::media::audio::common::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
+
+class HalSoundDoseMock : public BnSoundDose {
+public:
+ MOCK_METHOD(ndk::ScopedAStatus, getOutputRs2, (float*), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, setOutputRs2, (float), (override));
+ MOCK_METHOD(ndk::ScopedAStatus, registerSoundDoseCallback,
+ (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>&), (override));
+};
+
+class SoundDoseManagerTest : public ::testing::Test {
+protected:
+ void SetUp() override {
+ mSoundDoseManager = sp<SoundDoseManager>::make();
+ mHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
+
+ ON_CALL(*mHalSoundDose.get(), setOutputRs2)
+ .WillByDefault([] (float rs2) {
+ EXPECT_EQ(rs2, ISoundDose::DEFAULT_MAX_RS2);
+ return ndk::ScopedAStatus::ok();
+ });
+ }
+
+ sp<SoundDoseManager> mSoundDoseManager;
+ std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
+};
+
+TEST_F(SoundDoseManagerTest, GetProcessorForExistingStream) {
sp<audio_utils::MelProcessor> processor1 =
- soundDoseManager.getOrCreateProcessorForDevice(/*deviceId=*/1,
+ mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/1,
/*streamHandle=*/1,
/*sampleRate*/44100,
/*channelCount*/2,
/*format*/AUDIO_FORMAT_PCM_FLOAT);
sp<audio_utils::MelProcessor> processor2 =
- soundDoseManager.getOrCreateProcessorForDevice(/*deviceId=*/2,
+ mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
/*streamHandle=*/1,
/*sampleRate*/44100,
/*channelCount*/2,
@@ -42,18 +72,17 @@
EXPECT_EQ(processor1, processor2);
}
-TEST(SoundDoseManagerTest, RemoveExistingStream) {
- SoundDoseManager soundDoseManager;
+TEST_F(SoundDoseManagerTest, RemoveExistingStream) {
sp<audio_utils::MelProcessor> processor1 =
- soundDoseManager.getOrCreateProcessorForDevice(/*deviceId=*/1,
+ mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/1,
/*streamHandle=*/1,
/*sampleRate*/44100,
/*channelCount*/2,
/*format*/AUDIO_FORMAT_PCM_FLOAT);
- soundDoseManager.removeStreamProcessor(1);
+ mSoundDoseManager->removeStreamProcessor(1);
sp<audio_utils::MelProcessor> processor2 =
- soundDoseManager.getOrCreateProcessorForDevice(/*deviceId=*/2,
+ mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
/*streamHandle=*/1,
/*sampleRate*/44100,
/*channelCount*/2,
@@ -62,13 +91,150 @@
EXPECT_NE(processor1, processor2);
}
-TEST(SoundDoseManagerTest, NewMelValuesCacheNewRecord) {
- SoundDoseManager soundDoseManager;
+TEST_F(SoundDoseManagerTest, NewMelValuesCacheNewRecord) {
std::vector<float>mels{1, 1};
- soundDoseManager.onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1);
+ mSoundDoseManager->onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1);
- EXPECT_EQ(soundDoseManager.getCachedMelRecordsSize(), size_t{1});
+ EXPECT_EQ(mSoundDoseManager->getCachedMelRecordsSize(), size_t{1});
+}
+
+TEST_F(SoundDoseManagerTest, InvalidHalInterfaceIsNotSet) {
+ EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
+}
+
+TEST_F(SoundDoseManagerTest, SetHalSoundDoseDisablesNewMelProcessorCallbacks) {
+ EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2).Times(1);
+ EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ EXPECT_NE(nullptr, callback);
+ return ndk::ScopedAStatus::ok();
+ });
+
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+
+ EXPECT_EQ(nullptr, mSoundDoseManager->getOrCreateProcessorForDevice(/*deviceId=*/2,
+ /*streamHandle=*/1,
+ /*sampleRate*/44100,
+ /*channelCount*/2,
+ /*format*/AUDIO_FORMAT_PCM_FLOAT));
+}
+
+TEST_F(SoundDoseManagerTest, SetHalSoundDoseRegistersHalCallbacks) {
+ EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2).Times(1);
+ EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ EXPECT_NE(nullptr, callback);
+ return ndk::ScopedAStatus::ok();
+ });
+
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+}
+
+TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalWithNoAddressIllegalArgument) {
+ std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
+
+ EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2).Times(1);
+ EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ halCallback = callback;
+ return ndk::ScopedAStatus::ok();
+ });
+
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+
+ EXPECT_NE(nullptr, halCallback);
+ AudioDevice audioDevice = {};
+ audioDevice.address.set<AudioDeviceAddress::id>("test");
+ auto status = halCallback->onMomentaryExposureWarning(
+ /*in_currentDbA=*/101.f, audioDevice);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(SoundDoseManagerTest, MomentaryExposureFromHalAfterInternalSelectedReturnsException) {
+ std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
+
+ EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2).Times(1);
+ EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ halCallback = callback;
+ return ndk::ScopedAStatus::ok();
+ });
+
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+ EXPECT_NE(nullptr, halCallback);
+ EXPECT_FALSE(mSoundDoseManager->setHalSoundDoseInterface(nullptr));
+
+ AudioDevice audioDevice = {};
+ audioDevice.address.set<AudioDeviceAddress::id>("test");
+ auto status = halCallback->onMomentaryExposureWarning(
+ /*in_currentDbA=*/101.f, audioDevice);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(SoundDoseManagerTest, OnNewMelValuesFromHalWithNoAddressIllegalArgument) {
+ std::shared_ptr<ISoundDose::IHalSoundDoseCallback> halCallback;
+
+ EXPECT_CALL(*mHalSoundDose.get(), setOutputRs2).Times(1);
+ EXPECT_CALL(*mHalSoundDose.get(), registerSoundDoseCallback)
+ .Times(1)
+ .WillOnce([&] (const std::shared_ptr<ISoundDose::IHalSoundDoseCallback>& callback) {
+ halCallback = callback;
+ return ndk::ScopedAStatus::ok();
+ });
+
+ EXPECT_TRUE(mSoundDoseManager->setHalSoundDoseInterface(mHalSoundDose));
+
+ EXPECT_NE(nullptr, halCallback);
+ AudioDevice audioDevice = {};
+ audioDevice.address.set<AudioDeviceAddress::id>("test");
+ auto status = halCallback->onNewMelValues(/*in_melRecord=*/{}, audioDevice);
+ EXPECT_FALSE(status.isOk());
+}
+
+TEST_F(SoundDoseManagerTest, GetIdReturnsMappedAddress) {
+ const std::string address = "testAddress";
+ const audio_port_handle_t deviceId = 2;
+ const AudioDeviceTypeAddr adt{audio_devices_t{0}, address};
+ AudioDevice audioDevice;
+ audioDevice.address.set<AudioDeviceAddress::id>(address);
+
+ mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
+
+ EXPECT_EQ(deviceId, mSoundDoseManager->getIdForAudioDevice(audioDevice));
+}
+
+TEST_F(SoundDoseManagerTest, GetAfterClearIdReturnsNone) {
+ const std::string address = "testAddress";
+ const AudioDeviceTypeAddr adt {audio_devices_t{0}, address};
+ const audio_port_handle_t deviceId = 2;
+ AudioDevice audioDevice;
+ audioDevice.address.set<AudioDeviceAddress::id>(address);
+
+ mSoundDoseManager->mapAddressToDeviceId(adt, deviceId);
+ mSoundDoseManager->clearMapDeviceIdEntries(deviceId);
+
+ EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice));
+}
+
+TEST_F(SoundDoseManagerTest, GetUnmappedIdReturnsHandleNone) {
+ const std::string address = "testAddress";
+ AudioDevice audioDevice;
+ audioDevice.address.set<AudioDeviceAddress::id>(address);
+
+ EXPECT_EQ(AUDIO_PORT_HANDLE_NONE, mSoundDoseManager->getIdForAudioDevice(audioDevice));
+}
+
+TEST_F(SoundDoseManagerTest, GetDefaultForceComputeCsdOnAllDevices) {
+ EXPECT_FALSE(mSoundDoseManager->forceComputeCsdOnAllDevices());
+}
+
+TEST_F(SoundDoseManagerTest, GetDefaultForceUseFrameworkMel) {
+ EXPECT_FALSE(mSoundDoseManager->forceUseFrameworkMel());
}
} // namespace
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index a5fa78b..8f9c60b 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -137,7 +137,7 @@
audio_io_handle_t *output,
audio_session_t session,
audio_stream_type_t *stream,
- const AttributionSourceState& attributionSouce,
+ const AttributionSourceState& attributionSource,
audio_config_t *config,
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
@@ -160,7 +160,7 @@
audio_io_handle_t *input,
audio_unique_id_t riid,
audio_session_t session,
- const AttributionSourceState& attributionSouce,
+ const AttributionSourceState& attributionSource,
audio_config_base_t *config,
audio_input_flags_t flags,
audio_port_handle_t *selectedDeviceId,
@@ -300,6 +300,8 @@
virtual bool isUltrasoundSupported() = 0;
+ virtual bool isHotwordStreamSupported(bool lookbackAudio) = 0;
+
virtual status_t getHwOffloadFormatsSupportedForBluetoothMedia(
audio_devices_t device, std::vector<audio_format_t> *formats) = 0;
@@ -323,8 +325,11 @@
const AudioDeviceTypeAddrVector &devices) = 0;
virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
- device_role_t role) = 0;
+ device_role_t role,
+ const AudioDeviceTypeAddrVector &devices) = 0;
+ virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role) = 0;
virtual status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
device_role_t role,
@@ -492,9 +497,6 @@
virtual status_t setStreamVolume(audio_stream_type_t stream, float volume,
audio_io_handle_t output, int delayMs = 0) = 0;
- // invalidate a stream type, causing a reroute to an unspecified new output
- virtual status_t invalidateStream(audio_stream_type_t stream) = 0;
-
// function enabling to send proprietary informations directly from audio policy manager to
// audio hardware interface.
virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs,
@@ -564,6 +566,8 @@
const TrackSecondaryOutputsMap& trackSecondaryOutputs) = 0;
virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+
+ virtual status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) = 0;
};
// These are the signatures of createAudioPolicyManager/destroyAudioPolicyManager
diff --git a/services/audiopolicy/TEST_MAPPING b/services/audiopolicy/TEST_MAPPING
index 4d43eb0..2612393 100644
--- a/services/audiopolicy/TEST_MAPPING
+++ b/services/audiopolicy/TEST_MAPPING
@@ -31,5 +31,10 @@
}
]
}
+ ],
+ "auto-presubmit": [
+ {
+ "name": "audiopolicy_tests"
+ }
]
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index c513098..52a000f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -442,6 +442,8 @@
bool isConfigurationMatched(const audio_config_base_t& config, audio_output_flags_t flags);
+ PortHandleVector getClientsForStream(audio_stream_type_t streamType) const;
+
const sp<IOProfile> mProfile; // I/O profile this output derives from
audio_io_handle_t mIoHandle; // output handle
uint32_t mLatency; //
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 54a143c..92292e1 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -62,11 +62,24 @@
void closeOutput(sp<SwAudioOutputDescriptor> &desc);
/**
- * Try to find an output descriptor for the given attributes.
+ * Tries to find the best matching audio policy mix
*
- * @param[in] attributes to consider fowr the research of output descriptor.
- * @param[out] desc to return if an primary output could be found.
- * @param[out] secondaryDesc other desc that the audio should be routed to.
+ * @param[in] attributes to consider for the research of the audio policy mix.
+ * @param[in] config to consider for the research of the audio policy mix.
+ * @param[in] uid to consider for the research of the audio policy mix.
+ * @param[in] session to consider for the research of the audio policy mix.
+ * @param[in] flags to consider for the research of the audio policy mix.
+ * @param[in] availableOutputDevices available output devices can be use during the research
+ * of the audio policy mix
+ * @param[in] requestedDevice currently requested device that can be used determined if the
+ * matching audio policy mix should be used instead of the currently set preferred device.
+ * @param[out] primaryMix to return in case a matching audio plicy mix could be found.
+ * @param[out] secondaryMixes that audio should be routed to in case a matching
+ * secondary mixes could be found.
+ * @param[out] usePrimaryOutputFromPolicyMixes to return in case the audio policy mix
+ * should be use, including the case where the requested device is explicitly disallowed
+ * by the audio policy.
+ *
* @return OK if the request is valid
* otherwise if the request is not supported
*/
@@ -75,8 +88,11 @@
uid_t uid,
audio_session_t session,
audio_output_flags_t flags,
+ const DeviceVector &availableOutputDevices,
+ const sp<DeviceDescriptor>& requestedDevice,
sp<AudioPolicyMix> &primaryMix,
- std::vector<sp<AudioPolicyMix>> *secondaryMixes);
+ std::vector<sp<AudioPolicyMix>> *secondaryMixes,
+ bool& usePrimaryOutputFromPolicyMixes);
sp<DeviceDescriptor> getDeviceAndMixForInputSource(const audio_attributes_t& attributes,
const DeviceVector &availableDeviceTypes,
@@ -132,6 +148,13 @@
const audio_config_base_t& config,
uid_t uid,
audio_session_t session);
+ bool mixDisallowsRequestedDevice(const AudioMix* mix,
+ const sp<DeviceDescriptor>& requestedDevice,
+ const sp<DeviceDescriptor>& mixDevice,
+ const uid_t uid);
+
+ sp<DeviceDescriptor> getOutputDeviceForMix(const AudioMix* mix,
+ const DeviceVector& availableOutputDevices);
};
std::optional<std::string> extractAddressFromAudioAttributes(const audio_attributes_t& attr);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index c7296e9..a46186b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -947,6 +947,17 @@
&& mFormat == config.format;
}
+PortHandleVector SwAudioOutputDescriptor::getClientsForStream(
+ audio_stream_type_t streamType) const {
+ PortHandleVector clientsForStream;
+ for (const auto& client : getClientIterable()) {
+ if (client->stream() == streamType) {
+ clientsForStream.push_back(client->portId());
+ }
+ }
+ return clientsForStream;
+}
+
void SwAudioOutputCollection::dump(String8 *dst) const
{
dst->appendFormat("\n Outputs (%zu):\n", size());
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 003dcaf..ba5a6a7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "APM_AudioPolicyMix"
-//#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <algorithm>
#include <iterator>
@@ -259,14 +259,25 @@
const audio_attributes_t& attributes, const audio_config_base_t& config, const uid_t uid,
const audio_session_t session,
audio_output_flags_t flags,
+ const DeviceVector &availableOutputDevices,
+ const sp<DeviceDescriptor>& requestedDevice,
sp<AudioPolicyMix> &primaryMix,
- std::vector<sp<AudioPolicyMix>> *secondaryMixes)
+ std::vector<sp<AudioPolicyMix>> *secondaryMixes,
+ bool& usePrimaryOutputFromPolicyMixes)
{
ALOGV("getOutputForAttr() querying %zu mixes:", size());
primaryMix.clear();
+ bool mixesDisallowsRequestedDevice = false;
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = itemAt(i);
const bool primaryOutputMix = !is_mix_loopback_render(policyMix->mRouteFlags);
+ sp<DeviceDescriptor> mixDevice = getOutputDeviceForMix(policyMix.get(),
+ availableOutputDevices);
+ if (mixDisallowsRequestedDevice(policyMix.get(), requestedDevice, mixDevice, uid)) {
+ ALOGV("%s: Mix %zu: does not allows device", __func__, i);
+ mixesDisallowsRequestedDevice = true;
+ }
+
if (!primaryOutputMix && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) {
// AAudio does not support MMAP_NO_IRQ loopback render, and there is no way with
// the current MmapStreamInterface::start to reject a specific client added to a shared
@@ -288,6 +299,11 @@
continue; // skip the mix
}
+ if (mixDevice != nullptr && mixDevice->equals(requestedDevice)) {
+ ALOGV("%s: Mix %zu: requested device mathches", __func__, i);
+ mixesDisallowsRequestedDevice = false;
+ }
+
if (primaryOutputMix) {
primaryMix = policyMix;
ALOGV("%s: Mix %zu: set primary desc", __func__, i);
@@ -298,9 +314,36 @@
}
}
}
+
+ // Explicit routing is higher priority than dynamic policy primary output, but policy may
+ // explicitly deny it
+ usePrimaryOutputFromPolicyMixes =
+ (mixesDisallowsRequestedDevice || requestedDevice == nullptr) && primaryMix != nullptr;
+
return NO_ERROR;
}
+sp<DeviceDescriptor> AudioPolicyMixCollection::getOutputDeviceForMix(const AudioMix* mix,
+ const DeviceVector& availableOutputDevices) {
+ ALOGV("%s: device (0x%x, addr=%s) forced by mix", __func__, mix->mDeviceType,
+ mix->mDeviceAddress.c_str());
+ return availableOutputDevices.getDevice(mix->mDeviceType, mix->mDeviceAddress,
+ AUDIO_FORMAT_DEFAULT);
+}
+
+bool AudioPolicyMixCollection::mixDisallowsRequestedDevice(const AudioMix* mix,
+ const sp<DeviceDescriptor>& requestedDevice,
+ const sp<DeviceDescriptor>& mixDevice,
+ const uid_t uid) {
+ if (requestedDevice == nullptr || mixDevice == nullptr) {
+ return false;
+ }
+
+ return is_mix_disallows_preferred_device(mix->mRouteFlags)
+ && requestedDevice->equals(mixDevice)
+ && mix->hasUserIdRule(false /* match */, multiuser_get_user_id(uid));
+}
+
bool AudioPolicyMixCollection::mixMatch(const AudioMix* mix, size_t mixIndex,
const audio_attributes_t& attributes, const audio_config_base_t& config,
uid_t uid, audio_session_t session) {
@@ -361,11 +404,7 @@
for (size_t i = 0; i < size(); i++) {
if (itemAt(i)->getOutput() == output) {
// This Desc is involved in a Mix, which has the highest prio
- audio_devices_t deviceType = itemAt(i)->mDeviceType;
- String8 address = itemAt(i)->mDeviceAddress;
- ALOGV("%s: device (0x%x, addr=%s) forced by mix",
- __FUNCTION__, deviceType, address.c_str());
- return availableOutputDevices.getDevice(deviceType, address, AUDIO_FORMAT_DEFAULT);
+ return getOutputDeviceForMix(itemAt(i).get(), availableOutputDevices);
}
}
return nullptr;
@@ -568,13 +607,14 @@
break;
}
}
- if (!deviceMatch && !mix->hasMatchUserIdRule()) {
+ if (!deviceMatch && !mix->hasUserIdRule(true /*match*/)) {
// this mix doesn't go to one of the listed devices for the given userId,
// and it's not already restricting the mix on a userId,
// modify its rules to exclude the userId
- if (!mix->hasUserIdRule(false /*match*/, userId)) {
+ if (!mix->hasUserIdRule(false /* match */, userId)) {
// no need to do it again if userId is already excluded
mix->setExcludeUserId(userId);
+ mix->mRouteFlags = mix->mRouteFlags | MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
}
}
}
@@ -595,6 +635,10 @@
EraseCriteriaIf(mix->mCriteria, [userId](const AudioMixMatchCriterion& c) {
return c.mRule == RULE_EXCLUDE_USERID && c.mValue.mUserId == userId;
});
+
+ if (!mix->hasUserIdRule(false /* match */)) {
+ mix->mRouteFlags = mix->mRouteFlags & ~MIX_ROUTE_FLAG_DISALLOWS_PREFERRED_DEVICE;
+ }
}
return NO_ERROR;
}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index 7d21ae0..8cfa592 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -105,7 +105,10 @@
status_t setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
const AudioDeviceTypeAddrVector &devices) override;
- status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) override;
+ status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+ const AudioDeviceTypeAddrVector &devices) override;
+
+ status_t clearDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) override;
status_t getDevicesForRoleAndStrategy(product_strategy_t strategy, device_role_t role,
AudioDeviceTypeAddrVector &devices) const override;
diff --git a/services/audiopolicy/engine/common/include/VolumeGroup.h b/services/audiopolicy/engine/common/include/VolumeGroup.h
index 5378f64..f40ab1c 100644
--- a/services/audiopolicy/engine/common/include/VolumeGroup.h
+++ b/services/audiopolicy/engine/common/include/VolumeGroup.h
@@ -39,7 +39,7 @@
VolumeCurves *getVolumeCurves() { return &mGroupVolumeCurves; }
void addSupportedAttributes(const audio_attributes_t &attr);
- AttributesVector getSupportedAttributes() const { return mGroupVolumeCurves.getAttributes(); }
+ AttributesVector getSupportedAttributes() const;
void addSupportedStream(audio_stream_type_t stream);
StreamTypeVector getStreamTypes() const { return mGroupVolumeCurves.getStreamTypes(); }
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index 9b78758..8015ae0 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -369,13 +369,11 @@
}
switch (role) {
- case DEVICE_ROLE_PREFERRED:
- case DEVICE_ROLE_DISABLED: {
+ case DEVICE_ROLE_PREFERRED: {
tDevicesRoleMap[std::make_pair(t, role)] = devices;
// The preferred devices and disabled devices are mutually exclusive. Once a device is added
// the a list, it must be removed from the other one.
- const device_role_t roleToRemove = role == DEVICE_ROLE_PREFERRED ? DEVICE_ROLE_DISABLED
- : DEVICE_ROLE_PREFERRED;
+ const device_role_t roleToRemove = DEVICE_ROLE_DISABLED;
auto it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
if (it != tDevicesRoleMap.end()) {
it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
@@ -384,6 +382,25 @@
}
}
} break;
+ case DEVICE_ROLE_DISABLED: {
+ auto it = tDevicesRoleMap.find(std::make_pair(t, role));
+ if (it != tDevicesRoleMap.end()) {
+ it->second = joinDeviceTypeAddrs(it->second, devices);
+ } else {
+ tDevicesRoleMap[std::make_pair(t, role)] = devices;
+ }
+
+ // The preferred devices and disabled devices are mutually exclusive. Once a device is added
+ // the a list, it must be removed from the other one.
+ const device_role_t roleToRemove = DEVICE_ROLE_PREFERRED;
+ it = tDevicesRoleMap.find(std::make_pair(t, roleToRemove));
+ if (it != tDevicesRoleMap.end()) {
+ it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
+ if (it->second.empty()) {
+ tDevicesRoleMap.erase(it);
+ }
+ }
+ } break;
case DEVICE_ROLE_NONE:
// Intentionally fall-through as it is no need to set device role as none for a strategy.
default:
@@ -394,6 +411,36 @@
}
template <typename T>
+status_t removeDevicesRoleForT(
+ std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
+ T t, device_role_t role, const AudioDeviceTypeAddrVector &devices,
+ const std::string& logStr, std::function<bool(T)> p) {
+ if (!p(t)) {
+ ALOGE("%s invalid %s %u", __func__, logStr.c_str(), t);
+ return BAD_VALUE;
+ }
+
+ switch (role) {
+ case DEVICE_ROLE_PREFERRED:
+ case DEVICE_ROLE_DISABLED: {
+ auto it = tDevicesRoleMap.find(std::make_pair(t, role));
+ if (it != tDevicesRoleMap.end()) {
+ it->second = excludeDeviceTypeAddrsFrom(it->second, devices);
+ if (it->second.empty()) {
+ tDevicesRoleMap.erase(it);
+ }
+ }
+ } break;
+ case DEVICE_ROLE_NONE:
+ // Intentionally fall-through as it is not needed to set device role as none for a strategy.
+ default:
+ ALOGE("%s invalid role %d", __func__, role);
+ return BAD_VALUE;
+ }
+ return NO_ERROR;
+}
+
+template <typename T>
status_t removeAllDevicesRoleForT(
std::map<std::pair<T, device_role_t>, AudioDeviceTypeAddrVector>& tDevicesRoleMap,
T t, device_role_t role, const std::string& logStr, std::function<bool(T)> p) {
@@ -462,7 +509,18 @@
mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
}
-status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role)
+status_t EngineBase::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+ const AudioDeviceTypeAddrVector &devices)
+{
+ std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
+ return mProductStrategies.find(strategy) != mProductStrategies.end();
+ };
+ return removeDevicesRoleForT(
+ mProductStrategyDeviceRoleMap, strategy, role, devices, "strategy" /*logStr*/, p);
+}
+
+status_t EngineBase::clearDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role)
{
std::function<bool(product_strategy_t)> p = [this](product_strategy_t strategy) {
return mProductStrategies.find(strategy) != mProductStrategies.end();
diff --git a/services/audiopolicy/engine/common/src/VolumeGroup.cpp b/services/audiopolicy/engine/common/src/VolumeGroup.cpp
index e189807..f5ffbba 100644
--- a/services/audiopolicy/engine/common/src/VolumeGroup.cpp
+++ b/services/audiopolicy/engine/common/src/VolumeGroup.cpp
@@ -37,6 +37,17 @@
{
}
+// Used for introspection, e.g. JAVA
+AttributesVector VolumeGroup::getSupportedAttributes() const
+{
+ AttributesVector supportedAttributes = {};
+ for (auto &aa : mGroupVolumeCurves.getAttributes()) {
+ aa.source = AUDIO_SOURCE_INVALID;
+ supportedAttributes.push_back(aa);
+ }
+ return supportedAttributes;
+}
+
void VolumeGroup::dump(String8 *dst, int spaces) const
{
dst->appendFormat("\n%*s-%s (id: %d)\n", spaces, "", mName.c_str(), mId);
diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h
index 70d25fc..b8e35ed 100644
--- a/services/audiopolicy/engine/interface/EngineInterface.h
+++ b/services/audiopolicy/engine/interface/EngineInterface.h
@@ -326,10 +326,22 @@
* for the given strategy
* @param strategy the audio strategy whose routing will be affected
* @param role the role of the devices for strategy
+ * @param devices the audio devices to be removed
* @return BAD_VALUE if the strategy or role is invalid,
* or NO_ERROR if the devices for this role was removed
*/
- virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
+ virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
+ const AudioDeviceTypeAddrVector &devices) = 0;
+
+ /**
+ * @brief clearDevicesRoleForStrategy removes the role of all devices previously set
+ * for the given strategy
+ * @param strategy the audio strategy whose routing will be affected
+ * @param role the role of the devices for strategy
+ * @return BAD_VALUE if the strategy or role is invalid,
+ * or NO_ERROR if the devices for this role was removed
+ */
+ virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
device_role_t role) = 0;
/**
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index d96ae21..f2df7ac 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -299,7 +299,9 @@
if ((strategy == STRATEGY_SONIFICATION) ||
(getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) {
- devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER);
+ // favor dock over speaker when available
+ devices = availableOutputDevices.getFirstDevicesFromTypes({
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_SPEAKER});
}
// if SCO headset is connected and we are told to use it, play ringtone over
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 092319c..f4a3a94 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -34,6 +34,7 @@
#include <map>
#include <math.h>
#include <set>
+#include <type_traits>
#include <unordered_set>
#include <vector>
@@ -68,16 +69,6 @@
// media / notification / system volume.
constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
-// Compressed formats for MSD module, ordered from most preferred to least preferred.
-static const std::vector<audio_format_t> msdCompressedFormatsOrder = {{
- AUDIO_FORMAT_IEC60958, AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
- AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
-// Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
-static const std::vector<audio_channel_mask_t> msdSurroundChannelMasksOrder = {{
- AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
- AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
- AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
-
template <typename T>
bool operator== (const SortedVector<T> &left, const SortedVector<T> &right)
{
@@ -114,7 +105,7 @@
const char* device_address,
const char* device_name,
audio_format_t encodedFormat) {
- media::AudioPort aidlPort;
+ media::AudioPortFw aidlPort;
if (status_t status = deviceToAudioPort(device, device_address, device_name, &aidlPort);
status == OK) {
return setDeviceConnectionState(state, aidlPort.hal, encodedFormat);
@@ -172,7 +163,7 @@
const char* device_address,
const char* device_name,
audio_format_t encodedFormat) {
- media::AudioPort aidlPort;
+ media::AudioPortFw aidlPort;
if (status_t status = deviceToAudioPort(deviceType, device_address, device_name, &aidlPort);
status == OK) {
return setDeviceConnectionStateInt(state, aidlPort.hal, encodedFormat);
@@ -460,7 +451,7 @@
status_t AudioPolicyManager::deviceToAudioPort(audio_devices_t device, const char* device_address,
const char* device_name,
- media::AudioPort* aidlPort) {
+ media::AudioPortFw* aidlPort) {
DeviceDescriptorBase devDescr(device, device_address);
devDescr.setName(device_name);
return devDescr.writeToParcelable(aidlPort);
@@ -830,7 +821,7 @@
if (isStateInCall(oldState)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
// force reevaluating accessibility routing when call stops
- mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
+ invalidateStreams({AUDIO_STREAM_ACCESSIBILITY});
}
/**
@@ -913,7 +904,7 @@
if (isStateInCall(state)) {
ALOGV("setPhoneState() in call state management: new state is %d", state);
// force reevaluating accessibility routing when call starts
- mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
+ invalidateStreams({AUDIO_STREAM_ACCESSIBILITY});
}
// Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
@@ -946,8 +937,7 @@
// force client reconnection to reevaluate flag AUDIO_FLAG_AUDIBILITY_ENFORCED
if (usage == AUDIO_POLICY_FORCE_FOR_SYSTEM) {
- mpClientInterface->invalidateStream(AUDIO_STREAM_SYSTEM);
- mpClientInterface->invalidateStream(AUDIO_STREAM_ENFORCED_AUDIBLE);
+ invalidateStreams({AUDIO_STREAM_SYSTEM, AUDIO_STREAM_ENFORCED_AUDIBLE});
}
//FIXME: workaround for truncated touch sounds
@@ -1178,6 +1168,8 @@
ALOGV("%s() attributes=%s stream=%s session %d selectedDeviceId %d", __func__,
toString(*resultAttr).c_str(), toString(*stream).c_str(), session, requestedPortId);
+ bool usePrimaryOutputFromPolicyMixes = false;
+
// The primary output is the explicit routing (eg. setPreferredDevice) if specified,
// otherwise, fallback to the dynamic policies, if none match, query the engine.
// Secondary outputs are always found by dynamic policies as the engine do not support them
@@ -1187,14 +1179,12 @@
.format = config->format,
};
status = mPolicyMixes.getOutputForAttr(*resultAttr, clientConfig, uid, session, *flags,
- primaryMix, secondaryMixes);
+ mAvailableOutputDevices, requestedDevice, primaryMix,
+ secondaryMixes, usePrimaryOutputFromPolicyMixes);
if (status != OK) {
return status;
}
- // Explicit routing is higher priority then any dynamic policy primary output
- bool usePrimaryOutputFromPolicyMixes = requestedDevice == nullptr && primaryMix != nullptr;
-
// FIXME: in case of RENDER policy, the output capabilities should be checked
if ((secondaryMixes != nullptr && !secondaryMixes->empty())
&& !audio_is_linear_pcm(config->format)) {
@@ -1291,17 +1281,26 @@
info = getPreferredMixerAttributesInfo(
outputDevices.itemAt(0)->getId(),
mEngine->getProductStrategyForAttributes(*resultAttr));
- if (info != nullptr && info->getUid() != uid && info->getActiveClientCount() == 0) {
- // Only use preferred mixer when the requested uid matched or
- // there is active client on preferred mixer.
+ // Only use preferred mixer if the uid matches or the preferred mixer is bit-perfect
+ // and it is currently active.
+ if (info != nullptr && info->getUid() != uid &&
+ ((info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) == AUDIO_OUTPUT_FLAG_NONE ||
+ info->getActiveClientCount() == 0)) {
info = nullptr;
}
}
*output = getOutputForDevices(outputDevices, session, resultAttr, config,
flags, isSpatialized, info, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
+ // The client will be active if the client is currently preferred mixer owner and the
+ // requested configuration matches the preferred mixer configuration.
*isBitPerfect = (info != nullptr
&& (info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE
- && *output != AUDIO_IO_HANDLE_NONE);
+ && info->getUid() == uid
+ && *output != AUDIO_IO_HANDLE_NONE
+ // When bit-perfect output is selected for the preferred mixer attributes owner,
+ // only need to consider the config matches.
+ && mOutputs.valueFor(*output)->isConfigurationMatched(
+ clientConfig, AUDIO_OUTPUT_FLAG_NONE));
}
if (*output == AUDIO_IO_HANDLE_NONE) {
AudioProfileVector profiles;
@@ -1712,10 +1711,28 @@
const AudioProfileVector &sourceProfiles, const AudioProfileVector &sinkProfiles,
audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
{
+ // Compressed formats for MSD module, ordered from most preferred to least preferred.
+ static const std::vector<audio_format_t> formatsOrder = {{
+ AUDIO_FORMAT_IEC60958, AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
+ AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
+ static const std::vector<audio_channel_mask_t> channelMasksOrder = [](){
+ // Channel position masks for MSD module, 3D > 2D > 1D ordering (most preferred to least
+ // preferred).
+ std::vector<audio_channel_mask_t> masks = {{
+ AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
+ AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
+ // insert index masks (higher counts most preferred) as preferred over position masks
+ for (int i = 1; i <= AUDIO_CHANNEL_COUNT_MAX; i++) {
+ masks.insert(
+ masks.begin(), audio_channel_mask_for_index_assignment_from_count(i));
+ }
+ return masks;
+ }();
+
struct audio_config_base bestSinkConfig;
- status_t result = findBestMatchingOutputConfig(sourceProfiles, sinkProfiles,
- msdCompressedFormatsOrder, msdSurroundChannelMasksOrder,
- true /*preferHigherSamplingRates*/, bestSinkConfig);
+ status_t result = findBestMatchingOutputConfig(sourceProfiles, sinkProfiles, formatsOrder,
+ channelMasksOrder, true /*preferHigherSamplingRates*/, bestSinkConfig);
if (result != NO_ERROR) {
ALOGD("%s() no matching config found for sink, hwAvSync: %d",
__func__, hwAvSync);
@@ -1737,7 +1754,10 @@
}
sourceConfig->sample_rate = bestSinkConfig.sample_rate;
// Specify exact channel mask to prevent guessing by bit count in PatchPanel.
- sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
+ sourceConfig->channel_mask =
+ audio_channel_mask_get_representation(bestSinkConfig.channel_mask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX ?
+ bestSinkConfig.channel_mask : audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
sourceConfig->format = bestSinkConfig.format;
// Copy input stream directly without any processing (e.g. resampling).
sourceConfig->flags.input = static_cast<audio_input_flags_t>(
@@ -2287,7 +2307,7 @@
// force reevaluating accessibility routing when ringtone or alarm starts
if (followsSameRouting(clientAttr, attributes_initializer(AUDIO_USAGE_ALARM))) {
- mpClientInterface->invalidateStream(AUDIO_STREAM_ACCESSIBILITY);
+ invalidateStreams({AUDIO_STREAM_ACCESSIBILITY});
}
if (waitMs > muteWaitMs) {
@@ -3856,14 +3876,48 @@
}
}
-status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy,
- device_role_t role)
+status_t
+AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role,
+ const AudioDeviceTypeAddrVector &devices) {
+ ALOGV("%s() strategy=%d role=%d %s", __func__, strategy, role,
+ dumpAudioDeviceTypeAddrVector(devices).c_str());
+
+ if (!areAllDevicesSupported(devices, audio_is_output_device, __func__)) {
+ return BAD_VALUE;
+ }
+ status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role, devices);
+ if (status != NO_ERROR) {
+ ALOGW("Engine could not remove devices %s for strategy %d role %d",
+ dumpAudioDeviceTypeAddrVector(devices).c_str(), strategy, role);
+ return status;
+ }
+
+ checkForDeviceAndOutputChanges();
+
+ bool forceVolumeReeval = false;
+ // TODO(b/263479999): workaround for truncated touch sounds
+ // to be removed when the problem is handled by system UI
+ uint32_t delayMs = 0;
+ if (strategy == mCommunnicationStrategy) {
+ forceVolumeReeval = true;
+ delayMs = TOUCH_SOUND_FIXED_DELAY_MS;
+ updateInputRouting();
+ }
+ updateCallAndOutputRouting(forceVolumeReeval, delayMs);
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::clearDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role)
{
ALOGV("%s() strategy=%d role=%d", __func__, strategy, role);
- status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role);
+ status_t status = mEngine->clearDevicesRoleForStrategy(strategy, role);
if (status != NO_ERROR) {
- ALOGV("Engine could not remove preferred device for strategy %d status %d",
+ ALOGW_IF(status != NAME_NOT_FOUND,
+ "Engine could not remove device role for strategy %d status %d",
strategy, status);
return status;
}
@@ -3935,10 +3989,11 @@
status_t status = mEngine->removeDevicesRoleForCapturePreset(
audioSource, role, devices);
- ALOGW_IF(status != NO_ERROR,
+ ALOGW_IF(status != NO_ERROR && status != NAME_NOT_FOUND,
"Engine could not remove devices role (%d) for capture preset %d", role, audioSource);
-
- updateInputRouting();
+ if (status == NO_ERROR) {
+ updateInputRouting();
+ }
return status;
}
@@ -3947,10 +4002,11 @@
ALOGV("%s() audioSource=%d role=%d", __func__, audioSource, role);
status_t status = mEngine->clearDevicesRoleForCapturePreset(audioSource, role);
- ALOGW_IF(status != NO_ERROR,
+ ALOGW_IF(status != NO_ERROR && status != NAME_NOT_FOUND,
"Engine could not clear devices role (%d) for capture preset %d", role, audioSource);
-
- updateInputRouting();
+ if (status == NO_ERROR) {
+ updateInputRouting();
+ }
return status;
}
@@ -5172,9 +5228,7 @@
// invalidate all tracks in this strategy to force re connection.
// Otherwise select new device on the output mix.
if (outputs.indexOf(mOutputs.keyAt(j)) < 0) {
- for (auto stream : mEngine->getStreamTypesForProductStrategy(ps)) {
- mpClientInterface->invalidateStream(stream);
- }
+ invalidateStreams(mEngine->getStreamTypesForProductStrategy(ps));
} else {
DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/);
if (outputDesc->mUsePreferredMixerAttributes && outputDesc->devices() != newDevices) {
@@ -5636,6 +5690,21 @@
return false;
}
+bool AudioPolicyManager::isHotwordStreamSupported(bool lookbackAudio)
+{
+ const auto mask = AUDIO_INPUT_FLAG_HOTWORD_TAP |
+ (lookbackAudio ? AUDIO_INPUT_FLAG_HW_LOOKBACK : 0);
+ for (const auto& hwModule : mHwModules) {
+ const InputProfileCollection &inputProfiles = hwModule->getInputProfiles();
+ for (const auto &inputProfile : inputProfiles) {
+ if ((inputProfile->getFlags() & mask) == mask) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
bool AudioPolicyManager::isCallScreenModeSupported()
{
return getConfig().isCallScreenModeSupported();
@@ -5742,9 +5811,7 @@
}
}
- for (audio_stream_type_t stream : streamsToInvalidate) {
- mpClientInterface->invalidateStream(stream);
- }
+ invalidateStreams(StreamTypeVector(streamsToInvalidate.begin(), streamsToInvalidate.end()));
}
@@ -5937,6 +6004,17 @@
return status;
}
+ // If microphones address is empty, set it according to device type
+ for (size_t i = 0; i < mInputDevicesAll.size(); i++) {
+ if (mInputDevicesAll[i]->address().empty()) {
+ if (mInputDevicesAll[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ mInputDevicesAll[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
+ } else if (mInputDevicesAll[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
+ mInputDevicesAll[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
+ }
+ }
+ }
+
mEngine->updateDeviceSelectionCache();
mCommunnicationStrategy = mEngine->getProductStrategyForAttributes(
mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL));
@@ -5951,17 +6029,6 @@
mDefaultOutputDevice->toString().c_str());
status = NO_INIT;
}
- // If microphones address is empty, set it according to device type
- for (size_t i = 0; i < mAvailableInputDevices.size(); i++) {
- if (mAvailableInputDevices[i]->address().empty()) {
- if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
- mAvailableInputDevices[i]->setAddress(AUDIO_BOTTOM_MICROPHONE_ADDRESS);
- } else if (mAvailableInputDevices[i]->type() == AUDIO_DEVICE_IN_BACK_MIC) {
- mAvailableInputDevices[i]->setAddress(AUDIO_BACK_MICROPHONE_ADDRESS);
- }
- }
- }
-
ALOGW_IF(mPrimaryOutput == nullptr, "The policy configuration does not declare a primary output");
// Silence ALOGV statements
@@ -6666,6 +6733,7 @@
SortedVector<audio_io_handle_t> dstOutputs = getOutputsForDevices(newDevices, mOutputs);
uint32_t maxLatency = 0;
+ bool unneededUsePrimaryOutputFromPolicyMixes = false;
std::vector<sp<SwAudioOutputDescriptor>> invalidatedOutputs;
// take into account dynamic audio policies related changes: if a client is now associated
// to a different policy mix than at creation time, invalidate corresponding stream
@@ -6680,7 +6748,9 @@
}
sp<AudioPolicyMix> primaryMix;
status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
- client->uid(), client->session(), client->flags(), primaryMix, nullptr);
+ client->uid(), client->session(), client->flags(), mAvailableOutputDevices,
+ nullptr /* requestedDevice */, primaryMix, nullptr /* secondaryMixes */,
+ unneededUsePrimaryOutputFromPolicyMixes);
if (status != OK) {
continue;
}
@@ -6758,9 +6828,7 @@
}
// Move tracks associated to this stream (and linked) from previous output to new output
if (!invalidatedOutputs.empty()) {
- for (auto stream : mEngine->getStreamTypesForProductStrategy(psId)) {
- mpClientInterface->invalidateStream(stream);
- }
+ invalidateStreams(mEngine->getStreamTypesForProductStrategy(psId));
for (sp<SwAudioOutputDescriptor> desc : invalidatedOutputs) {
desc->setTracksInvalidatedStatusByStrategy(psId);
}
@@ -6778,15 +6846,18 @@
}
void AudioPolicyManager::checkSecondaryOutputs() {
- std::set<audio_stream_type_t> streamsToInvalidate;
+ PortHandleVector clientsToInvalidate;
TrackSecondaryOutputsMap trackSecondaryOutputs;
+ bool unneededUsePrimaryOutputFromPolicyMixes = false;
for (size_t i = 0; i < mOutputs.size(); i++) {
const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
sp<AudioPolicyMix> primaryMix;
std::vector<sp<AudioPolicyMix>> secondaryMixes;
status_t status = mPolicyMixes.getOutputForAttr(client->attributes(), client->config(),
- client->uid(), client->session(), client->flags(), primaryMix, &secondaryMixes);
+ client->uid(), client->session(), client->flags(), mAvailableOutputDevices,
+ nullptr /* requestedDevice */, primaryMix, &secondaryMixes,
+ unneededUsePrimaryOutputFromPolicyMixes);
std::vector<sp<SwAudioOutputDescriptor>> secondaryDescs;
for (auto &secondaryMix : secondaryMixes) {
sp<SwAudioOutputDescriptor> outputDesc = secondaryMix->getOutput();
@@ -6796,8 +6867,11 @@
}
}
- if (status != OK) {
- streamsToInvalidate.insert(client->stream());
+ if (status != OK &&
+ (client->flags() & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == AUDIO_OUTPUT_FLAG_NONE) {
+ // When it failed to query secondary output, only invalidate the client that is not
+ // MMAP. The reason is that MMAP stream will not support secondary output.
+ clientsToInvalidate.push_back(client->portId());
} else if (!std::equal(
client->getSecondaryOutputs().begin(),
client->getSecondaryOutputs().end(),
@@ -6805,7 +6879,7 @@
if (!audio_is_linear_pcm(client->config().format)) {
// If the format is not PCM, the tracks should be invalidated to get correct
// behavior when the secondary output is changed.
- streamsToInvalidate.insert(client->stream());
+ clientsToInvalidate.push_back(client->portId());
} else {
std::vector<wp<SwAudioOutputDescriptor>> weakSecondaryDescs;
std::vector<audio_io_handle_t> secondaryOutputIds;
@@ -6822,9 +6896,9 @@
if (!trackSecondaryOutputs.empty()) {
mpClientInterface->updateSecondaryOutputs(trackSecondaryOutputs);
}
- for (audio_stream_type_t stream : streamsToInvalidate) {
- ALOGD("%s Invalidate stream %d due to fail getting output for attr", __func__, stream);
- mpClientInterface->invalidateStream(stream);
+ if (!clientsToInvalidate.empty()) {
+ ALOGD("%s Invalidate clients due to fail getting output for attr", __func__);
+ mpClientInterface->invalidateTracks(clientsToInvalidate);
}
}
@@ -7390,8 +7464,11 @@
// TODO: perhaps isCompatibleProfile should return a "matching" score so we can return
// the best matching profile, not the first one.
- const audio_input_flags_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ;
- const audio_input_flags_t oriFlags = flags;
+ using underlying_input_flag_t = std::underlying_type_t<audio_input_flags_t>;
+ const underlying_input_flag_t mustMatchFlag = AUDIO_INPUT_FLAG_MMAP_NOIRQ |
+ AUDIO_INPUT_FLAG_HOTWORD_TAP | AUDIO_INPUT_FLAG_HW_LOOKBACK;
+
+ const underlying_input_flag_t oriFlags = flags;
for (;;) {
sp<IOProfile> firstInexact = nullptr;
@@ -8214,9 +8291,11 @@
// check dynamic policies but only for primary descriptors (secondary not used for audible
// audio routing, only used for duplication for playback capture)
sp<AudioPolicyMix> policyMix;
+ bool unneededUsePrimaryOutputFromPolicyMixes = false;
status_t status = mPolicyMixes.getOutputForAttr(attr, AUDIO_CONFIG_BASE_INITIALIZER,
- 0 /*uid unknown here*/, AUDIO_SESSION_NONE, AUDIO_OUTPUT_FLAG_NONE, policyMix,
- nullptr /* secondaryMixes */);
+ 0 /*uid unknown here*/, AUDIO_SESSION_NONE, AUDIO_OUTPUT_FLAG_NONE,
+ mAvailableOutputDevices, nullptr /* requestedDevice */, policyMix,
+ nullptr /* secondaryMixes */, unneededUsePrimaryOutputFromPolicyMixes);
if (status != OK) {
return status;
}
@@ -8321,4 +8400,23 @@
}
}
+PortHandleVector AudioPolicyManager::getClientsForStream(
+ audio_stream_type_t streamType) const {
+ PortHandleVector clients;
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ PortHandleVector clientsForStream = mOutputs.valueAt(i)->getClientsForStream(streamType);
+ clients.insert(clients.end(), clientsForStream.begin(), clientsForStream.end());
+ }
+ return clients;
+}
+
+void AudioPolicyManager::invalidateStreams(StreamTypeVector streams) const {
+ PortHandleVector clients;
+ for (auto stream : streams) {
+ PortHandleVector clientsForStream = getClientsForStream(stream);
+ clients.insert(clients.end(), clientsForStream.begin(), clientsForStream.end());
+ }
+ mpClientInterface->invalidateTracks(clients);
+}
+
} // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 1ada3cc..3bbcf69 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -299,8 +299,11 @@
const AudioDeviceTypeAddrVector &devices);
virtual status_t removeDevicesRoleForStrategy(product_strategy_t strategy,
- device_role_t role);
+ device_role_t role,
+ const AudioDeviceTypeAddrVector &devices);
+ virtual status_t clearDevicesRoleForStrategy(product_strategy_t strategy,
+ device_role_t role);
virtual status_t getDevicesForRoleAndStrategy(product_strategy_t strategy,
device_role_t role,
@@ -352,6 +355,8 @@
virtual bool isUltrasoundSupported();
+ bool isHotwordStreamSupported(bool lookbackAudio) override;
+
virtual status_t listAudioProductStrategies(AudioProductStrategyVector &strategies)
{
return mEngine->listAudioProductStrategies(strategies);
@@ -1035,7 +1040,7 @@
// Called by setDeviceConnectionState()
status_t deviceToAudioPort(audio_devices_t deviceType, const char* device_address,
- const char* device_name, media::AudioPort* aidPort);
+ const char* device_name, media::AudioPortFw* aidPort);
bool isMsdPatch(const audio_patch_handle_t &handle) const;
private:
@@ -1305,6 +1310,7 @@
sp<PreferredMixerAttributesInfo> getPreferredMixerAttributesInfo(
audio_port_handle_t devicePortId, product_strategy_t strategy);
+
sp<SwAudioOutputDescriptor> reopenOutput(
sp<SwAudioOutputDescriptor> outputDesc,
const audio_config_t *config,
@@ -1313,6 +1319,9 @@
void reopenOutputsWithDevices(
const std::map<audio_io_handle_t, DeviceVector>& outputsToReopen);
+
+ PortHandleVector getClientsForStream(audio_stream_type_t streamType) const;
+ void invalidateStreams(StreamTypeVector streams) const;
};
};
diff --git a/services/audiopolicy/service/Android.bp b/services/audiopolicy/service/Android.bp
index 4c19d40..10403fa 100644
--- a/services/audiopolicy/service/Android.bp
+++ b/services/audiopolicy/service/Android.bp
@@ -36,6 +36,7 @@
"libaudiohal",
"libaudiopolicy",
"libaudiopolicymanagerdefault",
+ "libaudiousecasevalidation",
"libaudioutils",
"libbinder",
"libcutils",
@@ -85,6 +86,7 @@
export_shared_lib_headers: [
"libactivitymanager_aidl",
+ "libaudiousecasevalidation",
"libheadtracking",
"libheadtracking-binding",
"libsensorprivacy",
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index c766a15..1bb89df 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -69,6 +69,12 @@
*halConfig = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioConfig_audio_config_t(response.config, false /*isInput*/));
*latencyMs = VALUE_OR_RETURN_STATUS(convertIntegral<uint32_t>(response.latencyMs));
+
+ audio_config_base_t config = {.sample_rate = halConfig->sample_rate,
+ .channel_mask = halConfig->channel_mask,
+ .format = halConfig->format,
+ };
+ mAudioPolicyService->registerOutput(*output, config, flags);
}
return status;
}
@@ -91,7 +97,7 @@
if (af == 0) {
return PERMISSION_DENIED;
}
-
+ mAudioPolicyService->unregisterOutput(output);
return af->closeOutput(output);
}
@@ -168,16 +174,6 @@
delay_ms);
}
-status_t AudioPolicyService::AudioPolicyClient::invalidateStream(audio_stream_type_t stream)
-{
- sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0) {
- return PERMISSION_DENIED;
- }
-
- return af->invalidateStream(stream);
-}
-
void AudioPolicyService::AudioPolicyClient::setParameters(audio_io_handle_t io_handle,
const String8& keyValuePairs,
int delay_ms)
@@ -322,5 +318,15 @@
return af->setDeviceConnectedState(port, connected);
}
+status_t AudioPolicyService::AudioPolicyClient::invalidateTracks(
+ const std::vector<audio_port_handle_t>& portIds) {
+ sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
+ if (af == 0) {
+ return PERMISSION_DENIED;
+ }
+
+ return af->invalidateTracks(portIds);
+}
+
} // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 4eb5336..35411f9 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -417,6 +417,9 @@
}
if (result == NO_ERROR) {
+ attr = VALUE_OR_RETURN_BINDER_STATUS(
+ mUsecaseValidator->verifyAudioAttributes(output, attributionSource, attr));
+
sp<AudioPlaybackClient> client =
new AudioPlaybackClient(attr, output, attributionSource, session,
portId, selectedDeviceId, stream, isSpatialized);
@@ -435,6 +438,8 @@
legacy2aidl_audio_io_handle_t_int32_t));
_aidl_return->isSpatialized = isSpatialized;
_aidl_return->isBitPerfect = isBitPerfect;
+ _aidl_return->attr = VALUE_OR_RETURN_BINDER_STATUS(
+ legacy2aidl_audio_attributes_t_AudioAttributesInternal(attr));
} else {
_aidl_return->configBase.format = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_format_t_AudioFormatDescription(config.format));
@@ -486,6 +491,10 @@
AutoCallerClear acc;
status_t status = mAudioPolicyManager->startOutput(portId);
if (status == NO_ERROR) {
+ //TODO b/257922898: decide if/how we need to handle attributes update when playback starts
+ // or during playback
+ (void)mUsecaseValidator->startClient(client->io, client->portId, client->attributionSource,
+ client->attributes, nullptr /* callback */);
client->active = true;
onUpdateActiveSpatializerTracks_l();
}
@@ -526,6 +535,7 @@
if (status == NO_ERROR) {
client->active = false;
onUpdateActiveSpatializerTracks_l();
+ mUsecaseValidator->stopClient(client->io, client->portId);
}
return status;
}
@@ -657,7 +667,9 @@
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- if (((flags & AUDIO_INPUT_FLAG_HW_HOTWORD) != 0)
+ if (((flags & (AUDIO_INPUT_FLAG_HW_HOTWORD |
+ AUDIO_INPUT_FLAG_HOTWORD_TAP |
+ AUDIO_INPUT_FLAG_HW_LOOKBACK)) != 0)
&& !canCaptureHotword) {
ALOGE("%s: permission denied: hotword mode not allowed"
" for uid %d pid %d", __func__, attributionSource.uid, attributionSource.pid);
@@ -1497,7 +1509,7 @@
Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
media::AudioPortType typeAidl, Int* count,
- std::vector<media::AudioPort>* portsAidl,
+ std::vector<media::AudioPortFw>* portsAidl,
int32_t* _aidl_return) {
audio_port_role_t role = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPortRole_audio_port_role_t(roleAidl));
@@ -1522,14 +1534,14 @@
numPortsReq = std::min(numPortsReq, num_ports);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
- legacy2aidl_audio_port_v7_AudioPort)));
+ legacy2aidl_audio_port_v7_AudioPortFw)));
count->value = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int32_t>(num_ports));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int32_t>(generation));
return Status::ok();
}
Status AudioPolicyService::getAudioPort(int portId,
- media::AudioPort* _aidl_return) {
+ media::AudioPortFw* _aidl_return) {
audio_port_v7 port{ .id = portId };
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
@@ -1537,14 +1549,15 @@
}
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
- *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPort(port));
+ *_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
return Status::ok();
}
-Status AudioPolicyService::createAudioPatch(const media::AudioPatch& patchAidl, int32_t handleAidl,
+Status AudioPolicyService::createAudioPatch(const media::AudioPatchFw& patchAidl,
+ int32_t handleAidl,
int32_t* _aidl_return) {
audio_patch patch = VALUE_OR_RETURN_BINDER_STATUS(
- aidl2legacy_AudioPatch_audio_patch(patchAidl));
+ aidl2legacy_AudioPatchFw_audio_patch(patchAidl));
audio_patch_handle_t handle = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(handleAidl));
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(AudioValidator::validateAudioPatch(patch)));
@@ -1582,7 +1595,7 @@
}
Status AudioPolicyService::listAudioPatches(Int* count,
- std::vector<media::AudioPatch>* patchesAidl,
+ std::vector<media::AudioPatchFw>* patchesAidl,
int32_t* _aidl_return) {
unsigned int num_patches = VALUE_OR_RETURN_BINDER_STATUS(
convertIntegral<unsigned int>(count->value));
@@ -1603,16 +1616,16 @@
numPatchesReq = std::min(numPatchesReq, num_patches);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(patches.get(), patches.get() + numPatchesReq,
- std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatch)));
+ std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
count->value = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int32_t>(num_patches));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int32_t>(generation));
return Status::ok();
}
-Status AudioPolicyService::setAudioPortConfig(const media::AudioPortConfig& configAidl)
+Status AudioPolicyService::setAudioPortConfig(const media::AudioPortConfigFw& configAidl)
{
audio_port_config config = VALUE_OR_RETURN_BINDER_STATUS(
- aidl2legacy_AudioPortConfig_audio_port_config(configAidl));
+ aidl2legacy_AudioPortConfigFw_audio_port_config(configAidl));
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(AudioValidator::validateAudioPortConfig(config)));
@@ -1782,11 +1795,11 @@
return binderStatusFromStatusT(mAudioPolicyManager->removeUserIdDeviceAffinities(userId));
}
-Status AudioPolicyService::startAudioSource(const media::AudioPortConfig& sourceAidl,
+Status AudioPolicyService::startAudioSource(const media::AudioPortConfigFw& sourceAidl,
const media::AudioAttributesInternal& attributesAidl,
int32_t* _aidl_return) {
audio_port_config source = VALUE_OR_RETURN_BINDER_STATUS(
- aidl2legacy_AudioPortConfig_audio_port_config(sourceAidl));
+ aidl2legacy_AudioPortConfigFw_audio_port_config(sourceAidl));
audio_attributes_t attributes = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioAttributesInternal_audio_attributes_t(attributesAidl));
audio_port_handle_t portId;
@@ -2032,6 +2045,17 @@
return Status::ok();
}
+Status AudioPolicyService::isHotwordStreamSupported(bool lookbackAudio, bool* _aidl_return)
+{
+ if (mAudioPolicyManager == nullptr) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ Mutex::Autolock _l(mLock);
+ AutoCallerClear acc;
+ *_aidl_return = mAudioPolicyManager->isHotwordStreamSupported(lookbackAudio);
+ return Status::ok();
+}
+
Status AudioPolicyService::listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) {
AudioProductStrategyVector strategies;
@@ -2143,8 +2167,31 @@
return binderStatusFromStatusT(status);
}
-Status AudioPolicyService::removeDevicesRoleForStrategy(int32_t strategyAidl,
- media::DeviceRole roleAidl) {
+Status AudioPolicyService::removeDevicesRoleForStrategy(
+ int32_t strategyAidl,
+ media::DeviceRole roleAidl,
+ const std::vector<AudioDevice>& devicesAidl) {
+ product_strategy_t strategy = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_int32_t_product_strategy_t(strategyAidl));
+ device_role_t role = VALUE_OR_RETURN_BINDER_STATUS(
+ aidl2legacy_DeviceRole_device_role_t(roleAidl));
+ AudioDeviceTypeAddrVector devices = VALUE_OR_RETURN_BINDER_STATUS(
+ convertContainer<AudioDeviceTypeAddrVector>(devicesAidl,
+ aidl2legacy_AudioDeviceTypeAddress));
+
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ Mutex::Autolock _l(mLock);
+ status_t status = mAudioPolicyManager->removeDevicesRoleForStrategy(strategy, role, devices);
+ if (status == NO_ERROR) {
+ onCheckSpatializer_l();
+ }
+ return binderStatusFromStatusT(status);
+}
+
+Status AudioPolicyService::clearDevicesRoleForStrategy(int32_t strategyAidl,
+ media::DeviceRole roleAidl) {
product_strategy_t strategy = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_product_strategy_t(strategyAidl));
device_role_t role = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2153,7 +2200,7 @@
return binderStatusFromStatusT(NO_INIT);
}
Mutex::Autolock _l(mLock);
- status_t status = mAudioPolicyManager->removeDevicesRoleForStrategy(strategy, role);
+ status_t status = mAudioPolicyManager->clearDevicesRoleForStrategy(strategy, role);
if (status == NO_ERROR) {
onCheckSpatializer_l();
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 48997db..974ae38 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -137,6 +137,7 @@
BINDER_METHOD_ENTRY(setCurrentImeUid) \
BINDER_METHOD_ENTRY(isHapticPlaybackSupported) \
BINDER_METHOD_ENTRY(isUltrasoundSupported) \
+BINDER_METHOD_ENTRY(isHotwordStreamSupported) \
BINDER_METHOD_ENTRY(listAudioProductStrategies) \
BINDER_METHOD_ENTRY(getProductStrategyFromAudioAttributes) \
BINDER_METHOD_ENTRY(listAudioVolumeGroups) \
@@ -145,6 +146,7 @@
BINDER_METHOD_ENTRY(isCallScreenModeSupported) \
BINDER_METHOD_ENTRY(setDevicesRoleForStrategy) \
BINDER_METHOD_ENTRY(removeDevicesRoleForStrategy) \
+BINDER_METHOD_ENTRY(clearDevicesRoleForStrategy) \
BINDER_METHOD_ENTRY(getDevicesForRoleAndStrategy) \
BINDER_METHOD_ENTRY(setDevicesRoleForCapturePreset) \
BINDER_METHOD_ENTRY(addDevicesRoleForCapturePreset) \
@@ -205,7 +207,8 @@
mPhoneState(AUDIO_MODE_INVALID),
mCaptureStateNotifier(false),
mCreateAudioPolicyManager(createAudioPolicyManager),
- mDestroyAudioPolicyManager(destroyAudioPolicyManager) {
+ mDestroyAudioPolicyManager(destroyAudioPolicyManager),
+ mUsecaseValidator(media::createUsecaseValidator()) {
setMinSchedulerPolicy(SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
}
@@ -1312,11 +1315,13 @@
case TRANSACTION_getVolumeGroupFromAudioAttributes:
case TRANSACTION_acquireSoundTriggerSession:
case TRANSACTION_releaseSoundTriggerSession:
+ case TRANSACTION_isHotwordStreamSupported:
case TRANSACTION_setRttEnabled:
case TRANSACTION_isCallScreenModeSupported:
case TRANSACTION_setDevicesRoleForStrategy:
case TRANSACTION_setSupportedSystemUsages:
case TRANSACTION_removeDevicesRoleForStrategy:
+ case TRANSACTION_clearDevicesRoleForStrategy:
case TRANSACTION_getDevicesForRoleAndStrategy:
case TRANSACTION_getDevicesForAttributes:
case TRANSACTION_setAllowedCapturePolicy:
@@ -1537,6 +1542,16 @@
" help print this message\n");
}
+status_t AudioPolicyService::registerOutput(audio_io_handle_t output,
+ const audio_config_base_t& config,
+ const audio_output_flags_t flags) {
+ return mUsecaseValidator->registerStream(output, config, flags);
+}
+
+status_t AudioPolicyService::unregisterOutput(audio_io_handle_t output) {
+ return mUsecaseValidator->unregisterStream(output);
+}
+
// ----------- AudioPolicyService::UidPolicy implementation ----------
void AudioPolicyService::UidPolicy::registerSelf() {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 58af46d..31d5249 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -36,6 +36,7 @@
#include <media/ToneGenerator.h>
#include <media/AudioEffect.h>
#include <media/AudioPolicy.h>
+#include <media/UsecaseValidator.h>
#include <mediautils/ServiceUtilities.h>
#include "AudioPolicyEffects.h"
#include "CaptureStateNotifier.h"
@@ -69,7 +70,7 @@
public IBinder::DeathRecipient,
public SpatializerPolicyCallback
{
- friend class BinderService<AudioPolicyService>;
+ friend class sp<AudioPolicyService>;
public:
// for BinderService
@@ -172,16 +173,16 @@
const media::AudioAttributesInternal& attributes,
bool* _aidl_return) override;
binder::Status listAudioPorts(media::AudioPortRole role, media::AudioPortType type,
- Int* count, std::vector<media::AudioPort>* ports,
+ Int* count, std::vector<media::AudioPortFw>* ports,
int32_t* _aidl_return) override;
binder::Status getAudioPort(int portId,
- media::AudioPort* _aidl_return) override;
- binder::Status createAudioPatch(const media::AudioPatch& patch, int32_t handle,
+ media::AudioPortFw* _aidl_return) override;
+ binder::Status createAudioPatch(const media::AudioPatchFw& patch, int32_t handle,
int32_t* _aidl_return) override;
binder::Status releaseAudioPatch(int32_t handle) override;
- binder::Status listAudioPatches(Int* count, std::vector<media::AudioPatch>* patches,
+ binder::Status listAudioPatches(Int* count, std::vector<media::AudioPatchFw>* patches,
int32_t* _aidl_return) override;
- binder::Status setAudioPortConfig(const media::AudioPortConfig& config) override;
+ binder::Status setAudioPortConfig(const media::AudioPortConfigFw& config) override;
binder::Status registerClient(const sp<media::IAudioPolicyServiceClient>& client) override;
binder::Status setAudioPortCallbacksEnabled(bool enabled) override;
binder::Status setAudioVolumeGroupCallbacksEnabled(bool enabled) override;
@@ -197,7 +198,7 @@
int32_t userId,
const std::vector<AudioDevice>& devices) override;
binder::Status removeUserIdDeviceAffinities(int32_t userId) override;
- binder::Status startAudioSource(const media::AudioPortConfig& source,
+ binder::Status startAudioSource(const media::AudioPortConfigFw& source,
const media::AudioAttributesInternal& attributes,
int32_t* _aidl_return) override;
binder::Status stopAudioSource(int32_t portId) override;
@@ -222,6 +223,7 @@
binder::Status setCurrentImeUid(int32_t uid) override;
binder::Status isHapticPlaybackSupported(bool* _aidl_return) override;
binder::Status isUltrasoundSupported(bool* _aidl_return) override;
+ binder::Status isHotwordStreamSupported(bool lookbackAudio, bool* _aidl_return) override;
binder::Status listAudioProductStrategies(
std::vector<media::AudioProductStrategy>* _aidl_return) override;
binder::Status getProductStrategyFromAudioAttributes(const media::AudioAttributesInternal& aa,
@@ -237,7 +239,12 @@
binder::Status setDevicesRoleForStrategy(
int32_t strategy, media::DeviceRole role,
const std::vector<AudioDevice>& devices) override;
- binder::Status removeDevicesRoleForStrategy(int32_t strategy, media::DeviceRole role) override;
+ binder::Status removeDevicesRoleForStrategy(
+ int32_t strategy, media::DeviceRole role,
+ const std::vector<AudioDevice>& devices) override;
+ binder::Status clearDevicesRoleForStrategy(
+ int32_t strategy,
+ media::DeviceRole role) override;
binder::Status getDevicesForRoleAndStrategy(
int32_t strategy, media::DeviceRole role,
std::vector<AudioDevice>* _aidl_return) override;
@@ -431,6 +438,11 @@
*/
static bool isAppOpSource(audio_source_t source);
+ status_t registerOutput(audio_io_handle_t output,
+ const audio_config_base_t& config,
+ const audio_output_flags_t flags);
+ status_t unregisterOutput(audio_io_handle_t output);
+
// If recording we need to make sure the UID is allowed to do that. If the UID is idle
// then it cannot record and gets buffers with zeros - silence. As soon as the UID
// transitions to an active state we will start reporting buffers with data. This approach
@@ -776,9 +788,6 @@
// for each output (destination device) it is attached to.
virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, audio_io_handle_t output, int delayMs = 0);
- // invalidate a stream type, causing a reroute to an unspecified new output
- virtual status_t invalidateStream(audio_stream_type_t stream);
-
// function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
// function enabling to receive proprietary informations directly from audio hardware interface to audio policy manager.
@@ -838,6 +847,8 @@
status_t setDeviceConnectedState(
const struct audio_port_v7 *port, bool connected) override;
+ status_t invalidateTracks(const std::vector<audio_port_handle_t>& portIds) override;
+
private:
AudioPolicyService *mAudioPolicyService;
};
@@ -903,7 +914,7 @@
const audio_attributes_t attributes; // source, flags ...
const audio_io_handle_t io; // audio HAL stream IO handle
- const AttributionSourceState& attributionSource; //client attributionsource
+ const AttributionSourceState attributionSource; //client attributionsource
const audio_session_t session; // audio session ID
const audio_port_handle_t portId;
const audio_port_handle_t deviceId; // selected input device port ID
@@ -1082,6 +1093,7 @@
void *mLibraryHandle = nullptr;
CreateAudioPolicyManagerInstance mCreateAudioPolicyManager;
DestroyAudioPolicyManagerInstance mDestroyAudioPolicyManager;
+ std::unique_ptr<media::UsecaseValidator> mUsecaseValidator;
};
} // namespace android
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 3e4dd69..ccbbf66 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -23,6 +23,7 @@
#include <android/media/SpatializationLevel.h>
#include <android/media/SpatializationMode.h>
#include <android/media/SpatializerHeadTrackingMode.h>
+#include <android/media/audio/common/AudioLatencyMode.h>
#include <audio_utils/SimpleLog.h>
#include <math.h>
#include <media/AudioEffect.h>
@@ -167,8 +168,9 @@
static std::string toString(audio_latency_mode_t mode) {
// We convert to the AIDL type to print (eventually the legacy type will be removed).
- const auto result = legacy2aidl_audio_latency_mode_t_LatencyMode(mode);
- return result.has_value() ? media::toString(*result) : "unknown_latency_mode";
+ const auto result = legacy2aidl_audio_latency_mode_t_AudioLatencyMode(mode);
+ return result.has_value() ?
+ media::audio::common::toString(*result) : "unknown_latency_mode";
}
/**
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 72dba3d..ab1b6f7 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -192,7 +192,7 @@
mHeadSensor = INVALID_SENSOR;
}
- mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */);
+ mProcessor->recenter(true /* recenterHead */, false /* recenterScreen */, __func__);
}
void SpatializerPoseController::setScreenSensor(int32_t sensor) {
@@ -229,7 +229,7 @@
mScreenSensor = INVALID_SENSOR;
}
- mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */);
+ mProcessor->recenter(false /* recenterHead */, true /* recenterScreen */, __func__);
}
void SpatializerPoseController::setDesiredMode(HeadTrackingMode mode) {
@@ -276,7 +276,7 @@
void SpatializerPoseController::recenter() {
std::lock_guard lock(mMutex);
- mProcessor->recenter();
+ mProcessor->recenter(true /* recenterHead */, true /* recenterScreen */, __func__);
}
void SpatializerPoseController::onPose(int64_t timestamp, int32_t sensor, const Pose3f& pose,
@@ -286,13 +286,13 @@
mProcessor->setWorldToHeadPose(timestamp, pose,
twist.value_or(Twist3f()) / kTicksPerSecond);
if (isNewReference) {
- mProcessor->recenter(true, false);
+ mProcessor->recenter(true, false, __func__);
}
}
if (sensor == mScreenSensor) {
mProcessor->setWorldToScreenPose(timestamp, pose);
if (isNewReference) {
- mProcessor->recenter(false, true);
+ mProcessor->recenter(false, true, __func__);
}
}
}
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index 6813587..bf82680 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -28,6 +28,7 @@
"liblog",
"libmedia_helper",
"libutils",
+ "libcutils",
"libxml2",
"framework-permission-aidl-cpp",
"libbinder",
@@ -54,7 +55,10 @@
"-Wall",
],
- test_suites: ["device-tests"],
+ test_suites: [
+ "device-tests",
+ "automotive-tests",
+ ],
}
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 8a85fee..0c04e35 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -54,7 +54,6 @@
float /*volume*/,
audio_io_handle_t /*output*/,
int /*delayMs*/) override { return NO_INIT; }
- status_t invalidateStream(audio_stream_type_t /*stream*/) override { return NO_INIT; }
void setParameters(audio_io_handle_t /*ioHandle*/,
const String8& /*keyValuePairs*/,
int /*delayMs*/) override { }
@@ -101,6 +100,9 @@
const struct audio_port_v7 *port __unused, bool connected __unused) override {
return NO_INIT;
}
+ status_t invalidateTracks(const std::vector<audio_port_handle_t>& /*portIds*/) override {
+ return NO_INIT;
+ }
};
} // namespace android
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index 10f8dc0..798332c 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -111,7 +111,7 @@
continue;
}
std::string address = "11:22:33:44:55:66";
- media::AudioPort aidlPort;
+ media::AudioPortFw aidlPort;
ASSERT_EQ(OK, manager.deviceToAudioPort(device->type(), address.c_str(), "" /*name*/,
&aidlPort));
ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 386a67e..ef829e1 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -32,6 +32,7 @@
#include <media/RecordingActivityTracker.h>
#include <utils/Log.h>
#include <utils/Vector.h>
+#include <cutils/multiuser.h>
#include "AudioPolicyInterface.h"
#include "AudioPolicyManagerTestClient.h"
@@ -51,6 +52,13 @@
return criterion;
}
+AudioMixMatchCriterion createUserIdCriterion(int userId, bool exclude = false) {
+ AudioMixMatchCriterion criterion;
+ criterion.mValue.mUserId = userId;
+ criterion.mRule = exclude ? RULE_EXCLUDE_USERID : RULE_MATCH_USERID;
+ return criterion;
+}
+
AudioMixMatchCriterion createUsageCriterion(audio_usage_t usage, bool exclude = false) {
AudioMixMatchCriterion criterion;
criterion.mValue.mUsage = usage;
@@ -161,7 +169,8 @@
audio_port_handle_t *portId = nullptr,
audio_attributes_t attr = {},
audio_session_t session = AUDIO_SESSION_NONE,
- int uid = 0);
+ int uid = 0,
+ bool* isBitPerfect = nullptr);
void getInputForAttr(
const audio_attributes_t &attr,
audio_session_t session,
@@ -246,7 +255,8 @@
audio_port_handle_t *portId,
audio_attributes_t attr,
audio_session_t session,
- int uid) {
+ int uid,
+ bool* isBitPerfect) {
audio_io_handle_t localOutput;
if (!output) output = &localOutput;
*output = AUDIO_IO_HANDLE_NONE;
@@ -260,14 +270,15 @@
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::output_type_t outputType;
bool isSpatialized;
- bool isBitPerfect;
+ bool isBitPerfectInternal;
// TODO b/182392769: use attribution source util
AttributionSourceState attributionSource = AttributionSourceState();
attributionSource.uid = uid;
attributionSource.token = sp<BBinder>::make();
ASSERT_EQ(OK, mManager->getOutputForAttr(
&attr, output, session, &stream, attributionSource, &config, &flags,
- selectedDeviceId, portId, {}, &outputType, &isSpatialized, &isBitPerfect));
+ selectedDeviceId, portId, {}, &outputType, &isSpatialized,
+ isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
}
@@ -461,7 +472,7 @@
sp<AudioProfile> ac3OutputProfile = new AudioProfile(
AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, k48000SamplingRate);
sp<AudioProfile> iec958OutputProfile = new AudioProfile(
- AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
+ AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_INDEX_MASK_24, k48000SamplingRate);
mMsdOutputDevice->addAudioProfile(pcmOutputProfile);
mMsdOutputDevice->addAudioProfile(ac3OutputProfile);
mMsdOutputDevice->addAudioProfile(iec958OutputProfile);
@@ -534,7 +545,7 @@
// Add HDMI input device with IEC60958 profile for HDMI in -> MSD patching.
mHdmiInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_HDMI);
sp<AudioProfile> iec958InputProfile = new AudioProfile(
- AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate);
+ AUDIO_FORMAT_IEC60958, AUDIO_CHANNEL_INDEX_MASK_24, k48000SamplingRate);
mHdmiInputDevice->addAudioProfile(iec958InputProfile);
config.addDevice(mHdmiInputDevice);
sp<InputProfile> hdmiInputProfile = new InputProfile("hdmi input");
@@ -692,8 +703,8 @@
ASSERT_EQ(AUDIO_PORT_ROLE_SINK, patch->mPatch.sinks[0].role);
ASSERT_EQ(AUDIO_FORMAT_IEC60958, patch->mPatch.sources[0].format);
ASSERT_EQ(AUDIO_FORMAT_IEC60958, patch->mPatch.sinks[0].format);
- ASSERT_EQ(AUDIO_CHANNEL_IN_STEREO, patch->mPatch.sources[0].channel_mask);
- ASSERT_EQ(AUDIO_CHANNEL_OUT_STEREO, patch->mPatch.sinks[0].channel_mask);
+ ASSERT_EQ(AUDIO_CHANNEL_INDEX_MASK_24, patch->mPatch.sources[0].channel_mask);
+ ASSERT_EQ(AUDIO_CHANNEL_INDEX_MASK_24, patch->mPatch.sinks[0].channel_mask);
ASSERT_EQ(k48000SamplingRate, patch->mPatch.sources[0].sample_rate);
ASSERT_EQ(k48000SamplingRate, patch->mPatch.sinks[0].sample_rate);
ASSERT_EQ(1, patchCount.deltaFromSnapshot());
@@ -769,7 +780,7 @@
audio_config_base_t msdDirectConfig2 = AUDIO_CONFIG_BASE_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
msdDirectConfig2.sample_rate = 48000;
- msdDirectConfig2.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_base_t msdNonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
msdNonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
@@ -836,7 +847,7 @@
audio_config_t msdDirectConfig2 = AUDIO_CONFIG_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
msdDirectConfig2.sample_rate = 48000;
- msdDirectConfig2.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_t msdNonDirectConfig = AUDIO_CONFIG_INITIALIZER;
msdNonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
@@ -1119,6 +1130,116 @@
"", "", AUDIO_FORMAT_LDAC));
}
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, BitPerfectPlayback) {
+ const audio_format_t bitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
+ const audio_channel_mask_t bitPerfectChannelMask = AUDIO_CHANNEL_OUT_QUAD;
+ const uint32_t bitPerfectSampleRate = 48000;
+ mClient->addSupportedFormat(bitPerfectFormat);
+ mClient->addSupportedChannelMask(bitPerfectChannelMask);
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ "", "", AUDIO_FORMAT_DEFAULT));
+ auto devices = mManager->getAvailableOutputDevices();
+ audio_port_handle_t usbPortId = AUDIO_PORT_HANDLE_NONE;
+ for (auto device : devices) {
+ if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) {
+ usbPortId = device->getId();
+ break;
+ }
+ }
+ EXPECT_NE(AUDIO_PORT_HANDLE_NONE, usbPortId);
+
+ const uid_t uid = 1234;
+ const uid_t anotherUid = 5678;
+ const audio_attributes_t mediaAttr = {
+ .content_type = AUDIO_CONTENT_TYPE_MUSIC,
+ .usage = AUDIO_USAGE_MEDIA,
+ };
+
+ std::vector<audio_mixer_attributes_t> mixerAttributes;
+ EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes));
+ EXPECT_GT(mixerAttributes.size(), 0);
+ size_t bitPerfectIndex = 0;
+ for (; bitPerfectIndex < mixerAttributes.size(); ++bitPerfectIndex) {
+ if (mixerAttributes[bitPerfectIndex].mixer_behavior == AUDIO_MIXER_BEHAVIOR_BIT_PERFECT) {
+ break;
+ }
+ }
+ EXPECT_LT(bitPerfectIndex, mixerAttributes.size());
+ EXPECT_EQ(bitPerfectFormat, mixerAttributes[bitPerfectIndex].config.format);
+ EXPECT_EQ(bitPerfectChannelMask, mixerAttributes[bitPerfectIndex].config.channel_mask);
+ EXPECT_EQ(bitPerfectSampleRate, mixerAttributes[bitPerfectIndex].config.sample_rate);
+ EXPECT_EQ(NO_ERROR,
+ mManager->setPreferredMixerAttributes(
+ &mediaAttr, usbPortId, uid, &mixerAttributes[bitPerfectIndex]));
+
+ audio_io_handle_t bitPerfectOutput = AUDIO_IO_HANDLE_NONE;
+ audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t bitPerfectPortId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ bool isBitPerfect;
+
+ // When there is no active bit-perfect playback, the output selection will follow default
+ // routing strategy.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
+ uid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, output);
+ const auto outputDesc = mManager->getOutputs().valueFor(output);
+ EXPECT_NE(nullptr, outputDesc);
+ EXPECT_NE(AUDIO_OUTPUT_FLAG_BIT_PERFECT, outputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
+
+ // Start bit-perfect playback
+ getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
+ bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
+ mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
+ status_t status = mManager->startOutput(bitPerfectPortId);
+ if (status == DEAD_OBJECT) {
+ getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
+ bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
+ mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
+ status = mManager->startOutput(bitPerfectPortId);
+ }
+ EXPECT_EQ(NO_ERROR, status);
+ EXPECT_TRUE(isBitPerfect);
+ EXPECT_NE(AUDIO_IO_HANDLE_NONE, bitPerfectOutput);
+ const auto bitPerfectOutputDesc = mManager->getOutputs().valueFor(bitPerfectOutput);
+ EXPECT_NE(nullptr, bitPerfectOutputDesc);
+ EXPECT_EQ(AUDIO_OUTPUT_FLAG_BIT_PERFECT,
+ bitPerfectOutputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);
+
+ // If the playback is from preferred mixer attributes owner but the request doesn't match
+ // preferred mixer attributes, it will not be bit-perfect.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
+ uid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(bitPerfectOutput, output);
+
+ // When bit-perfect playback is active, all other playback will be routed to bit-perfect output.
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
+ anotherUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(bitPerfectOutput, output);
+
+ // When configuration matches preferred mixer attributes, which is bit-perfect, but the client
+ // is not the owner of preferred mixer attributes, the playback will not be bit-perfect.
+ getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
+ bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+ AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
+ EXPECT_FALSE(isBitPerfect);
+ EXPECT_EQ(bitPerfectOutput, output);
+
+ EXPECT_EQ(NO_ERROR,
+ mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid));
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
+ AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ "", "", AUDIO_FORMAT_LDAC));
+}
+
class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void TearDown() override;
@@ -2007,7 +2128,7 @@
}
const std::string name = std::get<1>(GetParam());
const std::string address = std::get<2>(GetParam());
- android::media::AudioPort audioPort;
+ android::media::AudioPortFw audioPort;
ASSERT_EQ(NO_ERROR,
mManager->deviceToAudioPort(type, address.c_str(), name.c_str(), &audioPort));
android::media::audio::common::AudioPort& port = audioPort.hal;
@@ -2048,11 +2169,23 @@
std::string getConfigFile() override { return sCarConfig; }
static const std::string sCarConfig;
+ static const std::string sCarBusMediaOutput;
+ static const std::string sCarBusNavigationOutput;
+ static const std::string sCarRearZoneOneOutput;
+ static const std::string sCarRearZoneTwoOutput;
};
const std::string AudioPolicyManagerCarTest::sCarConfig =
AudioPolicyManagerCarTest::sExecutableDir + "test_car_ap_atmos_offload_configuration.xml";
+const std::string AudioPolicyManagerCarTest::sCarBusMediaOutput = "bus0_media_out";
+
+const std::string AudioPolicyManagerCarTest::sCarBusNavigationOutput = "bus1_navigation_out";
+
+const std::string AudioPolicyManagerCarTest::sCarRearZoneOneOutput = "bus100_audio_zone_1";
+
+const std::string AudioPolicyManagerCarTest::sCarRearZoneTwoOutput = "bus200_audio_zone_2";
+
TEST_F(AudioPolicyManagerCarTest, InitSuccess) {
// SetUp must finish with no assertions.
}
@@ -2064,9 +2197,8 @@
TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrAtmosOutputAfterRegisteringPolicyMix) {
status_t ret;
audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
- const std::string kTestBusMediaOutput = "bus0_media_out";
ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
- AUDIO_DEVICE_OUT_BUS, kTestBusMediaOutput, audioConfig);
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig);
ASSERT_EQ(NO_ERROR, ret);
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
@@ -2094,6 +2226,415 @@
ASSERT_EQ(k48000SamplingRate, outDesc->getSamplingRate());
}
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrAfterRegisteringPolicyMix) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 mediaDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusMediaOutput, &mediaDevicePort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(mediaDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrWithSelectedOutputAfterRegisteringPolicyMix) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrWithSelectedOutputAfterUserAffinities) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddrVector outputDevices = {mediaOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, outputDevices);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute);
+
+ ASSERT_NE(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrWithExcludeUserIdCriteria) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false),
+ createUserIdCriterion(/* userId */ 0, /* exclude */ true)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t navigationAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, navigationAttribute);
+
+ ASSERT_NE(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrWithSelectedOutputExcludeUserIdCriteria) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false),
+ createUserIdCriterion(0 /* userId */, /* exclude */ true)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest,
+ GetOutputForAttrWithMatchingMixAndSelectedOutputAfterUserAffinities) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddr navOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput);
+ const AudioDeviceTypeAddrVector outputDevices = {mediaOutputDevice, navOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, outputDevices);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest,
+ GetOutputForAttrWithNoMatchingMaxAndSelectedOutputAfterUserAffinities) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddr navOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput);
+ const AudioDeviceTypeAddrVector outputDevices = {mediaOutputDevice, navOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, outputDevices);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t alarmAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, alarmAttribute);
+
+ ASSERT_EQ(navDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest,
+ GetOutputForAttrWithMatMixAfterUserAffinitiesForOneUser) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneOneOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneTwoOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddrVector primaryZoneDevices = {mediaOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, primaryZoneDevices);
+ audio_port_v7 primaryZoneDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusMediaOutput, &primaryZoneDevicePort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+ uid_t user11AppUid = multiuser_get_uid(/* user_id */ 11, /* app_id */ 12345);
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute,
+ AUDIO_SESSION_NONE, user11AppUid);
+
+ ASSERT_EQ(primaryZoneDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest,
+ GetOutputForAttrWithMatMixAfterUserAffinitiesForTwoUsers) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneOneOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneTwoOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddrVector primaryZoneDevices = {mediaOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, primaryZoneDevices);
+ const AudioDeviceTypeAddr secondaryOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarRearZoneOneOutput);
+ const AudioDeviceTypeAddrVector secondaryZoneDevices = {secondaryOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 11, secondaryZoneDevices);
+ audio_port_v7 secondaryZoneDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarRearZoneOneOutput, &secondaryZoneDevicePort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+ uid_t user11AppUid = multiuser_get_uid(/* user_id */ 11, /* app_id */ 12345);
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute,
+ AUDIO_SESSION_NONE, user11AppUid);
+
+ ASSERT_EQ(secondaryZoneDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest,
+ GetOutputForAttrWithMatMixAfterUserAffinitiesForThreeUsers) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneOneOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarRearZoneTwoOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddrVector primaryZoneDevices = {mediaOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, primaryZoneDevices);
+ const AudioDeviceTypeAddr secondaryOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarRearZoneOneOutput);
+ const AudioDeviceTypeAddrVector secondaryZoneDevices = {secondaryOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 11, secondaryZoneDevices);
+ const AudioDeviceTypeAddr tertiaryOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarRearZoneTwoOutput);
+ const AudioDeviceTypeAddrVector tertiaryZoneDevices = {tertiaryOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 15, tertiaryZoneDevices);
+ audio_port_v7 tertiaryZoneDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarRearZoneTwoOutput, &tertiaryZoneDevicePort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t mediaAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_MEDIA,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+ uid_t user15AppUid = multiuser_get_uid(/* user_id */ 15, /* app_id */ 12345);
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, mediaAttribute,
+ AUDIO_SESSION_NONE, user15AppUid);
+
+ ASSERT_EQ(tertiaryZoneDevicePort.id, selectedDeviceId);
+}
+
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrWithNoMatchingMix) {
+ status_t ret;
+ audio_config_t audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ std::vector<AudioMixMatchCriterion> mediaMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_MEDIA, /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ std::vector<AudioMixMatchCriterion> navMatchCriteria = {
+ createUsageCriterion(AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ /*exclude=*/ false)};
+ ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput, audioConfig, navMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ const AudioDeviceTypeAddr mediaOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusMediaOutput);
+ const AudioDeviceTypeAddr navOutputDevice(AUDIO_DEVICE_OUT_BUS, sCarBusNavigationOutput);
+ const AudioDeviceTypeAddrVector outputDevices = {mediaOutputDevice, navOutputDevice};
+ mManager->setUserIdDeviceAffinities(/* userId */ 0, outputDevices);
+ audio_port_v7 navDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusNavigationOutput, &navDevicePort));
+ audio_port_handle_t selectedDeviceId = navDevicePort.id;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ const audio_attributes_t alarmAttribute = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ALARM,
+ AUDIO_SOURCE_DEFAULT, AUDIO_FLAG_NONE, ""};
+
+ getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_DIRECT, &output, &portId, alarmAttribute);
+
+ ASSERT_EQ(navDevicePort.id, selectedDeviceId);
+}
+
class AudioPolicyManagerTVTest : public AudioPolicyManagerTestWithConfigurationFile {
protected:
std::string getConfigFile() override { return sTvConfig; }
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index c937d3a..2eb771d 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -54,7 +54,7 @@
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
- <mixPort name="hifi_output" role="source"/>
+ <mixPort name="hifi_output" role="source" flags="AUDIO_OUTPUT_FLAG_BIT_PERFECT"/>
</mixPorts>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index d52e540..1c922ce 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -65,6 +65,7 @@
"api2/DepthCompositeStream.cpp",
"api2/HeicEncoderInfoManager.cpp",
"api2/HeicCompositeStream.cpp",
+ "api2/JpegRCompositeStream.cpp",
"device3/BufferUtils.cpp",
"device3/Camera3Device.cpp",
"device3/Camera3OfflineSession.cpp",
@@ -94,6 +95,12 @@
"hidl/HidlCameraDeviceUser.cpp",
"hidl/HidlCameraService.cpp",
"hidl/Utils.cpp",
+ "aidl/AidlCameraDeviceCallbacks.cpp",
+ "aidl/AidlCameraDeviceUser.cpp",
+ "aidl/AidlCameraService.cpp",
+ "aidl/AidlCameraServiceListener.cpp",
+ "aidl/AidlUtils.cpp",
+ "aidl/DeathPipe.cpp",
"utils/CameraServiceProxyWrapper.cpp",
"utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
@@ -136,6 +143,7 @@
"libhidlbase",
"libimage_io",
"libjpeg",
+ "libjpegrecoverymap",
"libmedia_codeclist",
"libmedia_omx",
"libmemunreachable",
@@ -150,6 +158,9 @@
"android.frameworks.cameraservice.service@2.2",
"android.frameworks.cameraservice.device@2.0",
"android.frameworks.cameraservice.device@2.1",
+ "android.frameworks.cameraservice.common-V1-ndk",
+ "android.frameworks.cameraservice.service-V1-ndk",
+ "android.frameworks.cameraservice.device-V1-ndk",
"android.hardware.camera.common@1.0",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 0213623..c812cd7 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -33,9 +33,11 @@
#include <android/hardware/ICamera.h>
#include <android/hardware/ICameraClient.h>
+#include <aidl/AidlCameraService.h>
#include <android-base/macros.h>
#include <android-base/parseint.h>
#include <android-base/stringprintf.h>
+#include <android/permission/PermissionChecker.h>
#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
@@ -80,6 +82,9 @@
namespace {
const char* kPermissionServiceName = "permission";
+ const char* kActivityServiceName = "activity";
+ const char* kSensorPrivacyServiceName = "sensor_privacy";
+ const char* kAppopsServiceName = "appops";
}; // namespace anonymous
namespace android {
@@ -88,6 +93,7 @@
using binder::Status;
using namespace camera3;
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
+using frameworks::cameraservice::service::implementation::AidlCameraService;
using hardware::ICamera;
using hardware::ICameraClient;
using hardware::ICameraServiceListener;
@@ -165,6 +171,20 @@
return (CameraThreadState::getCallingUid() < AID_APP_START);
}
+// Enable processes with isolated AID to request the binder
+void CameraService::instantiate() {
+ CameraService::publish(true);
+}
+
+void CameraService::onServiceRegistration(const String16& name, const sp<IBinder>&) {
+ if (name != String16(kAppopsServiceName)) {
+ return;
+ }
+
+ ALOGV("appops service registered. setting camera audio restriction");
+ mAppOps.setCameraAudioRestriction(mAudioRestriction);
+}
+
void CameraService::onFirstRef()
{
@@ -189,13 +209,30 @@
mSensorPrivacyPolicy = new SensorPrivacyPolicy(this);
mSensorPrivacyPolicy->registerSelf();
mInjectionStatusListener = new InjectionStatusListener(this);
- mAppOps.setCameraAudioRestriction(mAudioRestriction);
+
+ // appops function setCamerAudioRestriction uses getService which
+ // is blocking till the appops service is ready. To enable early
+ // boot availability for cameraservice, use checkService which is
+ // non blocking and register for notifications
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(String16(kAppopsServiceName));
+ if (!binder) {
+ sm->registerForNotifications(String16(kAppopsServiceName), this);
+ } else {
+ mAppOps.setCameraAudioRestriction(mAudioRestriction);
+ }
+
sp<HidlCameraService> hcs = HidlCameraService::getInstance(this);
if (hcs->registerAsService() != android::OK) {
- ALOGE("%s: Failed to register default android.frameworks.cameraservice.service@1.0",
+ // Deprecated, so it will fail to register on newer devices
+ ALOGW("%s: Did not register default android.frameworks.cameraservice.service@2.2",
__FUNCTION__);
}
+ if (!AidlCameraService::registerService(this)) {
+ ALOGE("%s: Failed to register default AIDL VNDK CameraService", __FUNCTION__);
+ }
+
// This needs to be last call in this function, so that it's as close to
// ServiceManager::addService() as possible.
mCameraServiceProxyWrapper->pingCameraServiceProxy();
@@ -660,11 +697,18 @@
broadcastTorchModeStatus(cameraId, newStatus, systemCameraKind);
}
-static bool hasPermissionsForSystemCamera(int callingPid, int callingUid,
- bool logPermissionFailure = false) {
- return checkPermission(sSystemCameraPermission, callingPid, callingUid,
- logPermissionFailure) &&
- checkPermission(sCameraPermission, callingPid, callingUid);
+static bool hasPermissionsForSystemCamera(int callingPid, int callingUid) {
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+ attributionSource.pid = callingPid;
+ attributionSource.uid = callingUid;
+ bool checkPermissionForSystemCamera = permissionChecker.checkPermissionForPreflight(
+ sSystemCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
+ bool checkPermissionForCamera = permissionChecker.checkPermissionForPreflight(
+ sCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
+ return checkPermissionForSystemCamera && checkPermissionForCamera;
}
Status CameraService::getNumberOfCameras(int32_t type, int32_t* numCameras) {
@@ -743,8 +787,14 @@
const std::vector<std::string> *deviceIds = &mNormalDeviceIdsWithoutSystemCamera;
auto callingPid = CameraThreadState::getCallingPid();
auto callingUid = CameraThreadState::getCallingUid();
- if (checkPermission(sSystemCameraPermission, callingPid, callingUid,
- /*logPermissionFailure*/false) || getpid() == callingPid) {
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+ attributionSource.pid = callingPid;
+ attributionSource.uid = callingUid;
+ bool checkPermissionForSystemCamera = permissionChecker.checkPermissionForPreflight(
+ sSystemCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
+ if (checkPermissionForSystemCamera || getpid() == callingPid) {
deviceIds = &mNormalDeviceIds;
}
if (cameraIdInt < 0 || cameraIdInt >= static_cast<int>(deviceIds->size())) {
@@ -815,9 +865,16 @@
// If it's not calling from cameraserver, check the permission only if
// android.permission.CAMERA is required. If android.permission.SYSTEM_CAMERA was needed,
// it would've already been checked in shouldRejectSystemCameraConnection.
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+ attributionSource.pid = callingPid;
+ attributionSource.uid = callingUid;
+ bool checkPermissionForCamera = permissionChecker.checkPermissionForPreflight(
+ sCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
if ((callingPid != getpid()) &&
(deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
- !checkPermission(sCameraPermission, callingPid, callingUid)) {
+ !checkPermissionForCamera) {
res = cameraInfo->removePermissionEntries(
mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
&tagsRemoved);
@@ -1251,6 +1308,9 @@
Status CameraService::validateClientPermissionsLocked(const String8& cameraId,
const String8& clientName8, int& clientUid, int& clientPid,
/*out*/int& originalClientPid) const {
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+
int callingPid = CameraThreadState::getCallingPid();
int callingUid = CameraThreadState::getCallingUid();
@@ -1297,9 +1357,14 @@
// If it's not calling from cameraserver, check the permission if the
// device isn't a system only camera (shouldRejectSystemCameraConnection already checks for
// android.permission.SYSTEM_CAMERA for system only camera devices).
+ attributionSource.pid = clientPid;
+ attributionSource.uid = clientUid;
+ attributionSource.packageName = clientName8;
+ bool checkPermissionForCamera = permissionChecker.checkPermissionForPreflight(
+ sCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
if (callingPid != getpid() &&
- (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) &&
- !checkPermission(sCameraPermission, clientPid, clientUid)) {
+ (deviceKind != SystemCameraKind::SYSTEM_ONLY_CAMERA) && !checkPermissionForCamera) {
ALOGE("Permission Denial: can't use the camera pid=%d, uid=%d", clientPid, clientUid);
return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
"Caller \"%s\" (PID %d, UID %d) cannot open camera \"%s\" without camera permission",
@@ -1688,7 +1753,7 @@
// characteristics) even if clients don't have android.permission.CAMERA. We do not want the
// same behavior for system camera devices.
if (!systemClient && systemCameraKind == SystemCameraKind::SYSTEM_ONLY_CAMERA &&
- !hasPermissionsForSystemCamera(cPid, cUid, /*logPermissionFailure*/true)) {
+ !hasPermissionsForSystemCamera(cPid, cUid)) {
ALOGW("Rejecting access to system only camera %s, inadequete permissions",
cameraId.c_str());
return true;
@@ -2067,6 +2132,7 @@
}
client->setImageDumpMask(mImageDumpMask);
+ client->setStreamUseCaseOverrides(mStreamUseCaseOverrides);
} // lock is destroyed, allow further connect calls
// Important: release the mutex here so the client can call back into the service from its
@@ -2641,7 +2707,14 @@
// Check for camera permissions
int callingPid = CameraThreadState::getCallingPid();
int callingUid = CameraThreadState::getCallingUid();
- if ((callingPid != getpid()) && !checkPermission(sCameraPermission, callingPid, callingUid)) {
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+ attributionSource.pid = callingPid;
+ attributionSource.uid = callingUid;
+ bool checkPermissionForCamera = permissionChecker.checkPermissionForPreflight(
+ sCameraPermission, attributionSource, String16(), AppOpsManager::OP_NONE)
+ != permission::PermissionChecker::PERMISSION_HARD_DENIED;
+ if ((callingPid != getpid()) && !checkPermissionForCamera) {
ALOGE("%s: pid %d doesn't have camera permissions", __FUNCTION__, callingPid);
return STATUS_ERROR(ERROR_PERMISSION_DENIED,
"android.permission.CAMERA needed to call"
@@ -2688,8 +2761,13 @@
auto clientUid = CameraThreadState::getCallingUid();
auto clientPid = CameraThreadState::getCallingPid();
- bool openCloseCallbackAllowed = checkPermission(sCameraOpenCloseListenerPermission,
- clientPid, clientUid, /*logPermissionFailure*/false);
+ permission::PermissionChecker permissionChecker;
+ AttributionSourceState attributionSource{};
+ attributionSource.uid = clientUid;
+ attributionSource.pid = clientPid;
+ bool openCloseCallbackAllowed = permissionChecker.checkPermissionForPreflight(
+ sCameraOpenCloseListenerPermission, attributionSource, String16(),
+ AppOpsManager::OP_NONE) != permission::PermissionChecker::PERMISSION_HARD_DENIED;
Mutex::Autolock lock(mServiceLock);
@@ -3525,6 +3603,11 @@
mClientPackageName);
bool isCameraPrivacyEnabled =
sCameraService->mSensorPrivacyPolicy->isCameraPrivacyEnabled();
+ // We don't want to return EACCESS if the CameraPrivacy is enabled.
+ // We prefer to successfully open the camera and perform camera muting
+ // or blocking in connectHelper as handleAppOpMode can be called before the
+ // connection has been fully established and at that time camera muting
+ // capabilities are unknown.
if (!isUidActive || !isCameraPrivacyEnabled) {
ALOGI("Camera %s: Access for \"%s\" has been restricted",
mCameraIdStr.string(), String8(mClientPackageName).string());
@@ -3779,7 +3862,7 @@
// UidPolicy
// ----------------------------------------------------------------------------
-void CameraService::UidPolicy::registerSelf() {
+void CameraService::UidPolicy::registerWithActivityManager() {
Mutex::Autolock _l(mUidLock);
if (mRegistered) return;
@@ -3796,6 +3879,27 @@
}
}
+void CameraService::UidPolicy::onServiceRegistration(const String16& name, const sp<IBinder>&) {
+ if (name != String16(kActivityServiceName)) {
+ return;
+ }
+
+ registerWithActivityManager();
+}
+
+void CameraService::UidPolicy::registerSelf() {
+ // Use check service to see if the activity service is available
+ // If not available then register for notifications, instead of blocking
+ // till the service is ready
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(String16(kActivityServiceName));
+ if (!binder) {
+ sm->registerForNotifications(String16(kActivityServiceName), this);
+ } else {
+ registerWithActivityManager();
+ }
+}
+
void CameraService::UidPolicy::unregisterSelf() {
Mutex::Autolock _l(mUidLock);
@@ -4009,7 +4113,9 @@
// ----------------------------------------------------------------------------
// SensorPrivacyPolicy
// ----------------------------------------------------------------------------
-void CameraService::SensorPrivacyPolicy::registerSelf() {
+
+void CameraService::SensorPrivacyPolicy::registerWithSensorPrivacyManager()
+{
Mutex::Autolock _l(mSensorPrivacyLock);
if (mRegistered) {
return;
@@ -4024,6 +4130,27 @@
}
}
+void CameraService::SensorPrivacyPolicy::onServiceRegistration(const String16& name,
+ const sp<IBinder>&) {
+ if (name != String16(kSensorPrivacyServiceName)) {
+ return;
+ }
+
+ registerWithSensorPrivacyManager();
+}
+
+void CameraService::SensorPrivacyPolicy::registerSelf() {
+ // Use checkservice to see if the sensor_privacy service is available
+ // If service is not available then register for notification
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(String16(kSensorPrivacyServiceName));
+ if (!binder) {
+ sm->registerForNotifications(String16(kSensorPrivacyServiceName),this);
+ } else {
+ registerWithSensorPrivacyManager();
+ }
+}
+
void CameraService::SensorPrivacyPolicy::unregisterSelf() {
Mutex::Autolock _l(mSensorPrivacyLock);
mSpm.removeSensorPrivacyListener(this);
@@ -4033,6 +4160,10 @@
}
bool CameraService::SensorPrivacyPolicy::isSensorPrivacyEnabled() {
+ if (!mRegistered) {
+ registerWithSensorPrivacyManager();
+ }
+
Mutex::Autolock _l(mSensorPrivacyLock);
return mSensorPrivacyEnabled;
}
@@ -4445,6 +4576,13 @@
String8 activeClientString = mActiveClientManager.toString();
dprintf(fd, "Active Camera Clients:\n%s", activeClientString.string());
dprintf(fd, "Allowed user IDs: %s\n", toString(mAllowedUsers).string());
+ if (mStreamUseCaseOverrides.size() > 0) {
+ dprintf(fd, "Active stream use case overrides:");
+ for (int64_t useCaseOverride : mStreamUseCaseOverrides) {
+ dprintf(fd, " %" PRId64, useCaseOverride);
+ }
+ dprintf(fd, "\n");
+ }
dumpEventLog(fd);
@@ -4948,6 +5086,11 @@
return handleGetImageDumpMask(out);
} else if (args.size() >= 2 && args[0] == String16("set-camera-mute")) {
return handleSetCameraMute(args);
+ } else if (args.size() >= 2 && args[0] == String16("set-stream-use-case-override")) {
+ return handleSetStreamUseCaseOverrides(args);
+ } else if (args.size() >= 1 && args[0] == String16("clear-stream-use-case-override")) {
+ handleClearStreamUseCaseOverrides();
+ return OK;
} else if (args.size() >= 2 && args[0] == String16("watch")) {
return handleWatchCommand(args, in, out);
} else if (args.size() >= 2 && args[0] == String16("set-watchdog")) {
@@ -5154,6 +5297,43 @@
return OK;
}
+status_t CameraService::handleSetStreamUseCaseOverrides(const Vector<String16>& args) {
+ std::vector<int64_t> useCasesOverride;
+ for (size_t i = 1; i < args.size(); i++) {
+ int64_t useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ String8 arg8 = String8(args[i]);
+ if (arg8 == "DEFAULT") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT;
+ } else if (arg8 == "PREVIEW") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW;
+ } else if (arg8 == "STILL_CAPTURE") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE;
+ } else if (arg8 == "VIDEO_RECORD") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD;
+ } else if (arg8 == "PREVIEW_VIDEO_STILL") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL;
+ } else if (arg8 == "VIDEO_CALL") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL;
+ } else if (arg8 == "CROPPED_RAW") {
+ useCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW;
+ } else {
+ ALOGE("%s: Invalid stream use case %s", __FUNCTION__, arg8.c_str());
+ return BAD_VALUE;
+ }
+ useCasesOverride.push_back(useCase);
+ }
+
+ Mutex::Autolock lock(mServiceLock);
+ mStreamUseCaseOverrides = std::move(useCasesOverride);
+
+ return OK;
+}
+
+void CameraService::handleClearStreamUseCaseOverrides() {
+ Mutex::Autolock lock(mServiceLock);
+ mStreamUseCaseOverrides.clear();
+}
+
status_t CameraService::handleWatchCommand(const Vector<String16>& args, int inFd, int outFd) {
if (args.size() >= 3 && args[1] == String16("start")) {
return startWatchingTags(args, outFd);
@@ -5511,6 +5691,15 @@
" Valid values 0=OFF, 1=ON for JPEG\n"
" get-image-dump-mask returns the current image-dump-mask value\n"
" set-camera-mute <0/1> enable or disable camera muting\n"
+ " set-stream-use-case-override <usecase1> <usecase2> ... override stream use cases\n"
+ " Use cases applied in descending resolutions. So usecase1 is assigned to the\n"
+ " largest resolution, usecase2 is assigned to the 2nd largest resolution, and so\n"
+ " on. In case the number of usecases is smaller than the number of streams, the\n"
+ " last use case is assigned to all the remaining streams. In case of multiple\n"
+ " streams with the same resolution, the tie-breaker is (JPEG, RAW, YUV, and PRIV)\n"
+ " Valid values are (case sensitive): DEFAULT, PREVIEW, STILL_CAPTURE, VIDEO_RECORD,\n"
+ " PREVIEW_VIDEO_STILL, VIDEO_CALL, CROPPED_RAW\n"
+ " clear-stream-use-case-override clear the stream use case override\n"
" watch <start|stop|dump|print|clear> manages tag monitoring in connected clients\n"
" help print this message\n");
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 4f92f15..59c5534 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -71,7 +71,8 @@
public BinderService<CameraService>,
public virtual ::android::hardware::BnCameraService,
public virtual IBinder::DeathRecipient,
- public virtual CameraProviderManager::StatusListener
+ public virtual CameraProviderManager::StatusListener,
+ public virtual IServiceManager::LocalRegistrationCallback
{
friend class BinderService<CameraService>;
friend class CameraOfflineSessionClient;
@@ -98,9 +99,15 @@
// Event log ID
static const int SN_EVENT_LOG_ID = 0x534e4554;
+ // Register camera service
+ static void instantiate();
+
// Implementation of BinderService<T>
static char const* getServiceName() { return "media.camera"; }
+ // Implementation of IServiceManager::LocalRegistrationCallback
+ virtual void onServiceRegistration(const String16& name, const sp<IBinder>& binder) override;
+
// Non-null arguments for cameraServiceProxyWrapper should be provided for
// testing purposes only.
CameraService(std::shared_ptr<CameraServiceProxyWrapper>
@@ -355,6 +362,13 @@
// Set Camera service watchdog
virtual status_t setCameraServiceWatchdog(bool enabled) = 0;
+ // Set stream use case overrides
+ virtual void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) = 0;
+
+ // Clear stream use case overrides
+ virtual void clearStreamUseCaseOverrides() = 0;
+
// The injection camera session to replace the internal camera
// session.
virtual status_t injectCamera(const String8& injectedCamId,
@@ -707,7 +721,10 @@
// Observer for UID lifecycle enforcing that UIDs in idle
// state cannot use the camera to protect user privacy.
- class UidPolicy : public BnUidObserver, public virtual IBinder::DeathRecipient {
+ class UidPolicy :
+ public BnUidObserver,
+ public virtual IBinder::DeathRecipient,
+ public virtual IServiceManager::LocalRegistrationCallback {
public:
explicit UidPolicy(sp<CameraService> service)
: mRegistered(false), mService(service) {}
@@ -732,12 +749,16 @@
void registerMonitorUid(uid_t uid);
void unregisterMonitorUid(uid_t uid);
+ // Implementation of IServiceManager::LocalRegistrationCallback
+ virtual void onServiceRegistration(const String16& name,
+ const sp<IBinder>& binder) override;
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
private:
bool isUidActiveLocked(uid_t uid, String16 callingPackage);
int32_t getProcStateLocked(uid_t uid);
void updateOverrideUid(uid_t uid, String16 callingPackage, bool active, bool insert);
+ void registerWithActivityManager();
struct MonitoredUid {
int32_t procState;
@@ -757,7 +778,8 @@
// If sensor privacy is enabled then all apps, including those that are active, should be
// prevented from accessing the camera.
class SensorPrivacyPolicy : public hardware::BnSensorPrivacyListener,
- public virtual IBinder::DeathRecipient {
+ public virtual IBinder::DeathRecipient,
+ public virtual IServiceManager::LocalRegistrationCallback {
public:
explicit SensorPrivacyPolicy(wp<CameraService> service)
: mService(service), mSensorPrivacyEnabled(false), mRegistered(false) {}
@@ -771,6 +793,9 @@
binder::Status onSensorPrivacyChanged(int toggleType, int sensor,
bool enabled);
+ // Implementation of IServiceManager::LocalRegistrationCallback
+ virtual void onServiceRegistration(const String16& name,
+ const sp<IBinder>& binder) override;
// IBinder::DeathRecipient implementation
virtual void binderDied(const wp<IBinder> &who);
@@ -782,6 +807,7 @@
bool mRegistered;
bool hasCameraPrivacyFeature();
+ void registerWithSensorPrivacyManager();
};
sp<UidPolicy> mUidPolicy;
@@ -1257,6 +1283,12 @@
// Set the camera mute state
status_t handleSetCameraMute(const Vector<String16>& args);
+ // Set the stream use case overrides
+ status_t handleSetStreamUseCaseOverrides(const Vector<String16>& args);
+
+ // Clear the stream use case overrides
+ void handleClearStreamUseCaseOverrides();
+
// Handle 'watch' command as passed through 'cmd'
status_t handleWatchCommand(const Vector<String16> &args, int inFd, int outFd);
@@ -1355,6 +1387,9 @@
// Camera Service watchdog flag
bool mCameraServiceWatchdogEnabled = true;
+ // Current stream use case overrides
+ std::vector<int64_t> mStreamUseCaseOverrides;
+
/**
* A listener class that implements the IBinder::DeathRecipient interface
* for use to call back the error state injected by the external camera, and
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
index 74497d1..e80064a 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.cpp
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "CameraServiceWatchdog"
#include "CameraServiceWatchdog.h"
+#include "utils/CameraServiceProxyWrapper.h"
namespace android {
@@ -43,6 +44,8 @@
if (tidToCycleCounterMap[currentThreadId] >= mMaxCycles) {
ALOGW("CameraServiceWatchdog triggering abort for pid: %d tid: %d", getpid(),
currentThreadId);
+ mCameraServiceProxyWrapper->logClose(mCameraId, 0 /*latencyMs*/,
+ true /*deviceError*/);
// We use abort here so we can get a tombstone for better
// debugging.
abort();
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
index e35d69e..6617873 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.h
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -32,10 +32,13 @@
#include <chrono>
#include <thread>
#include <time.h>
+#include <utils/String8.h>
#include <utils/Thread.h>
#include <utils/Log.h>
#include <unordered_map>
+#include "utils/CameraServiceProxyWrapper.h"
+
// Used to wrap the call of interest in start and stop calls
#define WATCH(toMonitor) watchThread([&]() { return toMonitor;}, gettid())
#define WATCH_CUSTOM_TIMER(toMonitor, cycles, cycleLength) \
@@ -50,12 +53,18 @@
class CameraServiceWatchdog : public Thread {
public:
- explicit CameraServiceWatchdog() : mPause(true), mMaxCycles(kMaxCycles),
- mCycleLengthMs(kCycleLengthMs), mEnabled(true) {};
+ explicit CameraServiceWatchdog(const String8 &cameraId,
+ std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
+ mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
+ mCycleLengthMs(kCycleLengthMs), mEnabled(true),
+ mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
- explicit CameraServiceWatchdog (size_t maxCycles, uint32_t cycleLengthMs, bool enabled) :
- mPause(true), mMaxCycles(maxCycles), mCycleLengthMs(cycleLengthMs), mEnabled(enabled)
- {};
+ explicit CameraServiceWatchdog (const String8 &cameraId, size_t maxCycles,
+ uint32_t cycleLengthMs, bool enabled,
+ std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
+ mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
+ mCycleLengthMs(cycleLengthMs), mEnabled(enabled),
+ mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
virtual ~CameraServiceWatchdog() {};
@@ -75,8 +84,8 @@
// Lock for mEnabled
mEnabledLock.lock();
- sp<CameraServiceWatchdog> tempWatchdog =
- new CameraServiceWatchdog(cycles, cycleLength, mEnabled);
+ sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog(
+ mCameraId, cycles, cycleLength, mEnabled, mCameraServiceProxyWrapper);
mEnabledLock.unlock();
status_t status = tempWatchdog->run("CameraServiceWatchdog");
@@ -134,11 +143,14 @@
Mutex mWatchdogLock; // Lock for condition variable
Mutex mEnabledLock; // Lock for enabled status
Condition mWatchdogCondition; // Condition variable for stop/start
+ String8 mCameraId; // Camera Id the watchdog belongs to
bool mPause; // True if tid map is empty
uint32_t mMaxCycles; // Max cycles
uint32_t mCycleLengthMs; // Length of time elapsed per cycle
bool mEnabled; // True if watchdog is enabled
+ std::shared_ptr<CameraServiceProxyWrapper> mCameraServiceProxyWrapper;
+
std::unordered_map<uint32_t, uint32_t> tidToCycleCounterMap; // Thread Id to cycle counter map
};
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
new file mode 100644
index 0000000..4c6d6f6
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlCameraDeviceCallbacks"
+
+#include <aidl/AidlCameraDeviceCallbacks.h>
+#include <aidl/AidlUtils.h>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <hidl/Utils.h>
+#include <utility>
+
+namespace android::frameworks::cameraservice::device::implementation {
+
+// VNDK classes
+using SCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using SCaptureResultExtras =
+ ::aidl::android::frameworks::cameraservice::device::CaptureResultExtras;
+using SPhysicalCaptureResultInfo =
+ ::aidl::android::frameworks::cameraservice::device::PhysicalCaptureResultInfo;
+using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
+// NDK classes
+using UCaptureResultExtras = ::android::hardware::camera2::impl::CaptureResultExtras;
+using UPhysicalCaptureResultInfo = ::android::hardware::camera2::impl::PhysicalCaptureResultInfo;
+
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
+
+const char *AidlCameraDeviceCallbacks::kResultKey = "CaptureResult";
+
+
+bool AidlCameraDeviceCallbacks::initializeLooper(int vndkVersion) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("cs-looper");
+ status_t err = mCbLooper->start(/*runOnCallingThread*/ false, /*canCallJava*/ false,
+ PRIORITY_DEFAULT);
+ if (err !=OK) {
+ ALOGE("Unable to start camera device callback looper");
+ return false;
+ }
+ mHandler = new CallbackHandler(this, vndkVersion);
+ mCbLooper->registerHandler(mHandler);
+ return true;
+}
+
+AidlCameraDeviceCallbacks::AidlCameraDeviceCallbacks(
+ const std::shared_ptr<SICameraDeviceCallback>& base):
+ mBase(base), mDeathPipe(this, base->asBinder()) {}
+
+AidlCameraDeviceCallbacks::~AidlCameraDeviceCallbacks() {
+ if (mCbLooper != nullptr) {
+ if (mHandler != nullptr) {
+ mCbLooper->unregisterHandler(mHandler->id());
+ }
+ mCbLooper->stop();
+ }
+ mCbLooper.clear();
+ mHandler.clear();
+}
+
+binder::Status AidlCameraDeviceCallbacks::onDeviceError(
+ int32_t errorCode, const CaptureResultExtras& resultExtras) {
+ using hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+ SCaptureResultExtras cre = convertToAidl(resultExtras);
+ auto ret = mBase->onDeviceError(convertToAidl(errorCode), cre);
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onDeviceError")
+ return binder::Status::ok();
+}
+
+binder::Status AidlCameraDeviceCallbacks::onDeviceIdle() {
+ auto ret = mBase->onDeviceIdle();
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onDeviceIdle")
+ return binder::Status::ok();
+}
+
+binder::Status AidlCameraDeviceCallbacks::onCaptureStarted(
+ const CaptureResultExtras& resultExtras, int64_t timestamp) {
+ using hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+ SCaptureResultExtras hCaptureResultExtras = convertToAidl(resultExtras);
+ auto ret = mBase->onCaptureStarted(hCaptureResultExtras, timestamp);
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onCaptureStarted")
+ return binder::Status::ok();
+}
+
+void AidlCameraDeviceCallbacks::convertResultMetadataToAidl(const camera_metadata_t* src,
+ SCaptureMetadataInfo* dst) {
+ // First try writing to fmq.
+ size_t metadata_size = get_camera_metadata_size(src);
+ if ((metadata_size > 0) &&
+ (mCaptureResultMetadataQueue->availableToWrite() > 0)) {
+ if (mCaptureResultMetadataQueue->write((int8_t *)src, metadata_size)) {
+ dst->set<SCaptureMetadataInfo::fmqMetadataSize>(metadata_size);
+ } else {
+ ALOGW("%s Couldn't use fmq, falling back to hwbinder", __FUNCTION__);
+ SCameraMetadata metadata;
+ hardware::cameraservice::utils::conversion::aidl::cloneToAidl(src, &metadata);
+ dst->set<SCaptureMetadataInfo::metadata>(std::move(metadata));
+ }
+ }
+}
+
+void AidlCameraDeviceCallbacks::CallbackHandler::onMessageReceived(const sp<AMessage> &msg) {
+ sp<RefBase> obj = nullptr;
+ sp<ResultWrapper> resultWrapper = nullptr;
+ bool found = false;
+ switch (msg->what()) {
+ case kWhatResultReceived:
+ found = msg->findObject(kResultKey, &obj);
+ if (!found || obj == nullptr) {
+ ALOGE("Cannot find result object in callback message");
+ return;
+ }
+ resultWrapper = static_cast<ResultWrapper*>(obj.get());
+ processResultMessage(resultWrapper);
+ break;
+ default:
+ ALOGE("Unknown callback sent");
+ break;
+ }
+ }
+
+void AidlCameraDeviceCallbacks::CallbackHandler::processResultMessage(
+ sp<ResultWrapper> &resultWrapper) {
+ sp<AidlCameraDeviceCallbacks> converter = mConverter.promote();
+ if (converter == nullptr) {
+ ALOGE("Callback wrapper has died, result callback cannot be made");
+ return;
+ }
+ CameraMetadataNative &result = resultWrapper->mResult;
+ auto resultExtras = resultWrapper->mResultExtras;
+ SCaptureResultExtras convResultExtras =
+ hardware::cameraservice::utils::conversion::aidl::convertToAidl(resultExtras);
+
+ // Convert Metadata into HCameraMetadata;
+ SCaptureMetadataInfo captureMetadataInfo;
+ if (filterVndkKeys(mVndkVersion, result, /*isStatic*/false) != OK) {
+ ALOGE("%s: filtering vndk keys from result failed, not sending onResultReceived callback",
+ __FUNCTION__);
+ return;
+ }
+ const camera_metadata_t *rawMetadata = result.getAndLock();
+ converter->convertResultMetadataToAidl(rawMetadata, &captureMetadataInfo);
+ result.unlock(rawMetadata);
+
+ auto &physicalCaptureResultInfos = resultWrapper->mPhysicalCaptureResultInfos;
+ std::vector<SPhysicalCaptureResultInfo> stableCaptureResInfo =
+ convertToAidl(physicalCaptureResultInfos, converter->mCaptureResultMetadataQueue);
+ auto ret = converter->mBase->onResultReceived(captureMetadataInfo,
+ convResultExtras,
+ stableCaptureResInfo);
+
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "OnResultReceived")
+}
+
+binder::Status AidlCameraDeviceCallbacks::onResultReceived(
+ const CameraMetadataNative& result,
+ const UCaptureResultExtras& resultExtras,
+ const ::std::vector<UPhysicalCaptureResultInfo>& physicalCaptureResultInfos) {
+ // Wrap CameraMetadata, resultExtras and physicalCaptureResultInfos in on
+ // sp<RefBase>-able structure and post it.
+ sp<ResultWrapper> resultWrapper = new ResultWrapper(const_cast<CameraMetadataNative &>(result),
+ resultExtras, physicalCaptureResultInfos);
+ sp<AMessage> msg = new AMessage(kWhatResultReceived, mHandler);
+ msg->setObject(kResultKey, resultWrapper);
+ msg->post();
+ return binder::Status::ok();
+}
+
+binder::Status AidlCameraDeviceCallbacks::onPrepared(int32_t) {
+ // not implemented
+ return binder::Status::ok();
+}
+
+binder::Status AidlCameraDeviceCallbacks::onRepeatingRequestError(
+ int64_t lastFrameNumber,
+ int32_t repeatingRequestId) {
+ auto ret =
+ mBase->onRepeatingRequestError(lastFrameNumber, repeatingRequestId);
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onRepeatingRequestError")
+ return binder::Status::ok();
+}
+binder::Status AidlCameraDeviceCallbacks::onRequestQueueEmpty() {
+ // not implemented
+ return binder::Status::ok();
+}
+
+status_t AidlCameraDeviceCallbacks::linkToDeath(const sp<DeathRecipient>& recipient,
+ void* cookie, uint32_t flags) {
+ return mDeathPipe.linkToDeath(recipient, cookie, flags);
+}
+status_t AidlCameraDeviceCallbacks::unlinkToDeath(const wp<DeathRecipient>& recipient,
+ void* cookie,
+ uint32_t flags,
+ wp<DeathRecipient>* outRecipient) {
+ return mDeathPipe.unlinkToDeath(recipient, cookie, flags, outRecipient);
+}
+
+} // namespace android::frameworks::cameraservice::device::implementation
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
new file mode 100644
index 0000000..5cff5b3
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceCallbacks.h
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICECALLBACKS_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICECALLBACKS_H_
+
+#include <CameraService.h>
+#include <aidl/DeathPipe.h>
+#include <aidl/android/frameworks/cameraservice/device/BnCameraDeviceCallback.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCaptureResultInfo.h>
+#include <android/hardware/camera2/BnCameraDeviceCallbacks.h>
+#include <fmq/AidlMessageQueue.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <mutex>
+#include <thread>
+#include <utility>
+
+namespace android::frameworks::cameraservice::device::implementation {
+
+// VNDK classes
+using SCaptureMetadataInfo = ::aidl::android::frameworks::cameraservice::device::CaptureMetadataInfo;
+using SICameraDeviceCallback =
+ ::aidl::android::frameworks::cameraservice::device::ICameraDeviceCallback;
+// NDK classes
+using UBnCameraDeviceCallbacks = ::android::hardware::camera2::BnCameraDeviceCallbacks;
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::frameworks::cameraservice::utils::DeathPipe;
+using ::android::hardware::camera2::impl::CameraMetadataNative;
+
+using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
+class AidlCameraDeviceCallbacks : public UBnCameraDeviceCallbacks {
+ public:
+ explicit AidlCameraDeviceCallbacks(const std::shared_ptr<SICameraDeviceCallback>& base);
+
+ ~AidlCameraDeviceCallbacks() override;
+
+ bool initializeLooper(int vndkVersion);
+
+ binder::Status onDeviceError(int32_t errorCode,
+ const CaptureResultExtras& resultExtras) override;
+
+ binder::Status onDeviceIdle() override;
+
+ binder::Status onCaptureStarted(const CaptureResultExtras& resultExtras,
+ int64_t timestamp) override;
+
+ binder::Status onResultReceived(
+ const CameraMetadataNative& result, const CaptureResultExtras& resultExtras,
+ const std::vector<PhysicalCaptureResultInfo>& physicalCaptureResultInfos) override;
+
+ binder::Status onPrepared(int32_t streamId) override;
+
+ binder::Status onRepeatingRequestError(int64_t lastFrameNumber,
+ int32_t repeatingRequestId) override;
+
+ binder::Status onRequestQueueEmpty() override;
+
+ status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie,
+ uint32_t flags) override;
+ status_t unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient) override;
+
+ void setCaptureResultMetadataQueue(std::shared_ptr<CaptureResultMetadataQueue> metadataQueue) {
+ mCaptureResultMetadataQueue = std::move(metadataQueue);
+ }
+
+ private:
+ // Wrapper struct so that parameters to onResultReceived callback may be
+ // sent through an AMessage.
+ struct ResultWrapper : public RefBase {
+ CameraMetadataNative mResult;
+ CaptureResultExtras mResultExtras;
+ std::vector<PhysicalCaptureResultInfo> mPhysicalCaptureResultInfos;
+
+ ResultWrapper(CameraMetadataNative &result,
+ CaptureResultExtras resultExtras,
+ std::vector<PhysicalCaptureResultInfo> physicalCaptureResultInfos) :
+ // TODO: make this std::movable
+ mResult(result),
+ mResultExtras(std::move(resultExtras)),
+ mPhysicalCaptureResultInfos(std::move(physicalCaptureResultInfos)) { }
+ };
+
+ struct CallbackHandler : public AHandler {
+ public:
+ void onMessageReceived(const sp<AMessage> &msg) override;
+ CallbackHandler(AidlCameraDeviceCallbacks *converter, int vndkVersion) :
+ mConverter(converter), mVndkVersion(vndkVersion) { }
+ private:
+ void processResultMessage(sp<ResultWrapper> &resultWrapper);
+ wp<AidlCameraDeviceCallbacks> mConverter = nullptr;
+ int mVndkVersion = -1;
+ };
+
+ void convertResultMetadataToAidl(const camera_metadata * src, SCaptureMetadataInfo * dst);
+ enum {
+ kWhatResultReceived,
+ };
+
+ static const char *kResultKey;
+
+ private:
+ std::shared_ptr<SICameraDeviceCallback> mBase;
+ std::shared_ptr<CaptureResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
+ sp<CallbackHandler> mHandler = nullptr;
+ sp<ALooper> mCbLooper = nullptr;
+
+ // Pipes death subscription from current NDK interface to VNDK mBase.
+ // Should consume calls to linkToDeath and unlinkToDeath.
+ DeathPipe mDeathPipe;
+};
+
+} // namespace android::frameworks::cameraservice::device::implementation
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICECALLBACKS_H_
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
new file mode 100644
index 0000000..d9ec0b6
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlCameraDeviceUser"
+
+#include "AidlCameraDeviceUser.h"
+#include <aidl/AidlUtils.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
+
+namespace android::frameworks::cameraservice::device::implementation {
+
+// VNDK classes
+using SCaptureMetadataInfo = ::aidl::android::frameworks::cameraservice::device::CaptureMetadataInfo;
+// NDK classes
+using UOutputConfiguration = ::android::hardware::camera2::params::OutputConfiguration;
+using USessionConfiguration = ::android::hardware::camera2::params::SessionConfiguration;
+using UStatus = ::android::binder::Status;
+using USubmitInfo = ::android::hardware::camera2::utils::SubmitInfo;
+
+using ::android::CameraMetadata;
+using ::android::hardware::cameraservice::utils::conversion::aidl::cloneFromAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::cloneToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertFromAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+using ::ndk::ScopedAStatus;
+
+namespace {
+constexpr int32_t CAMERA_REQUEST_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;
+constexpr int32_t CAMERA_RESULT_METADATA_QUEUE_SIZE = 1 << 20 /* 1 MB */;
+
+inline ScopedAStatus fromSStatus(const SStatus& s) {
+ return s == SStatus::NO_ERROR ? ScopedAStatus::ok()
+ : ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(s));
+}
+inline ScopedAStatus fromUStatus(const UStatus& status) {
+ return status.isOk() ? ScopedAStatus::ok() : fromSStatus(convertToAidl(status));
+}
+} // anonymous namespace
+
+AidlCameraDeviceUser::AidlCameraDeviceUser(const sp<UICameraDeviceUser>& deviceRemote):
+ mDeviceRemote(deviceRemote) {
+ mInitSuccess = initDevice();
+}
+bool AidlCameraDeviceUser::initDevice() {
+ // TODO: Get request and result metadata queue size from a system property.
+ int32_t reqFMQSize = CAMERA_REQUEST_METADATA_QUEUE_SIZE;
+
+ mCaptureRequestMetadataQueue =
+ std::make_unique<CaptureRequestMetadataQueue>(static_cast<size_t>(reqFMQSize),
+ false /* non blocking */);
+ if (!mCaptureRequestMetadataQueue->isValid()) {
+ ALOGE("%s: invalid request fmq", __FUNCTION__);
+ return false;
+ }
+
+ int32_t resFMQSize = CAMERA_RESULT_METADATA_QUEUE_SIZE;
+ mCaptureResultMetadataQueue =
+ std::make_shared<CaptureResultMetadataQueue>(static_cast<size_t>(resFMQSize),
+ false /* non blocking */);
+ if (!mCaptureResultMetadataQueue->isValid()) {
+ ALOGE("%s: invalid result fmq", __FUNCTION__);
+ return false;
+ }
+ return true;
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::getCaptureRequestMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+ if (mInitSuccess) {
+ *_aidl_return = mCaptureRequestMetadataQueue->dupeDesc();
+ }
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) {
+ if (mInitSuccess) {
+ *_aidl_return = mCaptureResultMetadataQueue->dupeDesc();
+ }
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::submitRequestList(
+ const std::vector<SCaptureRequest>& in_requestList, bool in_isRepeating,
+ SSubmitInfo* _aidl_return) {
+ USubmitInfo submitInfo;
+ std::vector<UCaptureRequest> requests;
+ for (const auto& req: in_requestList) {
+ requests.emplace_back();
+ if (!convertRequestFromAidl(req, &requests.back())) {
+ ALOGE("%s: Failed to convert AIDL CaptureRequest.", __FUNCTION__);
+ return fromSStatus(SStatus::ILLEGAL_ARGUMENT);
+ }
+ }
+ UStatus ret = mDeviceRemote->submitRequestList(requests,
+ in_isRepeating, &submitInfo);
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed submitRequestList to cameraservice: %s",
+ __FUNCTION__, ret.toString8().string());
+ return fromUStatus(ret);
+ }
+ mRequestId = submitInfo.mRequestId;
+ convertToAidl(submitInfo, _aidl_return);
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::cancelRepeatingRequest(int64_t* _aidl_return) {
+ UStatus ret = mDeviceRemote->cancelRequest(mRequestId, _aidl_return);
+ return fromUStatus(ret);
+}
+
+ScopedAStatus AidlCameraDeviceUser::beginConfigure() {
+ UStatus ret = mDeviceRemote->beginConfigure();
+ return fromUStatus(ret);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::endConfigure(SStreamConfigurationMode in_operatingMode,
+ const SCameraMetadata& in_sessionParams,
+ int64_t in_startTimeNs) {
+ CameraMetadata metadata;
+ if (!cloneFromAidl(in_sessionParams, &metadata)) {
+ return fromSStatus(SStatus::ILLEGAL_ARGUMENT);
+ }
+
+ std::vector<int32_t> offlineStreamIds;
+ UStatus ret = mDeviceRemote->endConfigure(convertFromAidl(in_operatingMode),
+ metadata, in_startTimeNs,
+ &offlineStreamIds);
+ return fromUStatus(ret);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::createStream(
+ const SOutputConfiguration& in_outputConfiguration, int32_t* _aidl_return) {
+ UOutputConfiguration outputConfig = convertFromAidl(in_outputConfiguration);
+ int32_t newStreamId;
+ UStatus ret = mDeviceRemote->createStream(outputConfig, &newStreamId);
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed to create stream: %s", __FUNCTION__, ret.toString8().string());
+ }
+ *_aidl_return = newStreamId;
+ return fromUStatus(ret);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::createDefaultRequest(STemplateId in_templateId,
+ SCameraMetadata* _aidl_return) {
+ CameraMetadata metadata;
+ UStatus ret = mDeviceRemote->createDefaultRequest(convertFromAidl(in_templateId),
+ &metadata);
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed to create default request: %s", __FUNCTION__, ret.toString8().string());
+ return fromUStatus(ret);
+ }
+ const camera_metadata_t* rawMetadata = metadata.getAndLock();
+ cloneToAidl(rawMetadata, _aidl_return);
+ metadata.unlock(rawMetadata);
+ return ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::waitUntilIdle() {
+ UStatus ret = mDeviceRemote->waitUntilIdle();
+ return fromUStatus(ret);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::flush(int64_t* _aidl_return) {
+ UStatus ret = mDeviceRemote->flush(_aidl_return);
+ return fromUStatus(ret);
+}
+
+ndk::ScopedAStatus AidlCameraDeviceUser::updateOutputConfiguration(
+ int32_t in_streamId, const SOutputConfiguration& in_outputConfiguration) {
+ UOutputConfiguration outputConfig = convertFromAidl(in_outputConfiguration);
+ UStatus ret = mDeviceRemote->updateOutputConfiguration(in_streamId, outputConfig);
+ if (!ret.isOk()) {
+ ALOGE("%s: Failed to update output config for stream id: %d: %s",
+ __FUNCTION__, in_streamId, ret.toString8().string());
+ }
+ return fromUStatus(ret);
+}
+ndk::ScopedAStatus AidlCameraDeviceUser::isSessionConfigurationSupported(
+ const SSessionConfiguration& in_sessionConfiguration, bool* _aidl_return) {
+ USessionConfiguration sessionConfig = convertFromAidl(in_sessionConfiguration);
+ UStatus ret = mDeviceRemote->isSessionConfigurationSupported(sessionConfig,
+ _aidl_return);
+ return fromUStatus(ret);
+}
+ndk::ScopedAStatus AidlCameraDeviceUser::deleteStream(int32_t in_streamId) {
+ UStatus ret = mDeviceRemote->deleteStream(in_streamId);
+ return fromUStatus(ret);
+}
+ndk::ScopedAStatus AidlCameraDeviceUser::disconnect() {
+ UStatus ret = mDeviceRemote->disconnect();
+ return fromUStatus(ret);
+}
+bool AidlCameraDeviceUser::convertRequestFromAidl(
+ const SCaptureRequest& src, UCaptureRequest* dst) {
+ dst->mIsReprocess = false;
+ for (const auto& streamAndWindowId : src.streamAndWindowIds) {
+ dst->mStreamIdxList.push_back(streamAndWindowId.streamId);
+ dst->mSurfaceIdxList.push_back(streamAndWindowId.windowId);
+ }
+
+ return copyPhysicalCameraSettings(src.physicalCameraSettings,
+ &(dst->mPhysicalCameraSettings));
+}
+bool AidlCameraDeviceUser::copyPhysicalCameraSettings(
+ const std::vector<SPhysicalCameraSettings>& src,
+ std::vector<UCaptureRequest::PhysicalCameraSettings>* dst) {
+ bool converted = false;
+ for (auto &e : src) {
+ dst->emplace_back();
+ CaptureRequest::PhysicalCameraSettings &physicalCameraSetting =
+ dst->back();
+ physicalCameraSetting.id = e.id;
+
+ // Read the settings either from the fmq or straightaway from the
+ // request. We don't need any synchronization, since submitRequestList
+ // is guaranteed to be called serially by the client if it decides to
+ // use fmq.
+ if (e.settings.getTag() == SCaptureMetadataInfo::fmqMetadataSize) {
+ /**
+ * Get settings from the fmq.
+ */
+ SCameraMetadata settingsFmq;
+ int64_t metadataSize = e.settings.get<SCaptureMetadataInfo::fmqMetadataSize>();
+ settingsFmq.metadata.resize(metadataSize);
+ int8_t* metadataPtr = (int8_t*) settingsFmq.metadata.data();
+ bool read = mCaptureRequestMetadataQueue->read(metadataPtr,
+ metadataSize);
+ if (!read) {
+ ALOGE("%s capture request settings could't be read from fmq size", __FUNCTION__);
+ converted = false;
+ } else {
+ converted = cloneFromAidl(settingsFmq, &physicalCameraSetting.settings);
+ }
+ } else {
+ /**
+ * The settings metadata is contained in request settings field.
+ */
+ converted = cloneFromAidl(e.settings.get<SCaptureMetadataInfo::metadata>(),
+ &physicalCameraSetting.settings);
+ }
+ if (!converted) {
+ ALOGE("%s: Unable to convert physicalCameraSettings from HIDL to AIDL.", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+} // namespace android::frameworks::cameraservice::device::implementation
\ No newline at end of file
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
new file mode 100644
index 0000000..41a3f43
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICEUSER_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICEUSER_H_
+
+#include <CameraService.h>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/device/BnCameraDeviceUser.h>
+#include <aidl/android/frameworks/cameraservice/device/CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/device/OutputConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCameraSettings.h>
+#include <aidl/android/frameworks/cameraservice/device/SessionConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/StreamConfigurationMode.h>
+#include <aidl/android/frameworks/cameraservice/device/SubmitInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/TemplateId.h>
+#include <aidl/android/hardware/common/fmq/MQDescriptor.h>
+#include <android/hardware/camera2/ICameraDeviceCallbacks.h>
+#include <fmq/AidlMessageQueue.h>
+#include <memory>
+
+namespace android::frameworks::cameraservice::device::implementation {
+
+using ::aidl::android::hardware::common::fmq::MQDescriptor;
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using CaptureRequestMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
+// Stable NDK classes
+using SBnCameraDeviceUser = ::aidl::android::frameworks::cameraservice::device::BnCameraDeviceUser;
+using SCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using SCaptureRequest = ::aidl::android::frameworks::cameraservice::device::CaptureRequest;
+using SOutputConfiguration =
+ ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
+using SPhysicalCameraSettings =
+ ::aidl::android::frameworks::cameraservice::device::PhysicalCameraSettings;
+using SSessionConfiguration =
+ ::aidl::android::frameworks::cameraservice::device::SessionConfiguration;
+using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
+using SStreamConfigurationMode =
+ ::aidl::android::frameworks::cameraservice::device::StreamConfigurationMode;
+using SSubmitInfo = ::aidl::android::frameworks::cameraservice::device::SubmitInfo;
+using STemplateId = ::aidl::android::frameworks::cameraservice::device::TemplateId;
+// Unstable NDK classes
+using UCaptureRequest= ::android::hardware::camera2::CaptureRequest;
+using UICameraDeviceUser = ::android::hardware::camera2::ICameraDeviceUser;
+
+static constexpr int32_t REQUEST_ID_NONE = -1;
+
+class AidlCameraDeviceUser final : public SBnCameraDeviceUser {
+ public:
+ explicit AidlCameraDeviceUser(const sp<UICameraDeviceUser> &deviceRemote);
+ ~AidlCameraDeviceUser() override = default;
+
+ ndk::ScopedAStatus beginConfigure() override;
+ ndk::ScopedAStatus cancelRepeatingRequest(int64_t* _aidl_return) override;
+ ndk::ScopedAStatus createDefaultRequest(STemplateId in_templateId,
+ SCameraMetadata* _aidl_return) override;
+ ndk::ScopedAStatus createStream(const SOutputConfiguration& in_outputConfiguration,
+ int32_t* _aidl_return) override;
+ ndk::ScopedAStatus deleteStream(int32_t in_streamId) override;
+ ndk::ScopedAStatus disconnect() override;
+ ndk::ScopedAStatus endConfigure(SStreamConfigurationMode in_operatingMode,
+ const SCameraMetadata& in_sessionParams,
+ int64_t in_startTimeNs) override;
+ ndk::ScopedAStatus flush(int64_t* _aidl_return) override;
+ ndk::ScopedAStatus getCaptureRequestMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+ ndk::ScopedAStatus getCaptureResultMetadataQueue(
+ MQDescriptor<int8_t, SynchronizedReadWrite>* _aidl_return) override;
+ ndk::ScopedAStatus isSessionConfigurationSupported(
+ const SSessionConfiguration& in_sessionConfiguration, bool* _aidl_return) override;
+ ndk::ScopedAStatus submitRequestList(const std::vector<SCaptureRequest>& in_requestList,
+ bool in_isRepeating, SSubmitInfo* _aidl_return) override;
+ ndk::ScopedAStatus updateOutputConfiguration(
+ int32_t in_streamId, const SOutputConfiguration& in_outputConfiguration) override;
+ ndk::ScopedAStatus waitUntilIdle() override;
+
+ [[nodiscard]] bool initStatus() const { return mInitSuccess; }
+
+ std::shared_ptr<CaptureResultMetadataQueue> getCaptureResultMetadataQueue() {
+ return mCaptureResultMetadataQueue;
+ }
+
+ private:
+ bool initDevice();
+
+ bool convertRequestFromAidl(const SCaptureRequest &src, UCaptureRequest *dst);
+ bool copyPhysicalCameraSettings(const std::vector<SPhysicalCameraSettings> &src,
+ std::vector<CaptureRequest::PhysicalCameraSettings> *dst);
+
+ const sp<UICameraDeviceUser> mDeviceRemote;
+ std::unique_ptr<CaptureRequestMetadataQueue> mCaptureRequestMetadataQueue = nullptr;
+ std::shared_ptr<CaptureResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
+ bool mInitSuccess = false;
+ int32_t mRequestId = REQUEST_ID_NONE;
+};
+
+} // namespace android::frameworks::cameraservice::device::implementation
+
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERADEVICEUSER_H_
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
new file mode 100644
index 0000000..4232a81
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlCameraService"
+
+#include "AidlCameraService.h"
+#include <aidl/AidlCameraDeviceCallbacks.h>
+#include <aidl/AidlCameraDeviceUser.h>
+#include <aidl/AidlCameraServiceListener.h>
+#include <aidl/AidlUtils.h>
+#include <aidl/android/frameworks/cameraservice/common/CameraMetadataType.h>
+#include <android-base/properties.h>
+#include <android/binder_ibinder.h>
+#include <android/binder_manager.h>
+#include <binder/Status.h>
+#include <hidl/HidlTransportSupport.h>
+
+namespace android::frameworks::cameraservice::service::implementation {
+
+using ::android::frameworks::cameraservice::device::implementation::AidlCameraDeviceCallbacks;
+using ::android::frameworks::cameraservice::device::implementation::AidlCameraDeviceUser;
+using ::android::hardware::cameraservice::utils::conversion::aidl::areBindersEqual;
+using ::android::hardware::cameraservice::utils::conversion::aidl::cloneToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
+using ::ndk::ScopedAStatus;
+
+// VNDK classes
+using SCameraMetadataType = ::aidl::android::frameworks::cameraservice::common::CameraMetadataType;
+using SVendorTag = ::aidl::android::frameworks::cameraservice::common::VendorTag;
+using SVendorTagSection = ::aidl::android::frameworks::cameraservice::common::VendorTagSection;
+// NDK classes
+using UICameraService = ::android::hardware::ICameraService;
+using UStatus = ::android::binder::Status;
+
+namespace {
+inline ScopedAStatus fromSStatus(const SStatus& s) {
+ return s == SStatus::NO_ERROR ? ScopedAStatus::ok()
+ : ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(s));
+}
+inline ScopedAStatus fromUStatus(const UStatus& s) {
+ return s.isOk() ? ScopedAStatus::ok() : fromSStatus(convertToAidl(s));
+}
+} // anonymous namespace
+
+std::shared_ptr<AidlCameraService> kCameraService;
+
+bool AidlCameraService::registerService(::android::CameraService* cameraService) {
+ kCameraService = SharedRefBase::make<AidlCameraService>(cameraService);
+ std::string serviceName = SBnCameraService::descriptor;
+ serviceName += "/default";
+ bool isDeclared = AServiceManager_isDeclared(serviceName.c_str());
+ if (!isDeclared) {
+ ALOGI("%s: AIDL vndk not declared.", __FUNCTION__);
+ return false;
+ }
+
+ binder_exception_t registered = AServiceManager_addService(
+ kCameraService->asBinder().get(), serviceName.c_str());
+ ALOGE_IF(registered != EX_NONE,
+ "%s: AIDL VNDK declared, but failed to register service: %d",
+ __FUNCTION__, registered);
+ return registered == EX_NONE;
+}
+
+AidlCameraService::AidlCameraService(::android::CameraService* cameraService):
+ mCameraService(cameraService) {
+ mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+}
+ScopedAStatus AidlCameraService::getCameraCharacteristics(const std::string& in_cameraId,
+ SCameraMetadata* _aidl_return) {
+ if (_aidl_return == nullptr) { return fromSStatus(SStatus::ILLEGAL_ARGUMENT); }
+
+ ::android::CameraMetadata cameraMetadata;
+ UStatus ret = mCameraService->getCameraCharacteristics(String16(in_cameraId.c_str()),
+ mVndkVersion,
+ /* overrideToPortrait= */ false,
+ &cameraMetadata);
+ if (!ret.isOk()) {
+ if (ret.exceptionCode() != EX_SERVICE_SPECIFIC) {
+ ALOGE("%s: Transaction error when getting camera characteristics"
+ " from camera service: %d.",
+ __FUNCTION__ , ret.exceptionCode());
+ return fromUStatus(ret);
+ }
+ switch (ret.serviceSpecificErrorCode()) {
+ case UICameraService::ERROR_ILLEGAL_ARGUMENT:
+ ALOGE("%s: Camera ID %s does not exist!", __FUNCTION__, in_cameraId.c_str());
+ return fromSStatus(SStatus::ILLEGAL_ARGUMENT);
+ default:
+ ALOGE("Get camera characteristics from camera service failed: %s",
+ ret.toString8().string());
+ return fromUStatus(ret);
+ }
+ }
+
+ if (filterVndkKeys(mVndkVersion, cameraMetadata) != OK) {
+ ALOGE("%s: Unable to filter vndk metadata keys for version %d",
+ __FUNCTION__, mVndkVersion);
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+
+ const camera_metadata_t* rawMetadata = cameraMetadata.getAndLock();
+ cloneToAidl(rawMetadata, _aidl_return);
+ cameraMetadata.unlock(rawMetadata);
+
+ return ScopedAStatus::ok();
+}
+ndk::ScopedAStatus AidlCameraService::connectDevice(
+ const std::shared_ptr<SICameraDeviceCallback>& in_callback,
+ const std::string& in_cameraId,
+ std::shared_ptr<SICameraDeviceUser>* _aidl_return) {
+ // Here, we first get NDK ICameraDeviceUser from mCameraService, then save
+ // that interface in the newly created AidlCameraDeviceUser impl class.
+ if (mCameraService == nullptr) {
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+ sp<hardware::camera2::ICameraDeviceUser> unstableDevice = nullptr;
+ // Create a hardware::camera2::ICameraDeviceCallback object which internally
+ // calls callback functions passed through hCallback.
+ sp<AidlCameraDeviceCallbacks> hybridCallbacks = new AidlCameraDeviceCallbacks(in_callback);
+ if (!hybridCallbacks->initializeLooper(mVndkVersion)) {
+ ALOGE("Unable to handle callbacks on device, cannot connect");
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+ sp<hardware::camera2::ICameraDeviceCallbacks> callbacks = hybridCallbacks;
+ binder::Status serviceRet = mCameraService->connectDevice(
+ callbacks,
+ String16(in_cameraId.c_str()),
+ String16(""),
+ /* clientFeatureId= */{},
+ hardware::ICameraService::USE_CALLING_UID,
+ /* scoreOffset= */ 0,
+ /* targetSdkVersion= */ __ANDROID_API_FUTURE__,
+ /* overrideToPortrait= */ false,
+ &unstableDevice);
+ if (!serviceRet.isOk()) {
+ ALOGE("%s: Unable to connect to camera device: %s", __FUNCTION__,
+ serviceRet.toString8().c_str());
+ return fromUStatus(serviceRet);
+ }
+
+ // Now we create a AidlCameraDeviceUser class, store the unstableDevice in it,
+ // and return that back. All calls on that interface will be forwarded to
+ // the NDK AIDL interface.
+ std::shared_ptr<AidlCameraDeviceUser> stableDevice =
+ ndk::SharedRefBase::make<AidlCameraDeviceUser>(unstableDevice);
+ if (!stableDevice->initStatus()) {
+ ALOGE("%s: Unable to initialize camera device AIDL wrapper", __FUNCTION__);
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+ hybridCallbacks->setCaptureResultMetadataQueue(
+ stableDevice->getCaptureResultMetadataQueue());
+ *_aidl_return = stableDevice;
+ return ScopedAStatus::ok();
+}
+void AidlCameraService::addToListenerCacheLocked(
+ std::shared_ptr<SICameraServiceListener> stableCsListener,
+ sp<UICameraServiceListener> csListener) {
+ mListeners.emplace_back(std::make_pair(stableCsListener, csListener));
+}
+sp<UICameraServiceListener> AidlCameraService::searchListenerCacheLocked(
+ const std::shared_ptr<SICameraServiceListener>& listener, bool removeIfFound) {
+ // Go through the mListeners list and compare the listener with the VNDK AIDL
+ // listener registered.
+ if (listener == nullptr) {
+ return nullptr;
+ }
+
+ auto it = mListeners.begin();
+ sp<UICameraServiceListener> csListener = nullptr;
+ for (;it != mListeners.end(); it++) {
+ if (areBindersEqual(listener->asBinder(), it->first->asBinder())) {
+ break;
+ }
+ }
+ if (it != mListeners.end()) {
+ csListener = it->second;
+ if (removeIfFound) {
+ mListeners.erase(it);
+ }
+ }
+ return csListener;
+}
+ndk::ScopedAStatus AidlCameraService::addListener(
+ const std::shared_ptr<SICameraServiceListener>& in_listener,
+ std::vector<SCameraStatusAndId>* _aidl_return) {
+ std::vector<hardware::CameraStatus> cameraStatusAndIds{};
+ SStatus status = addListenerInternal(
+ in_listener, &cameraStatusAndIds);
+ if (status != SStatus::NO_ERROR) {
+ return fromSStatus(status);
+ }
+
+ // Convert cameraStatusAndIds to VNDK AIDL
+ convertToAidl(cameraStatusAndIds, _aidl_return);
+ return ScopedAStatus::ok();
+}
+SStatus AidlCameraService::addListenerInternal(
+ const std::shared_ptr<SICameraServiceListener>& listener,
+ std::vector<hardware::CameraStatus>* cameraStatusAndIds) {
+ if (mCameraService == nullptr) {
+ return SStatus::UNKNOWN_ERROR;
+ }
+ if (listener == nullptr || cameraStatusAndIds == nullptr) {
+ ALOGE("%s listener and cameraStatusAndIds must not be NULL", __FUNCTION__);
+ return SStatus::ILLEGAL_ARGUMENT;
+ }
+ sp<UICameraServiceListener> csListener = nullptr;
+ // Check the cache for previously registered callbacks
+ {
+ Mutex::Autolock l(mListenerListLock);
+ csListener = searchListenerCacheLocked(listener);
+ if (csListener == nullptr) {
+ // Wrap a listener with AidlCameraServiceListener and pass it to
+ // CameraService.
+ csListener = sp<AidlCameraServiceListener>::make(listener);
+ // Add to cache
+ addToListenerCacheLocked(listener, csListener);
+ } else {
+ ALOGE("%s: Trying to add a listener %p already registered",
+ __FUNCTION__, listener.get());
+ return SStatus::ILLEGAL_ARGUMENT;
+ }
+ }
+ binder::Status serviceRet =
+ mCameraService->addListenerHelper(csListener, cameraStatusAndIds, true);
+ if (!serviceRet.isOk()) {
+ ALOGE("%s: Unable to add camera device status listener", __FUNCTION__);
+ return convertToAidl(serviceRet);
+ }
+
+ cameraStatusAndIds->erase(std::remove_if(cameraStatusAndIds->begin(),
+ cameraStatusAndIds->end(),
+ [this](const hardware::CameraStatus& s) {
+ bool supportsHAL3 = false;
+ binder::Status sRet =
+ mCameraService->supportsCameraApi(String16(s.cameraId),
+ UICameraService::API_VERSION_2, &supportsHAL3);
+ return !sRet.isOk() || !supportsHAL3;
+ }), cameraStatusAndIds->end());
+
+ return SStatus::NO_ERROR;
+}
+ndk::ScopedAStatus AidlCameraService::removeListener(
+ const std::shared_ptr<SICameraServiceListener>& in_listener) {
+ if (in_listener == nullptr) {
+ ALOGE("%s listener must not be NULL", __FUNCTION__);
+ return fromSStatus(SStatus::ILLEGAL_ARGUMENT);
+ }
+ sp<UICameraServiceListener> csListener = nullptr;
+ {
+ Mutex::Autolock l(mListenerListLock);
+ csListener = searchListenerCacheLocked(in_listener, /*removeIfFound*/true);
+ }
+ if (csListener != nullptr) {
+ mCameraService->removeListener(csListener);
+ } else {
+ ALOGE("%s Removing unregistered listener %p", __FUNCTION__, in_listener.get());
+ return fromSStatus(SStatus::ILLEGAL_ARGUMENT);
+ }
+ return ScopedAStatus::ok();
+}
+ndk::ScopedAStatus AidlCameraService::getCameraVendorTagSections(
+ std::vector<SProviderIdAndVendorTagSections>* _aidl_return) {
+ sp<VendorTagDescriptorCache> gCache = VendorTagDescriptorCache::getGlobalVendorTagCache();
+ if (gCache == nullptr) {
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+
+ const std::unordered_map<metadata_vendor_id_t, sp<android::VendorTagDescriptor>>
+ &vendorIdsAndTagDescs = gCache->getVendorIdsAndTagDescriptors();
+ if (vendorIdsAndTagDescs.empty()) {
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+
+ std::vector<SProviderIdAndVendorTagSections>& tagIdAndVendorTagSections = *_aidl_return;
+ tagIdAndVendorTagSections.resize(vendorIdsAndTagDescs.size());
+ size_t j = 0;
+ for (auto &vendorIdAndTagDescs : vendorIdsAndTagDescs) {
+ std::vector<SVendorTagSection> vendorTagSections;
+ sp<VendorTagDescriptor> desc = vendorIdAndTagDescs.second;
+ const SortedVector<String8>* sectionNames = desc->getAllSectionNames();
+ size_t numSections = sectionNames->size();
+ std::vector<std::vector<SVendorTag>> tagsBySection(numSections);
+ int tagCount = desc->getTagCount();
+ if (tagCount <= 0) {
+ continue;
+ }
+ std::vector<uint32_t> tags(tagCount);
+ desc->getTagArray(tags.data());
+ for (int i = 0; i < tagCount; i++) {
+ SVendorTag vt;
+ vt.tagId = tags[i];
+ vt.tagName = desc->getTagName(tags[i]);
+ vt.tagType = (SCameraMetadataType) desc->getTagType(tags[i]);
+ ssize_t sectionIdx = desc->getSectionIndex(tags[i]);
+ tagsBySection[sectionIdx].push_back(vt);
+ }
+ vendorTagSections.resize(numSections);
+ for (size_t s = 0; s < numSections; s++) {
+ vendorTagSections[s].sectionName = (*sectionNames)[s].string();
+ vendorTagSections[s].tags = tagsBySection[s];
+ }
+ SProviderIdAndVendorTagSections & prvdrIdAndVendorTagSection =
+ tagIdAndVendorTagSections[j];
+ prvdrIdAndVendorTagSection.providerId = vendorIdAndTagDescs.first;
+ prvdrIdAndVendorTagSection.vendorTagSections = std::move(vendorTagSections);
+ j++;
+ }
+ return ScopedAStatus::ok();
+}
+
+} // namespace android::frameworks::cameraservice::service::implementation
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.h b/services/camera/libcameraservice/aidl/AidlCameraService.h
new file mode 100644
index 0000000..4c67ac7
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.h
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICE_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICE_H_
+
+#include <CameraService.h>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/service/BnCameraService.h>
+
+namespace android::frameworks::cameraservice::service::implementation {
+
+// VNDK classes
+using SBnCameraService = ::aidl::android::frameworks::cameraservice::service::BnCameraService;
+using SCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using SCameraStatusAndId = ::aidl::android::frameworks::cameraservice::service::CameraStatusAndId;
+using SICameraDeviceCallback =
+ ::aidl::android::frameworks::cameraservice::device::ICameraDeviceCallback;
+using SICameraDeviceUser = ::aidl::android::frameworks::cameraservice::device::ICameraDeviceUser;
+using SICameraServiceListener =
+ ::aidl::android::frameworks::cameraservice::service::ICameraServiceListener;
+using SProviderIdAndVendorTagSections =
+ ::aidl::android::frameworks::cameraservice::common::ProviderIdAndVendorTagSections;
+using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
+// NDK classes
+using UICameraServiceListener = ::android::hardware::ICameraServiceListener;
+
+class AidlCameraService: public SBnCameraService {
+ public:
+ static bool registerService(::android::CameraService* cameraService);
+
+ explicit AidlCameraService(::android::CameraService* cameraService);
+ ~AidlCameraService() override = default;
+ ndk::ScopedAStatus getCameraCharacteristics(const std::string& in_cameraId,
+ SCameraMetadata* _aidl_return) override;
+
+ ndk::ScopedAStatus connectDevice(const std::shared_ptr<SICameraDeviceCallback>& in_callback,
+ const std::string& in_cameraId,
+ std::shared_ptr<SICameraDeviceUser>* _aidl_return) override;
+
+ ndk::ScopedAStatus addListener(const std::shared_ptr<SICameraServiceListener>& in_listener,
+ std::vector<SCameraStatusAndId>* _aidl_return) override;
+
+ ndk::ScopedAStatus getCameraVendorTagSections(
+ std::vector<SProviderIdAndVendorTagSections>* _aidl_return) override;
+
+ ndk::ScopedAStatus removeListener(
+ const std::shared_ptr<SICameraServiceListener>& in_listener) override;
+
+ private:
+ void addToListenerCacheLocked(std::shared_ptr<SICameraServiceListener> stableCsListener,
+ sp<hardware::ICameraServiceListener> csListener);
+
+ sp<UICameraServiceListener> searchListenerCacheLocked(
+ const std::shared_ptr<SICameraServiceListener>& listener, bool removeIfFound = false);
+
+ SStatus addListenerInternal(const std::shared_ptr<SICameraServiceListener>& listener,
+ std::vector<hardware::CameraStatus>* cameraStatusAndIds);
+
+
+ ::android::CameraService* mCameraService;
+
+ Mutex mListenerListLock;
+ std::list<std::pair<std::shared_ptr<SICameraServiceListener>,
+ sp<UICameraServiceListener>>> mListeners;
+ int mVndkVersion = -1;
+
+};
+
+} // namespace android::frameworks::cameraservice::service::implementation
+
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICE_H_
diff --git a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp
new file mode 100644
index 0000000..e183063
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.cpp
@@ -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.
+ */
+
+#include <aidl/AidlCameraServiceListener.h>
+#include <aidl/AidlUtils.h>
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraStatusAndId.h>
+
+namespace android::frameworks::cameraservice::service::implementation {
+
+using ::android::hardware::cameraservice::utils::conversion::aidl::convertCameraStatusToAidl;
+// VNDK classes
+using SCameraStatusAndId = ::aidl::android::frameworks::cameraservice::service::CameraStatusAndId;
+using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
+
+binder::Status AidlCameraServiceListener::onStatusChanged(
+ int32_t status, const ::android::String16& cameraId) {
+ SCameraDeviceStatus sStatus = convertCameraStatusToAidl(status);
+ std::string sCameraId = String8(cameraId).string();
+ auto ret = mBase->onStatusChanged(sStatus, sCameraId);
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onStatusChanged")
+ return binder::Status::ok();
+}
+
+binder::Status AidlCameraServiceListener::onPhysicalCameraStatusChanged(
+ int32_t status, const ::android::String16& cameraId,
+ const ::android::String16& physicalCameraId) {
+ SCameraDeviceStatus sStatus = convertCameraStatusToAidl(status);
+ std::string sCameraId = String8(cameraId).string();
+ std::string sPhysicalCameraId = String8(physicalCameraId).string();
+
+ auto ret = mBase->onPhysicalCameraStatusChanged(sStatus, sCameraId, sPhysicalCameraId);
+ LOG_STATUS_ERROR_IF_NOT_OK(ret, "onPhysicalCameraStatusChanged")
+ return binder::Status::ok();
+}
+
+::android::binder::Status AidlCameraServiceListener::onTorchStatusChanged(
+ int32_t, const ::android::String16&) {
+ // We don't implement onTorchStatusChanged
+ return binder::Status::ok();
+}
+
+::android::binder::Status AidlCameraServiceListener::onTorchStrengthLevelChanged(
+ const ::android::String16&, int32_t) {
+ // We don't implement onTorchStrengthLevelChanged
+ return binder::Status::ok();
+}
+status_t AidlCameraServiceListener::linkToDeath(const sp<DeathRecipient>& recipient, void* cookie,
+ uint32_t flags) {
+ return mDeathPipe.linkToDeath(recipient, cookie, flags);
+}
+status_t AidlCameraServiceListener::unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie,
+ uint32_t flags,
+ wp<DeathRecipient>* outRecipient) {
+ return mDeathPipe.unlinkToDeath(recipient, cookie, flags, outRecipient);
+}
+
+} // namespace android::frameworks::cameraservice::service::implementation
diff --git a/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
new file mode 100644
index 0000000..906dd8e
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlCameraServiceListener.h
@@ -0,0 +1,86 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICELISTENER_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICELISTENER_H_
+
+
+#include <aidl/DeathPipe.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraDeviceStatus.h>
+#include <aidl/android/frameworks/cameraservice/service/ICameraServiceListener.h>
+#include <android/hardware/BnCameraServiceListener.h>
+
+namespace android::frameworks::cameraservice::service::implementation {
+
+using ::android::frameworks::cameraservice::utils::DeathPipe;
+
+// VNDK classes
+using SCameraDeviceStatus = ::aidl::android::frameworks::cameraservice::service::CameraDeviceStatus;
+using SICameraServiceListener =
+ ::aidl::android::frameworks::cameraservice::service::ICameraServiceListener;
+// NDK classes
+using UBnCameraServiceListener = ::android::hardware::BnCameraServiceListener;
+
+/**
+ * A simple shim to pass calls from CameraService to VNDK client.
+ */
+class AidlCameraServiceListener : public UBnCameraServiceListener {
+ public:
+ AidlCameraServiceListener(const std::shared_ptr<SICameraServiceListener>& base):
+ mBase(base), mDeathPipe(this, base->asBinder()) {}
+
+ ~AidlCameraServiceListener() = default;
+
+ ::android::binder::Status onStatusChanged(int32_t status,
+ const ::android::String16& cameraId) override;
+ ::android::binder::Status onPhysicalCameraStatusChanged(int32_t status,
+ const ::android::String16& cameraId,
+ const ::android::String16& physicalCameraId) override;
+
+ ::android::binder::Status onTorchStatusChanged(
+ int32_t status, const ::android::String16& cameraId) override;
+ ::android::binder::Status onTorchStrengthLevelChanged(
+ const ::android::String16& cameraId, int32_t newStrengthLevel) override;
+ binder::Status onCameraAccessPrioritiesChanged() override {
+ // TODO: no implementation yet.
+ return binder::Status::ok();
+ }
+ binder::Status onCameraOpened(const ::android::String16& /*cameraId*/,
+ const ::android::String16& /*clientPackageId*/) override {
+ // empty implementation
+ return binder::Status::ok();
+ }
+ binder::Status onCameraClosed(const ::android::String16& /*cameraId*/) override {
+ // empty implementation
+ return binder::Status::ok();
+ }
+
+ status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie,
+ uint32_t flags) override;
+ status_t unlinkToDeath(const wp<DeathRecipient>& recipient, void* cookie, uint32_t flags,
+ wp<DeathRecipient>* outRecipient) override;
+
+ private:
+ std::shared_ptr<SICameraServiceListener> mBase;
+
+ // Pipes death subscription to current NDK AIDL interface to VNDK mBase.
+ // Should consume calls to linkToDeath and unlinkToDeath.
+ DeathPipe mDeathPipe;
+};
+
+} // android
+
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLCAMERASERVICELISTENER_H_
\ No newline at end of file
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
new file mode 100644
index 0000000..1b8e53b
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -0,0 +1,305 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AidlUtils"
+
+#include <aidl/AidlUtils.h>
+#include <aidl/VndkVersionMetadataTags.h>
+#include <aidlcommonsupport/NativeHandle.h>
+#include <device3/Camera3StreamInterface.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <mediautils/AImageReaderUtils.h>
+
+namespace android::hardware::cameraservice::utils::conversion::aidl {
+
+using aimg::AImageReader_getHGBPFromHandle;
+using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void cloneToAidl(const camera_metadata_t* src, SCameraMetadata* dst) {
+ if (src == nullptr) {
+ ALOGW("%s:attempt to convert empty metadata to AIDL", __FUNCTION__);
+ return;
+ }
+ size_t size = get_camera_metadata_size(src);
+ uint8_t* startPtr = (uint8_t*)src;
+ uint8_t* endPtr = startPtr + size;
+ dst->metadata.assign(startPtr, endPtr);
+}
+
+// The camera metadata here is cloned. Since we're reading metadata over
+// the binder we would need to clone it in order to avoid alignment issues.
+bool cloneFromAidl(const SCameraMetadata &src, CameraMetadata *dst) {
+ const camera_metadata_t *buffer =
+ reinterpret_cast<const camera_metadata_t*>(src.metadata.data());
+ size_t expectedSize = src.metadata.size();
+ if (buffer != nullptr) {
+ int res = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (res == OK || res == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ *dst = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ return false;
+ }
+ }
+ return true;
+}
+
+int32_t convertFromAidl(SStreamConfigurationMode streamConfigurationMode) {
+ switch (streamConfigurationMode) {
+ case SStreamConfigurationMode::CONSTRAINED_HIGH_SPEED_MODE:
+ return camera2::ICameraDeviceUser::CONSTRAINED_HIGH_SPEED_MODE;
+ case SStreamConfigurationMode::NORMAL_MODE:
+ return camera2::ICameraDeviceUser::NORMAL_MODE;
+ default:
+ // TODO: Fix this
+ return camera2::ICameraDeviceUser::VENDOR_MODE_START;
+ }
+}
+
+UOutputConfiguration convertFromAidl(const SOutputConfiguration &src) {
+ std::vector<sp<IGraphicBufferProducer>> iGBPs;
+ auto &windowHandles = src.windowHandles;
+ iGBPs.reserve(windowHandles.size());
+
+ for (auto &handle : windowHandles) {
+ native_handle_t* nh = makeFromAidl(handle);
+ iGBPs.push_back(new H2BGraphicBufferProducer(AImageReader_getHGBPFromHandle(nh)));
+ native_handle_delete(nh);
+ }
+ String16 physicalCameraId16(src.physicalCameraId.c_str());
+ UOutputConfiguration outputConfiguration(
+ iGBPs, convertFromAidl(src.rotation), physicalCameraId16,
+ src.windowGroupId, OutputConfiguration::SURFACE_TYPE_UNKNOWN, 0, 0,
+ (windowHandles.size() > 1));
+ return outputConfiguration;
+}
+
+USessionConfiguration convertFromAidl(const SSessionConfiguration &src) {
+ USessionConfiguration sessionConfig(src.inputWidth, src.inputHeight,
+ src.inputFormat, static_cast<int>(src.operationMode));
+
+ for (const auto& os : src.outputStreams) {
+ UOutputConfiguration config = convertFromAidl(os);
+ sessionConfig.addOutputConfiguration(config);
+ }
+
+ return sessionConfig;
+}
+
+int convertFromAidl(SOutputConfiguration::Rotation rotation) {
+ switch(rotation) {
+ case SOutputConfiguration::Rotation::R270:
+ return android::camera3::CAMERA_STREAM_ROTATION_270;
+ case SOutputConfiguration::Rotation::R180:
+ return android::camera3::CAMERA_STREAM_ROTATION_180;
+ case SOutputConfiguration::Rotation::R90:
+ return android::camera3::CAMERA_STREAM_ROTATION_90;
+ case SOutputConfiguration::Rotation::R0:
+ default:
+ return android::camera3::CAMERA_STREAM_ROTATION_0;
+ }
+}
+
+int32_t convertFromAidl(STemplateId templateId) {
+ switch(templateId) {
+ case STemplateId::PREVIEW:
+ return camera2::ICameraDeviceUser::TEMPLATE_PREVIEW;
+ case STemplateId::STILL_CAPTURE:
+ return camera2::ICameraDeviceUser::TEMPLATE_STILL_CAPTURE;
+ case STemplateId::RECORD:
+ return camera2::ICameraDeviceUser::TEMPLATE_RECORD;
+ case STemplateId::VIDEO_SNAPSHOT:
+ return camera2::ICameraDeviceUser::TEMPLATE_VIDEO_SNAPSHOT;
+ case STemplateId::ZERO_SHUTTER_LAG:
+ return camera2::ICameraDeviceUser::TEMPLATE_ZERO_SHUTTER_LAG;
+ case STemplateId::MANUAL:
+ return camera2::ICameraDeviceUser::TEMPLATE_MANUAL;
+ }
+}
+
+void convertToAidl(const camera2::utils::SubmitInfo& submitInfo, SSubmitInfo* hSubmitInfo) {
+ hSubmitInfo->requestId = submitInfo.mRequestId;
+ hSubmitInfo->lastFrameNumber = submitInfo.mLastFrameNumber;
+}
+
+
+SStatus convertToAidl(const binder::Status &status) {
+ if (status.isOk()) {
+ return SStatus::NO_ERROR;
+ }
+ if (status.exceptionCode() != EX_SERVICE_SPECIFIC) {
+ return SStatus::UNKNOWN_ERROR;
+ }
+
+ switch (status.serviceSpecificErrorCode()) {
+ case hardware::ICameraService::ERROR_DISCONNECTED:
+ return SStatus::DISCONNECTED;
+ case hardware::ICameraService::ERROR_CAMERA_IN_USE:
+ return SStatus::CAMERA_IN_USE;
+ case hardware::ICameraService::ERROR_MAX_CAMERAS_IN_USE:
+ return SStatus::MAX_CAMERAS_IN_USE;
+ case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
+ return SStatus::ILLEGAL_ARGUMENT;
+ case hardware::ICameraService::ERROR_DEPRECATED_HAL:
+ // Should not reach here since we filtered legacy HALs earlier
+ return SStatus::DEPRECATED_HAL;
+ case hardware::ICameraService::ERROR_DISABLED:
+ return SStatus::DISABLED;
+ case hardware::ICameraService::ERROR_PERMISSION_DENIED:
+ return SStatus::PERMISSION_DENIED;
+ case hardware::ICameraService::ERROR_INVALID_OPERATION:
+ return SStatus::INVALID_OPERATION;
+ default:
+ return SStatus::UNKNOWN_ERROR;
+ }
+}
+
+SCaptureResultExtras convertToAidl(const UCaptureResultExtras &src) {
+ SCaptureResultExtras dst;
+ dst.requestId = src.requestId;
+ dst.burstId = src.burstId;
+ dst.frameNumber = src.frameNumber;
+ dst.partialResultCount = src.partialResultCount;
+ dst.errorStreamId = src.errorStreamId;
+ dst.errorPhysicalCameraId = String8(src.errorPhysicalCameraId).string();
+ return dst;
+}
+
+SErrorCode convertToAidl(int32_t errorCode) {
+ switch(errorCode) {
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED:
+ return SErrorCode::CAMERA_DISCONNECTED;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE :
+ return SErrorCode::CAMERA_DEVICE;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE:
+ return SErrorCode::CAMERA_SERVICE;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_REQUEST:
+ return SErrorCode::CAMERA_REQUEST;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_RESULT:
+ return SErrorCode::CAMERA_RESULT;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_BUFFER:
+ return SErrorCode::CAMERA_BUFFER;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED:
+ return SErrorCode::CAMERA_DISABLED;
+ case camera2::ICameraDeviceCallbacks::ERROR_CAMERA_INVALID_ERROR:
+ return SErrorCode::CAMERA_INVALID_ERROR;
+ default:
+ return SErrorCode::CAMERA_UNKNOWN_ERROR;
+ }
+}
+
+std::vector<SPhysicalCaptureResultInfo> convertToAidl(
+ const std::vector<UPhysicalCaptureResultInfo>& src,
+ std::shared_ptr<CaptureResultMetadataQueue>& fmq) {
+ std::vector<SPhysicalCaptureResultInfo> dst;
+ dst.resize(src.size());
+ size_t i = 0;
+ for (auto &physicalCaptureResultInfo : src) {
+ dst[i++] = convertToAidl(physicalCaptureResultInfo, fmq);
+ }
+ return dst;
+}
+
+SPhysicalCaptureResultInfo convertToAidl(const UPhysicalCaptureResultInfo & src,
+ std::shared_ptr<CaptureResultMetadataQueue> & fmq) {
+ SPhysicalCaptureResultInfo dst;
+ dst.physicalCameraId = String8(src.mPhysicalCameraId).string();
+
+ const camera_metadata_t *rawMetadata = src.mPhysicalCameraMetadata.getAndLock();
+ // Try using fmq at first.
+ size_t metadata_size = get_camera_metadata_size(rawMetadata);
+ if ((metadata_size > 0) && (fmq->availableToWrite() > 0)) {
+ if (fmq->write((int8_t *)rawMetadata, metadata_size)) {
+ dst.physicalCameraMetadata.set<SCaptureMetadataInfo::fmqMetadataSize>(metadata_size);
+ } else {
+ ALOGW("%s Couldn't use fmq, falling back to hwbinder", __FUNCTION__);
+ SCameraMetadata metadata;
+ cloneToAidl(rawMetadata, &metadata);
+ dst.physicalCameraMetadata.set<SCaptureMetadataInfo::metadata>(std::move(metadata));
+ }
+ }
+ src.mPhysicalCameraMetadata.unlock(rawMetadata);
+ return dst;
+}
+
+void convertToAidl(const std::vector<hardware::CameraStatus> &src,
+ std::vector<SCameraStatusAndId>* dst) {
+ dst->resize(src.size());
+ size_t i = 0;
+ for (const auto &statusAndId : src) {
+ auto &a = (*dst)[i++];
+ a.cameraId = statusAndId.cameraId.c_str();
+ a.deviceStatus = convertCameraStatusToAidl(statusAndId.status);
+ size_t numUnvailPhysicalCameras = statusAndId.unavailablePhysicalIds.size();
+ a.unavailPhysicalCameraIds.resize(numUnvailPhysicalCameras);
+ for (size_t j = 0; j < numUnvailPhysicalCameras; j++) {
+ a.unavailPhysicalCameraIds[j] = statusAndId.unavailablePhysicalIds[j].c_str();
+ }
+ }
+}
+
+SCameraDeviceStatus convertCameraStatusToAidl(int32_t src) {
+ SCameraDeviceStatus deviceStatus = SCameraDeviceStatus::STATUS_UNKNOWN;
+ switch(src) {
+ case hardware::ICameraServiceListener::STATUS_NOT_PRESENT:
+ deviceStatus = SCameraDeviceStatus::STATUS_NOT_PRESENT;
+ break;
+ case hardware::ICameraServiceListener::STATUS_PRESENT:
+ deviceStatus = SCameraDeviceStatus::STATUS_PRESENT;
+ break;
+ case hardware::ICameraServiceListener::STATUS_ENUMERATING:
+ deviceStatus = SCameraDeviceStatus::STATUS_ENUMERATING;
+ break;
+ case hardware::ICameraServiceListener::STATUS_NOT_AVAILABLE:
+ deviceStatus = SCameraDeviceStatus::STATUS_NOT_AVAILABLE;
+ break;
+ default:
+ break;
+ }
+ return deviceStatus;
+}
+
+bool areBindersEqual(const ndk::SpAIBinder& b1, const ndk::SpAIBinder& b2) {
+ return !AIBinder_lt(b1.get(), b2.get()) && !AIBinder_lt(b2.get(), b1.get());
+}
+
+status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic) {
+ if (vndkVersion == __ANDROID_API_FUTURE__) {
+ // VNDK version in ro.vndk.version is a version code-name that
+ // corresponds to the current version.
+ return OK;
+ }
+ const auto &apiLevelToKeys =
+ isStatic ? static_api_level_to_keys : dynamic_api_level_to_keys;
+ // Find the vndk versions above the given vndk version. All the vndk
+ // versions above the given one, need to have their keys filtered from the
+ // metadata in order to avoid metadata invalidation.
+ auto it = apiLevelToKeys.upper_bound(vndkVersion);
+ while (it != apiLevelToKeys.end()) {
+ for (const auto &key : it->second) {
+ status_t res = metadata.erase(key);
+ if (res != OK) {
+ ALOGE("%s metadata key %d could not be erased", __FUNCTION__, key);
+ return res;
+ }
+ }
+ it++;
+ }
+ return OK;
+}
+
+} // namespace android::hardware::cameraservice::utils::conversion::aidl
\ No newline at end of file
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.h b/services/camera/libcameraservice/aidl/AidlUtils.h
new file mode 100644
index 0000000..c89d7ff
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/AidlUtils.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLUTILS_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLUTILS_H_
+
+#include <aidl/android/frameworks/cameraservice/common/Status.h>
+#include <aidl/android/frameworks/cameraservice/device/CameraMetadata.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureResultExtras.h>
+#include <aidl/android/frameworks/cameraservice/device/ErrorCode.h>
+#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/OutputConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/PhysicalCaptureResultInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/SessionConfiguration.h>
+#include <aidl/android/frameworks/cameraservice/device/StreamConfigurationMode.h>
+#include <aidl/android/frameworks/cameraservice/device/SubmitInfo.h>
+#include <aidl/android/frameworks/cameraservice/device/TemplateId.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraDeviceStatus.h>
+#include <aidl/android/frameworks/cameraservice/service/CameraStatusAndId.h>
+#include <android/hardware/ICameraService.h>
+#include <android/hardware/camera2/ICameraDeviceUser.h>
+#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <camera/CameraMetadata.h>
+#include <fmq/AidlMessageQueue.h>
+#include <hardware/camera.h>
+
+namespace android::hardware::cameraservice::utils::conversion::aidl {
+
+using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite;
+using ::android::AidlMessageQueue;
+using ::android::CameraMetadata;
+using CaptureResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
+
+// VNDK classes
+using SCameraDeviceStatus = ::aidl::android::frameworks::cameraservice::service::CameraDeviceStatus;
+using SCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
+using SCameraStatusAndId = ::aidl::android::frameworks::cameraservice::service::CameraStatusAndId;
+using SCaptureResultExtras =
+ ::aidl::android::frameworks::cameraservice::device::CaptureResultExtras;
+using SErrorCode = ::aidl::android::frameworks::cameraservice::device::ErrorCode;
+using SCaptureMetadataInfo = ::aidl::android::frameworks::cameraservice::device::CaptureMetadataInfo;
+using SOutputConfiguration =
+ ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
+using SPhysicalCaptureResultInfo =
+ ::aidl::android::frameworks::cameraservice::device::PhysicalCaptureResultInfo;
+using SSessionConfiguration =
+ ::aidl::android::frameworks::cameraservice::device::SessionConfiguration;
+using SStatus = ::aidl::android::frameworks::cameraservice::common::Status;
+using SStreamConfigurationMode =
+ ::aidl::android::frameworks::cameraservice::device::StreamConfigurationMode;
+using SSubmitInfo = ::aidl::android::frameworks::cameraservice::device::SubmitInfo;
+using STemplateId = ::aidl::android::frameworks::cameraservice::device::TemplateId;
+// NDK classes
+using UCaptureResultExtras = ::android::hardware::camera2::impl::CaptureResultExtras;
+using UOutputConfiguration = ::android::hardware::camera2::params::OutputConfiguration;
+using UPhysicalCaptureResultInfo = ::android::hardware::camera2::impl::PhysicalCaptureResultInfo;
+using USessionConfiguration = ::android::hardware::camera2::params::SessionConfiguration;
+
+// Common macro to log errors returned from stable AIDL calls
+#define LOG_STATUS_ERROR_IF_NOT_OK(status, callName) \
+ if (!(status).isOk()) { \
+ if ((status).getExceptionCode() == EX_SERVICE_SPECIFIC) { \
+ SStatus errStatus = static_cast<SStatus>((status).getServiceSpecificError()); \
+ ALOGE("%s: %s callback failed: %s", __FUNCTION__, callName, \
+ toString(errStatus).c_str()); \
+ } else { \
+ ALOGE("%s: Transaction failed during %s: %d", __FUNCTION__, callName, \
+ (status).getExceptionCode()); \
+ } \
+ }
+
+// Note: existing data in dst will be gone. Caller still owns the memory of src
+void cloneToAidl(const camera_metadata_t *src, SCameraMetadata* dst);
+
+bool cloneFromAidl(const SCameraMetadata &src, CameraMetadata *dst);
+
+int32_t convertFromAidl(SStreamConfigurationMode streamConfigurationMode);
+
+UOutputConfiguration convertFromAidl(const SOutputConfiguration &src);
+
+USessionConfiguration convertFromAidl(const SSessionConfiguration &src);
+
+int convertFromAidl(SOutputConfiguration::Rotation rotation);
+
+int32_t convertFromAidl(STemplateId templateId);
+
+void convertToAidl(const hardware::camera2::utils::SubmitInfo &submitInfo,
+ SSubmitInfo *hSubmitInfo);
+
+SStatus convertToAidl(const binder::Status &status);
+
+SCaptureResultExtras convertToAidl(const UCaptureResultExtras &captureResultExtras);
+
+SErrorCode convertToAidl(int32_t errorCode);
+
+std::vector<SPhysicalCaptureResultInfo> convertToAidl(
+ const std::vector<UPhysicalCaptureResultInfo>& src,
+ std::shared_ptr<CaptureResultMetadataQueue>& fmq);
+
+SPhysicalCaptureResultInfo convertToAidl(const UPhysicalCaptureResultInfo& src,
+ std::shared_ptr<CaptureResultMetadataQueue>& fmq);
+
+void convertToAidl(const std::vector<hardware::CameraStatus> &src,
+ std::vector<SCameraStatusAndId>* dst);
+
+SCameraDeviceStatus convertCameraStatusToAidl(int32_t src);
+
+bool areBindersEqual(const ndk::SpAIBinder& b1, const ndk::SpAIBinder& b2);
+
+status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic = true);
+
+} // namespace android::hardware::cameraservice::utils::conversion::aidl
+
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_AIDLUTILS_H_
diff --git a/services/camera/libcameraservice/aidl/DeathPipe.cpp b/services/camera/libcameraservice/aidl/DeathPipe.cpp
new file mode 100644
index 0000000..de46411
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/DeathPipe.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "DeathPipe"
+
+#include "DeathPipe.h"
+
+namespace android::frameworks::cameraservice::utils {
+
+DeathPipe::DeathPipe(IBinder* parent, const ::ndk::SpAIBinder& binder):
+ mParent(parent), mAIBinder(binder) {
+ mDeathRecipient = ::ndk::ScopedAIBinder_DeathRecipient(
+ AIBinder_DeathRecipient_new(DeathPipe::onDeathCallback));
+ // Set an unlinked callback that allows Obituaries to be deallocated
+ AIBinder_DeathRecipient_setOnUnlinked(mDeathRecipient.get(),
+ DeathPipe::onUnlinkedCallback);
+}
+
+status_t DeathPipe::linkToDeath(const sp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags) {
+ LOG_ALWAYS_FATAL_IF(recipient == nullptr, "%s: recipient must be non-nullptr", __FUNCTION__);
+ std::lock_guard<std::mutex> _l(mLock);
+
+ // Create and immortalize an obituary before linking it to death.
+ // The created Obituary can now only be garbage collected if it is unlinked from death
+ std::shared_ptr<Obituary> obituary = std::make_shared<Obituary>(recipient, cookie,
+ flags, /* who= */ mParent);
+ obituary->immortalize();
+
+ // Ensure that "cookie" is a pointer to an immortal obituary.
+ // AIBinder_linkToDeath calls DeathPipe::onUnlinkedCallback if linking to death fails, marking
+ // it for garbage collection
+ binder_status_t ret = AIBinder_linkToDeath(mAIBinder.get(),
+ mDeathRecipient.get(),
+ /* cookie= */ obituary.get());
+ if (ret != STATUS_OK) {
+ return DEAD_OBJECT;
+ }
+ mObituaries.emplace_back(obituary);
+ return NO_ERROR;
+}
+
+status_t DeathPipe::unlinkToDeath(const wp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags,
+ wp<IBinder::DeathRecipient>* outRecipient) {
+ std::lock_guard<std::mutex> _l(mLock);
+ // Temporary Obituary for checking equality
+ std::shared_ptr<Obituary> inObituary = std::make_shared<Obituary>(recipient, cookie,
+ flags, mParent);
+ for (auto it = mObituaries.begin(); it != mObituaries.end(); it++) {
+ if ((*inObituary) == (**it)) {
+ if (outRecipient != nullptr) {
+ *outRecipient = (*it)->recipient;
+ }
+ // Unlink the found Obituary from death. AIBinder_unlinkToDeath calls
+ // DeathPipe::onUnlinkedCallback with the given cookie when unlinking is done
+ binder_status_t ret = AIBinder_unlinkToDeath(mAIBinder.get(),
+ mDeathRecipient.get(),
+ /* cookie= */ (*it).get());
+ mObituaries.erase(it);
+ return ret == STATUS_OK ? NO_ERROR : DEAD_OBJECT;
+ }
+ }
+ return NAME_NOT_FOUND;
+}
+
+DeathPipe::~DeathPipe() = default;
+
+
+void DeathPipe::onDeathCallback(void* cookie) {
+ // Cookie will always be a pointer to a valid immortal Obituary
+ Obituary* obituary = static_cast<Obituary*>(cookie);
+ obituary->onDeath();
+ // Don't call Obituary::clear() because VNDK Binder will call DeathPipe::onUnlinkedCallback()
+ // when it is ready
+}
+
+void DeathPipe::onUnlinkedCallback(void* cookie) {
+ // Cookie will always be a pointer to a valid immortal Obituary.
+ Obituary* obituary = static_cast<Obituary*>(cookie);
+ // Mark obituary to be garbage collected if needed. onDeathCallback won't be called with
+ // this particular cookie after this.
+ obituary->clear();
+}
+
+} // namespace android::frameworks::cameraservice::utils
\ No newline at end of file
diff --git a/services/camera/libcameraservice/aidl/DeathPipe.h b/services/camera/libcameraservice/aidl/DeathPipe.h
new file mode 100644
index 0000000..a816dd0
--- /dev/null
+++ b/services/camera/libcameraservice/aidl/DeathPipe.h
@@ -0,0 +1,129 @@
+/*
+ * 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.
+ */
+
+#ifndef FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_DEATHPIPE_H_
+#define FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_DEATHPIPE_H_
+
+#include <android/binder_auto_utils.h>
+#include <android/binder_ibinder.h>
+#include <binder/Parcel.h>
+#include <list>
+
+namespace android::frameworks::cameraservice::utils {
+
+/**
+ * This is a helper class to pipe death notifications from VNDK {@code AIBinder} to
+ * S/NDK {@code IBinder}.
+ *
+ * To use this class, create a DeathPipe member object as a field of NDK interface
+ * implementation, and forward functions {@code BBinder::linkToDeath} and
+ * {@code BBinder::unlinkToDeath} to corresponding DeathPipe functions.
+ */
+class DeathPipe {
+ public:
+ /**
+ * @param parent the NDK Binder object. Assumed to live longer than the DeathPipe
+ * object
+ * @param binder the VNDK Binder object which DeathPipe with subscribe to.
+ */
+ explicit DeathPipe(IBinder* parent, const ::ndk::SpAIBinder& binder);
+ ~DeathPipe();
+
+ status_t linkToDeath(const sp<IBinder::DeathRecipient>& recipient, void* cookie,
+ uint32_t flags);
+ status_t unlinkToDeath(const wp<IBinder::DeathRecipient>& recipient,
+ void* cookie, uint32_t flags, wp<IBinder::DeathRecipient>* outRecipient);
+
+ // Static functions that will be called by VNDK binder upon death or unlinking
+ static void onDeathCallback(void* cookie);
+ static void onUnlinkedCallback(void* cookie);
+
+ private:
+ /**
+ * {@code Obituary} is a tiny container that contains some metadata to pass VNDK binder's
+ * death notification to the NDK binder. A pointer to the Obituary is used as the
+ * {@code cookie} in VNDK binder's death notification.
+ *
+ * Theoretically, the VNDK binder might send out death notification after the DeathPipe
+ * object is destroyed, so care must be taken to ensure that Obituaries aren't accidentally
+ * destroyed before VNDK binder stops using its cookies.
+ *
+ */
+ struct Obituary: public std::enable_shared_from_this<Obituary> {
+ wp<IBinder::DeathRecipient> recipient; // NDK death recipient
+ void *cookie; // cookie sent by the NDK recipient
+ uint32_t flags; // flags sent by the NDK recipient
+ wp<IBinder> who; // NDK binder whose death 'recipient' subscribed to
+
+ // Self ptr to ensure we don't destroy this obituary while it can still be notified by the
+ // VNDK Binder. When populated with Obituary::immortalize, this Obituary won't be
+ // garbage collected until Obituary::clear is called.
+ std::shared_ptr<Obituary> mSelfPtr;
+
+ Obituary(const wp<IBinder::DeathRecipient>& recipient, void* cookie,
+ uint32_t flags, IBinder* who) :
+ recipient(recipient), cookie(cookie), flags(flags),
+ who(who), mSelfPtr(nullptr) {}
+
+ // Function to be called when the VNDK Binder dies. Pipes the notification to the relevant
+ // NDK recipient if it still exists
+ void onDeath() const {
+ sp<IBinder::DeathRecipient> r = recipient.promote();
+ if (r == nullptr) { return; }
+ r->binderDied(who);
+ };
+
+ // Should be called before calling AIBinder_linkToDeath. Once this function returns this
+ // Obituary won't be garbage collected until Obituary::clear is called.
+ void immortalize() {
+ mSelfPtr = shared_from_this();
+ }
+
+ // Should be called when this Obituary can be garbage collected.
+ // Typically, after the Obituary is no longer linked to a VNDK DeathRecipient
+ void clear() {
+ mSelfPtr = nullptr;
+ }
+
+ bool operator==(const Obituary& rhs) const {
+ return recipient == rhs.recipient &&
+ cookie == rhs.cookie &&
+ flags == rhs.flags &&
+ who == rhs.who;
+ }
+ };
+
+ // Parent to which the cameraservice wants to subscribe to for death notification
+ IBinder* mParent;
+
+ // VNDK Binder object to which the death notification will be bound to. If it dies,
+ // cameraservice will be notified as if mParent died.
+ ::ndk::SpAIBinder mAIBinder;
+
+ // Owning VNDK's deathRecipient ensures that all linked death notifications are cleaned up
+ // when this class destructs.
+ ::ndk::ScopedAIBinder_DeathRecipient mDeathRecipient;
+
+ // Lock to protect access to fields below.
+ std::mutex mLock;
+ // List of all obituaries created by DeathPipe, used to unlink death subscription
+ std::list<std::shared_ptr<Obituary>> mObituaries;
+
+};
+
+} // namespace android::frameworks::cameraservice::utils
+
+#endif // FRAMEWORKS_AV_SERVICES_CAMERA_LIBCAMERASERVICE_AIDL_DEATHPIPE_H_
diff --git a/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
similarity index 90%
rename from services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
rename to services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index 8b9b92b..48c804d 100644
--- a/services/camera/libcameraservice/hidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -21,7 +21,7 @@
* ! Do not edit this file directly !
*
* Generated automatically from vndk_camera_metadata_tags.mako. To be included in libcameraservice
- * only by hidl/Utils.cpp.
+ * only by aidl/AidlUtils.cpp.
*/
/**
@@ -77,6 +77,12 @@
{34, {
ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS,
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION,
ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP,
} },
};
@@ -102,5 +108,6 @@
ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
ANDROID_EXTENSION_CURRENT_TYPE,
ANDROID_EXTENSION_STRENGTH,
+ ANDROID_SCALER_RAW_CROP_REGION,
} },
};
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index d447fe0..23a70db 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -501,12 +501,13 @@
ALOGV("Camera %d: Disconnecting device", mCameraId);
+ bool hasDeviceError = mDevice->hasDeviceError();
mDevice->disconnect();
CameraService::Client::disconnect();
int32_t closeLatencyMs = ns2ms(systemTime() - startTime);
- mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs);
+ mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError);
return res;
}
@@ -2380,6 +2381,15 @@
return mDevice->setCameraMute(enabled);
}
+void Camera2Client::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ mDevice->setStreamUseCaseOverrides(useCaseOverrides);
+}
+
+void Camera2Client::clearStreamUseCaseOverrides() {
+ mDevice->clearStreamUseCaseOverrides();
+}
+
status_t Camera2Client::waitUntilCurrentRequestIdLocked() {
int32_t activeRequestId = mStreamingProcessor->getActiveRequestId();
if (activeRequestId != 0) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index c5324db..f035fea 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -93,6 +93,10 @@
virtual status_t setCameraServiceWatchdog(bool enabled);
+ virtual void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides);
+ virtual void clearStreamUseCaseOverrides();
+
/**
* Interface used by CameraService
*/
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index d80b6ec..34b3948 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -36,6 +36,7 @@
#include "DepthCompositeStream.h"
#include "HeicCompositeStream.h"
+#include "JpegRCompositeStream.h"
// Convenience methods for constructing binder::Status objects for error returns
@@ -889,6 +890,7 @@
int timestampBase = outputConfiguration.getTimestampBase();
int mirrorMode = outputConfiguration.getMirrorMode();
int32_t colorSpace = outputConfiguration.getColorSpace();
+ bool useReadoutTimestamp = outputConfiguration.useReadoutTimestamp();
res = SessionConfigurationUtils::checkSurfaceType(numBufferProducers, deferredConsumer,
outputConfiguration.getSurfaceType());
@@ -954,20 +956,26 @@
std::vector<int> surfaceIds;
bool isDepthCompositeStream =
camera3::DepthCompositeStream::isDepthCompositeStream(surfaces[0]);
- bool isHeicCompisiteStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
- if (isDepthCompositeStream || isHeicCompisiteStream) {
+ bool isHeicCompositeStream = camera3::HeicCompositeStream::isHeicCompositeStream(surfaces[0]);
+ bool isJpegRCompositeStream =
+ camera3::JpegRCompositeStream::isJpegRCompositeStream(surfaces[0]);
+ if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
sp<CompositeStream> compositeStream;
if (isDepthCompositeStream) {
compositeStream = new camera3::DepthCompositeStream(mDevice, getRemoteCallback());
- } else {
+ } else if (isHeicCompositeStream) {
compositeStream = new camera3::HeicCompositeStream(mDevice, getRemoteCallback());
+ } else {
+ compositeStream = new camera3::JpegRCompositeStream(mDevice, getRemoteCallback());
}
err = compositeStream->createStream(surfaces, deferredConsumer, streamInfo.width,
streamInfo.height, streamInfo.format,
static_cast<camera_stream_rotation_t>(outputConfiguration.getRotation()),
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
- outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution);
+ outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
+ streamInfo.colorSpace, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase,
+ useReadoutTimestamp);
if (err == OK) {
Mutex::Autolock l(mCompositeLock);
mCompositeStreamMap.add(IInterface::asBinder(surfaces[0]->getIGraphicBufferProducer()),
@@ -980,7 +988,8 @@
&streamId, physicalCameraId, streamInfo.sensorPixelModesUsed, &surfaceIds,
outputConfiguration.getSurfaceSetID(), isShared, isMultiResolution,
/*consumerUsage*/0, streamInfo.dynamicRangeProfile, streamInfo.streamUseCase,
- streamInfo.timestampBase, streamInfo.mirrorMode, streamInfo.colorSpace);
+ streamInfo.timestampBase, streamInfo.mirrorMode, streamInfo.colorSpace,
+ useReadoutTimestamp);
}
if (err != OK) {
@@ -1079,7 +1088,8 @@
outputConfiguration.isMultiResolution(), consumerUsage,
outputConfiguration.getDynamicRangeProfile(),
outputConfiguration.getStreamUseCase(),
- outputConfiguration.getMirrorMode());
+ outputConfiguration.getMirrorMode(),
+ outputConfiguration.useReadoutTimestamp());
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
@@ -1771,6 +1781,15 @@
return mDevice->setCameraMute(enabled);
}
+void CameraDeviceClient::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ mDevice->setStreamUseCaseOverrides(useCaseOverrides);
+}
+
+void CameraDeviceClient::clearStreamUseCaseOverrides() {
+ mDevice->clearStreamUseCaseOverrides();
+}
+
binder::Status CameraDeviceClient::switchToOffline(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const std::vector<int>& offlineOutputIds,
@@ -1823,7 +1842,8 @@
for (const auto& gbp : mConfiguredOutputs.valueAt(index).getGraphicBufferProducers()) {
sp<Surface> s = new Surface(gbp, false /*controlledByApp*/);
isCompositeStream = camera3::DepthCompositeStream::isDepthCompositeStream(s) ||
- camera3::HeicCompositeStream::isHeicCompositeStream(s);
+ camera3::HeicCompositeStream::isHeicCompositeStream(s) ||
+ camera3::JpegRCompositeStream::isJpegRCompositeStream(s);
if (isCompositeStream) {
auto compositeIdx = mCompositeStreamMap.indexOfKey(IInterface::asBinder(gbp));
if (compositeIdx == NAME_NOT_FOUND) {
@@ -2080,10 +2100,11 @@
mCompositeStreamMap.clear();
}
+ bool hasDeviceError = mDevice->hasDeviceError();
Camera2ClientBase::detachDevice();
int32_t closeLatencyMs = ns2ms(systemTime() - startTime);
- mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs);
+ mCameraServiceProxyWrapper->logClose(mCameraIdStr, closeLatencyMs, hasDeviceError);
}
/** Device-related methods */
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index 0c87872..36c627a 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -214,6 +214,9 @@
virtual status_t setCameraServiceWatchdog(bool enabled);
+ virtual void setStreamUseCaseOverrides(const std::vector<int64_t>& useCaseOverrides);
+ virtual void clearStreamUseCaseOverrides() override;
+
/**
* Device listener interface
*/
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index ea90987..c260cfe 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -94,6 +94,13 @@
return INVALID_OPERATION;
}
+void CameraOfflineSessionClient::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& /*useCaseOverrides*/) {
+}
+
+void CameraOfflineSessionClient::clearStreamUseCaseOverrides() {
+}
+
status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 89b27f8..906d454 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -89,6 +89,11 @@
status_t setCameraServiceWatchdog(bool enabled) override;
+ void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) override;
+
+ void clearStreamUseCaseOverrides() override;
+
// permissions management
status_t startCameraOps() override;
status_t finishCameraOps() override;
diff --git a/services/camera/libcameraservice/api2/CompositeStream.cpp b/services/camera/libcameraservice/api2/CompositeStream.cpp
index 4b840fc..503cf23 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/CompositeStream.cpp
@@ -49,7 +49,8 @@
camera_stream_rotation_t rotation, int * id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> * surfaceIds,
- int streamSetId, bool isShared, bool isMultiResolution) {
+ int streamSetId, bool isShared, bool isMultiResolution, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) {
if (hasDeferredConsumer) {
ALOGE("%s: Deferred consumers not supported in case of composite streams!",
__FUNCTION__);
@@ -75,7 +76,8 @@
}
return createInternalStreams(consumers, hasDeferredConsumer, width, height, format, rotation,
- id, physicalCameraId, sensorPixelModesUsed, surfaceIds, streamSetId, isShared);
+ id, physicalCameraId, sensorPixelModesUsed, surfaceIds, streamSetId, isShared,
+ colorSpace, dynamicProfile, streamUseCase, useReadoutTimestamp);
}
status_t CompositeStream::deleteStream() {
diff --git a/services/camera/libcameraservice/api2/CompositeStream.h b/services/camera/libcameraservice/api2/CompositeStream.h
index 600bd28..c27faba 100644
--- a/services/camera/libcameraservice/api2/CompositeStream.h
+++ b/services/camera/libcameraservice/api2/CompositeStream.h
@@ -46,7 +46,8 @@
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds,
- int streamSetId, bool isShared, bool isMultiResolution);
+ int streamSetId, bool isShared, bool isMultiResolution, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp);
status_t deleteStream();
@@ -59,7 +60,8 @@
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds,
- int streamSetId, bool isShared) = 0;
+ int streamSetId, bool isShared, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) = 0;
// Release all internal streams and corresponding resources.
virtual status_t deleteInternalStreams() = 0;
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
index 048d85d..a3547dd 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.cpp
@@ -581,7 +581,8 @@
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds,
- int /*streamSetId*/, bool /*isShared*/) {
+ int /*streamSetId*/, bool /*isShared*/, int32_t /*colorSpace*/,
+ int64_t /*dynamicProfile*/, int64_t /*streamUseCase*/, bool useReadoutTimestamp) {
if (mSupportedDepthSizes.empty()) {
ALOGE("%s: This camera device doesn't support any depth map streams!", __FUNCTION__);
return INVALID_OPERATION;
@@ -612,7 +613,14 @@
mBlobSurface = new Surface(producer);
ret = device->createStream(mBlobSurface, width, height, format, kJpegDataSpace, rotation,
- id, physicalCameraId, sensorPixelModesUsed, surfaceIds);
+ id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
+ camera3::CAMERA3_STREAM_SET_ID_INVALID, /*isShared*/false, /*isMultiResolution*/false,
+ /*consumerUsage*/0, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ OutputConfiguration::MIRROR_MODE_AUTO,
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ useReadoutTimestamp);
if (ret == OK) {
mBlobStreamId = *id;
mBlobSurfaceId = (*surfaceIds)[0];
@@ -629,7 +637,14 @@
std::vector<int> depthSurfaceId;
ret = device->createStream(mDepthSurface, depthWidth, depthHeight, kDepthMapPixelFormat,
kDepthMapDataSpace, rotation, &mDepthStreamId, physicalCameraId, sensorPixelModesUsed,
- &depthSurfaceId);
+ &depthSurfaceId, camera3::CAMERA3_STREAM_SET_ID_INVALID, /*isShared*/false,
+ /*isMultiResolution*/false, /*consumerUsage*/0,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ OutputConfiguration::MIRROR_MODE_AUTO,
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ useReadoutTimestamp);
if (ret == OK) {
mDepthSurfaceId = depthSurfaceId[0];
} else {
diff --git a/services/camera/libcameraservice/api2/DepthCompositeStream.h b/services/camera/libcameraservice/api2/DepthCompositeStream.h
index c1c75c1..de0ed67 100644
--- a/services/camera/libcameraservice/api2/DepthCompositeStream.h
+++ b/services/camera/libcameraservice/api2/DepthCompositeStream.h
@@ -53,7 +53,8 @@
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds,
- int streamSetId, bool isShared) override;
+ int streamSetId, bool isShared, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) override;
status_t deleteInternalStreams() override;
status_t configureStream() override;
status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
index cd57299..e652546 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.cpp
@@ -120,8 +120,8 @@
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds,
- int /*streamSetId*/, bool /*isShared*/) {
-
+ int /*streamSetId*/, bool /*isShared*/, int32_t /*colorSpace*/,
+ int64_t /*dynamicProfile*/, int64_t /*streamUseCase*/, bool useReadoutTimestamp) {
sp<CameraDeviceBase> device = mDevice.promote();
if (!device.get()) {
ALOGE("%s: Invalid camera device!", __FUNCTION__);
@@ -147,7 +147,14 @@
res = device->createStream(mAppSegmentSurface, mAppSegmentMaxSize, 1, format,
kAppSegmentDataSpace, rotation, &mAppSegmentStreamId, physicalCameraId,
- sensorPixelModesUsed,surfaceIds);
+ sensorPixelModesUsed, surfaceIds, camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ /*isShared*/false, /*isMultiResolution*/false,
+ /*consumerUsage*/0, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ OutputConfiguration::MIRROR_MODE_AUTO,
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ useReadoutTimestamp);
if (res == OK) {
mAppSegmentSurfaceId = (*surfaceIds)[0];
} else {
@@ -183,7 +190,14 @@
int srcStreamFmt = mUseGrid ? HAL_PIXEL_FORMAT_YCbCr_420_888 :
HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
res = device->createStream(mMainImageSurface, width, height, srcStreamFmt, kHeifDataSpace,
- rotation, id, physicalCameraId, sensorPixelModesUsed, &sourceSurfaceId);
+ rotation, id, physicalCameraId, sensorPixelModesUsed, &sourceSurfaceId,
+ camera3::CAMERA3_STREAM_SET_ID_INVALID, /*isShared*/false, /*isMultiResolution*/false,
+ /*consumerUsage*/0, ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ OutputConfiguration::MIRROR_MODE_AUTO,
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ useReadoutTimestamp);
if (res == OK) {
mMainImageSurfaceId = sourceSurfaceId[0];
mMainImageStreamId = *id;
@@ -1601,7 +1615,7 @@
return OK;
}
-void HeicCompositeStream::initCopyRowFunction(int32_t width)
+void HeicCompositeStream::initCopyRowFunction([[maybe_unused]] int32_t width)
{
using namespace libyuv;
diff --git a/services/camera/libcameraservice/api2/HeicCompositeStream.h b/services/camera/libcameraservice/api2/HeicCompositeStream.h
index 1077a1f..3132183 100644
--- a/services/camera/libcameraservice/api2/HeicCompositeStream.h
+++ b/services/camera/libcameraservice/api2/HeicCompositeStream.h
@@ -47,8 +47,8 @@
bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
const std::unordered_set<int32_t> &sensorPixelModesUsed,
- std::vector<int> *surfaceIds,
- int streamSetId, bool isShared) override;
+ std::vector<int> *surfaceIds, int streamSetId, bool isShared, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) override;
status_t deleteInternalStreams() override;
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
new file mode 100644
index 0000000..9857fd8
--- /dev/null
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.cpp
@@ -0,0 +1,830 @@
+/*
+ * 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 "hardware/gralloc.h"
+#include "system/graphics-base-v1.0.h"
+#include "system/graphics-base-v1.1.h"
+#define LOG_TAG "Camera3-JpegRCompositeStream"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <aidl/android/hardware/camera/device/CameraBlob.h>
+#include <aidl/android/hardware/camera/device/CameraBlobId.h>
+
+#include "common/CameraProviderManager.h"
+#include <gui/Surface.h>
+#include <jpegrecoverymap/recoverymap.h>
+#include <utils/ExifUtils.h>
+#include <utils/Log.h>
+#include "utils/SessionConfigurationUtils.h"
+#include <utils/Trace.h>
+
+#include "JpegRCompositeStream.h"
+
+namespace android {
+namespace camera3 {
+
+using aidl::android::hardware::camera::device::CameraBlob;
+using aidl::android::hardware::camera::device::CameraBlobId;
+
+JpegRCompositeStream::JpegRCompositeStream(sp<CameraDeviceBase> device,
+ wp<hardware::camera2::ICameraDeviceCallbacks> cb) :
+ CompositeStream(device, cb),
+ mBlobStreamId(-1),
+ mBlobSurfaceId(-1),
+ mP010StreamId(-1),
+ mP010SurfaceId(-1),
+ mBlobWidth(0),
+ mBlobHeight(0),
+ mP010BufferAcquired(false),
+ mBlobBufferAcquired(false),
+ mOutputColorSpace(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED),
+ mProducerListener(new ProducerListener()),
+ mMaxJpegBufferSize(-1),
+ mUHRMaxJpegBufferSize(-1),
+ mStaticInfo(device->info()) {
+ auto entry = mStaticInfo.find(ANDROID_JPEG_MAX_SIZE);
+ if (entry.count > 0) {
+ mMaxJpegBufferSize = entry.data.i32[0];
+ } else {
+ ALOGW("%s: Maximum jpeg size absent from camera characteristics", __FUNCTION__);
+ }
+
+ mUHRMaxJpegSize =
+ SessionConfigurationUtils::getMaxJpegResolution(mStaticInfo,
+ /*ultraHighResolution*/true);
+ mDefaultMaxJpegSize =
+ SessionConfigurationUtils::getMaxJpegResolution(mStaticInfo,
+ /*isUltraHighResolution*/false);
+
+ mUHRMaxJpegBufferSize =
+ SessionConfigurationUtils::getUHRMaxJpegBufferSize(mUHRMaxJpegSize, mDefaultMaxJpegSize,
+ mMaxJpegBufferSize);
+}
+
+JpegRCompositeStream::~JpegRCompositeStream() {
+ mBlobConsumer.clear(),
+ mBlobSurface.clear(),
+ mBlobStreamId = -1;
+ mBlobSurfaceId = -1;
+ mP010Consumer.clear();
+ mP010Surface.clear();
+ mP010Consumer = nullptr;
+ mP010Surface = nullptr;
+}
+
+void JpegRCompositeStream::compilePendingInputLocked() {
+ CpuConsumer::LockedBuffer imgBuffer;
+
+ while (mSupportInternalJpeg && !mInputJpegBuffers.empty() && !mBlobBufferAcquired) {
+ auto it = mInputJpegBuffers.begin();
+ auto res = mBlobConsumer->lockNextBuffer(&imgBuffer);
+ if (res == NOT_ENOUGH_DATA) {
+ // Can not lock any more buffers.
+ break;
+ } else if (res != OK) {
+ ALOGE("%s: Error locking blob image buffer: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ mPendingInputFrames[*it].error = true;
+ mInputJpegBuffers.erase(it);
+ continue;
+ }
+
+ if (*it != imgBuffer.timestamp) {
+ ALOGW("%s: Expecting jpeg buffer with time stamp: %" PRId64 " received buffer with "
+ "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
+ }
+
+ if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+ (mPendingInputFrames[imgBuffer.timestamp].error)) {
+ mBlobConsumer->unlockBuffer(imgBuffer);
+ } else {
+ mPendingInputFrames[imgBuffer.timestamp].jpegBuffer = imgBuffer;
+ mBlobBufferAcquired = true;
+ }
+ mInputJpegBuffers.erase(it);
+ }
+
+ while (!mInputP010Buffers.empty() && !mP010BufferAcquired) {
+ auto it = mInputP010Buffers.begin();
+ auto res = mP010Consumer->lockNextBuffer(&imgBuffer);
+ if (res == NOT_ENOUGH_DATA) {
+ // Can not lock any more buffers.
+ break;
+ } else if (res != OK) {
+ ALOGE("%s: Error receiving P010 image buffer: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ mPendingInputFrames[*it].error = true;
+ mInputP010Buffers.erase(it);
+ continue;
+ }
+
+ if (*it != imgBuffer.timestamp) {
+ ALOGW("%s: Expecting P010 buffer with time stamp: %" PRId64 " received buffer with "
+ "time stamp: %" PRId64, __FUNCTION__, *it, imgBuffer.timestamp);
+ }
+
+ if ((mPendingInputFrames.find(imgBuffer.timestamp) != mPendingInputFrames.end()) &&
+ (mPendingInputFrames[imgBuffer.timestamp].error)) {
+ mP010Consumer->unlockBuffer(imgBuffer);
+ } else {
+ mPendingInputFrames[imgBuffer.timestamp].p010Buffer = imgBuffer;
+ mP010BufferAcquired = true;
+ }
+ mInputP010Buffers.erase(it);
+ }
+
+ while (!mCaptureResults.empty()) {
+ auto it = mCaptureResults.begin();
+ // Negative timestamp indicates that something went wrong during the capture result
+ // collection process.
+ if (it->first >= 0) {
+ mPendingInputFrames[it->first].frameNumber = std::get<0>(it->second);
+ mPendingInputFrames[it->first].result = std::get<1>(it->second);
+ }
+ mCaptureResults.erase(it);
+ }
+
+ while (!mFrameNumberMap.empty()) {
+ auto it = mFrameNumberMap.begin();
+ mPendingInputFrames[it->second].frameNumber = it->first;
+ mFrameNumberMap.erase(it);
+ }
+
+ auto it = mErrorFrameNumbers.begin();
+ while (it != mErrorFrameNumbers.end()) {
+ bool frameFound = false;
+ for (auto &inputFrame : mPendingInputFrames) {
+ if (inputFrame.second.frameNumber == *it) {
+ inputFrame.second.error = true;
+ frameFound = true;
+ break;
+ }
+ }
+
+ if (frameFound) {
+ it = mErrorFrameNumbers.erase(it);
+ } else {
+ ALOGW("%s: Not able to find failing input with frame number: %" PRId64, __FUNCTION__,
+ *it);
+ it++;
+ }
+ }
+}
+
+bool JpegRCompositeStream::getNextReadyInputLocked(int64_t *currentTs /*inout*/) {
+ if (currentTs == nullptr) {
+ return false;
+ }
+
+ bool newInputAvailable = false;
+ for (const auto& it : mPendingInputFrames) {
+ if ((!it.second.error) && (it.second.p010Buffer.data != nullptr) &&
+ ((it.second.jpegBuffer.data != nullptr) || !mSupportInternalJpeg) &&
+ (it.first < *currentTs)) {
+ *currentTs = it.first;
+ newInputAvailable = true;
+ }
+ }
+
+ return newInputAvailable;
+}
+
+int64_t JpegRCompositeStream::getNextFailingInputLocked(int64_t *currentTs /*inout*/) {
+ int64_t ret = -1;
+ if (currentTs == nullptr) {
+ return ret;
+ }
+
+ for (const auto& it : mPendingInputFrames) {
+ if (it.second.error && !it.second.errorNotified && (it.first < *currentTs)) {
+ *currentTs = it.first;
+ ret = it.second.frameNumber;
+ }
+ }
+
+ return ret;
+}
+
+status_t JpegRCompositeStream::processInputFrame(nsecs_t ts, const InputFrame &inputFrame) {
+ status_t res;
+ sp<ANativeWindow> outputANW = mOutputSurface;
+ ANativeWindowBuffer *anb;
+ int fenceFd;
+ void *dstBuffer;
+
+ size_t maxJpegRBufferSize = 0;
+ if (mMaxJpegBufferSize > 0) {
+ // If this is an ultra high resolution sensor and the input frames size
+ // is > default res jpeg.
+ if (mUHRMaxJpegSize.width != 0 &&
+ inputFrame.jpegBuffer.width * inputFrame.jpegBuffer.height >
+ mDefaultMaxJpegSize.width * mDefaultMaxJpegSize.height) {
+ maxJpegRBufferSize = mUHRMaxJpegBufferSize;
+ } else {
+ maxJpegRBufferSize = mMaxJpegBufferSize;
+ }
+ } else {
+ maxJpegRBufferSize = inputFrame.p010Buffer.width * inputFrame.p010Buffer.height;
+ }
+
+ uint8_t jpegQuality = 100;
+ auto entry = inputFrame.result.find(ANDROID_JPEG_QUALITY);
+ if (entry.count > 0) {
+ jpegQuality = entry.data.u8[0];
+ }
+
+ uint8_t jpegOrientation = 0;
+ entry = inputFrame.result.find(ANDROID_JPEG_ORIENTATION);
+ if (entry.count > 0) {
+ jpegOrientation = entry.data.i32[0];
+ }
+
+ if ((res = native_window_set_buffers_dimensions(mOutputSurface.get(), maxJpegRBufferSize, 1))
+ != OK) {
+ ALOGE("%s: Unable to configure stream buffer dimensions"
+ " %zux%u for stream %d", __FUNCTION__, maxJpegRBufferSize, 1U, mP010StreamId);
+ return res;
+ }
+
+ res = outputANW->dequeueBuffer(mOutputSurface.get(), &anb, &fenceFd);
+ if (res != OK) {
+ ALOGE("%s: Error retrieving output buffer: %s (%d)", __FUNCTION__, strerror(-res),
+ res);
+ return res;
+ }
+
+ sp<GraphicBuffer> gb = GraphicBuffer::from(anb);
+ GraphicBufferLocker gbLocker(gb);
+ res = gbLocker.lockAsync(&dstBuffer, fenceFd);
+ if (res != OK) {
+ ALOGE("%s: Error trying to lock output buffer fence: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+ return res;
+ }
+
+ if ((gb->getWidth() < maxJpegRBufferSize) || (gb->getHeight() != 1)) {
+ ALOGE("%s: Blob buffer size mismatch, expected %zux%u received %dx%d", __FUNCTION__,
+ maxJpegRBufferSize, 1, gb->getWidth(), gb->getHeight());
+ outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+ return BAD_VALUE;
+ }
+
+ size_t actualJpegRSize = 0;
+ recoverymap::jpegr_uncompressed_struct p010;
+ recoverymap::jpegr_compressed_struct jpegR;
+ recoverymap::RecoveryMap recoveryMap;
+
+ p010.height = inputFrame.p010Buffer.height;
+ p010.width = inputFrame.p010Buffer.width;
+ p010.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT2100;
+ size_t yChannelSizeInByte = p010.width * p010.height * 2;
+ size_t uvChannelSizeInByte = p010.width * p010.height;
+ p010.data = new uint8_t[yChannelSizeInByte + uvChannelSizeInByte];
+ std::unique_ptr<uint8_t[]> p010_data;
+ p010_data.reset(reinterpret_cast<uint8_t*>(p010.data));
+ memcpy((uint8_t*)p010.data, inputFrame.p010Buffer.data, yChannelSizeInByte);
+ memcpy((uint8_t*)p010.data + yChannelSizeInByte, inputFrame.p010Buffer.dataCb,
+ uvChannelSizeInByte);
+
+ jpegR.data = dstBuffer;
+ jpegR.maxLength = maxJpegRBufferSize;
+
+ recoverymap::jpegr_transfer_function transferFunction;
+ switch (mP010DynamicRange) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+ transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_PQ;
+ break;
+ default:
+ transferFunction = recoverymap::jpegr_transfer_function::JPEGR_TF_HLG;
+ }
+
+ if (mSupportInternalJpeg) {
+ recoverymap::jpegr_compressed_struct jpeg;
+
+ jpeg.data = inputFrame.jpegBuffer.data;
+ jpeg.length = android::camera2::JpegProcessor::findJpegSize(inputFrame.jpegBuffer.data,
+ inputFrame.jpegBuffer.width);
+ if (jpeg.length == 0) {
+ ALOGW("%s: Failed to find input jpeg size, default to using entire buffer!",
+ __FUNCTION__);
+ jpeg.length = inputFrame.jpegBuffer.width;
+ }
+
+ if (mOutputColorSpace == ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3) {
+ jpeg.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_P3;
+ } else {
+ jpeg.colorGamut = recoverymap::jpegr_color_gamut::JPEGR_COLORGAMUT_BT709;
+ }
+
+ res = recoveryMap.encodeJPEGR(&p010, &jpeg, transferFunction, &jpegR);
+ } else {
+ const uint8_t* exifBuffer = nullptr;
+ size_t exifBufferSize = 0;
+ std::unique_ptr<ExifUtils> utils(ExifUtils::create());
+ utils->initializeEmpty();
+ utils->setFromMetadata(inputFrame.result, mStaticInfo, inputFrame.p010Buffer.width,
+ inputFrame.p010Buffer.height);
+ if (utils->generateApp1()) {
+ exifBuffer = utils->getApp1Buffer();
+ exifBufferSize = utils->getApp1Length();
+ } else {
+ ALOGE("%s: Unable to generate App1 buffer", __FUNCTION__);
+ }
+
+ recoverymap::jpegr_exif_struct exif;
+ exif.data = reinterpret_cast<void*>(const_cast<uint8_t*>(exifBuffer));
+ exif.length = exifBufferSize;
+
+ res = recoveryMap.encodeJPEGR(&p010, transferFunction, &jpegR, jpegQuality, &exif);
+ }
+
+ if (res != OK) {
+ ALOGE("%s: Error trying to encode JPEG/R: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ actualJpegRSize = jpegR.length;
+ p010_data.release();
+
+ size_t finalJpegRSize = actualJpegRSize + sizeof(CameraBlob);
+ if (finalJpegRSize > maxJpegRBufferSize) {
+ ALOGE("%s: Final jpeg buffer not large enough for the jpeg blob header", __FUNCTION__);
+ outputANW->cancelBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+ return NO_MEMORY;
+ }
+
+ res = native_window_set_buffers_timestamp(mOutputSurface.get(), ts);
+ if (res != OK) {
+ ALOGE("%s: Stream %d: Error setting timestamp: %s (%d)", __FUNCTION__,
+ getStreamId(), strerror(-res), res);
+ return res;
+ }
+
+ ALOGV("%s: Final jpeg size: %zu", __func__, finalJpegRSize);
+ uint8_t* header = static_cast<uint8_t *> (dstBuffer) +
+ (gb->getWidth() - sizeof(CameraBlob));
+ CameraBlob blobHeader = {
+ .blobId = CameraBlobId::JPEG,
+ .blobSizeBytes = static_cast<int32_t>(actualJpegRSize)
+ };
+ memcpy(header, &blobHeader, sizeof(CameraBlob));
+ outputANW->queueBuffer(mOutputSurface.get(), anb, /*fence*/ -1);
+
+ return res;
+}
+
+void JpegRCompositeStream::releaseInputFrameLocked(InputFrame *inputFrame /*out*/) {
+ if (inputFrame == nullptr) {
+ return;
+ }
+
+ if (inputFrame->p010Buffer.data != nullptr) {
+ mP010Consumer->unlockBuffer(inputFrame->p010Buffer);
+ inputFrame->p010Buffer.data = nullptr;
+ mP010BufferAcquired = false;
+ }
+
+ if (inputFrame->jpegBuffer.data != nullptr) {
+ mBlobConsumer->unlockBuffer(inputFrame->jpegBuffer);
+ inputFrame->jpegBuffer.data = nullptr;
+ mBlobBufferAcquired = false;
+ }
+
+ if ((inputFrame->error || mErrorState) && !inputFrame->errorNotified) {
+ //TODO: Figure out correct requestId
+ notifyError(inputFrame->frameNumber, -1 /*requestId*/);
+ inputFrame->errorNotified = true;
+ }
+}
+
+void JpegRCompositeStream::releaseInputFramesLocked(int64_t currentTs) {
+ auto it = mPendingInputFrames.begin();
+ while (it != mPendingInputFrames.end()) {
+ if (it->first <= currentTs) {
+ releaseInputFrameLocked(&it->second);
+ it = mPendingInputFrames.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+bool JpegRCompositeStream::threadLoop() {
+ int64_t currentTs = INT64_MAX;
+ bool newInputAvailable = false;
+
+ {
+ Mutex::Autolock l(mMutex);
+
+ if (mErrorState) {
+ // In case we landed in error state, return any pending buffers and
+ // halt all further processing.
+ compilePendingInputLocked();
+ releaseInputFramesLocked(currentTs);
+ return false;
+ }
+
+ while (!newInputAvailable) {
+ compilePendingInputLocked();
+ newInputAvailable = getNextReadyInputLocked(¤tTs);
+ if (!newInputAvailable) {
+ auto failingFrameNumber = getNextFailingInputLocked(¤tTs);
+ if (failingFrameNumber >= 0) {
+ // We cannot erase 'mPendingInputFrames[currentTs]' at this point because it is
+ // possible for two internal stream buffers to fail. In such scenario the
+ // composite stream should notify the client about a stream buffer error only
+ // once and this information is kept within 'errorNotified'.
+ // Any present failed input frames will be removed on a subsequent call to
+ // 'releaseInputFramesLocked()'.
+ releaseInputFrameLocked(&mPendingInputFrames[currentTs]);
+ currentTs = INT64_MAX;
+ }
+
+ auto ret = mInputReadyCondition.waitRelative(mMutex, kWaitDuration);
+ if (ret == TIMED_OUT) {
+ return true;
+ } else if (ret != OK) {
+ ALOGE("%s: Timed wait on condition failed: %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ return false;
+ }
+ }
+ }
+ }
+
+ auto res = processInputFrame(currentTs, mPendingInputFrames[currentTs]);
+ Mutex::Autolock l(mMutex);
+ if (res != OK) {
+ ALOGE("%s: Failed processing frame with timestamp: %" PRIu64 ": %s (%d)", __FUNCTION__,
+ currentTs, strerror(-res), res);
+ mPendingInputFrames[currentTs].error = true;
+ }
+
+ releaseInputFramesLocked(currentTs);
+
+ return true;
+}
+
+bool JpegRCompositeStream::isJpegRCompositeStream(const sp<Surface> &surface) {
+ if (CameraProviderManager::kFrameworkJpegRDisabled) {
+ return false;
+ }
+ ANativeWindow *anw = surface.get();
+ status_t err;
+ int format;
+ if ((err = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+ ALOGE("%s: Failed to query Surface format: %s (%d)", __FUNCTION__, strerror(-err),
+ err);
+ return false;
+ }
+
+ int dataspace;
+ if ((err = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE, &dataspace)) != OK) {
+ ALOGE("%s: Failed to query Surface dataspace: %s (%d)", __FUNCTION__, strerror(-err),
+ err);
+ return false;
+ }
+
+ if ((format == HAL_PIXEL_FORMAT_BLOB) && (dataspace == static_cast<int>(kJpegRDataSpace))) {
+ return true;
+ }
+
+ return false;
+}
+
+void JpegRCompositeStream::deriveDynamicRangeAndDataspace(int64_t dynamicProfile,
+ int64_t* /*out*/dynamicRange, int64_t* /*out*/dataSpace) {
+ if ((dynamicRange == nullptr) || (dataSpace == nullptr)) {
+ return;
+ }
+
+ switch (dynamicProfile) {
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HDR10_PLUS:
+ *dynamicRange = dynamicProfile;
+ *dataSpace = HAL_DATASPACE_BT2020_ITU_PQ;
+ break;
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_REF_PO:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM:
+ case ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_DOLBY_VISION_10B_HDR_OEM_PO:
+ *dynamicRange = dynamicProfile;
+ *dataSpace = HAL_DATASPACE_BT2020_ITU_HLG;
+ break;
+ default:
+ *dynamicRange = kP010DefaultDynamicRange;
+ *dataSpace = kP010DefaultDataSpace;
+ }
+
+}
+
+status_t JpegRCompositeStream::createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ bool /*hasDeferredConsumer*/, uint32_t width, uint32_t height, int format,
+ camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int /*streamSetId*/, bool /*isShared*/, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) {
+ sp<CameraDeviceBase> device = mDevice.promote();
+ if (!device.get()) {
+ ALOGE("%s: Invalid camera device!", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ deriveDynamicRangeAndDataspace(dynamicProfile, &mP010DynamicRange, &mP010DataSpace);
+ mSupportInternalJpeg = CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(
+ mStaticInfo, mP010DynamicRange,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD);
+
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mP010Consumer = new CpuConsumer(consumer, /*maxLockedBuffers*/1, /*controlledByApp*/ true);
+ mP010Consumer->setFrameAvailableListener(this);
+ mP010Consumer->setName(String8("Camera3-P010CompositeStream"));
+ mP010Surface = new Surface(producer);
+
+ auto ret = device->createStream(mP010Surface, width, height, kP010PixelFormat,
+ static_cast<android_dataspace>(mP010DataSpace), rotation,
+ id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
+ camera3::CAMERA3_STREAM_SET_ID_INVALID, false /*isShared*/, false /*isMultiResolution*/,
+ GRALLOC_USAGE_SW_READ_OFTEN, mP010DynamicRange, streamUseCase,
+ OutputConfiguration::TIMESTAMP_BASE_DEFAULT, OutputConfiguration::MIRROR_MODE_AUTO,
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED, useReadoutTimestamp);
+ if (ret == OK) {
+ mP010StreamId = *id;
+ mP010SurfaceId = (*surfaceIds)[0];
+ mOutputSurface = consumers[0];
+ } else {
+ return ret;
+ }
+
+ if (mSupportInternalJpeg) {
+ BufferQueue::createBufferQueue(&producer, &consumer);
+ mBlobConsumer = new CpuConsumer(consumer, /*maxLockedBuffers*/ 1, /*controlledByApp*/ true);
+ mBlobConsumer->setFrameAvailableListener(this);
+ mBlobConsumer->setName(String8("Camera3-JpegRCompositeStream"));
+ mBlobSurface = new Surface(producer);
+ std::vector<int> blobSurfaceId;
+ ret = device->createStream(mBlobSurface, width, height, format,
+ kJpegDataSpace, rotation, &mBlobStreamId, physicalCameraId, sensorPixelModesUsed,
+ &blobSurfaceId,
+ /*streamSetI*/ camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ /*isShared*/ false,
+ /*isMultiResolution*/ false,
+ /*consumerUsage*/ GRALLOC_USAGE_SW_READ_OFTEN,
+ /*dynamicProfile*/ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD,
+ streamUseCase,
+ /*timestampBase*/ OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
+ /*mirrorMode*/ OutputConfiguration::MIRROR_MODE_AUTO,
+ /*colorSpace*/ colorSpace, useReadoutTimestamp);
+ if (ret == OK) {
+ mBlobSurfaceId = blobSurfaceId[0];
+ } else {
+ return ret;
+ }
+
+ ret = registerCompositeStreamListener(mBlobStreamId);
+ if (ret != OK) {
+ ALOGE("%s: Failed to register jpeg stream listener!", __FUNCTION__);
+ return ret;
+ }
+ }
+
+ ret = registerCompositeStreamListener(getStreamId());
+ if (ret != OK) {
+ ALOGE("%s: Failed to register P010 stream listener!", __FUNCTION__);
+ return ret;
+ }
+
+ mOutputColorSpace = colorSpace;
+ mBlobWidth = width;
+ mBlobHeight = height;
+
+ return ret;
+}
+
+status_t JpegRCompositeStream::configureStream() {
+ if (isRunning()) {
+ // Processing thread is already running, nothing more to do.
+ return NO_ERROR;
+ }
+
+ if (mOutputSurface.get() == nullptr) {
+ ALOGE("%s: No valid output surface set!", __FUNCTION__);
+ return NO_INIT;
+ }
+
+ auto res = mOutputSurface->connect(NATIVE_WINDOW_API_CAMERA, mProducerListener);
+ if (res != OK) {
+ ALOGE("%s: Unable to connect to native window for stream %d",
+ __FUNCTION__, mP010StreamId);
+ return res;
+ }
+
+ if ((res = native_window_set_buffers_format(mOutputSurface.get(), HAL_PIXEL_FORMAT_BLOB))
+ != OK) {
+ ALOGE("%s: Unable to configure stream buffer format for stream %d", __FUNCTION__,
+ mP010StreamId);
+ return res;
+ }
+
+ int maxProducerBuffers;
+ ANativeWindow *anw = mP010Surface.get();
+ if ((res = anw->query(anw, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxProducerBuffers)) != OK) {
+ ALOGE("%s: Unable to query consumer undequeued"
+ " buffer count for stream %d", __FUNCTION__, mP010StreamId);
+ return res;
+ }
+
+ ANativeWindow *anwConsumer = mOutputSurface.get();
+ int maxConsumerBuffers;
+ if ((res = anwConsumer->query(anwConsumer, NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+ &maxConsumerBuffers)) != OK) {
+ ALOGE("%s: Unable to query consumer undequeued"
+ " buffer count for stream %d", __FUNCTION__, mP010StreamId);
+ return res;
+ }
+
+ if ((res = native_window_set_buffer_count(
+ anwConsumer, maxProducerBuffers + maxConsumerBuffers)) != OK) {
+ ALOGE("%s: Unable to set buffer count for stream %d", __FUNCTION__, mP010StreamId);
+ return res;
+ }
+
+ run("JpegRCompositeStreamProc");
+
+ return NO_ERROR;
+}
+
+status_t JpegRCompositeStream::deleteInternalStreams() {
+ // The 'CameraDeviceClient' parent will delete the P010 stream
+ requestExit();
+
+ auto ret = join();
+ if (ret != OK) {
+ ALOGE("%s: Failed to join with the main processing thread: %s (%d)", __FUNCTION__,
+ strerror(-ret), ret);
+ }
+
+ if (mBlobStreamId >= 0) {
+ // Camera devices may not be valid after switching to offline mode.
+ // In this case, all offline streams including internal composite streams
+ // are managed and released by the offline session.
+ sp<CameraDeviceBase> device = mDevice.promote();
+ if (device.get() != nullptr) {
+ ret = device->deleteStream(mBlobStreamId);
+ }
+
+ mBlobStreamId = -1;
+ }
+
+ if (mOutputSurface != nullptr) {
+ mOutputSurface->disconnect(NATIVE_WINDOW_API_CAMERA);
+ mOutputSurface.clear();
+ }
+
+ return ret;
+}
+
+void JpegRCompositeStream::onFrameAvailable(const BufferItem& item) {
+ if (item.mDataSpace == kJpegDataSpace) {
+ ALOGV("%s: Jpeg buffer with ts: %" PRIu64 " ms. arrived!",
+ __func__, ns2ms(item.mTimestamp));
+
+ Mutex::Autolock l(mMutex);
+ if (!mErrorState) {
+ mInputJpegBuffers.push_back(item.mTimestamp);
+ mInputReadyCondition.signal();
+ }
+ } else if (item.mDataSpace == static_cast<android_dataspace_t>(mP010DataSpace)) {
+ ALOGV("%s: P010 buffer with ts: %" PRIu64 " ms. arrived!", __func__,
+ ns2ms(item.mTimestamp));
+
+ Mutex::Autolock l(mMutex);
+ if (!mErrorState) {
+ mInputP010Buffers.push_back(item.mTimestamp);
+ mInputReadyCondition.signal();
+ }
+ } else {
+ ALOGE("%s: Unexpected data space: 0x%x", __FUNCTION__, item.mDataSpace);
+ }
+}
+
+status_t JpegRCompositeStream::insertGbp(SurfaceMap* /*out*/outSurfaceMap,
+ Vector<int32_t> * /*out*/outputStreamIds, int32_t* /*out*/currentStreamId) {
+ if (outputStreamIds == nullptr) {
+ return BAD_VALUE;
+ }
+
+ if (outSurfaceMap->find(mP010StreamId) == outSurfaceMap->end()) {
+ outputStreamIds->push_back(mP010StreamId);
+ }
+ (*outSurfaceMap)[mP010StreamId].push_back(mP010SurfaceId);
+
+ if (mSupportInternalJpeg) {
+ if (outSurfaceMap->find(mBlobStreamId) == outSurfaceMap->end()) {
+ outputStreamIds->push_back(mBlobStreamId);
+ }
+ (*outSurfaceMap)[mBlobStreamId].push_back(mBlobSurfaceId);
+ }
+
+ if (currentStreamId != nullptr) {
+ *currentStreamId = mP010StreamId;
+ }
+
+ return NO_ERROR;
+}
+
+status_t JpegRCompositeStream::insertCompositeStreamIds(
+ std::vector<int32_t>* compositeStreamIds /*out*/) {
+ if (compositeStreamIds == nullptr) {
+ return BAD_VALUE;
+ }
+
+ compositeStreamIds->push_back(mP010StreamId);
+ if (mSupportInternalJpeg) {
+ compositeStreamIds->push_back(mBlobStreamId);
+ }
+
+ return OK;
+}
+
+void JpegRCompositeStream::onResultError(const CaptureResultExtras& resultExtras) {
+ // Processing can continue even in case of result errors.
+ // At the moment Jpeg/R composite stream processing relies mainly on static camera
+ // characteristics data. The actual result data can be used for the jpeg quality but
+ // in case it is absent we can default to maximum.
+ eraseResult(resultExtras.frameNumber);
+}
+
+bool JpegRCompositeStream::onStreamBufferError(const CaptureResultExtras& resultExtras) {
+ bool ret = false;
+ // Buffer errors concerning internal composite streams should not be directly visible to
+ // camera clients. They must only receive a single buffer error with the public composite
+ // stream id.
+ if ((resultExtras.errorStreamId == mP010StreamId) ||
+ (resultExtras.errorStreamId == mBlobStreamId)) {
+ flagAnErrorFrameNumber(resultExtras.frameNumber);
+ ret = true;
+ }
+
+ return ret;
+}
+
+status_t JpegRCompositeStream::getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+ const CameraMetadata& staticInfo,
+ std::vector<OutputStreamInfo>* compositeOutput /*out*/) {
+ if (compositeOutput == nullptr) {
+ return BAD_VALUE;
+ }
+
+ int64_t dynamicRange, dataSpace;
+ deriveDynamicRangeAndDataspace(streamInfo.dynamicRangeProfile, &dynamicRange, &dataSpace);
+
+ compositeOutput->clear();
+ compositeOutput->push_back({});
+ (*compositeOutput)[0].width = streamInfo.width;
+ (*compositeOutput)[0].height = streamInfo.height;
+ (*compositeOutput)[0].format = kP010PixelFormat;
+ (*compositeOutput)[0].dataSpace = static_cast<android_dataspace_t>(dataSpace);
+ (*compositeOutput)[0].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+ (*compositeOutput)[0].dynamicRangeProfile = dynamicRange;
+ (*compositeOutput)[0].colorSpace =
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED;
+
+ if (CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(staticInfo,
+ streamInfo.dynamicRangeProfile,
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD)) {
+ compositeOutput->push_back({});
+ (*compositeOutput)[1].width = streamInfo.width;
+ (*compositeOutput)[1].height = streamInfo.height;
+ (*compositeOutput)[1].format = HAL_PIXEL_FORMAT_BLOB;
+ (*compositeOutput)[1].dataSpace = kJpegDataSpace;
+ (*compositeOutput)[1].consumerUsage = GRALLOC_USAGE_SW_READ_OFTEN;
+ (*compositeOutput)[1].dynamicRangeProfile =
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ (*compositeOutput)[1].colorSpace = streamInfo.colorSpace;
+ }
+
+ return NO_ERROR;
+}
+
+}; // namespace camera3
+}; // namespace android
diff --git a/services/camera/libcameraservice/api2/JpegRCompositeStream.h b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
new file mode 100644
index 0000000..4b462b5
--- /dev/null
+++ b/services/camera/libcameraservice/api2/JpegRCompositeStream.h
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA3_JPEG_R_COMPOSITE_STREAM_H
+#define ANDROID_SERVERS_CAMERA_CAMERA3_JPEG_R_COMPOSITE_STREAM_H
+
+#include <gui/CpuConsumer.h>
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
+#include "system/graphics-base-v1.1.h"
+
+#include "api1/client2/JpegProcessor.h"
+
+#include "CompositeStream.h"
+
+namespace android {
+
+class CameraDeviceClient;
+class CameraMetadata;
+class Surface;
+
+namespace camera3 {
+
+class JpegRCompositeStream : public CompositeStream, public Thread,
+ public CpuConsumer::FrameAvailableListener {
+
+public:
+ JpegRCompositeStream(sp<CameraDeviceBase> device,
+ wp<hardware::camera2::ICameraDeviceCallbacks> cb);
+ ~JpegRCompositeStream() override;
+
+ static bool isJpegRCompositeStream(const sp<Surface> &surface);
+
+ // CompositeStream overrides
+ status_t createInternalStreams(const std::vector<sp<Surface>>& consumers,
+ bool hasDeferredConsumer, uint32_t width, uint32_t height, int format,
+ camera_stream_rotation_t rotation, int *id, const String8& physicalCameraId,
+ const std::unordered_set<int32_t> &sensorPixelModesUsed,
+ std::vector<int> *surfaceIds,
+ int streamSetId, bool isShared, int32_t colorSpace,
+ int64_t dynamicProfile, int64_t streamUseCase, bool useReadoutTimestamp) override;
+ status_t deleteInternalStreams() override;
+ status_t configureStream() override;
+ status_t insertGbp(SurfaceMap* /*out*/outSurfaceMap, Vector<int32_t>* /*out*/outputStreamIds,
+ int32_t* /*out*/currentStreamId) override;
+ status_t insertCompositeStreamIds(std::vector<int32_t>* compositeStreamIds /*out*/) override;
+ int getStreamId() override { return mP010StreamId; }
+
+ // CpuConsumer listener implementation
+ void onFrameAvailable(const BufferItem& item) override;
+
+ // Return stream information about the internal camera streams
+ static status_t getCompositeStreamInfo(const OutputStreamInfo &streamInfo,
+ const CameraMetadata& ch, std::vector<OutputStreamInfo>* compositeOutput /*out*/);
+
+protected:
+
+ bool threadLoop() override;
+ bool onStreamBufferError(const CaptureResultExtras& resultExtras) override;
+ void onResultError(const CaptureResultExtras& resultExtras) override;
+
+private:
+ struct InputFrame {
+ CpuConsumer::LockedBuffer p010Buffer;
+ CpuConsumer::LockedBuffer jpegBuffer;
+ CameraMetadata result;
+ bool error;
+ bool errorNotified;
+ int64_t frameNumber;
+ int32_t requestId;
+
+ InputFrame() : error(false), errorNotified(false), frameNumber(-1), requestId(-1) { }
+ };
+
+ status_t processInputFrame(nsecs_t ts, const InputFrame &inputFrame);
+
+ // Buffer/Results handling
+ void compilePendingInputLocked();
+ void releaseInputFrameLocked(InputFrame *inputFrame /*out*/);
+ void releaseInputFramesLocked(int64_t currentTs);
+
+ // Find first complete and valid frame with smallest timestamp
+ bool getNextReadyInputLocked(int64_t *currentTs /*inout*/);
+
+ // Find next failing frame number with smallest timestamp and return respective frame number
+ int64_t getNextFailingInputLocked(int64_t *currentTs /*inout*/);
+
+ static void deriveDynamicRangeAndDataspace(int64_t dynamicProfile, int64_t* /*out*/dynamicRange,
+ int64_t* /*out*/dataSpace);
+
+ static const nsecs_t kWaitDuration = 10000000; // 10 ms
+ static const auto kP010PixelFormat = HAL_PIXEL_FORMAT_YCBCR_P010;
+ static const auto kP010DefaultDataSpace = HAL_DATASPACE_BT2020_ITU_HLG;
+ static const auto kP010DefaultDynamicRange =
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10;
+ static const auto kJpegDataSpace = HAL_DATASPACE_V0_JFIF;
+ static const auto kJpegRDataSpace =
+ aidl::android::hardware::graphics::common::Dataspace::JPEG_R;
+
+ bool mSupportInternalJpeg = false;
+ int64_t mP010DataSpace = HAL_DATASPACE_BT2020_HLG;
+ int64_t mP010DynamicRange =
+ ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_HLG10;
+ int mBlobStreamId, mBlobSurfaceId, mP010StreamId, mP010SurfaceId;
+ size_t mBlobWidth, mBlobHeight;
+ sp<CpuConsumer> mBlobConsumer, mP010Consumer;
+ bool mP010BufferAcquired, mBlobBufferAcquired;
+ sp<Surface> mP010Surface, mBlobSurface, mOutputSurface;
+ int32_t mOutputColorSpace;
+ sp<ProducerListener> mProducerListener;
+
+ ssize_t mMaxJpegBufferSize;
+ ssize_t mUHRMaxJpegBufferSize;
+
+ camera3::Size mDefaultMaxJpegSize;
+ camera3::Size mUHRMaxJpegSize;
+
+ // Keep all incoming P010 buffer timestamps pending further processing.
+ std::vector<int64_t> mInputP010Buffers;
+
+ // Keep all incoming Jpeg/Blob buffer timestamps pending further processing.
+ std::vector<int64_t> mInputJpegBuffers;
+
+ // Map of all input frames pending further processing.
+ std::unordered_map<int64_t, InputFrame> mPendingInputFrames;
+
+ const CameraMetadata mStaticInfo;
+};
+
+}; //namespace camera3
+}; //namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 4555838..0a2819c 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -158,7 +158,8 @@
}
/** Start watchdog thread */
- mCameraServiceWatchdog = new CameraServiceWatchdog();
+ mCameraServiceWatchdog = new CameraServiceWatchdog(TClientBase::mCameraIdStr,
+ mCameraServiceProxyWrapper);
res = mCameraServiceWatchdog->run("Camera2ClientBaseWatchdog");
if (res != OK) {
ALOGE("%s: Unable to start camera service watchdog thread: %s (%d)",
@@ -359,6 +360,29 @@
}
template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyPhysicalCameraChange(const std::string &physicalId) {
+ // We're only interested in this notification if overrideToPortrait is turned on.
+ if (!TClientBase::mOverrideToPortrait) {
+ return;
+ }
+
+ String8 physicalId8(physicalId.c_str());
+ auto physicalCameraMetadata = mDevice->infoPhysical(physicalId8);
+ auto orientationEntry = physicalCameraMetadata.find(ANDROID_SENSOR_ORIENTATION);
+
+ if (orientationEntry.count == 1) {
+ int orientation = orientationEntry.data.i32[0];
+ int rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_NONE;
+
+ if (orientation == 0 || orientation == 180) {
+ rotateAndCropMode = ANDROID_SCALER_ROTATE_AND_CROP_90;
+ }
+
+ static_cast<TClientBase *>(this)->setRotateAndCropOverride(rotateAndCropMode);
+ }
+}
+
+template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::notifyActive(float maxPreviewFps) {
if (!mDeviceActive) {
status_t res = TClientBase::startCameraStreamingOps();
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 89347eb..5cf3033 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -77,6 +77,7 @@
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras& resultExtras);
+ virtual void notifyPhysicalCameraChange(const std::string &physicalId) override;
// Returns errors on app ops permission failures
virtual status_t notifyActive(float maxPreviewFps);
virtual void notifyIdle(int64_t /*requestCount*/, int64_t /*resultErrorCount*/,
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 977ab7c..6f15653 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -193,7 +193,8 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false)
= 0;
/**
@@ -216,7 +217,8 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false)
= 0;
/**
@@ -473,11 +475,25 @@
virtual wp<camera3::StatusTracker> getStatusTracker() = 0;
/**
+ * If the device is in eror state
+ */
+ virtual bool hasDeviceError() = 0;
+
+ /**
* Set bitmask for image dump flag
*/
void setImageDumpMask(int mask) { mImageDumpMask = mask; }
/**
+ * Set stream use case overrides
+ */
+ void setStreamUseCaseOverrides(const std::vector<int64_t>& useCaseOverrides) {
+ mStreamUseCaseOverrides = useCaseOverrides;
+ }
+
+ void clearStreamUseCaseOverrides() {}
+
+ /**
* The injection camera session to replace the internal camera
* session.
*/
@@ -491,6 +507,7 @@
protected:
bool mImageDumpMask = 0;
+ std::vector<int64_t> mStreamUseCaseOverrides;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
index f39b92a..63abcf0 100644
--- a/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
+++ b/services/camera/libcameraservice/common/CameraOfflineSessionBase.h
@@ -40,6 +40,10 @@
// Required for API 1 and 2
virtual void notifyError(int32_t errorCode,
const CaptureResultExtras &resultExtras) = 0;
+
+ // Optional for API 1 and 2
+ virtual void notifyPhysicalCameraChange(const std::string &/*physicalId*/) {}
+
// May return an error since it checks appops
virtual status_t notifyActive(float maxPreviewFps) = 0;
virtual void notifyIdle(int64_t requestCount, int64_t resultError, bool deviceError,
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 89c7459..a70cc19 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include "system/graphics-base-v1.0.h"
+#include "system/graphics-base-v1.1.h"
#define LOG_TAG "CameraProviderManager"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
@@ -40,6 +42,7 @@
#include <cutils/properties.h>
#include <hwbinder/IPCThreadState.h>
#include <utils/Trace.h>
+#include <ui/PublicFormat.h>
#include "api2/HeicCompositeStream.h"
#include "device3/ZoomRatioMapper.h"
@@ -59,6 +62,8 @@
} // anonymous namespace
const float CameraProviderManager::kDepthARTolerance = .1f;
+const bool CameraProviderManager::kFrameworkJpegRDisabled =
+ property_get_bool("ro.camera.disableJpegR", false);
CameraProviderManager::HidlServiceInteractionProxyImpl
CameraProviderManager::sHidlServiceInteractionProxy{};
@@ -1071,6 +1076,201 @@
}
}
+bool CameraProviderManager::isConcurrentDynamicRangeCaptureSupported(
+ const CameraMetadata& deviceInfo, int64_t profile, int64_t concurrentProfile) {
+ auto entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (entry.count == 0) {
+ return false;
+ }
+
+ const auto it = std::find(entry.data.u8, entry.data.u8 + entry.count,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT);
+ if (it == entry.data.u8 + entry.count) {
+ return false;
+ }
+
+ entry = deviceInfo.find(ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP);
+ if (entry.count == 0 || ((entry.count % 3) != 0)) {
+ return false;
+ }
+
+ for (size_t i = 0; i < entry.count; i += 3) {
+ if (entry.data.i64[i] == profile) {
+ if (entry.data.i64[i+1] & concurrentProfile) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+status_t CameraProviderManager::ProviderInfo::DeviceInfo3::deriveJpegRTags(bool maxResolution) {
+ if (kFrameworkJpegRDisabled) {
+ return OK;
+ }
+
+ const int32_t scalerSizesTag =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t scalerMinFrameDurationsTag =
+ ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS;
+ const int32_t scalerStallDurationsTag =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_SCALER_AVAILABLE_STALL_DURATIONS, maxResolution);
+
+ const int32_t jpegRSizesTag =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS, maxResolution);
+ const int32_t jpegRStallDurationsTag =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS, maxResolution);
+ const int32_t jpegRMinFrameDurationsTag =
+ SessionConfigurationUtils::getAppropriateModeTag(
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS, maxResolution);
+
+ auto& c = mCameraCharacteristics;
+ std::vector<int32_t> supportedChTags;
+ auto chTags = c.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ if (chTags.count == 0) {
+ ALOGE("%s: No supported camera characteristics keys!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ std::vector<std::tuple<size_t, size_t>> supportedP010Sizes, supportedBlobSizes,
+ supportedDynamicDepthSizes, internalDepthSizes;
+ auto capabilities = c.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
+ if (capabilities.count == 0) {
+ ALOGE("%s: Supported camera capabilities is empty!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ auto end = capabilities.data.u8 + capabilities.count;
+ bool isTenBitOutputSupported = std::find(capabilities.data.u8, end,
+ ANDROID_REQUEST_AVAILABLE_CAPABILITIES_DYNAMIC_RANGE_TEN_BIT) != end;
+ if (!isTenBitOutputSupported) {
+ // No 10-bit support, nothing more to do.
+ return OK;
+ }
+
+ getSupportedSizes(c, scalerSizesTag,
+ static_cast<android_pixel_format_t>(HAL_PIXEL_FORMAT_BLOB), &supportedBlobSizes);
+ getSupportedSizes(c, scalerSizesTag,
+ static_cast<android_pixel_format_t>(HAL_PIXEL_FORMAT_YCBCR_P010), &supportedP010Sizes);
+ auto it = supportedP010Sizes.begin();
+ while (it != supportedP010Sizes.end()) {
+ // Resolutions that don't align on 32 pixels are not supported by Jpeg/R.
+ // This can be removed as soon as the encoder restriction is lifted.
+ if ((std::find(supportedBlobSizes.begin(), supportedBlobSizes.end(), *it) ==
+ supportedBlobSizes.end()) || ((std::get<0>(*it) % 32) != 0)) {
+ it = supportedP010Sizes.erase(it);
+ } else {
+ it++;
+ }
+ }
+ if (supportedP010Sizes.empty()) {
+ // Nothing to do in this case.
+ return OK;
+ }
+
+ std::vector<int32_t> jpegREntries;
+ for (const auto& it : supportedP010Sizes) {
+ int32_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(it)),
+ static_cast<int32_t> (std::get<1>(it)),
+ ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_OUTPUT };
+ jpegREntries.insert(jpegREntries.end(), entry, entry + 4);
+ }
+
+ std::vector<int64_t> blobMinDurations, blobStallDurations;
+ std::vector<int64_t> jpegRMinDurations, jpegRStallDurations;
+
+ // We use the jpeg stall and min frame durations to approximate the respective jpeg/r
+ // durations.
+ getSupportedDurations(c, scalerMinFrameDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+ supportedP010Sizes, &blobMinDurations);
+ getSupportedDurations(c, scalerStallDurationsTag, HAL_PIXEL_FORMAT_BLOB,
+ supportedP010Sizes, &blobStallDurations);
+ if (blobStallDurations.empty() || blobMinDurations.empty() ||
+ (blobMinDurations.size() != blobStallDurations.size())) {
+ ALOGE("%s: Unexpected number of available blob durations! %zu vs. %zu",
+ __FUNCTION__, blobMinDurations.size(), blobStallDurations.size());
+ return BAD_VALUE;
+ }
+
+ auto itDuration = blobMinDurations.begin();
+ auto itSize = supportedP010Sizes.begin();
+ while (itDuration != blobMinDurations.end()) {
+ int64_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(*itSize)),
+ static_cast<int32_t> (std::get<1>(*itSize)), *itDuration};
+ jpegRMinDurations.insert(jpegRMinDurations.end(), entry, entry + 4);
+ itDuration++; itSize++;
+ }
+
+ itDuration = blobStallDurations.begin();
+ itSize = supportedP010Sizes.begin();
+ while (itDuration != blobStallDurations.end()) {
+ int64_t entry[4] = {HAL_PIXEL_FORMAT_BLOB, static_cast<int32_t> (std::get<0>(*itSize)),
+ static_cast<int32_t> (std::get<1>(*itSize)), *itDuration};
+ jpegRStallDurations.insert(jpegRStallDurations.end(), entry, entry + 4);
+ itDuration++; itSize++;
+ }
+
+ supportedChTags.reserve(chTags.count + 3);
+ supportedChTags.insert(supportedChTags.end(), chTags.data.i32,
+ chTags.data.i32 + chTags.count);
+ supportedChTags.push_back(jpegRSizesTag);
+ supportedChTags.push_back(jpegRMinFrameDurationsTag);
+ supportedChTags.push_back(jpegRStallDurationsTag);
+ c.update(jpegRSizesTag, jpegREntries.data(), jpegREntries.size());
+ c.update(jpegRMinFrameDurationsTag, jpegRMinDurations.data(), jpegRMinDurations.size());
+ c.update(jpegRStallDurationsTag, jpegRStallDurations.data(), jpegRStallDurations.size());
+ c.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, supportedChTags.data(),
+ supportedChTags.size());
+
+ auto colorSpaces = c.find(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP);
+ if (colorSpaces.count > 0 && !maxResolution) {
+ bool displayP3Support = false;
+ int64_t dynamicRange = ANDROID_REQUEST_AVAILABLE_DYNAMIC_RANGE_PROFILES_MAP_STANDARD;
+ for (size_t i = 0; i < colorSpaces.count; i += 3) {
+ auto colorSpace = colorSpaces.data.i64[i];
+ auto format = colorSpaces.data.i64[i+1];
+ bool formatMatch = (format == static_cast<int64_t>(PublicFormat::JPEG)) ||
+ (format == static_cast<int64_t>(PublicFormat::UNKNOWN));
+ bool colorSpaceMatch =
+ colorSpace == ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3;
+ if (formatMatch && colorSpaceMatch) {
+ displayP3Support = true;
+ }
+
+ // Jpeg/R will support the same dynamic range profiles as P010
+ if (format == static_cast<int64_t>(PublicFormat::YCBCR_P010)) {
+ dynamicRange |= colorSpaces.data.i64[i+2];
+ }
+ }
+ if (displayP3Support) {
+ std::vector<int64_t> supportedColorSpaces;
+ // Jpeg/R must support the default system as well ase display P3 color space
+ supportedColorSpaces.reserve(colorSpaces.count + 3*2);
+ supportedColorSpaces.insert(supportedColorSpaces.end(), colorSpaces.data.i64,
+ colorSpaces.data.i64 + colorSpaces.count);
+
+ supportedColorSpaces.push_back(static_cast<int64_t>(
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB));
+ supportedColorSpaces.push_back(static_cast<int64_t>(PublicFormat::JPEG_R));
+ supportedColorSpaces.push_back(dynamicRange);
+
+ supportedColorSpaces.push_back(static_cast<int64_t>(
+ ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3));
+ supportedColorSpaces.push_back(static_cast<int64_t>(PublicFormat::JPEG_R));
+ supportedColorSpaces.push_back(dynamicRange);
+ c.update(ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP,
+ supportedColorSpaces.data(), supportedColorSpaces.size());
+ }
+ }
+
+ return OK;
+}
+
status_t CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags(
bool maxResolution) {
const int32_t depthExclTag = ANDROID_DEPTH_DEPTH_IS_EXCLUSIVE;
@@ -2046,7 +2246,7 @@
}
CameraMetadata info2;
res = device->getCameraCharacteristics(true /*overrideForPerfClass*/, &info2,
- /*overrideToPortrait*/true);
+ /*overrideToPortrait*/false);
if (res == INVALID_OPERATION) {
dprintf(fd, " API2 not directly supported\n");
} else if (res != OK) {
@@ -2397,8 +2597,8 @@
if (overrideToPortrait) {
const auto &lensFacingEntry = characteristics->find(ANDROID_LENS_FACING);
const auto &sensorOrientationEntry = characteristics->find(ANDROID_SENSOR_ORIENTATION);
+ uint8_t lensFacing = lensFacingEntry.data.u8[0];
if (lensFacingEntry.count > 0 && sensorOrientationEntry.count > 0) {
- uint8_t lensFacing = lensFacingEntry.data.u8[0];
int32_t sensorOrientation = sensorOrientationEntry.data.i32[0];
int32_t newSensorOrientation = sensorOrientation;
@@ -2419,6 +2619,8 @@
}
if (characteristics->exists(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS)) {
+ ALOGV("%s: Erasing ANDROID_INFO_DEVICE_STATE_ORIENTATIONS for lens facing %d",
+ __FUNCTION__, lensFacing);
characteristics->erase(ANDROID_INFO_DEVICE_STATE_ORIENTATIONS);
}
}
@@ -2454,8 +2656,8 @@
for (size_t i = 0; i < streamConfigs.count; i += 4) {
if ((streamConfigs.data.i32[i] == HAL_PIXEL_FORMAT_BLOB) && (streamConfigs.data.i32[i+3] ==
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT)) {
- if (streamConfigs.data.i32[i+1] < thresholdW ||
- streamConfigs.data.i32[i+2] < thresholdH) {
+ if (streamConfigs.data.i32[i+1] * streamConfigs.data.i32[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount ++;
@@ -2475,8 +2677,8 @@
mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS);
for (size_t i = 0; i < minDurations.count; i += 4) {
if (minDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
- if (minDurations.data.i64[i+1] < thresholdW ||
- minDurations.data.i64[i+2] < thresholdH) {
+ if ((int32_t)minDurations.data.i64[i+1] * (int32_t)minDurations.data.i64[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount++;
@@ -2496,8 +2698,8 @@
mCameraCharacteristics.find(ANDROID_SCALER_AVAILABLE_STALL_DURATIONS);
for (size_t i = 0; i < stallDurations.count; i += 4) {
if (stallDurations.data.i64[i] == HAL_PIXEL_FORMAT_BLOB) {
- if (stallDurations.data.i64[i+1] < thresholdW ||
- stallDurations.data.i64[i+2] < thresholdH) {
+ if ((int32_t)stallDurations.data.i64[i+1] * (int32_t)stallDurations.data.i64[i+2] <
+ thresholdW * thresholdH) {
continue;
} else {
largeJpegCount++;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index ab1b389..acf511b 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -407,7 +407,11 @@
status_t notifyUsbDeviceEvent(int32_t eventId, const std::string &usbDeviceId);
+ static bool isConcurrentDynamicRangeCaptureSupported(const CameraMetadata& deviceInfo,
+ int64_t profile, int64_t concurrentProfile);
+
static const float kDepthARTolerance;
+ static const bool kFrameworkJpegRDisabled;
private:
// All private members, unless otherwise noted, expect mInterfaceMutex to be locked before use
mutable std::mutex mInterfaceMutex;
@@ -675,6 +679,7 @@
status_t fixupTorchStrengthTags();
status_t addDynamicDepthTags(bool maxResolution = false);
status_t deriveHeicTags(bool maxResolution = false);
+ status_t deriveJpegRTags(bool maxResolution = false);
status_t addRotateCropTags();
status_t addAutoframingTags();
status_t addPreCorrectionActiveArraySize();
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index 5a449b6..84fe3a5 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -501,6 +501,11 @@
ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities: %s (%d)",
__FUNCTION__, strerror(-res), res);
}
+ res = deriveJpegRTags();
+ if (OK != res) {
+ ALOGE("%s: Unable to derive Jpeg/R tags based on camera and media capabilities: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
if (camera3::SessionConfigurationUtils::isUltraHighResolutionSensor(mCameraCharacteristics)) {
status_t status = addDynamicDepthTags(/*maxResolution*/true);
@@ -514,6 +519,12 @@
ALOGE("%s: Unable to derive HEIC tags based on camera and media capabilities for"
"maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
}
+
+ status = deriveJpegRTags(/*maxResolution*/true);
+ if (OK != status) {
+ ALOGE("%s: Unable to derive Jpeg/R tags based on camera and media capabilities for"
+ "maximum resolution mode: %s (%d)", __FUNCTION__, strerror(-status), status);
+ }
}
res = addRotateCropTags();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 5e99389..427d972 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -52,15 +52,16 @@
#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
-#include "utils/CameraTraces.h"
-#include "mediautils/SchedulingPolicyService.h"
-#include "device3/Camera3Device.h"
-#include "device3/Camera3OutputStream.h"
-#include "device3/Camera3InputStream.h"
-#include "device3/Camera3FakeStream.h"
-#include "device3/Camera3SharedOutputStream.h"
#include "CameraService.h"
+#include "aidl/AidlUtils.h"
+#include "device3/Camera3Device.h"
+#include "device3/Camera3FakeStream.h"
+#include "device3/Camera3InputStream.h"
+#include "device3/Camera3OutputStream.h"
+#include "device3/Camera3SharedOutputStream.h"
+#include "mediautils/SchedulingPolicyService.h"
#include "utils/CameraThreadState.h"
+#include "utils/CameraTraces.h"
#include "utils/SessionConfigurationUtils.h"
#include "utils/TraceHFR.h"
@@ -96,7 +97,8 @@
mLastTemplateId(-1),
mNeedFixupMonochromeTags(false),
mOverrideForPerfClass(overrideForPerfClass),
- mOverrideToPortrait(overrideToPortrait)
+ mOverrideToPortrait(overrideToPortrait),
+ mActivePhysicalId("")
{
ATRACE_CALL();
ALOGV("%s: Created device for camera %s", __FUNCTION__, mId.string());
@@ -229,7 +231,7 @@
mInjectionMethods = createCamera3DeviceInjectionMethods(this);
/** Start watchdog thread */
- mCameraServiceWatchdog = new CameraServiceWatchdog();
+ mCameraServiceWatchdog = new CameraServiceWatchdog(mId, mCameraServiceProxyWrapper);
res = mCameraServiceWatchdog->run("CameraServiceWatchdog");
if (res != OK) {
SET_ERR_L("Unable to start camera service watchdog thread: %s (%d)",
@@ -1001,7 +1003,7 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
uint64_t consumerUsage, int64_t dynamicRangeProfile, int64_t streamUseCase,
- int timestampBase, int mirrorMode, int32_t colorSpace) {
+ int timestampBase, int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) {
ATRACE_CALL();
if (consumer == nullptr) {
@@ -1015,7 +1017,7 @@
return createStream(consumers, /*hasDeferredConsumer*/ false, width, height,
format, dataSpace, rotation, id, physicalCameraId, sensorPixelModesUsed, surfaceIds,
streamSetId, isShared, isMultiResolution, consumerUsage, dynamicRangeProfile,
- streamUseCase, timestampBase, mirrorMode, colorSpace);
+ streamUseCase, timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
}
static bool isRawFormat(int format) {
@@ -1036,7 +1038,7 @@
const String8& physicalCameraId, const std::unordered_set<int32_t> &sensorPixelModesUsed,
std::vector<int> *surfaceIds, int streamSetId, bool isShared, bool isMultiResolution,
uint64_t consumerUsage, int64_t dynamicRangeProfile, int64_t streamUseCase,
- int timestampBase, int mirrorMode, int32_t colorSpace) {
+ int timestampBase, int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
@@ -1045,10 +1047,11 @@
ALOGV("Camera %s: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
" consumer usage %" PRIu64 ", isShared %d, physicalCameraId %s, isMultiResolution %d"
" dynamicRangeProfile 0x%" PRIx64 ", streamUseCase %" PRId64 ", timestampBase %d,"
- " mirrorMode %d colorSpace %d",
+ " mirrorMode %d, colorSpace %d, useReadoutTimestamp %d",
mId.string(), mNextStreamId, width, height, format, dataSpace, rotation,
consumerUsage, isShared, physicalCameraId.string(), isMultiResolution,
- dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode, colorSpace);
+ dynamicRangeProfile, streamUseCase, timestampBase, mirrorMode, colorSpace,
+ useReadoutTimestamp);
status_t res;
bool wasActive = false;
@@ -1119,7 +1122,7 @@
width, height, blobBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace);
+ timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
} else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
bool maxResolution =
sensorPixelModesUsed.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
@@ -1134,25 +1137,25 @@
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace);
+ timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
} else if (isShared) {
newStream = new Camera3SharedOutputStream(mNextStreamId, consumers,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
mUseHalBufManager, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace);
+ timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
} else if (consumers.size() == 0 && hasDeferredConsumer) {
newStream = new Camera3OutputStream(mNextStreamId,
width, height, format, consumerUsage, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace);
+ timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumers[0],
width, height, format, dataSpace, rotation,
mTimestampOffset, physicalCameraId, sensorPixelModesUsed, transport, streamSetId,
isMultiResolution, dynamicRangeProfile, streamUseCase, mDeviceTimeBaseIsRealtime,
- timestampBase, mirrorMode, colorSpace);
+ timestampBase, mirrorMode, colorSpace, useReadoutTimestamp);
}
size_t consumerCount = consumers.size();
@@ -2363,6 +2366,9 @@
tryRemoveFakeStreamLocked();
}
+ // Override stream use case based on "adb shell command"
+ overrideStreamUseCaseLocked();
+
// Start configuring the streams
ALOGV("%s: Camera %s: Starting stream configuration", __FUNCTION__, mId.string());
@@ -2941,6 +2947,7 @@
mSupportCameraMute(supportCameraMute),
mOverrideToPortrait(overrideToPortrait) {
mStatusId = statusTracker->addComponent("RequestThread");
+ mVndkVersion = property_get_int32("ro.vndk.version", __ANDROID_API_FUTURE__);
}
Camera3Device::RequestThread::~RequestThread() {}
@@ -3735,6 +3742,17 @@
}
captureRequest->mRotationAndCropUpdated = true;
}
+
+ for (it = captureRequest->mSettingsList.begin();
+ it != captureRequest->mSettingsList.end(); it++) {
+ res = hardware::cameraservice::utils::conversion::aidl::filterVndkKeys(
+ mVndkVersion, it->metadata, false /*isStatic*/);
+ if (res != OK) {
+ SET_ERR("RequestThread: Failed during VNDK filter of capture requests "
+ "%d: %s (%d)", halRequest->frame_number, strerror(-res), res);
+ return INVALID_OPERATION;
+ }
+ }
}
}
@@ -4160,6 +4178,25 @@
return OK;
}
+void Camera3Device::setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides) {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ mStreamUseCaseOverrides = useCaseOverrides;
+}
+
+void Camera3Device::clearStreamUseCaseOverrides() {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ mStreamUseCaseOverrides.clear();
+}
+
+bool Camera3Device::hasDeviceError() {
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+ return mStatus == STATUS_ERROR;
+}
+
void Camera3Device::RequestThread::cleanUpFailedRequests(bool sendRequestError) {
if (mNextRequests.empty()) {
return;
@@ -5314,4 +5351,56 @@
return mInjectionMethods->stopInjection();
}
+void Camera3Device::overrideStreamUseCaseLocked() {
+ if (mStreamUseCaseOverrides.size() == 0) {
+ return;
+ }
+
+ // Start from an array of indexes in mStreamUseCaseOverrides, and sort them
+ // based first on size, and second on formats of [JPEG, RAW, YUV, PRIV].
+ // Refer to CameraService::printHelp for details.
+ std::vector<int> outputStreamsIndices(mOutputStreams.size());
+ for (size_t i = 0; i < outputStreamsIndices.size(); i++) {
+ outputStreamsIndices[i] = i;
+ }
+
+ std::sort(outputStreamsIndices.begin(), outputStreamsIndices.end(),
+ [&](int a, int b) -> bool {
+
+ auto formatScore = [](int format) {
+ switch (format) {
+ case HAL_PIXEL_FORMAT_BLOB:
+ return 4;
+ case HAL_PIXEL_FORMAT_RAW16:
+ case HAL_PIXEL_FORMAT_RAW10:
+ case HAL_PIXEL_FORMAT_RAW12:
+ return 3;
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ return 2;
+ case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
+ return 1;
+ default:
+ return 0;
+ }
+ };
+
+ int sizeA = mOutputStreams[a]->getWidth() * mOutputStreams[a]->getHeight();
+ int sizeB = mOutputStreams[a]->getWidth() * mOutputStreams[a]->getHeight();
+ int formatAScore = formatScore(mOutputStreams[a]->getFormat());
+ int formatBScore = formatScore(mOutputStreams[b]->getFormat());
+ if (sizeA > sizeB ||
+ (sizeA == sizeB && formatAScore >= formatBScore)) {
+ return true;
+ } else {
+ return false;
+ }
+ });
+
+ size_t overlapSize = std::min(mStreamUseCaseOverrides.size(), mOutputStreams.size());
+ for (size_t i = 0; i < mOutputStreams.size(); i++) {
+ mOutputStreams[outputStreamsIndices[i]]->setStreamUseCase(
+ mStreamUseCaseOverrides[std::min(i, overlapSize-1)]);
+ }
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 9b75ac5..c585d74 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -153,7 +153,8 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false)
override;
status_t createStream(const std::vector<sp<Surface>>& consumers,
@@ -170,7 +171,8 @@
int64_t streamUseCase = ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED)
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false)
override;
status_t createInputStream(
@@ -301,9 +303,19 @@
*/
status_t setCameraServiceWatchdog(bool enabled);
+ // Set stream use case overrides
+ void setStreamUseCaseOverrides(
+ const std::vector<int64_t>& useCaseOverrides);
+
+ // Clear stream use case overrides
+ void clearStreamUseCaseOverrides();
+
// Get the status trackeer for the camera device
wp<camera3::StatusTracker> getStatusTracker() { return mStatusTracker; }
+ // Whether the device is in error state
+ bool hasDeviceError();
+
/**
* The injection camera session to replace the internal camera
* session.
@@ -1122,6 +1134,7 @@
const bool mUseHalBufManager;
const bool mSupportCameraMute;
const bool mOverrideToPortrait;
+ int32_t mVndkVersion = -1;
};
virtual sp<RequestThread> createNewRequestThread(wp<Camera3Device> /*parent*/,
@@ -1404,6 +1417,9 @@
// app compatibility reasons.
bool mOverrideToPortrait;
+ // Current active physical id of the logical multi-camera, if any
+ std::string mActivePhysicalId;
+
// The current minimum expected frame duration based on AE_TARGET_FPS_RANGE
nsecs_t mMinExpectedDuration = 0;
// Whether the camera device runs at fixed frame rate based on AE_MODE and
@@ -1492,6 +1508,8 @@
sp<Camera3DeviceInjectionMethods> mInjectionMethods;
+ void overrideStreamUseCaseLocked();
+
}; // class Camera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3FakeStream.h b/services/camera/libcameraservice/device3/Camera3FakeStream.h
index a93d1da..1e9f478 100644
--- a/services/camera/libcameraservice/device3/Camera3FakeStream.h
+++ b/services/camera/libcameraservice/device3/Camera3FakeStream.h
@@ -101,6 +101,8 @@
virtual status_t setBatchSize(size_t batchSize) override;
virtual void onMinDurationChanged(nsecs_t /*duration*/, bool /*fixedFps*/) {}
+
+ virtual void setStreamUseCase(int64_t /*streamUseCase*/) {}
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 1abcd86..2227232 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -56,7 +56,7 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace) :
+ int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
@@ -67,7 +67,7 @@
mTraceFirstBuffer(true),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
- mUseReadoutTime(false),
+ mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(0),
mDropBuffers(false),
mMirrorMode(mirrorMode),
@@ -91,7 +91,7 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace) :
+ int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height, maxSize,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
setId, isMultiResolution, dynamicRangeProfile, streamUseCase,
@@ -101,7 +101,7 @@
mTraceFirstBuffer(true),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
- mUseReadoutTime(false),
+ mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(0),
mDropBuffers(false),
mMirrorMode(mirrorMode),
@@ -131,7 +131,7 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool isMultiResolution, int64_t dynamicRangeProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace) :
+ int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
Camera3IOStreamBase(id, CAMERA_STREAM_OUTPUT, width, height,
/*maxSize*/0, format, dataSpace, rotation,
physicalCameraId, sensorPixelModesUsed, setId, isMultiResolution,
@@ -142,7 +142,7 @@
mTraceFirstBuffer(true),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
- mUseReadoutTime(false),
+ mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
mMirrorMode(mirrorMode),
@@ -180,7 +180,8 @@
int setId, bool isMultiResolution,
int64_t dynamicRangeProfile, int64_t streamUseCase,
bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace) :
+ int mirrorMode, int32_t colorSpace,
+ bool useReadoutTimestamp) :
Camera3IOStreamBase(id, type, width, height,
/*maxSize*/0,
format, dataSpace, rotation,
@@ -191,7 +192,7 @@
mTraceFirstBuffer(true),
mUseBufferManager(false),
mTimestampOffset(timestampOffset),
- mUseReadoutTime(false),
+ mUseReadoutTime(useReadoutTimestamp),
mConsumerUsage(consumerUsage),
mDropBuffers(false),
mMirrorMode(mirrorMode),
@@ -467,7 +468,7 @@
}
}
- nsecs_t captureTime = (mUseReadoutTime && readoutTimestamp != 0 ?
+ nsecs_t captureTime = ((mUseReadoutTime || mSyncToDisplay) && readoutTimestamp != 0 ?
readoutTimestamp : timestamp) - mTimestampOffset;
if (mPreviewFrameSpacer != nullptr) {
nsecs_t readoutTime = (readoutTimestamp != 0 ? readoutTimestamp : timestamp)
@@ -719,16 +720,12 @@
mFrameCount = 0;
mLastTimestamp = 0;
- mUseReadoutTime =
- (timestampBase == OutputConfiguration::TIMESTAMP_BASE_READOUT_SENSOR || mSyncToDisplay);
-
if (isDeviceTimeBaseRealtime()) {
if (isDefaultTimeBase && !isConsumedByHWComposer() && !isVideoStream()) {
// Default time base, but not hardware composer or video encoder
mTimestampOffset = 0;
} else if (timestampBase == OutputConfiguration::TIMESTAMP_BASE_REALTIME ||
- timestampBase == OutputConfiguration::TIMESTAMP_BASE_SENSOR ||
- timestampBase == OutputConfiguration::TIMESTAMP_BASE_READOUT_SENSOR) {
+ timestampBase == OutputConfiguration::TIMESTAMP_BASE_SENSOR) {
mTimestampOffset = 0;
}
// If timestampBase is CHOREOGRAPHER SYNCED or MONOTONIC, leave
@@ -738,7 +735,7 @@
// Reverse offset for monotonicTime -> bootTime
mTimestampOffset = -mTimestampOffset;
} else {
- // If timestampBase is DEFAULT, MONOTONIC, SENSOR, READOUT_SENSOR or
+ // If timestampBase is DEFAULT, MONOTONIC, SENSOR or
// CHOREOGRAPHER_SYNCED, timestamp offset is 0.
mTimestampOffset = 0;
}
@@ -1389,6 +1386,11 @@
mFixedFps = fixedFps;
}
+void Camera3OutputStream::setStreamUseCase(int64_t streamUseCase) {
+ Mutex::Autolock l(mLock);
+ camera_stream::use_case = streamUseCase;
+}
+
void Camera3OutputStream::returnPrefetchedBuffersLocked() {
std::vector<Surface::BatchBuffer> batchedBuffers;
@@ -1523,7 +1525,8 @@
vsyncTime.deadlineTimestamp >= currentTime &&
((!cameraDisplayInSync && vsyncTime.expectedPresentationTime > minPresentT) ||
(cameraDisplayInSync && vsyncTime.expectedPresentationTime >
- mLastPresentTime + minInterval + biasForShortDelay * kTimelineThresholdNs))) {
+ mLastPresentTime + minInterval +
+ static_cast<nsecs_t>(biasForShortDelay * kTimelineThresholdNs)))) {
expectedPresentT = vsyncTime.expectedPresentationTime;
minDiff = std::abs(vsyncTime.expectedPresentationTime - idealPresentT);
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 0d758bc..9a08485 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -97,7 +97,8 @@
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false);
/**
* Set up a stream for formats that have a variable buffer size for the same
* dimensions, such as compressed JPEG.
@@ -115,7 +116,8 @@
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false);
/**
* Set up a stream with deferred consumer for formats that have 2 dimensions, such as
* RAW and YUV. The consumer must be set before using this stream for output. A valid
@@ -132,7 +134,8 @@
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false);
virtual ~Camera3OutputStream();
@@ -256,6 +259,11 @@
virtual void onMinDurationChanged(nsecs_t duration, bool fixedFps) override;
/**
+ * Modify stream use case
+ */
+ virtual void setStreamUseCase(int64_t streamUseCase) override;
+
+ /**
* Apply ZSL related consumer usage quirk.
*/
static void applyZSLUsageQuirk(int format, uint64_t *consumerUsage /*inout*/);
@@ -277,7 +285,8 @@
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false);
/**
* Note that we release the lock briefly in this function
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index dbc6fe1..4baa7e8 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -117,6 +117,11 @@
* AE_TARGET_FPS_RANGE in the capture request.
*/
virtual void onMinDurationChanged(nsecs_t duration, bool fixedFps) = 0;
+
+ /**
+ * Modify the stream use case for this output.
+ */
+ virtual void setStreamUseCase(int64_t streamUseCase) = 0;
};
// Helper class to organize a synchronized mapping of stream IDs to stream instances
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index a441638..738c314 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -623,27 +623,35 @@
if (result->partial_result != 0)
request.resultExtras.partialResultCount = result->partial_result;
- if ((result->result != nullptr) && !states.legacyClient && !states.overrideToPortrait) {
+ if (result->result != nullptr) {
camera_metadata_ro_entry entry;
auto ret = find_camera_metadata_ro_entry(result->result,
ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_ID, &entry);
if ((ret == OK) && (entry.count > 0)) {
std::string physicalId(reinterpret_cast<const char *>(entry.data.u8));
- auto deviceInfo = states.physicalDeviceInfoMap.find(physicalId);
- if (deviceInfo != states.physicalDeviceInfoMap.end()) {
- auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
- if (orientation.count > 0) {
- ret = CameraUtils::getRotationTransform(deviceInfo->second,
- OutputConfiguration::MIRROR_MODE_AUTO, &request.transform);
- if (ret != OK) {
- ALOGE("%s: Failed to calculate current stream transformation: %s (%d)",
- __FUNCTION__, strerror(-ret), ret);
+ if (!states.activePhysicalId.empty() && physicalId != states.activePhysicalId) {
+ states.listener->notifyPhysicalCameraChange(physicalId);
+ }
+ states.activePhysicalId = physicalId;
+
+ if (!states.legacyClient && !states.overrideToPortrait) {
+ auto deviceInfo = states.physicalDeviceInfoMap.find(physicalId);
+ if (deviceInfo != states.physicalDeviceInfoMap.end()) {
+ auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
+ if (orientation.count > 0) {
+ ret = CameraUtils::getRotationTransform(deviceInfo->second,
+ OutputConfiguration::MIRROR_MODE_AUTO, &request.transform);
+ if (ret != OK) {
+ ALOGE("%s: Failed to calculate current stream transformation: %s "
+ "(%d)", __FUNCTION__, strerror(-ret), ret);
+ }
+ } else {
+ ALOGE("%s: Physical device orientation absent!", __FUNCTION__);
}
} else {
- ALOGE("%s: Physical device orientation absent!", __FUNCTION__);
+ ALOGE("%s: Physical device not found in device info map found!",
+ __FUNCTION__);
}
- } else {
- ALOGE("%s: Physical device not found in device info map found!", __FUNCTION__);
}
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 019c8a8..d5328c5 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -108,6 +108,7 @@
nsecs_t& minFrameDuration;
bool& isFixedFps;
bool overrideToPortrait;
+ std::string &activePhysicalId;
};
void processCaptureResult(CaptureOutputStates& states, const camera_capture_result *result);
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
index da45227..f3a7359 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.cpp
@@ -35,12 +35,13 @@
const std::unordered_set<int32_t> &sensorPixelModesUsed, IPCTransport transport,
int setId, bool useHalBufManager, int64_t dynamicProfile,
int64_t streamUseCase, bool deviceTimeBaseIsRealtime, int timestampBase,
- int mirrorMode, int32_t colorSpace) :
+ int mirrorMode, int32_t colorSpace, bool useReadoutTimestamp) :
Camera3OutputStream(id, CAMERA_STREAM_OUTPUT, width, height,
format, dataSpace, rotation, physicalCameraId, sensorPixelModesUsed,
transport, consumerUsage, timestampOffset, setId,
/*isMultiResolution*/false, dynamicProfile, streamUseCase,
- deviceTimeBaseIsRealtime, timestampBase, mirrorMode, colorSpace),
+ deviceTimeBaseIsRealtime, timestampBase, mirrorMode, colorSpace,
+ useReadoutTimestamp),
mUseHalBufManager(useHalBufManager) {
size_t consumerCount = std::min(surfaces.size(), kMaxOutputs);
if (surfaces.size() > consumerCount) {
diff --git a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
index 5167225..1102ecb 100644
--- a/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3SharedOutputStream.h
@@ -46,7 +46,8 @@
bool deviceTimeBaseIsRealtime = false,
int timestampBase = OutputConfiguration::TIMESTAMP_BASE_DEFAULT,
int mirrorMode = OutputConfiguration::MIRROR_MODE_AUTO,
- int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED);
+ int32_t colorSpace = ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED,
+ bool useReadoutTimestamp = false);
virtual ~Camera3SharedOutputStream();
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 7eba57f..30f6d18 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -379,7 +379,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait}, mResultMetadataQueue
+ mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -421,7 +421,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, *(mInterface), mLegacyClient, mMinExpectedDuration, mIsFixedFps,
- mOverrideToPortrait}, mResultMetadataQueue
+ mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index 9ce0622..4b1fb1d 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -111,6 +111,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId(""); // Unused
AidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -125,7 +126,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -157,6 +158,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId(""); // Unused
AidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -171,7 +173,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
*this, mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 44c60cf..382b287 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -365,8 +365,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
//HidlCaptureOutputStates hidlStates {
@@ -428,8 +428,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& result : results) {
@@ -476,8 +476,8 @@
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
- *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait},
- mResultMetadataQueue
+ *mInterface, mLegacyClient, mMinExpectedDuration, mIsFixedFps, mOverrideToPortrait,
+ mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
index c7f8fa1..0a6a6f7 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -92,6 +92,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -106,7 +107,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -133,6 +134,7 @@
hardware::hidl_vec<hardware::camera::device::V3_4::PhysicalCameraMetadata> noPhysMetadata;
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -147,7 +149,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
std::lock_guard<std::mutex> lock(mProcessCaptureResultLock);
@@ -169,6 +171,7 @@
listener = mListener.promote();
}
+ std::string activePhysicalId("");
HidlCaptureOutputStates states {
{mId,
mOfflineReqsLock, mLastCompletedRegularFrameNumber,
@@ -183,7 +186,7 @@
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
mBufferRecords, /*legacyClient*/ false, mMinExpectedDuration, mIsFixedFps,
- /*overrideToPortrait*/false}, mResultMetadataQueue
+ /*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
camera3::notify(states, msg);
diff --git a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
index 3392db1..de51ffa 100644
--- a/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
+++ b/services/camera/libcameraservice/hidl/AidlCameraDeviceCallbacks.cpp
@@ -17,6 +17,7 @@
#include <hidl/AidlCameraDeviceCallbacks.h>
#include <hidl/Utils.h>
+#include <aidl/AidlUtils.h>
namespace android {
namespace frameworks {
@@ -144,7 +145,7 @@
// Convert Metadata into HCameraMetadata;
FmqSizeOrMetadata hResult;
- using hardware::cameraservice::utils::conversion::filterVndkKeys;
+ using hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
if (filterVndkKeys(mVndkVersion, result, /*isStatic*/false) != OK) {
ALOGE("%s: filtering vndk keys from result failed, not sending onResultReceived callback",
__FUNCTION__);
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 259e8a5..1d5213d 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -21,6 +21,7 @@
#include <hidl/HidlCameraService.h>
#include <hidl/HidlCameraDeviceUser.h>
#include <hidl/Utils.h>
+#include <aidl/AidlUtils.h>
#include <hidl/HidlTransportSupport.h>
@@ -34,9 +35,9 @@
using frameworks::cameraservice::service::V2_0::implementation::HidlCameraService;
using hardware::hidl_vec;
using hardware::cameraservice::utils::conversion::convertToHidl;
-using hardware::cameraservice::utils::conversion::filterVndkKeys;
using hardware::cameraservice::utils::conversion::B2HStatus;
using hardware::Void;
+using hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
using device::V2_0::implementation::H2BCameraDeviceCallbacks;
using device::V2_1::implementation::HidlCameraDeviceUser;
diff --git a/services/camera/libcameraservice/hidl/Utils.cpp b/services/camera/libcameraservice/hidl/Utils.cpp
index 057a6e9..2a24a23 100644
--- a/services/camera/libcameraservice/hidl/Utils.cpp
+++ b/services/camera/libcameraservice/hidl/Utils.cpp
@@ -15,7 +15,6 @@
*/
#include <hidl/Utils.h>
-#include <hidl/VndkVersionMetadataTags.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
#include <cutils/native_handle.h>
#include <mediautils/AImageReaderUtils.h>
@@ -298,31 +297,6 @@
return hPhysicalCaptureResultInfos;
}
-status_t filterVndkKeys(int vndkVersion, CameraMetadata &metadata, bool isStatic) {
- if (vndkVersion == __ANDROID_API_FUTURE__) {
- // VNDK version in ro.vndk.version is a version code-name that
- // corresponds to the current version.
- return OK;
- }
- const auto &apiLevelToKeys =
- isStatic ? static_api_level_to_keys : dynamic_api_level_to_keys;
- // Find the vndk versions above the given vndk version. All the vndk
- // versions above the given one, need to have their keys filtered from the
- // metadata in order to avoid metadata invalidation.
- auto it = apiLevelToKeys.upper_bound(vndkVersion);
- while (it != apiLevelToKeys.end()) {
- for (const auto &key : it->second) {
- status_t res = metadata.erase(key);
- if (res != OK) {
- ALOGE("%s metadata key %d could not be erased", __FUNCTION__, key);
- return res;
- }
- }
- it++;
- }
- return OK;
-}
-
} //conversion
} // utils
} //cameraservice
diff --git a/services/camera/libcameraservice/hidl/Utils.h b/services/camera/libcameraservice/hidl/Utils.h
index e6d4393..ec06571 100644
--- a/services/camera/libcameraservice/hidl/Utils.h
+++ b/services/camera/libcameraservice/hidl/Utils.h
@@ -97,8 +97,6 @@
HStatus B2HStatus(const binder::Status &bStatus);
-status_t filterVndkKeys(int vndk_version, CameraMetadata &metadata, bool isStatic = true);
-
} // conversion
} // utils
} // cameraservice
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
index bed576f..7aaf6b2 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.cpp
@@ -46,11 +46,13 @@
}
void CameraServiceProxyWrapper::CameraSessionStatsWrapper::onClose(
- sp<hardware::ICameraServiceProxy>& proxyBinder, int32_t latencyMs) {
+ sp<hardware::ICameraServiceProxy>& proxyBinder, int32_t latencyMs,
+ bool deviceError) {
Mutex::Autolock l(mLock);
mSessionStats.mNewCameraState = CameraSessionStats::CAMERA_STATE_CLOSED;
mSessionStats.mLatencyMs = latencyMs;
+ mSessionStats.mDeviceError = deviceError;
updateProxyDeviceState(proxyBinder);
}
@@ -259,7 +261,7 @@
sessionStats->onOpen(proxyBinder);
}
-void CameraServiceProxyWrapper::logClose(const String8& id, int32_t latencyMs) {
+void CameraServiceProxyWrapper::logClose(const String8& id, int32_t latencyMs, bool deviceError) {
std::shared_ptr<CameraSessionStatsWrapper> sessionStats;
{
Mutex::Autolock l(mLock);
@@ -275,13 +277,15 @@
__FUNCTION__, id.c_str());
return;
}
+
mSessionStatsMap.erase(id);
- ALOGV("%s: Erasing id %s", __FUNCTION__, id.c_str());
+ ALOGV("%s: Erasing id %s, deviceError %d", __FUNCTION__, id.c_str(), deviceError);
}
- ALOGV("%s: id %s, latencyMs %d", __FUNCTION__, id.c_str(), latencyMs);
+ ALOGV("%s: id %s, latencyMs %d, deviceError %d", __FUNCTION__,
+ id.c_str(), latencyMs, deviceError);
sp<hardware::ICameraServiceProxy> proxyBinder = getCameraServiceProxy();
- sessionStats->onClose(proxyBinder, latencyMs);
+ sessionStats->onClose(proxyBinder, latencyMs, deviceError);
}
bool CameraServiceProxyWrapper::isCameraDisabled(int userId) {
diff --git a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
index 0f77fc9..f90a841 100644
--- a/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
+++ b/services/camera/libcameraservice/utils/CameraServiceProxyWrapper.h
@@ -54,7 +54,8 @@
{ }
void onOpen(sp<hardware::ICameraServiceProxy>& proxyBinder);
- void onClose(sp<hardware::ICameraServiceProxy>& proxyBinder, int32_t latencyMs);
+ void onClose(sp<hardware::ICameraServiceProxy>& proxyBinder, int32_t latencyMs,
+ bool deviceError);
void onStreamConfigured(int operatingMode, bool internalReconfig, int32_t latencyMs);
void onActive(sp<hardware::ICameraServiceProxy>& proxyBinder, float maxPreviewFps);
void onIdle(sp<hardware::ICameraServiceProxy>& proxyBinder,
@@ -83,7 +84,7 @@
int32_t latencyMs);
// Close
- void logClose(const String8& id, int32_t latencyMs);
+ void logClose(const String8& id, int32_t latencyMs, bool deviceError);
// Stream configuration
void logStreamConfigured(const String8& id, int operatingMode, bool internalReconfig,
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index f9afd41..f786b79 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -19,6 +19,8 @@
#include "SessionConfigurationUtils.h"
#include "../api2/DepthCompositeStream.h"
#include "../api2/HeicCompositeStream.h"
+#include "aidl/android/hardware/graphics/common/Dataspace.h"
+#include "api2/JpegRCompositeStream.h"
#include "common/CameraDeviceBase.h"
#include "common/HalConversionsTemplated.h"
#include "../CameraService.h"
@@ -26,6 +28,7 @@
#include "device3/hidl/HidlCamera3Device.h"
#include "device3/Camera3OutputStream.h"
#include "system/graphics-base-v1.1.h"
+#include <ui/PublicFormat.h>
using android::camera3::OutputStreamInfo;
using android::camera3::OutputStreamInfo;
@@ -209,11 +212,18 @@
}
//check if format is 10-bit compatible
-bool is10bitCompatibleFormat(int32_t format) {
+bool is10bitCompatibleFormat(int32_t format, android_dataspace_t dataSpace) {
switch(format) {
case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
case HAL_PIXEL_FORMAT_YCBCR_P010:
return true;
+ case HAL_PIXEL_FORMAT_BLOB:
+ if (dataSpace == static_cast<android_dataspace_t>(
+ ::aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) {
+ return true;
+ }
+
+ return false;
default:
return false;
}
@@ -316,6 +326,10 @@
return false; // RAW_DEPTH, not applicable
} else if (format == HAL_PIXEL_FORMAT_RAW10 && dataSpace == HAL_DATASPACE_DEPTH) {
return false; // RAW_DEPTH10, not applicable
+ } else if (format == HAL_PIXEL_FORMAT_BLOB && dataSpace ==
+ static_cast<android_dataspace>(
+ ::aidl::android::hardware::graphics::common::Dataspace::JPEG_R)) {
+ format64 = static_cast<int64_t>(PublicFormat::JPEG_R);
}
camera_metadata_ro_entry_t entry =
@@ -499,7 +513,7 @@
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
}
if (SessionConfigurationUtils::is10bitDynamicRangeProfile(dynamicRangeProfile) &&
- !SessionConfigurationUtils::is10bitCompatibleFormat(format)) {
+ !SessionConfigurationUtils::is10bitCompatibleFormat(format, dataSpace)) {
String8 msg = String8::format("Camera %s: No 10-bit supported stream configurations with "
"format %#x defined and profile %" PRIx64 ", failed to create output stream",
logicalCameraId.string(), format, dynamicRangeProfile);
@@ -772,7 +786,9 @@
camera3::DepthCompositeStream::isDepthCompositeStream(surface);
bool isHeicCompositeStream =
camera3::HeicCompositeStream::isHeicCompositeStream(surface);
- if (isDepthCompositeStream || isHeicCompositeStream) {
+ bool isJpegRCompositeStream =
+ camera3::JpegRCompositeStream::isJpegRCompositeStream(surface);
+ if (isDepthCompositeStream || isHeicCompositeStream || isJpegRCompositeStream) {
// We need to take in to account that composite streams can have
// additional internal camera streams.
std::vector<OutputStreamInfo> compositeStreams;
@@ -780,10 +796,14 @@
// TODO: Take care of composite streams.
ret = camera3::DepthCompositeStream::getCompositeStreamInfo(streamInfo,
deviceInfo, &compositeStreams);
- } else {
+ } else if (isHeicCompositeStream) {
ret = camera3::HeicCompositeStream::getCompositeStreamInfo(streamInfo,
deviceInfo, &compositeStreams);
+ } else {
+ ret = camera3::JpegRCompositeStream::getCompositeStreamInfo(streamInfo,
+ deviceInfo, &compositeStreams);
}
+
if (ret != OK) {
String8 msg = String8::format(
"Camera %s: Failed adding composite streams: %s (%d)",
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 264045e..b5654ac 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -102,7 +102,7 @@
int32_t colorSpace);
//check if format is 10-bit output compatible
-bool is10bitCompatibleFormat(int32_t format);
+bool is10bitCompatibleFormat(int32_t format, android_dataspace_t dataSpace);
// check if the dynamic range requires 10-bit output
bool is10bitDynamicRangeProfile(int64_t dynamicRangeProfile);
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp
index 250ac63..28a22e1 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtilsHost.cpp
@@ -49,6 +49,12 @@
return ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
case ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS:
return ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS:
+ return ANDROID_JPEGR_AVAILABLE_JPEG_R_STREAM_CONFIGURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS:
+ return ANDROID_JPEGR_AVAILABLE_JPEG_R_MIN_FRAME_DURATIONS_MAXIMUM_RESOLUTION;
+ case ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS:
+ return ANDROID_JPEGR_AVAILABLE_JPEG_R_STALL_DURATIONS_MAXIMUM_RESOLUTION;
case ANDROID_SENSOR_OPAQUE_RAW_SIZE:
return ANDROID_SENSOR_OPAQUE_RAW_SIZE_MAXIMUM_RESOLUTION;
case ANDROID_LENS_INTRINSIC_CALIBRATION:
@@ -97,4 +103,4 @@
} // namespace SessionConfigurationUtils
} // namespace camera3
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index 3222950..a2f17c2 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -147,6 +147,9 @@
arm64: {
src: "seccomp_policy/mediacodec-arm64.policy",
},
+ riscv64: {
+ enabled: false,
+ },
x86: {
src: "seccomp_policy/mediacodec-x86.policy",
},
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index e8d3f6e..c90488f 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -138,6 +138,7 @@
"AudioTypes.cpp",
"cleaner.cpp",
"iface_statsd.cpp",
+ "MediaDrmStatsdHelper.cpp",
"MediaMetricsService.cpp",
"statsd_audiopolicy.cpp",
"statsd_audiorecord.cpp",
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index 7af6c41..948cee1 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -238,6 +238,9 @@
"sample_rate",
"content_type",
"sharing_requested",
+ "format_hardware",
+ "channel_count_hardware",
+ "sample_rate_hardware",
};
static constexpr const char * HeadTrackerDeviceEnabledFields[] {
@@ -1360,6 +1363,19 @@
const auto sharingModeRequested =
types::lookup<types::AAUDIO_SHARING_MODE, int32_t>(sharingModeRequestedStr);
+ std::string formatHardwareStr;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_ENCODINGHARDWARE, &formatHardwareStr);
+ const auto formatHardware = types::lookup<types::ENCODING, int32_t>(formatHardwareStr);
+
+ int32_t channelCountHardware = -1;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_CHANNELCOUNTHARDWARE, &channelCountHardware);
+
+ int32_t sampleRateHardware = 0;
+ mAudioAnalytics.mAnalyticsState->timeMachine().get(
+ key, AMEDIAMETRICS_PROP_SAMPLERATEHARDWARE, &sampleRateHardware);
+
LOG(LOG_LEVEL) << "key:" << key
<< " path:" << path
<< " direction:" << direction << "(" << directionStr << ")"
@@ -1379,7 +1395,10 @@
<< " sample_rate: " << sampleRate
<< " content_type: " << contentType << "(" << contentTypeStr << ")"
<< " sharing_requested:" << sharingModeRequested
- << "(" << sharingModeRequestedStr << ")";
+ << "(" << sharingModeRequestedStr << ")"
+ << " format_hardware:" << formatHardware << "(" << formatHardwareStr << ")"
+ << " channel_count_hardware:" << channelCountHardware
+ << " sample_rate_hardware: " << sampleRateHardware;
if (mAudioAnalytics.mDeliverStatistics) {
const stats::media_metrics::BytesField bf_serialized(
@@ -1404,6 +1423,9 @@
, sampleRate
, contentType
, sharingModeRequested
+ , formatHardware
+ , channelCountHardware
+ , sampleRateHardware
);
std::stringstream ss;
ss << "result:" << result;
@@ -1427,6 +1449,9 @@
, sampleRate
, contentType
, sharingModeRequested
+ , formatHardware
+ , channelCountHardware
+ , sampleRateHardware
);
ss << " " << fieldsStr;
std::string str = ss.str();
diff --git a/services/mediametrics/MediaDrmStatsdHelper.cpp b/services/mediametrics/MediaDrmStatsdHelper.cpp
new file mode 100644
index 0000000..d762672
--- /dev/null
+++ b/services/mediametrics/MediaDrmStatsdHelper.cpp
@@ -0,0 +1,127 @@
+/*
+ * 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 "MediaDrmStatsdHelper.h"
+#include <tuple>
+#include <map>
+#include <unordered_map>
+
+namespace {
+
+struct UUID {
+ uint64_t msb, lsb; // NOLINT(misc-non-private-member-variables-in-classes)
+ bool operator < (const UUID& that) const {
+ return std::tie(msb, lsb) < std::tie(that.msb, that.lsb);
+ }
+};
+
+// KEEP IN SYNC WITH frameworks/proto_logging/stats/enums/media/drm/enums.proto
+std::map<UUID, int32_t> const kUuidSchemeEnumMap {
+ {{.msb = 0x6DD8B3C345F44A68, .lsb = 0xBF3A64168D01A4A6}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__ABV_MODRM }, // ABV_MODRM
+ {{.msb = 0xF239E769EFA34850, .lsb = 0x9C16A903C6932EFB}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__ADOBE_PRIMETIME }, // ADOBE_PRIMETIME
+ {{.msb = 0x616C746963617374, .lsb = 0x2D50726F74656374}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__ALTICAST }, // ALTICAST
+ {{.msb = 0x94CE86FB07FF4F43, .lsb = 0xADB893D2FA968CA2}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__APPLE_FAIRPLAY }, // APPLE_FAIRPLAY
+ {{.msb = 0x279FE473512C48FE, .lsb = 0xADE8D176FEE6B40F}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__ARRIS_TITANIUM }, // ARRIS_TITANIUM
+ {{.msb = 0x3D5E6D359B9A41E8, .lsb = 0xB843DD3C6E72C42C}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CHINADRM }, // CHINADRM
+ {{.msb = 0x3EA8778F77424BF9, .lsb = 0xB18BE834B2ACBD47}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CLEAR_KEY_AES_128 }, // CLEAR_KEY_AES_128
+ {{.msb = 0xBE58615B19C44684, .lsb = 0x88B3C8C57E99E957}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CLEAR_KEY_SAMPLE_AES }, // CLEAR_KEY_SAMPLE_AES
+ {{.msb = 0xE2719D58A985B3C9, .lsb = 0x781AB030AF78D30E}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CLEAR_KEY_DASH_IF }, // CLEAR_KEY_DASH_IF
+ {{.msb = 0x644FE7B5260F4FAD, .lsb = 0x949A0762FFB054B4}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CMLA_OMA }, // CMLA_OMA
+ {{.msb = 0x37C332587B994C7E, .lsb = 0xB15D19AF74482154}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__COMMSCOPE_TITANIUM }, // COMMSCOPE_TITANIUM
+ {{.msb = 0x45D481CB8FE049C0, .lsb = 0xADA9AB2D2455B2F2}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__CORECRYPT }, // CORECRYPT
+ {{.msb = 0xDCF4E3E362F15818, .lsb = 0x7BA60A6FE33FF3DD}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__DIGICAP_SMARTXESS }, // DIGICAP_SMARTXESS
+ {{.msb = 0x35BF197B530E42D7, .lsb = 0x8B651B4BF415070F}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__DIVX }, // DIVX
+ {{.msb = 0x80A6BE7E14484C37, .lsb = 0x9E70D5AEBE04C8D2}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__IRDETO }, // IRDETO
+ {{.msb = 0x5E629AF538DA4063, .lsb = 0x897797FFBD9902D4}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__MARLIN }, // MARLIN
+ {{.msb = 0x9A04F07998404286, .lsb = 0xAB92E65BE0885F95}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__MICROSOFT_PLAYREADY }, // MICROSOFT_PLAYREADY
+ {{.msb = 0x6A99532D869F5922, .lsb = 0x9A91113AB7B1E2F3}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__MOBITV }, // MOBITV
+ {{.msb = 0xADB41C242DBF4A6D, .lsb = 0x958B4457C0D27B95}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__NAGRA_MEDIAACCESS }, // NAGRA_MEDIAACCESS
+ {{.msb = 0x1F83E1E86EE94F0D, .lsb = 0xBA2F5EC4E3ED1A66}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__SECUREMEDIA }, // SECUREMEDIA
+ {{.msb = 0x992C46E6C4374899, .lsb = 0xB6A050FA91AD0E39}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__SECUREMEDIA_STEELKNOT }, // SECUREMEDIA_STEELKNOT
+ {{.msb = 0xA68129D3575B4F1A, .lsb = 0x9CBA3223846CF7C3}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__SYNAMEDIA_VIDEOGUARD }, // SYNAMEDIA_VIDEOGUARD
+ {{.msb = 0xAA11967FCC014A4A, .lsb = 0x8E99C5D3DDDFEA2D}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__UNITEND_UDRM }, // UNITEND_UDRM
+ {{.msb = 0x9A27DD82FDE24725, .lsb = 0x8CBC4234AA06EC09}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__VERIMATRIX_VCAS }, // VERIMATRIX_VCAS
+ {{.msb = 0xB4413586C58CFFB0, .lsb = 0x94A5D4896C1AF6C3}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__VIACCESS_ORCA }, // VIACCESS_ORCA
+ {{.msb = 0x793B79569F944946, .lsb = 0xA94223E7EF7E44B4}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__VISIONCRYPT }, // VISIONCRYPT
+ {{.msb = 0x1077EFECC0B24D02, .lsb = 0xACE33C1E52E2FB4B}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__W3C_COMMON }, // W3C_COMMON
+ {{.msb = 0xEDEF8BA979D64ACE, .lsb = 0xA3C827DCD51D21ED}, android::stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__WIDEVINE }, // WIDEVINE
+};
+
+// KEEP IN SYNC WITH frameworks/av/drm/libmediadrm/include/mediadrm/IDrm.h
+// KEEP IN SYNC WITH frameworks/proto_logging/stats/enums/media/drm/enums.proto
+std::unordered_map<std::string, int32_t> const kDrmApiEnumMap {
+ {"initCheck" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_INIT_CHECK },
+ {"isCryptoSchemeSupported" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_IS_CRYPTO_SCHEME_SUPPORTED },
+ {"createPlugin" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_CREATE_PLUGIN },
+ {"destroyPlugin" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_DESTROY_PLUGIN },
+ {"openSession" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_OPEN_SESSION },
+ {"closeSession" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_CLOSE_SESSION },
+ {"getKeyRequest" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_KEY_REQUEST },
+ {"provideKeyResponse" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_PROVIDE_KEY_RESPONSE },
+ {"removeKeys" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REMOVE_KEYS },
+ {"restoreKeys" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_RESTORE_KEYS },
+ {"queryKeyStatus" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_QUERY_KEY_STATUS },
+ {"getProvisionRequest" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_PROVISION_REQUEST },
+ {"provideProvisionResponse" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_PROVIDE_PROVISION_RESPONSE },
+ {"getSecureStops" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_SECURE_STOPS },
+ {"getSecureStopIds" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_SECURE_STOP_IDS },
+ {"getSecureStop" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_SECURE_STOP },
+ {"releaseSecureStops" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_RELEASE_SECURE_STOPS },
+ {"removeSecureStop" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REMOVE_SECURE_STOP },
+ {"removeAllSecureStops" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REMOVE_ALL_SECURE_STOPS },
+ {"getHdcpLevels" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_HDCP_LEVELS },
+ {"getNumberOfSessions" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_NUMBER_OF_SESSIONS },
+ {"getSecurityLevel" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_SECURITY_LEVEL },
+ {"getOfflineLicenseKeySetIds" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_OFFLINE_LICENSE_KEY_SET_IDS },
+ {"removeOfflineLicense" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REMOVE_OFFLINE_LICENSE },
+ {"getOfflineLicenseState" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_OFFLINE_LICENSE_STATE },
+ {"getPropertyString" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_PROPERTY_STRING },
+ {"getPropertyByteArray" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_PROPERTY_BYTE_ARRAY },
+ {"setPropertyString" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_PROPERTY_STRING },
+ {"setPropertyByteArray" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_PROPERTY_BYTE_ARRAY },
+ {"getMetrics" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_METRICS },
+ {"setCipherAlgorithm" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_CIPHER_ALGORITHM },
+ {"setMacAlgorithm" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_MAC_ALGORITHM },
+ {"encrypt" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GENERIC_ENCRYPT },
+ {"decrypt" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GENERIC_DECRYPT },
+ {"sign" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GENERIC_SIGN },
+ {"verify" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GENERIC_VERIFY },
+ {"signRSA" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SIGN_RSA },
+ {"setListener" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_LISTENER },
+ {"requiresSecureDecoder" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REQUIRES_SECURE_DECODER },
+ {"requiresSecureDecoderLevel" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_REQUIRES_SECURE_DECODER_LEVEL },
+ {"setPlaybackId" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_SET_PLAYBACK_ID },
+ {"getLogMessages" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_LOG_MESSAGES },
+ {"getSupportedSchemes" , android::stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_GET_SUPPORTED_SCHEMES },
+};
+
+} // anonymous namespace
+
+namespace android {
+
+int32_t MediaDrmStatsdHelper::findDrmScheme(const int64_t msb, const int64_t lsb) {
+ auto it = kUuidSchemeEnumMap.find({.msb = static_cast<uint64_t>(msb), .lsb = static_cast<uint64_t>(lsb)});
+ if (it == kUuidSchemeEnumMap.end()) return stats::media_metrics::MEDIA_DRM_SESSION_OPENED__SCHEME__DRM_SCHEME_OTHER;
+ return it->second;
+}
+
+int32_t MediaDrmStatsdHelper::findDrmApi(const std::string& api) {
+ auto it = kDrmApiEnumMap.find(api);
+ if (it == kDrmApiEnumMap.end()) return stats::media_metrics::MEDIA_DRM_ERRORED__API__DRM_API_UNKNOWN;
+ return it->second;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index b4de4f4..adb2217 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -511,6 +511,8 @@
const std::string &key = item->getKey();
if (startsWith(key, "audio.")) return true;
if (startsWith(key, "drm.vendor.")) return true;
+ if (startsWith(key, "mediadrm.")) return true;
+
// the list of allowedKey uses statsd_handlers
// in iface_statsd.cpp as reference
// drmmanager is from a trusted uid, therefore not needed here
diff --git a/services/mediametrics/iface_statsd.cpp b/services/mediametrics/iface_statsd.cpp
index 8a48ce5..7f4e6e8 100644
--- a/services/mediametrics/iface_statsd.cpp
+++ b/services/mediametrics/iface_statsd.cpp
@@ -83,13 +83,13 @@
{ "drmmanager", statsd_drmmanager },
{ "extractor", statsd_extractor },
{ "mediadrm", statsd_mediadrm },
+ { "mediadrm.created", statsd_mediadrm_created },
+ { "mediadrm.errored", statsd_mediadrm_errored },
+ { "mediadrm.session_opened", statsd_mediadrm_session_opened },
{ "mediaparser", statsd_mediaparser },
{ "nuplayer", statsd_nuplayer },
{ "nuplayer2", statsd_nuplayer },
{ "recorder", statsd_recorder },
- { "media_drm_created", statsd_media_drm_created },
- { "media_drm_session_opened", statsd_media_drm_session_opened },
- { "media_drm_errored", statsd_media_drm_errored },
};
return dump2StatsdInternal(statsd_pushers, item, statsdLog);
}
diff --git a/services/mediametrics/include/mediametricsservice/MediaDrmStatsdHelper.h b/services/mediametrics/include/mediametricsservice/MediaDrmStatsdHelper.h
new file mode 100644
index 0000000..2e5e7ff
--- /dev/null
+++ b/services/mediametrics/include/mediametricsservice/MediaDrmStatsdHelper.h
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#ifndef MEDIA_DRM_STATSD_HELPER_H
+#define MEDIA_DRM_STATSD_HELPER_H
+
+#include <cstdint>
+#include <stats_media_metrics.h>
+#include <string>
+namespace android {
+
+class MediaDrmStatsdHelper {
+public:
+ static int32_t findDrmScheme(const int64_t msb, const int64_t lsb);
+ static int32_t findDrmApi(const std::string& api);
+};
+
+} // namespace android
+#endif // MEDIA_DRM_STATSD_HELPER_H
\ No newline at end of file
diff --git a/services/mediametrics/include/mediametricsservice/iface_statsd.h b/services/mediametrics/include/mediametricsservice/iface_statsd.h
index a97a386..5bc293b 100644
--- a/services/mediametrics/include/mediametricsservice/iface_statsd.h
+++ b/services/mediametrics/include/mediametricsservice/iface_statsd.h
@@ -30,16 +30,15 @@
extern statsd_pusher statsd_audiothread;
extern statsd_pusher statsd_audiotrack;
extern statsd_pusher statsd_codec;
+extern statsd_pusher statsd_drmmanager;
extern statsd_pusher statsd_extractor;
+extern statsd_pusher statsd_mediadrm;
+extern statsd_pusher statsd_mediadrm_created;
+extern statsd_pusher statsd_mediadrm_errored;
+extern statsd_pusher statsd_mediadrm_session_opened;
extern statsd_pusher statsd_mediaparser;
-extern statsd_pusher statsd_media_drm_created;
-extern statsd_pusher statsd_media_drm_session_opened;
-extern statsd_pusher statsd_media_drm_errored;
-
extern statsd_pusher statsd_nuplayer;
extern statsd_pusher statsd_recorder;
-extern statsd_pusher statsd_mediadrm;
-extern statsd_pusher statsd_drmmanager;
using statsd_puller = bool (const std::shared_ptr<const mediametrics::Item>& item,
AStatsEventList *, const std::shared_ptr<mediametrics::StatsdLog>& statsdLog);
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 1008531..863fdbe 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -18,8 +18,9 @@
#define LOG_TAG "statsd_drm"
#include <utils/Log.h>
#include <media/stagefright/foundation/base64.h>
+#include <binder/IPCThreadState.h>
-#include <stdint.h>
+#include <cstdint>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -32,6 +33,7 @@
#include <pwd.h>
#include "MediaMetricsService.h"
+#include "MediaDrmStatsdHelper.h"
#include "StringUtils.h"
#include "iface_statsd.h"
@@ -233,66 +235,76 @@
return true;
}
-bool statsd_media_drm_created(const std::shared_ptr<const mediametrics::Item>& item,
+bool statsd_mediadrm_created(const std::shared_ptr<const mediametrics::Item>& item,
const std::shared_ptr<mediametrics::StatsdLog>& statsdLog)
{
int64_t uuid_lsb = -1;
if (!item->getInt64("uuid_lsb", &uuid_lsb)) return false;
int64_t uuid_msb = -1;
if (!item->getInt64("uuid_msb", &uuid_msb)) return false;
- int64_t object_nonce_lsb = -1;
- if (!item->getInt64("object_nonce_lsb", &object_nonce_lsb)) return false;
- int64_t object_nonce_msb = -1;
- if (!item->getInt64("object_nonce_msb", &object_nonce_msb)) return false;
+ const int32_t scheme = MediaDrmStatsdHelper::findDrmScheme(uuid_msb, uuid_lsb);
+ const int32_t uid = IPCThreadState::self()->getCallingUid();
+ int32_t frontend = 0;
+ if (!item->getInt32("frontend", &frontend)) return false;
+
+ // Optional to be included
int64_t apex_version = -1;
item->getInt64("apex_version", &apex_version);
- const int result = stats_write(
- stats::media_metrics::MEDIA_DRM_CREATED,
- uuid_lsb, uuid_msb, object_nonce_lsb,
- object_nonce_msb, apex_version);
+ const int result = stats_write(stats::media_metrics::MEDIA_DRM_CREATED,
+ scheme, uuid_lsb, uuid_msb, uid, frontend, apex_version);
std::stringstream log;
log << "result:" << result << " {"
<< " media_drm_created:"
<< stats::media_metrics::MEDIA_DRM_CREATED
+ << " scheme:" << scheme
<< " uuid_lsb:" << uuid_lsb
<< " uuid_msb:" << uuid_msb
- << " object_nonce_lsb:" << object_nonce_lsb
- << " object_nonce_msb:" << object_nonce_msb
+ << " uid:" << uid
+ << " frontend:" << frontend
<< " apex_version:" << apex_version
<< " }";
statsdLog->log(stats::media_metrics::MEDIA_DRM_CREATED, log.str());
return true;
}
-bool statsd_media_drm_session_opened(const std::shared_ptr<const mediametrics::Item>& item,
+bool statsd_mediadrm_session_opened(const std::shared_ptr<const mediametrics::Item>& item,
const std::shared_ptr<mediametrics::StatsdLog>& statsdLog)
{
- int64_t object_nonce_lsb = -1;
- if (!item->getInt64("object_nonce_lsb", &object_nonce_lsb)) return false;
- int64_t object_nonce_msb = -1;
- if (!item->getInt64("object_nonce_msb", &object_nonce_msb)) return false;
- int64_t session_nonce_lsb = -1;
- if (!item->getInt64("session_nonce_lsb", &session_nonce_lsb)) return false;
- int64_t session_nonce_msb = -1;
- if (!item->getInt64("session_nonce_msb", &session_nonce_msb)) return false;
+ int64_t uuid_lsb = -1;
+ if (!item->getInt64("uuid_lsb", &uuid_lsb)) return false;
+ int64_t uuid_msb = -1;
+ if (!item->getInt64("uuid_msb", &uuid_msb)) return false;
+ const int32_t scheme = MediaDrmStatsdHelper::findDrmScheme(uuid_msb, uuid_lsb);
+ std::string object_nonce = "";
+ if (!item->getString("object_nonce", &object_nonce)) return false;
+ const int32_t uid = IPCThreadState::self()->getCallingUid();
+ int32_t frontend = 0;
+ if (!item->getInt32("frontend", &frontend)) return false;
int32_t requested_security_level = -1;
if (!item->getInt32("requested_security_level", &requested_security_level)) return false;
int32_t opened_security_level = -1;
if (!item->getInt32("opened_security_level", &opened_security_level)) return false;
- const int result = stats_write(
- stats::media_metrics::MEDIA_DRM_SESSION_OPENED, object_nonce_lsb,
- object_nonce_msb, session_nonce_lsb, session_nonce_msb,
- requested_security_level, opened_security_level);
+
+ // Optional to be included
+ int64_t apex_version = -1;
+ item->getInt64("apex_version", &apex_version);
+ const int result = stats_write(stats::media_metrics::MEDIA_DRM_SESSION_OPENED,
+ scheme, uuid_lsb, uuid_msb, uid, frontend, apex_version,
+ object_nonce.c_str(), requested_security_level,
+ opened_security_level);
std::stringstream log;
log << "result:" << result << " {"
<< " media_drm_session_opened:"
<< stats::media_metrics::MEDIA_DRM_SESSION_OPENED
- << " object_nonce_lsb:" << object_nonce_lsb
- << " object_nonce_msb:" << object_nonce_msb
- << " session_nonce_lsb:" << session_nonce_lsb
- << " session_nonce_msb:" << session_nonce_msb
+ << " scheme:" << scheme
+ << " uuid_lsb:" << uuid_lsb
+ << " uuid_msb:" << uuid_msb
+ << " uid:" << uid
+ << " frontend:" << frontend
+ << " apex_version:" << apex_version
+ << " object_nonce:" << object_nonce
<< " requested_security_level:" << requested_security_level
<< " opened_security_level:" << opened_security_level
<< " }";
@@ -300,42 +312,63 @@
return true;
}
-bool statsd_media_drm_errored(const std::shared_ptr<const mediametrics::Item>& item,
+bool statsd_mediadrm_errored(const std::shared_ptr<const mediametrics::Item>& item,
const std::shared_ptr<mediametrics::StatsdLog>& statsdLog)
{
- int64_t object_nonce_lsb = -1;
- if (!item->getInt64("object_nonce_lsb", &object_nonce_lsb)) return false;
- int64_t object_nonce_msb = -1;
- if (!item->getInt64("object_nonce_msb", &object_nonce_msb)) return false;
- int64_t session_nonce_lsb = 0;
- item->getInt64("session_nonce_lsb", &session_nonce_lsb);
- int64_t session_nonce_msb = 0;
- item->getInt64("session_nonce_msb", &session_nonce_msb);
- int32_t api = -1;
- if (!item->getInt32("api", &api)) return false;
+ int64_t uuid_lsb = -1;
+ if (!item->getInt64("uuid_lsb", &uuid_lsb)) return false;
+ int64_t uuid_msb = -1;
+ if (!item->getInt64("uuid_msb", &uuid_msb)) return false;
+ const int32_t scheme = MediaDrmStatsdHelper::findDrmScheme(uuid_msb, uuid_lsb);
+ const int32_t uid = IPCThreadState::self()->getCallingUid();
+ int32_t frontend = 0;
+ if (!item->getInt32("frontend", &frontend)) return false;
+ std::string object_nonce = "";
+ if (!item->getString("object_nonce", &object_nonce)) return false;
+ int32_t security_level = -1;
+ if (!item->getInt32("security_level", &security_level)) return false;
+ std::string api_str = "";
+ if (!item->getString("api", &api_str)) return false;
+ const int32_t api = MediaDrmStatsdHelper::findDrmApi(api_str);
int32_t error_code = -1;
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 session_nonce = "";
+ item->getString("session_nonce", &session_nonce);
+
int32_t cdm_err = 0;
item->getInt32("cdm_err", &cdm_err);
int32_t oem_err = 0;
item->getInt32("oem_err", &oem_err);
- const int result = stats_write(
- stats::media_metrics::MEDIA_DRM_ERRORED, object_nonce_lsb,
- object_nonce_msb, session_nonce_lsb, session_nonce_msb,
- api, error_code, cdm_err, oem_err);
+ int32_t error_context = -1;
+ 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(),
+ session_nonce.c_str(), security_level, api, error_code, cdm_err,
+ oem_err, error_context);
std::stringstream log;
log << "result:" << result << " {"
<< " media_drm_errored:"
<< stats::media_metrics::MEDIA_DRM_ERRORED
- << " object_nonce_lsb:" << object_nonce_lsb
- << " object_nonce_msb:" << object_nonce_msb
- << " session_nonce_lsb:" << session_nonce_lsb
- << " session_nonce_msb:" << session_nonce_msb
+ << " scheme:" << scheme
+ << " uuid_lsb:" << uuid_lsb
+ << " uuid_msb:" << uuid_msb
+ << " uid:" << uid
+ << " frontend:" << frontend
+ << " apex_version:" << apex_version
+ << " object_nonce:" << object_nonce
+ << " session_nonce:" << session_nonce
+ << " security_level:" << security_level
<< " api:" << api
<< " error_code:" << error_code
<< " cdm_err:" << cdm_err
<< " oem_err:" << oem_err
+ << " error_context:" << error_context
<< " }";
statsdLog->log(stats::media_metrics::MEDIA_DRM_ERRORED, log.str());
return true;
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 054a896..c0dac11 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -73,13 +73,13 @@
return AAUDIO_ERROR_NULL;
}
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
if (mNotificationClients.count(pid) == 0) {
- sp<IBinder> binder = IInterface::asBinder(client);
- sp<NotificationClient> notificationClient = new NotificationClient(pid, binder);
+ const sp<IBinder> binder = IInterface::asBinder(client);
+ const sp<NotificationClient> notificationClient = new NotificationClient(pid, binder);
mNotificationClients[pid] = notificationClient;
- status_t status = binder->linkToDeath(notificationClient);
+ const status_t status = binder->linkToDeath(notificationClient);
ALOGW_IF(status != NO_ERROR, "registerClient() linkToDeath = %d\n", status);
return AAudioConvert_androidToAAudioResult(status);
} else {
@@ -90,12 +90,12 @@
void AAudioClientTracker::unregisterClient(pid_t pid) {
ALOGV("unregisterClient(), calling pid = %d, getpid() = %d\n", pid, getpid());
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
mNotificationClients.erase(pid);
}
int32_t AAudioClientTracker::getStreamCount(pid_t pid) {
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
return it->second->getStreamCount();
@@ -105,18 +105,19 @@
}
aaudio_result_t
-AAudioClientTracker::registerClientStream(pid_t pid, sp<AAudioServiceStreamBase> serviceStream) {
+AAudioClientTracker::registerClientStream(
+ pid_t pid, const sp<AAudioServiceStreamBase>& serviceStream) {
ALOGV("registerClientStream(%d,)\n", pid);
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
return getNotificationClient_l(pid)->registerClientStream(serviceStream);
}
// Find the tracker for this process and remove it.
aaudio_result_t
AAudioClientTracker::unregisterClientStream(pid_t pid,
- sp<AAudioServiceStreamBase> serviceStream) {
+ const sp<AAudioServiceStreamBase>& serviceStream) {
ALOGV("unregisterClientStream(%d,)\n", pid);
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
auto it = mNotificationClients.find(pid);
if (it != mNotificationClients.end()) {
ALOGV("unregisterClientStream(%d,) found NotificationClient\n", pid);
@@ -129,12 +130,12 @@
void AAudioClientTracker::setExclusiveEnabled(pid_t pid, bool enabled) {
ALOGD("%s(%d, %d)\n", __func__, pid, enabled);
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
getNotificationClient_l(pid)->setExclusiveEnabled(enabled);
}
bool AAudioClientTracker::isExclusiveEnabled(pid_t pid) {
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
return getNotificationClient_l(pid)->isExclusiveEnabled();
}
@@ -158,24 +159,21 @@
: mProcessId(pid), mBinder(binder) {
}
-AAudioClientTracker::NotificationClient::~NotificationClient() {
-}
-
int32_t AAudioClientTracker::NotificationClient::getStreamCount() {
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
return mStreams.size();
}
aaudio_result_t AAudioClientTracker::NotificationClient::registerClientStream(
- sp<AAudioServiceStreamBase> serviceStream) {
- std::lock_guard<std::mutex> lock(mLock);
+ const sp<AAudioServiceStreamBase>& serviceStream) {
+ const std::lock_guard<std::mutex> lock(mLock);
mStreams.insert(serviceStream);
return AAUDIO_OK;
}
aaudio_result_t AAudioClientTracker::NotificationClient::unregisterClientStream(
- sp<AAudioServiceStreamBase> serviceStream) {
- std::lock_guard<std::mutex> lock(mLock);
+ const sp<AAudioServiceStreamBase>& serviceStream) {
+ const std::lock_guard<std::mutex> lock(mLock);
mStreams.erase(serviceStream);
return AAUDIO_OK;
}
@@ -189,20 +187,20 @@
std::set<sp<AAudioServiceStreamBase>> streamsToClose;
{
- std::lock_guard<std::mutex> lock(mLock);
+ const std::lock_guard<std::mutex> lock(mLock);
for (const auto& serviceStream : mStreams) {
streamsToClose.insert(serviceStream);
}
}
for (const auto& serviceStream : streamsToClose) {
- aaudio_handle_t handle = serviceStream->getHandle();
+ const aaudio_handle_t handle = serviceStream->getHandle();
ALOGW("binderDied() close abandoned stream 0x%08X\n", handle);
aaudioService->asAAudioServiceInterface().closeStream(handle);
}
// mStreams should be empty now
}
- sp<NotificationClient> keep(this);
+ const sp<NotificationClient> keep(this);
AAudioClientTracker::getInstance().unregisterClient(mProcessId);
}
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index 2b38621..cd3b75a 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -54,10 +54,10 @@
int32_t getStreamCount(pid_t pid);
aaudio_result_t registerClientStream(pid_t pid,
- android::sp<AAudioServiceStreamBase> serviceStream);
+ const android::sp<AAudioServiceStreamBase>& serviceStream);
- aaudio_result_t unregisterClientStream(pid_t pid,
- android::sp<AAudioServiceStreamBase> serviceStream);
+ aaudio_result_t unregisterClientStream(
+ pid_t pid, const android::sp<AAudioServiceStreamBase>& serviceStream);
/**
* Specify whether a process is allowed to create an EXCLUSIVE MMAP stream.
@@ -84,15 +84,17 @@
class NotificationClient : public IBinder::DeathRecipient {
public:
NotificationClient(pid_t pid, const android::sp<IBinder>& binder);
- virtual ~NotificationClient();
+ ~NotificationClient() override = default;
int32_t getStreamCount();
std::string dump() const;
- aaudio_result_t registerClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+ aaudio_result_t registerClientStream(
+ const android::sp<AAudioServiceStreamBase>& serviceStream);
- aaudio_result_t unregisterClientStream(android::sp<AAudioServiceStreamBase> serviceStream);
+ aaudio_result_t unregisterClientStream(
+ const android::sp<AAudioServiceStreamBase>& serviceStream);
void setExclusiveEnabled(bool enabled) {
mExclusiveEnabled = enabled;
@@ -103,7 +105,7 @@
}
// IBinder::DeathRecipient
- virtual void binderDied(const android::wp<IBinder>& who);
+ void binderDied(const android::wp<IBinder>& who) override;
private:
mutable std::mutex mLock;
diff --git a/services/oboeservice/AAudioCommandQueue.cpp b/services/oboeservice/AAudioCommandQueue.cpp
index 9bd18b3..be80b12 100644
--- a/services/oboeservice/AAudioCommandQueue.cpp
+++ b/services/oboeservice/AAudioCommandQueue.cpp
@@ -25,7 +25,7 @@
namespace aaudio {
-aaudio_result_t AAudioCommandQueue::sendCommand(std::shared_ptr<AAudioCommand> command) {
+aaudio_result_t AAudioCommandQueue::sendCommand(const std::shared_ptr<AAudioCommand>& command) {
{
std::scoped_lock<std::mutex> _l(mLock);
if (!mRunning) {
diff --git a/services/oboeservice/AAudioCommandQueue.h b/services/oboeservice/AAudioCommandQueue.h
index 64442a3..ad62d8a 100644
--- a/services/oboeservice/AAudioCommandQueue.h
+++ b/services/oboeservice/AAudioCommandQueue.h
@@ -26,7 +26,7 @@
namespace aaudio {
-typedef int32_t aaudio_command_opcode;
+using aaudio_command_opcode = int32_t;
class AAudioCommandParam {
public:
@@ -39,7 +39,7 @@
explicit AAudioCommand(
aaudio_command_opcode opCode, std::shared_ptr<AAudioCommandParam> param = nullptr,
bool waitForReply = false, int64_t timeoutNanos = 0)
- : operationCode(opCode), parameter(param), isWaitingForReply(waitForReply),
+ : operationCode(opCode), parameter(std::move(param)), isWaitingForReply(waitForReply),
timeoutNanoseconds(timeoutNanos) { }
virtual ~AAudioCommand() = default;
@@ -66,7 +66,7 @@
* @return the result of sending the command or the result of executing the command if command
* need to wait for a reply. If timeout happens, AAUDIO_ERROR_TIMEOUT will be returned.
*/
- aaudio_result_t sendCommand(std::shared_ptr<AAudioCommand> command);
+ aaudio_result_t sendCommand(const std::shared_ptr<AAudioCommand>& command);
/**
* Wait for next available command OR until the timeout is expired.
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 20e4cc5..b5ee2f2 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -162,7 +162,7 @@
const aaudio::AAudioStreamRequest &request,
sp<AAudioServiceEndpoint> &endpointToSteal) {
- std::lock_guard<std::mutex> lock(mExclusiveLock);
+ const std::lock_guard<std::mutex> lock(mExclusiveLock);
const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
@@ -183,19 +183,20 @@
// and START calls. This will help preserve app compatibility.
// An app can avoid having this happen by closing their streams when
// the app is paused.
- pid_t pid = VALUE_OR_FATAL(
+ const pid_t pid = VALUE_OR_FATAL(
aidl2legacy_int32_t_pid_t(request.getAttributionSource().pid));
AAudioClientTracker::getInstance().setExclusiveEnabled(pid, false);
endpointToSteal = endpoint; // return it to caller
}
return nullptr;
} else {
- sp<AAudioServiceEndpointMMAP> endpointMMap = new AAudioServiceEndpointMMAP(aaudioService);
+ const sp<AAudioServiceEndpointMMAP> endpointMMap =
+ new AAudioServiceEndpointMMAP(aaudioService);
ALOGV("%s(), no match so try to open MMAP %p for dev %d",
__func__, endpointMMap.get(), configuration.getDeviceId());
endpoint = endpointMMap;
- aaudio_result_t result = endpoint->open(request);
+ const aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
endpoint.clear();
} else {
@@ -217,10 +218,10 @@
AAudioService &aaudioService,
const aaudio::AAudioStreamRequest &request) {
- std::lock_guard<std::mutex> lock(mSharedLock);
+ const std::lock_guard<std::mutex> lock(mSharedLock);
const AAudioStreamConfiguration &configuration = request.getConstantConfiguration();
- aaudio_direction_t direction = configuration.getDirection();
+ const aaudio_direction_t direction = configuration.getDirection();
// Try to find an existing endpoint.
sp<AAudioServiceEndpointShared> endpoint = findSharedEndpoint_l(configuration);
@@ -228,7 +229,7 @@
// If we can't find an existing one then open a new one.
if (endpoint.get() == nullptr) {
// we must call openStream with audioserver identity
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ const int64_t token = IPCThreadState::self()->clearCallingIdentity();
switch (direction) {
case AAUDIO_DIRECTION_INPUT:
endpoint = new AAudioServiceEndpointCapture(aaudioService);
@@ -241,7 +242,7 @@
}
if (endpoint.get() != nullptr) {
- aaudio_result_t result = endpoint->open(request);
+ const aaudio_result_t result = endpoint->open(request);
if (result != AAUDIO_OK) {
endpoint.clear();
} else {
@@ -261,7 +262,7 @@
return endpoint;
}
-void AAudioEndpointManager::closeEndpoint(sp<AAudioServiceEndpoint>serviceEndpoint) {
+void AAudioEndpointManager::closeEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
if (serviceEndpoint->getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
return closeExclusiveEndpoint(serviceEndpoint);
} else {
@@ -269,14 +270,15 @@
}
}
-void AAudioEndpointManager::closeExclusiveEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
+void AAudioEndpointManager::closeExclusiveEndpoint(
+ const sp<AAudioServiceEndpoint>& serviceEndpoint) {
if (serviceEndpoint.get() == nullptr) {
return;
}
// Decrement the reference count under this lock.
- std::lock_guard<std::mutex> lock(mExclusiveLock);
- int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
+ const std::lock_guard<std::mutex> lock(mExclusiveLock);
+ const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
// If no longer in use then actually close it.
@@ -292,14 +294,14 @@
}
}
-void AAudioEndpointManager::closeSharedEndpoint(sp<AAudioServiceEndpoint> serviceEndpoint) {
+void AAudioEndpointManager::closeSharedEndpoint(const sp<AAudioServiceEndpoint>& serviceEndpoint) {
if (serviceEndpoint.get() == nullptr) {
return;
}
// Decrement the reference count under this lock.
- std::lock_guard<std::mutex> lock(mSharedLock);
- int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
+ const std::lock_guard<std::mutex> lock(mSharedLock);
+ const int32_t newRefCount = serviceEndpoint->getOpenCount() - 1;
serviceEndpoint->setOpenCount(newRefCount);
// If no longer in use then actually close it.
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index b07bcef..1d38d26 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -61,7 +61,7 @@
android::sp<AAudioServiceEndpoint> openEndpoint(android::AAudioService &audioService,
const aaudio::AAudioStreamRequest &request);
- void closeEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
+ void closeEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
private:
android::sp<AAudioServiceEndpoint> openExclusiveEndpoint(android::AAudioService &aaudioService,
@@ -79,8 +79,8 @@
const AAudioStreamConfiguration& configuration)
REQUIRES(mSharedLock);
- void closeExclusiveEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
- void closeSharedEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
+ void closeExclusiveEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
+ void closeSharedEndpoint(const android::sp<AAudioServiceEndpoint>& serviceEndpoint);
// Use separate locks because opening a Shared endpoint requires opening an Exclusive one.
// That could cause a recursive lock.
diff --git a/services/oboeservice/AAudioMixer.cpp b/services/oboeservice/AAudioMixer.cpp
index ad4b830..6890985 100644
--- a/services/oboeservice/AAudioMixer.cpp
+++ b/services/oboeservice/AAudioMixer.cpp
@@ -45,7 +45,8 @@
memset(mOutputBuffer.get(), 0, mBufferSizeInBytes);
}
-int32_t AAudioMixer::mix(int streamIndex, std::shared_ptr<FifoBuffer> fifo, bool allowUnderflow) {
+int32_t AAudioMixer::mix(
+ int streamIndex, const std::shared_ptr<FifoBuffer>& fifo, bool allowUnderflow) {
WrappingBuffer wrappingBuffer;
float *destination = mOutputBuffer.get();
diff --git a/services/oboeservice/AAudioMixer.h b/services/oboeservice/AAudioMixer.h
index 1a120f2..d773178 100644
--- a/services/oboeservice/AAudioMixer.h
+++ b/services/oboeservice/AAudioMixer.h
@@ -24,7 +24,7 @@
class AAudioMixer {
public:
- AAudioMixer() {}
+ AAudioMixer() = default;
void allocate(int32_t samplesPerFrame, int32_t framesPerBurst);
@@ -37,7 +37,9 @@
* @param allowUnderflow if true then allow mixer to advance read index past the write index
* @return frames read from this stream
*/
- int32_t mix(int streamIndex, std::shared_ptr<android::FifoBuffer> fifo, bool allowUnderflow);
+ int32_t mix(int streamIndex,
+ const std::shared_ptr<android::FifoBuffer>& fifo,
+ bool allowUnderflow);
float *getOutputBuffer();
diff --git a/services/oboeservice/AAudioService.cpp b/services/oboeservice/AAudioService.cpp
index 2679b2e..e9c0884 100644
--- a/services/oboeservice/AAudioService.cpp
+++ b/services/oboeservice/AAudioService.cpp
@@ -62,7 +62,7 @@
AAudioClientTracker::getInstance().setAAudioService(this);
}
-status_t AAudioService::dump(int fd, const Vector<String16>& args) {
+status_t AAudioService::dump(int fd, const Vector<String16>& /*args*/) {
std::string result;
if (!dumpAllowed()) {
@@ -83,7 +83,7 @@
}
Status AAudioService::registerClient(const sp<IAAudioClient> &client) {
- pid_t pid = IPCThreadState::self()->getCallingPid();
+ const pid_t pid = IPCThreadState::self()->getCallingPid();
AAudioClientTracker::getInstance().registerClient(pid, client);
return Status::ok();
}
@@ -106,24 +106,24 @@
// 4) Thread A can then get the lock and also open a shared stream.
// Without the lock. Thread A might sneak in and reallocate an exclusive stream
// before B can open the shared stream.
- std::unique_lock<std::recursive_mutex> lock(mOpenLock);
+ const std::unique_lock<std::recursive_mutex> lock(mOpenLock);
aaudio_result_t result = AAUDIO_OK;
sp<AAudioServiceStreamBase> serviceStream;
const AAudioStreamConfiguration &configurationInput = request.getConstantConfiguration();
- bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
- aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
+ const bool sharingModeMatchRequired = request.isSharingModeMatchRequired();
+ const aaudio_sharing_mode_t sharingMode = configurationInput.getSharingMode();
// Enforce limit on client processes.
AttributionSourceState attributionSource = request.getAttributionSource();
- pid_t pid = IPCThreadState::self()->getCallingPid();
+ const pid_t pid = IPCThreadState::self()->getCallingPid();
attributionSource.pid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
legacy2aidl_pid_t_int32_t(pid));
attributionSource.uid = VALUE_OR_RETURN_ILLEGAL_ARG_STATUS(
legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid()));
attributionSource.token = sp<BBinder>::make();
if (attributionSource.pid != mAudioClient.attributionSource.pid) {
- int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
+ const int32_t count = AAudioClientTracker::getInstance().getStreamCount(pid);
if (count >= MAX_STREAMS_PER_PROCESS) {
ALOGE("openStream(): exceeded max streams per process %d >= %d",
count, MAX_STREAMS_PER_PROCESS);
@@ -168,7 +168,7 @@
serviceStream.clear();
AIDL_RETURN(result);
} else {
- aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
+ const aaudio_handle_t handle = mStreamTracker.addStreamForHandle(serviceStream.get());
serviceStream->setHandle(handle);
AAudioClientTracker::getInstance().registerClientStream(pid, serviceStream);
paramsOut.copyFrom(*serviceStream);
@@ -185,7 +185,7 @@
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
// Check permission and ownership first.
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGE("closeStream(0x%0x), illegal stream handle", streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -197,13 +197,13 @@
int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
}
AudioEndpointParcelable endpointParcelable;
- aaudio_result_t result = serviceStream->getDescription(endpointParcelable);
+ const aaudio_result_t result = serviceStream->getDescription(endpointParcelable);
if (result == AAUDIO_OK) {
*endpoint = std::move(endpointParcelable).parcelable();
}
@@ -213,7 +213,7 @@
Status AAudioService::startStream(int32_t streamHandle, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -224,7 +224,7 @@
Status AAudioService::pauseStream(int32_t streamHandle, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -235,7 +235,7 @@
Status AAudioService::stopStream(int32_t streamHandle, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -246,7 +246,7 @@
Status AAudioService::flushStream(int32_t streamHandle, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -254,16 +254,16 @@
AIDL_RETURN(serviceStream->flush());
}
-Status AAudioService::registerAudioThread(int32_t streamHandle, int32_t clientThreadId, int64_t periodNanoseconds,
- int32_t *_aidl_return) {
+Status AAudioService::registerAudioThread(int32_t streamHandle, int32_t clientThreadId,
+ int64_t /*periodNanoseconds*/, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
}
- int32_t priority = isCallerInService()
+ const int32_t priority = isCallerInService()
? kRealTimeAudioPriorityService : kRealTimeAudioPriorityClient;
AIDL_RETURN(serviceStream->registerAudioThread(clientThreadId, priority));
}
@@ -272,7 +272,7 @@
int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
@@ -283,13 +283,13 @@
Status AAudioService::exitStandby(int32_t streamHandle, Endpoint* endpoint, int32_t *_aidl_return) {
static_assert(std::is_same_v<aaudio_result_t, std::decay_t<typeof(*_aidl_return)>>);
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGE("getStreamDescription(), illegal stream handle = 0x%0x", streamHandle);
AIDL_RETURN(AAUDIO_ERROR_INVALID_HANDLE);
}
AudioEndpointParcelable endpointParcelable;
- aaudio_result_t result = serviceStream->exitStandby(&endpointParcelable);
+ const aaudio_result_t result = serviceStream->exitStandby(&endpointParcelable);
if (result == AAUDIO_OK) {
*endpoint = std::move(endpointParcelable).parcelable();
}
@@ -297,16 +297,18 @@
}
bool AAudioService::isCallerInService() {
- pid_t clientPid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(mAudioClient.attributionSource.pid));
- uid_t clientUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
+ const pid_t clientPid = VALUE_OR_FATAL(
+ aidl2legacy_int32_t_pid_t(mAudioClient.attributionSource.pid));
+ const uid_t clientUid = VALUE_OR_FATAL(
+ aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
return clientPid == IPCThreadState::self()->getCallingPid() &&
clientUid == IPCThreadState::self()->getCallingUid();
}
-aaudio_result_t AAudioService::closeStream(sp<AAudioServiceStreamBase> serviceStream) {
+aaudio_result_t AAudioService::closeStream(const sp<AAudioServiceStreamBase>& serviceStream) {
// This is protected by a lock in AAudioClientTracker.
// It is safe to unregister the same stream twice.
- pid_t pid = serviceStream->getOwnerProcessId();
+ const pid_t pid = serviceStream->getOwnerProcessId();
AAudioClientTracker::getInstance().unregisterClientStream(pid, serviceStream);
// This is protected by a lock in mStreamTracker.
// It is safe to remove the same stream twice.
@@ -325,10 +327,10 @@
const uid_t ownerUserId = serviceStream->getOwnerUserId();
const uid_t clientUid = VALUE_OR_FATAL(
aidl2legacy_int32_t_uid_t(mAudioClient.attributionSource.uid));
- bool callerOwnsIt = callingUserId == ownerUserId;
- bool serverCalling = callingUserId == clientUid;
- bool serverOwnsIt = ownerUserId == clientUid;
- bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
+ const bool callerOwnsIt = callingUserId == ownerUserId;
+ const bool serverCalling = callingUserId == clientUid;
+ const bool serverOwnsIt = ownerUserId == clientUid;
+ const bool allowed = callerOwnsIt || serverCalling || serverOwnsIt;
if (!allowed) {
ALOGE("AAudioService: calling uid %d cannot access stream 0x%08X owned by %d",
callingUserId, streamHandle, ownerUserId);
@@ -342,7 +344,7 @@
const android::AudioClient& client,
const audio_attributes_t *attr,
audio_port_handle_t *clientHandle) {
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -352,7 +354,7 @@
aaudio_result_t AAudioService::stopClient(aaudio_handle_t streamHandle,
audio_port_handle_t portHandle) {
- sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
+ const sp<AAudioServiceStreamBase> serviceStream = convertHandleToServiceStream(streamHandle);
if (serviceStream.get() == nullptr) {
ALOGW("%s(), invalid streamHandle = 0x%0x", __func__, streamHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
@@ -364,14 +366,14 @@
// So we do not have to check permissions.
aaudio_result_t AAudioService::disconnectStreamByPortHandle(audio_port_handle_t portHandle) {
ALOGD("%s(%d) called", __func__, portHandle);
- sp<AAudioServiceStreamBase> serviceStream =
+ const sp<AAudioServiceStreamBase> serviceStream =
mStreamTracker.findStreamByPortHandle(portHandle);
if (serviceStream.get() == nullptr) {
ALOGE("%s(), could not find stream with portHandle = %d", __func__, portHandle);
return AAUDIO_ERROR_INVALID_HANDLE;
}
// This is protected by a lock and will just return if already stopped.
- aaudio_result_t result = serviceStream->stop();
+ const aaudio_result_t result = serviceStream->stop();
serviceStream->disconnect();
return result;
}
diff --git a/services/oboeservice/AAudioService.h b/services/oboeservice/AAudioService.h
index 0a111fb..df66f1b 100644
--- a/services/oboeservice/AAudioService.h
+++ b/services/oboeservice/AAudioService.h
@@ -45,7 +45,7 @@
public:
AAudioService();
- virtual ~AAudioService() = default;
+ ~AAudioService() override = default;
aaudio::AAudioServiceInterface& asAAudioServiceInterface() {
return mAdapter;
@@ -53,7 +53,7 @@
static const char* getServiceName() { return AAUDIO_SERVICE_NAME; }
- virtual status_t dump(int fd, const Vector<String16>& args) override;
+ status_t dump(int fd, const Vector<String16>& args) override;
binder::Status registerClient(const ::android::sp<::aaudio::IAAudioClient>& client) override;
@@ -103,7 +103,7 @@
* This is only called from within the Service.
* It bypasses the permission checks in closeStream(handle).
*/
- aaudio_result_t closeStream(sp<aaudio::AAudioServiceStreamBase> serviceStream);
+ aaudio_result_t closeStream(const sp<aaudio::AAudioServiceStreamBase>& serviceStream);
private:
class Adapter : public aaudio::AAudioBinderAdapter {
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index fd546f6..2b94dbf 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -88,7 +88,7 @@
// @return true if stream found
bool AAudioServiceEndpoint::isStreamRegistered(audio_port_handle_t portHandle) {
- std::lock_guard<std::mutex> lock(mLockStreams);
+ const std::lock_guard<std::mutex> lock(mLockStreams);
for (const auto& stream : mRegisteredStreams) {
if (stream->getPortHandle() == portHandle) {
return true;
@@ -101,7 +101,7 @@
AAudioServiceEndpoint::disconnectRegisteredStreams() {
std::vector<android::sp<AAudioServiceStreamBase>> streamsDisconnected;
{
- std::lock_guard<std::mutex> lock(mLockStreams);
+ const std::lock_guard<std::mutex> lock(mLockStreams);
mRegisteredStreams.swap(streamsDisconnected);
}
mConnected.store(false);
@@ -122,7 +122,7 @@
void AAudioServiceEndpoint::releaseRegisteredStreams() {
// List of streams to be closed after we disconnect everything.
- std::vector<android::sp<AAudioServiceStreamBase>> streamsToClose
+ const std::vector<android::sp<AAudioServiceStreamBase>> streamsToClose
= disconnectRegisteredStreams();
// Close outside the lock to avoid recursive locks.
@@ -133,14 +133,14 @@
}
}
-aaudio_result_t AAudioServiceEndpoint::registerStream(sp<AAudioServiceStreamBase>stream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
+aaudio_result_t AAudioServiceEndpoint::registerStream(const sp<AAudioServiceStreamBase>& stream) {
+ const std::lock_guard<std::mutex> lock(mLockStreams);
mRegisteredStreams.push_back(stream);
return AAUDIO_OK;
}
-aaudio_result_t AAudioServiceEndpoint::unregisterStream(sp<AAudioServiceStreamBase>stream) {
- std::lock_guard<std::mutex> lock(mLockStreams);
+aaudio_result_t AAudioServiceEndpoint::unregisterStream(const sp<AAudioServiceStreamBase>& stream) {
+ const std::lock_guard<std::mutex> lock(mLockStreams);
mRegisteredStreams.erase(std::remove(
mRegisteredStreams.begin(), mRegisteredStreams.end(), stream),
mRegisteredStreams.end());
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 92004c5..dff571b 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -43,7 +43,7 @@
, public AAudioStreamParameters {
public:
- virtual ~AAudioServiceEndpoint();
+ ~AAudioServiceEndpoint() override;
virtual std::string dump() const;
@@ -55,9 +55,9 @@
*/
virtual void close() = 0;
- aaudio_result_t registerStream(android::sp<AAudioServiceStreamBase> stream);
+ aaudio_result_t registerStream(const android::sp<AAudioServiceStreamBase>& stream);
- aaudio_result_t unregisterStream(android::sp<AAudioServiceStreamBase> stream);
+ aaudio_result_t unregisterStream(const android::sp<AAudioServiceStreamBase>& stream);
virtual aaudio_result_t startStream(android::sp<AAudioServiceStreamBase> stream,
audio_port_handle_t *clientHandle) = 0;
@@ -65,14 +65,14 @@
virtual aaudio_result_t stopStream(android::sp<AAudioServiceStreamBase> stream,
audio_port_handle_t clientHandle) = 0;
- virtual aaudio_result_t startClient(const android::AudioClient& client,
- const audio_attributes_t *attr,
- audio_port_handle_t *clientHandle) {
+ virtual aaudio_result_t startClient(const android::AudioClient& /*client*/,
+ const audio_attributes_t* /*attr*/,
+ audio_port_handle_t* /*clientHandle*/) {
ALOGD("AAudioServiceEndpoint::startClient(...) AAUDIO_ERROR_UNAVAILABLE");
return AAUDIO_ERROR_UNAVAILABLE;
}
- virtual aaudio_result_t stopClient(audio_port_handle_t clientHandle) {
+ virtual aaudio_result_t stopClient(audio_port_handle_t /*clientHandle*/) {
ALOGD("AAudioServiceEndpoint::stopClient(...) AAUDIO_ERROR_UNAVAILABLE");
return AAUDIO_ERROR_UNAVAILABLE;
}
@@ -82,7 +82,7 @@
return AAUDIO_ERROR_UNAVAILABLE;
}
- virtual aaudio_result_t exitStandby(AudioEndpointParcelable* parcelable) {
+ virtual aaudio_result_t exitStandby(AudioEndpointParcelable* /*parcelable*/) {
ALOGD("AAudioServiceEndpoint::exitStandby() AAUDIO_ERROR_UNAVAILABLE");
return AAUDIO_ERROR_UNAVAILABLE;
}
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.cpp b/services/oboeservice/AAudioServiceEndpointCapture.cpp
index 95bd4bb..ba8070b 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.cpp
+++ b/services/oboeservice/AAudioServiceEndpointCapture.cpp
@@ -90,5 +90,5 @@
}
ALOGD("callbackLoop() exiting");
- return NULL; // TODO review
+ return nullptr; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointCapture.h b/services/oboeservice/AAudioServiceEndpointCapture.h
index 2ca43cf..b77100d 100644
--- a/services/oboeservice/AAudioServiceEndpointCapture.h
+++ b/services/oboeservice/AAudioServiceEndpointCapture.h
@@ -30,7 +30,7 @@
class AAudioServiceEndpointCapture : public AAudioServiceEndpointShared {
public:
explicit AAudioServiceEndpointCapture(android::AAudioService &audioService);
- virtual ~AAudioServiceEndpointCapture() = default;
+ ~AAudioServiceEndpointCapture() override = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 3d237b3..d4cdb0b 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -37,7 +37,7 @@
#include "AAudioServiceEndpointPlay.h"
#include "AAudioServiceEndpointMMAP.h"
-#define AAUDIO_BUFFER_CAPACITY_MIN 4 * 512
+#define AAUDIO_BUFFER_CAPACITY_MIN (4 * 512)
#define AAUDIO_SAMPLE_RATE_DEFAULT 48000
// This is an estimate of the time difference between the HW and the MMAP time.
@@ -85,7 +85,7 @@
return it != NEXT_FORMAT_TO_TRY.end() ? it->second : AUDIO_FORMAT_DEFAULT;
}
-}
+} // namespace
aaudio_result_t AAudioServiceEndpointMMAP::open(const aaudio::AAudioStreamRequest &request) {
aaudio_result_t result = AAUDIO_OK;
@@ -111,7 +111,7 @@
audio_format_t nextFormatToTry = AUDIO_FORMAT_DEFAULT;
result = openWithFormat(audioFormat, &nextFormatToTry);
- if (result == AAUDIO_OK || result != AAUDIO_ERROR_UNAVAILABLE) {
+ if (result != AAUDIO_ERROR_UNAVAILABLE) {
// Return if it is successful or there is an error that is not
// AAUDIO_ERROR_UNAVAILABLE happens.
ALOGI("Opened format=%#x with result=%d", audioFormat, result);
@@ -165,12 +165,12 @@
return AAUDIO_ERROR_ILLEGAL_ARGUMENT;
}
- MmapStreamInterface::stream_direction_t streamDirection =
+ const MmapStreamInterface::stream_direction_t streamDirection =
(direction == AAUDIO_DIRECTION_OUTPUT)
? MmapStreamInterface::DIRECTION_OUTPUT
: MmapStreamInterface::DIRECTION_INPUT;
- aaudio_session_id_t requestedSessionId = getSessionId();
+ const aaudio_session_id_t requestedSessionId = getSessionId();
audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
// Open HAL stream. Set mMmapStream
@@ -178,15 +178,15 @@
"sample_rate=%u, channel_mask=%#x, device=%d",
__func__, config.format, config.sample_rate,
config.channel_mask, deviceId);
- status_t status = MmapStreamInterface::openMmapStream(streamDirection,
- &attributes,
- &config,
- mMmapClient,
- &deviceId,
- &sessionId,
- this, // callback
- mMmapStream,
- &mPortHandle);
+ const status_t status = MmapStreamInterface::openMmapStream(streamDirection,
+ &attributes,
+ &config,
+ mMmapClient,
+ &deviceId,
+ &sessionId,
+ this, // callback
+ mMmapStream,
+ &mPortHandle);
ALOGD("%s() mMapClient.attributionSource = %s => portHandle = %d\n",
__func__, mMmapClient.attributionSource.toString().c_str(), mPortHandle);
if (status != OK) {
@@ -209,7 +209,7 @@
ALOGW("%s() - openMmapStream() failed to set sessionId", __func__);
}
- aaudio_session_id_t actualSessionId =
+ const aaudio_session_id_t actualSessionId =
(requestedSessionId == AAUDIO_SESSION_ID_NONE)
? AAUDIO_SESSION_ID_NONE
: (aaudio_session_id_t) sessionId;
@@ -278,7 +278,7 @@
if (stream != nullptr) {
attr = getAudioAttributesFrom(stream.get());
}
- aaudio_result_t result = startClient(
+ const aaudio_result_t result = startClient(
mMmapClient, stream == nullptr ? nullptr : &attr, &tempHandle);
// When AudioFlinger is passed a valid port handle then it should not change it.
LOG_ALWAYS_FATAL_IF(tempHandle != mPortHandle,
@@ -288,8 +288,8 @@
return result;
}
-aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> stream,
- audio_port_handle_t clientHandle __unused) {
+aaudio_result_t AAudioServiceEndpointMMAP::stopStream(sp<AAudioServiceStreamBase> /*stream*/,
+ audio_port_handle_t /*clientHandle*/) {
mFramesTransferred.reset32();
// Round 64-bit counter up to a multiple of the buffer capacity.
@@ -306,23 +306,21 @@
aaudio_result_t AAudioServiceEndpointMMAP::startClient(const android::AudioClient& client,
const audio_attributes_t *attr,
audio_port_handle_t *clientHandle) {
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- status_t status = mMmapStream->start(client, attr, clientHandle);
- return AAudioConvert_androidToAAudioResult(status);
+ return mMmapStream == nullptr
+ ? AAUDIO_ERROR_NULL
+ : AAudioConvert_androidToAAudioResult(mMmapStream->start(client, attr, clientHandle));
}
aaudio_result_t AAudioServiceEndpointMMAP::stopClient(audio_port_handle_t clientHandle) {
- if (mMmapStream == nullptr) return AAUDIO_ERROR_NULL;
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
- return result;
+ return mMmapStream == nullptr
+ ? AAUDIO_ERROR_NULL
+ : AAudioConvert_androidToAAudioResult(mMmapStream->stop(clientHandle));
}
aaudio_result_t AAudioServiceEndpointMMAP::standby() {
- if (mMmapStream == nullptr) {
- return AAUDIO_ERROR_NULL;
- }
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(mMmapStream->standby());
- return result;
+ return mMmapStream == nullptr
+ ? AAUDIO_ERROR_NULL
+ : AAudioConvert_androidToAAudioResult(mMmapStream->standby());
}
aaudio_result_t AAudioServiceEndpointMMAP::exitStandby(AudioEndpointParcelable* parcelable) {
@@ -330,11 +328,12 @@
return AAUDIO_ERROR_NULL;
}
mAudioDataFileDescriptor.reset();
- aaudio_result_t result = createMmapBuffer(&mAudioDataFileDescriptor);
+ const aaudio_result_t result = createMmapBuffer(&mAudioDataFileDescriptor);
if (result == AAUDIO_OK) {
- int32_t bytesPerFrame = calculateBytesPerFrame();
- int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
- int fdIndex = parcelable->addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
+ const int32_t bytesPerFrame = calculateBytesPerFrame();
+ const int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
+ const int fdIndex = parcelable->addFileDescriptor(
+ mAudioDataFileDescriptor, capacityInBytes);
parcelable->mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
parcelable->mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
parcelable->mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
@@ -350,10 +349,10 @@
if (mMmapStream == nullptr) {
return AAUDIO_ERROR_NULL;
}
- status_t status = mMmapStream->getMmapPosition(&position);
+ const status_t status = mMmapStream->getMmapPosition(&position);
ALOGV("%s() status= %d, pos = %d, nanos = %lld\n",
__func__, status, position.position_frames, (long long) position.time_nanoseconds);
- aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
+ const aaudio_result_t result = AAudioConvert_androidToAAudioResult(status);
if (result == AAUDIO_ERROR_UNAVAILABLE) {
ALOGW("%s(): getMmapPosition() has no position data available", __func__);
} else if (result != AAUDIO_OK) {
@@ -367,8 +366,8 @@
return result;
}
-aaudio_result_t AAudioServiceEndpointMMAP::getTimestamp(int64_t *positionFrames,
- int64_t *timeNanos) {
+aaudio_result_t AAudioServiceEndpointMMAP::getTimestamp(int64_t* /*positionFrames*/,
+ int64_t* /*timeNanos*/) {
return 0; // TODO
}
@@ -381,7 +380,7 @@
} else {
// Must be a SHARED stream?
ALOGD("%s(%d) disconnect a specific stream", __func__, portHandle);
- aaudio_result_t result = mAAudioService.disconnectStreamByPortHandle(portHandle);
+ const aaudio_result_t result = mAAudioService.disconnectStreamByPortHandle(portHandle);
ALOGD("%s(%d) disconnectStreamByPortHandle returned %d", __func__, portHandle, result);
}
};
@@ -389,7 +388,7 @@
// This is called by AudioFlinger when it wants to destroy a stream.
void AAudioServiceEndpointMMAP::onTearDown(audio_port_handle_t portHandle) {
ALOGD("%s(portHandle = %d) called", __func__, portHandle);
- android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
+ const android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
std::thread asyncTask([holdEndpoint, portHandle]() {
holdEndpoint->handleTearDownAsync(portHandle);
});
@@ -398,18 +397,18 @@
void AAudioServiceEndpointMMAP::onVolumeChanged(float volume) {
ALOGD("%s() volume = %f", __func__, volume);
- std::lock_guard<std::mutex> lock(mLockStreams);
+ const std::lock_guard<std::mutex> lock(mLockStreams);
for(const auto& stream : mRegisteredStreams) {
stream->onVolumeChanged(volume);
}
};
void AAudioServiceEndpointMMAP::onRoutingChanged(audio_port_handle_t portHandle) {
- const int32_t deviceId = static_cast<int32_t>(portHandle);
+ const auto deviceId = static_cast<int32_t>(portHandle);
ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
if (getDeviceId() != deviceId) {
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
- android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
+ const android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
std::thread asyncTask([holdEndpoint, deviceId]() {
ALOGD("onRoutingChanged() asyncTask launched");
holdEndpoint->disconnectRegisteredStreams();
@@ -429,9 +428,9 @@
AudioEndpointParcelable* parcelable)
{
// Gather information on the data queue based on HAL info.
- int32_t bytesPerFrame = calculateBytesPerFrame();
- int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
- int fdIndex = parcelable->addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
+ const int32_t bytesPerFrame = calculateBytesPerFrame();
+ const int32_t capacityInBytes = getBufferCapacity() * bytesPerFrame;
+ const int fdIndex = parcelable->addFileDescriptor(mAudioDataFileDescriptor, capacityInBytes);
parcelable->mDownDataQueueParcelable.setupMemory(fdIndex, 0, capacityInBytes);
parcelable->mDownDataQueueParcelable.setBytesPerFrame(bytesPerFrame);
parcelable->mDownDataQueueParcelable.setFramesPerBurst(mFramesPerBurst);
@@ -447,7 +446,7 @@
}
uint64_t tempPositionFrames;
int64_t tempTimeNanos;
- status_t status = mMmapStream->getExternalPosition(&tempPositionFrames, &tempTimeNanos);
+ const status_t status = mMmapStream->getExternalPosition(&tempPositionFrames, &tempTimeNanos);
if (status != OK) {
// getExternalPosition reports error. The HAL may not support the API. Cache the result
// so that the call will not go to the HAL next time.
@@ -527,8 +526,8 @@
if (minSizeFrames <= 0) { // zero will get rejected
minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
}
- status_t status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
- bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
+ const status_t status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
+ const bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
if (status != OK) {
ALOGE("%s() - createMmapBuffer() failed with status %d %s",
__func__, status, strerror(-status));
@@ -545,7 +544,7 @@
setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
if (!isBufferShareable) {
// Exclusive mode can only be used by the service because the FD cannot be shared.
- int32_t audioServiceUid =
+ const int32_t audioServiceUid =
VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(getuid()));
if ((mMmapClient.attributionSource.uid != audioServiceUid) &&
getSharingMode() == AAUDIO_SHARING_MODE_EXCLUSIVE) {
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.h b/services/oboeservice/AAudioServiceEndpointMMAP.h
index 73e0f61..4f77393 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.h
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.h
@@ -44,7 +44,7 @@
public:
explicit AAudioServiceEndpointMMAP(android::AAudioService &audioService);
- virtual ~AAudioServiceEndpointMMAP() = default;
+ ~AAudioServiceEndpointMMAP() override = default;
std::string dump() const override;
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 2a5939f..637405d 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -158,5 +158,5 @@
ALOGD("%s() exiting, enabled = %d, state = %d, result = %d <<<<<<<<<<<<< MIXER",
__func__, mCallbackEnabled.load(), getStreamInternal()->getState(), result);
- return NULL; // TODO review
+ return nullptr; // TODO review
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 02202d8..1dd0c3a 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -103,8 +103,7 @@
// Prevent the stream from being deleted while being used.
// This is just for extra safety. It is probably not needed because
// this callback should be joined before the stream is closed.
- AAudioServiceEndpointShared *endpointPtr =
- static_cast<AAudioServiceEndpointShared *>(arg);
+ auto endpointPtr = static_cast<AAudioServiceEndpointShared *>(arg);
android::sp<AAudioServiceEndpointShared> endpoint(endpointPtr);
// Balance the incStrong() in startSharingThread_l().
endpoint->decStrong(nullptr);
@@ -140,7 +139,7 @@
aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() {
mCallbackEnabled.store(false);
- return getStreamInternal()->joinThread(NULL);
+ return getStreamInternal()->joinThread(nullptr);
}
aaudio_result_t AAudioServiceEndpointShared::startStream(
@@ -180,8 +179,8 @@
return result;
}
-aaudio_result_t AAudioServiceEndpointShared::stopStream(sp<AAudioServiceStreamBase> sharedStream,
- audio_port_handle_t clientHandle) {
+aaudio_result_t AAudioServiceEndpointShared::stopStream(
+ sp<AAudioServiceStreamBase> /*sharedStream*/, audio_port_handle_t clientHandle) {
// Ignore result.
(void) getStreamInternal()->stopClient(clientHandle);
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 3e760c4..0efb227 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -39,7 +39,7 @@
public:
explicit AAudioServiceEndpointShared(AudioStreamInternal *streamInternal);
- virtual ~AAudioServiceEndpointShared() = default;
+ ~AAudioServiceEndpointShared() override = default;
std::string dump() const override;
@@ -79,6 +79,6 @@
std::atomic<int> mRunningStreamCount{0};
};
-}
+} // namespace aaudio
#endif //AAUDIO_SERVICE_ENDPOINT_SHARED_H
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 35d712c..8e1e497 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -83,9 +83,8 @@
}
std::string AAudioServiceStreamBase::dumpHeader() {
- return std::string(
- " T Handle UId Port Run State Format Burst Chan Mask Capacity"
- " HwFormat HwChan HwRate");
+ return {" T Handle UId Port Run State Format Burst Chan Mask Capacity"
+ " HwFormat HwChan HwRate"};
}
std::string AAudioServiceStreamBase::dump() const {
@@ -477,8 +476,7 @@
disconnect_l();
break;
case REGISTER_AUDIO_THREAD: {
- RegisterAudioThreadParam *param =
- (RegisterAudioThreadParam *) command->parameter.get();
+ auto param = (RegisterAudioThreadParam *) command->parameter.get();
command->result =
param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
: registerAudioThread_l(param->mOwnerPid,
@@ -487,21 +485,20 @@
}
break;
case UNREGISTER_AUDIO_THREAD: {
- UnregisterAudioThreadParam *param =
- (UnregisterAudioThreadParam *) command->parameter.get();
+ auto param = (UnregisterAudioThreadParam *) command->parameter.get();
command->result =
param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
: unregisterAudioThread_l(param->mClientThreadId);
}
break;
case GET_DESCRIPTION: {
- GetDescriptionParam *param = (GetDescriptionParam *) command->parameter.get();
+ auto param = (GetDescriptionParam *) command->parameter.get();
command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
: getDescription_l(param->mParcelable);
}
break;
case EXIT_STANDBY: {
- ExitStandbyParam *param = (ExitStandbyParam *) command->parameter.get();
+ auto param = (ExitStandbyParam *) command->parameter.get();
command->result = param == nullptr ? AAUDIO_ERROR_ILLEGAL_ARGUMENT
: exitStandby_l(param->mParcelable);
standbyTime = AudioClock::getNanoseconds() + IDLE_TIMEOUT_NANOS;
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index b5f8b90..0f51503 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -62,7 +62,7 @@
public:
explicit AAudioServiceStreamBase(android::AAudioService &aAudioService);
- virtual ~AAudioServiceStreamBase();
+ ~AAudioServiceStreamBase() override;
enum {
ILLEGAL_THREAD_ID = 0
@@ -254,7 +254,7 @@
RegisterAudioThreadParam(pid_t ownerPid, pid_t clientThreadId, int priority)
: AAudioCommandParam(), mOwnerPid(ownerPid),
mClientThreadId(clientThreadId), mPriority(priority) { }
- ~RegisterAudioThreadParam() = default;
+ ~RegisterAudioThreadParam() override = default;
pid_t mOwnerPid;
pid_t mClientThreadId;
@@ -265,9 +265,9 @@
class UnregisterAudioThreadParam : public AAudioCommandParam {
public:
- UnregisterAudioThreadParam(pid_t clientThreadId)
+ explicit UnregisterAudioThreadParam(pid_t clientThreadId)
: AAudioCommandParam(), mClientThreadId(clientThreadId) { }
- ~UnregisterAudioThreadParam() = default;
+ ~UnregisterAudioThreadParam() override = default;
pid_t mClientThreadId;
};
@@ -275,9 +275,9 @@
class GetDescriptionParam : public AAudioCommandParam {
public:
- GetDescriptionParam(AudioEndpointParcelable* parcelable)
+ explicit GetDescriptionParam(AudioEndpointParcelable* parcelable)
: AAudioCommandParam(), mParcelable(parcelable) { }
- ~GetDescriptionParam() = default;
+ ~GetDescriptionParam() override = default;
AudioEndpointParcelable* mParcelable;
};
@@ -324,9 +324,9 @@
}
class ExitStandbyParam : public AAudioCommandParam {
public:
- ExitStandbyParam(AudioEndpointParcelable* parcelable)
+ explicit ExitStandbyParam(AudioEndpointParcelable* parcelable)
: AAudioCommandParam(), mParcelable(parcelable) { }
- ~ExitStandbyParam() = default;
+ ~ExitStandbyParam() override = default;
AudioEndpointParcelable* mParcelable;
};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index cd8c91e..8b8c5e6 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -47,7 +47,7 @@
public:
AAudioServiceStreamMMAP(android::AAudioService &aAudioService,
bool inService);
- virtual ~AAudioServiceStreamMMAP() = default;
+ ~AAudioServiceStreamMMAP() override = default;
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 78f9787..0b2513a 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -44,7 +44,7 @@
public:
explicit AAudioServiceStreamShared(android::AAudioService &aAudioService);
- virtual ~AAudioServiceStreamShared() = default;
+ ~AAudioServiceStreamShared() override = default;
static std::string dumpHeader();
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
index 9bbbc73..c86a7a2 100644
--- a/services/oboeservice/AAudioStreamTracker.cpp
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -78,7 +78,8 @@
return handle;
}
-aaudio_handle_t AAudioStreamTracker::addStreamForHandle(sp<AAudioServiceStreamBase> serviceStream) {
+aaudio_handle_t AAudioStreamTracker::addStreamForHandle(
+ const sp<AAudioServiceStreamBase>& serviceStream) {
std::lock_guard<std::mutex> lock(mHandleLock);
aaudio_handle_t handle = mPreviousHandle;
// Assign a unique handle.
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index 43870fc..99f4b6c 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -64,7 +64,7 @@
* @param serviceStream
* @return handle for identifying the stream
*/
- aaudio_handle_t addStreamForHandle(android::sp<AAudioServiceStreamBase> serviceStream);
+ aaudio_handle_t addStreamForHandle(const android::sp<AAudioServiceStreamBase>& serviceStream);
/**
* @return string that can be added to dumpsys
diff --git a/services/oboeservice/AAudioThread.h b/services/oboeservice/AAudioThread.h
index b2774e0..91ad715 100644
--- a/services/oboeservice/AAudioThread.h
+++ b/services/oboeservice/AAudioThread.h
@@ -29,7 +29,7 @@
*/
class Runnable {
public:
- Runnable() {};
+ Runnable() = default;
virtual ~Runnable() = default;
virtual void run() = 0;
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 5076239..56c0dc9 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -21,6 +21,64 @@
default_applicable_licenses: ["frameworks_av_license"],
}
+tidy_errors = [
+ // https://clang.llvm.org/extra/clang-tidy/checks/list.html
+ // For many categories, the checks are too many to specify individually.
+ // Feel free to disable as needed - as warnings are generally ignored,
+ // we treat warnings as errors.
+ "android-*",
+ "bugprone-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ "google-*",
+ "misc-*",
+ //"modernize-*", // explicitly list the modernize as they can be subjective.
+ "modernize-avoid-bind",
+ //"modernize-avoid-c-arrays", // std::array<> can be verbose
+ "modernize-concat-nested-namespaces",
+ //"modernize-deprecated-headers", // C headers still ok even if there is C++ equivalent.
+ "modernize-deprecated-ios-base-aliases",
+ "modernize-loop-convert",
+ "modernize-make-shared",
+ "modernize-make-unique",
+ "modernize-pass-by-value",
+ "modernize-raw-string-literal",
+ "modernize-redundant-void-arg",
+ "modernize-replace-auto-ptr",
+ "modernize-replace-random-shuffle",
+ "modernize-return-braced-init-list",
+ "modernize-shrink-to-fit",
+ "modernize-unary-static-assert",
+ "modernize-use-auto",
+ "modernize-use-bool-literals",
+ "modernize-use-default-member-init",
+ "modernize-use-emplace",
+ "modernize-use-equals-default",
+ "modernize-use-equals-delete",
+ // "modernize-use-nodiscard", // Maybe add this in the future
+ "modernize-use-noexcept",
+ "modernize-use-nullptr",
+ "modernize-use-override",
+ // "modernize-use-trailing-return-type", // not necessarily more readable
+ "modernize-use-transparent-functors",
+ "modernize-use-uncaught-exceptions",
+ "modernize-use-using",
+ "performance-*",
+
+ // Remove some pedantic stylistic requirements.
+ "-android-cloexec-dup", // found in AAudioServiceEndpointMMAP.cpp
+ "-bugprone-narrowing-conversions", // found in several interface from size_t to int32_t
+
+ "-google-readability-casting", // C++ casts not always necessary and may be verbose
+ "-google-readability-todo", // do not require TODO(info)
+ "-google-build-using-namespace", // Reenable and fix later.
+ "-google-global-names-in-headers", // found in several files
+
+ "-misc-non-private-member-variables-in-classes", // found in aidl generated files
+
+]
+
+
cc_library {
name: "libaaudioservice",
@@ -89,4 +147,11 @@
"frameworks/av/media/libnbaio/include_mono",
"frameworks/av/media/libnbaio/include",
],
+
+ tidy: true,
+ tidy_checks: tidy_errors,
+ tidy_checks_as_errors: tidy_errors,
+ tidy_flags: [
+ "-format-style=file",
+ ]
}
diff --git a/services/oboeservice/SharedMemoryProxy.cpp b/services/oboeservice/SharedMemoryProxy.cpp
index 78d4884..549a36e 100644
--- a/services/oboeservice/SharedMemoryProxy.cpp
+++ b/services/oboeservice/SharedMemoryProxy.cpp
@@ -58,7 +58,7 @@
}
// Get original memory address.
- mOriginalSharedMemory = (uint8_t *) mmap(0, mSharedMemorySizeInBytes,
+ mOriginalSharedMemory = (uint8_t *) mmap(nullptr, mSharedMemorySizeInBytes,
PROT_READ|PROT_WRITE,
MAP_SHARED,
mOriginalFileDescriptor, 0);
diff --git a/services/oboeservice/SharedMemoryProxy.h b/services/oboeservice/SharedMemoryProxy.h
index 89eeb4b..81a0753 100644
--- a/services/oboeservice/SharedMemoryProxy.h
+++ b/services/oboeservice/SharedMemoryProxy.h
@@ -30,7 +30,7 @@
*/
class SharedMemoryProxy {
public:
- SharedMemoryProxy() {}
+ SharedMemoryProxy() = default;
~SharedMemoryProxy();
diff --git a/services/oboeservice/SharedRingBuffer.cpp b/services/oboeservice/SharedRingBuffer.cpp
index fd2a454..eebff51 100644
--- a/services/oboeservice/SharedRingBuffer.cpp
+++ b/services/oboeservice/SharedRingBuffer.cpp
@@ -62,7 +62,7 @@
// Map the fd to memory addresses. Use a temporary pointer to keep the mmap result and update
// it to `mSharedMemory` only when mmap operate successfully.
- uint8_t* tmpPtr = (uint8_t *) mmap(0, mSharedMemorySizeInBytes,
+ auto tmpPtr = (uint8_t *) mmap(nullptr, mSharedMemorySizeInBytes,
PROT_READ|PROT_WRITE,
MAP_SHARED,
mFileDescriptor.get(), 0);
@@ -74,10 +74,8 @@
mSharedMemory = tmpPtr;
// Get addresses for our counters and data from the shared memory.
- fifo_counter_t *readCounterAddress =
- (fifo_counter_t *) &mSharedMemory[SHARED_RINGBUFFER_READ_OFFSET];
- fifo_counter_t *writeCounterAddress =
- (fifo_counter_t *) &mSharedMemory[SHARED_RINGBUFFER_WRITE_OFFSET];
+ auto readCounterAddress = (fifo_counter_t *) &mSharedMemory[SHARED_RINGBUFFER_READ_OFFSET];
+ auto writeCounterAddress = (fifo_counter_t *) &mSharedMemory[SHARED_RINGBUFFER_WRITE_OFFSET];
uint8_t *dataAddress = &mSharedMemory[SHARED_RINGBUFFER_DATA_OFFSET];
mFifoBuffer = std::make_shared<FifoBufferIndirect>(bytesPerFrame, capacityInFrames,
diff --git a/services/oboeservice/SharedRingBuffer.h b/services/oboeservice/SharedRingBuffer.h
index cff1261..463bf11 100644
--- a/services/oboeservice/SharedRingBuffer.h
+++ b/services/oboeservice/SharedRingBuffer.h
@@ -39,7 +39,7 @@
*/
class SharedRingBuffer {
public:
- SharedRingBuffer() {}
+ SharedRingBuffer() = default;
virtual ~SharedRingBuffer();
diff --git a/services/oboeservice/TimestampScheduler.h b/services/oboeservice/TimestampScheduler.h
index baa5c41..6b5f4b1 100644
--- a/services/oboeservice/TimestampScheduler.h
+++ b/services/oboeservice/TimestampScheduler.h
@@ -31,7 +31,7 @@
class TimestampScheduler
{
public:
- TimestampScheduler() {};
+ TimestampScheduler() = default;
virtual ~TimestampScheduler() = default;
/**
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
index 0649061..ea5139d 100644
--- a/services/tuner/Android.bp
+++ b/services/tuner/Android.bp
@@ -88,6 +88,7 @@
"libbase",
"libbinder",
"libfmq",
+ "libhidlbase",
"liblog",
"libtunerservice",
"libutils",
diff --git a/services/tuner/TunerHelper.cpp b/services/tuner/TunerHelper.cpp
index dc67110..a03386f 100644
--- a/services/tuner/TunerHelper.cpp
+++ b/services/tuner/TunerHelper.cpp
@@ -83,6 +83,22 @@
tunerRM->setFrontendInfoList(feInfos);
tunerRM->setLnbInfoList(lnbHandles);
}
+void TunerHelper::updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
+ const vector<TunerDemuxInfo>& demuxInfos,
+ const vector<int32_t>& lnbHandles) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
+ shared_ptr<ITunerResourceManager> tunerRM = ITunerResourceManager::fromBinder(binder);
+ if (tunerRM == nullptr) {
+ return;
+ }
+
+ updateTunerResources(feInfos, lnbHandles);
+
+ // for Tuner 2.0 and below, Demux resource is not really managed under TRM
+ if (demuxInfos.size() > 0) {
+ tunerRM->setDemuxInfoList(demuxInfos);
+ }
+}
// TODO: create a map between resource id and handles.
int TunerHelper::getResourceIdFromHandle(int resourceHandle, int /*type*/) {
diff --git a/services/tuner/TunerHelper.h b/services/tuner/TunerHelper.h
index 755df57..65a9b0b 100644
--- a/services/tuner/TunerHelper.h
+++ b/services/tuner/TunerHelper.h
@@ -17,9 +17,11 @@
#ifndef ANDROID_MEDIA_TUNERDVRHELPER_H
#define ANDROID_MEDIA_TUNERDVRHELPER_H
+#include <aidl/android/media/tv/tunerresourcemanager/TunerDemuxInfo.h>
#include <aidl/android/media/tv/tunerresourcemanager/TunerFrontendInfo.h>
#include <utils/String16.h>
+using ::aidl::android::media::tv::tunerresourcemanager::TunerDemuxInfo;
using ::aidl::android::media::tv::tunerresourcemanager::TunerFrontendInfo;
using ::android::String16;
@@ -55,6 +57,10 @@
// TODO: update Demux, Descrambler.
static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
const vector<int32_t>& lnbHandles);
+
+ static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
+ const vector<TunerDemuxInfo>& demuxInfos,
+ const vector<int32_t>& lnbHandles);
// TODO: create a map between resource id and handles.
static int getResourceIdFromHandle(int resourceHandle, int type);
static int getResourceHandleFromId(int id, int resourceType);
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index d59d95f..e5bcf1f 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -82,18 +82,75 @@
return AServiceManager_addService(tunerService->asBinder().get(), getServiceName());
}
-::ndk::ScopedAStatus TunerService::openDemux(int32_t /* in_demuxHandle */,
+::ndk::ScopedAStatus TunerService::openDemux(int32_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) {
ALOGV("openDemux");
- vector<int32_t> id;
shared_ptr<IDemux> demux;
- auto status = mTuner->openDemux(&id, &demux);
- if (status.isOk()) {
- *_aidl_return =
- ::ndk::SharedRefBase::make<TunerDemux>(demux, id[0], this->ref<TunerService>());
+ bool fallBackToOpenDemux = false;
+ vector<int32_t> ids;
+
+ if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
+ fallBackToOpenDemux = true;
+ } else {
+ mTuner->getDemuxIds(&ids);
+ if (ids.size() == 0) {
+ fallBackToOpenDemux = true;
+ }
}
- return status;
+ if (fallBackToOpenDemux) {
+ auto status = mTuner->openDemux(&ids, &demux);
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ } else {
+ int id = TunerHelper::getResourceIdFromHandle(in_demuxHandle, DEMUX);
+ auto status = mTuner->openDemuxById(id, &demux);
+ if (status.isOk()) {
+ *_aidl_return =
+ ::ndk::SharedRefBase::make<TunerDemux>(demux, id, this->ref<TunerService>());
+ }
+ return status;
+ }
+}
+
+::ndk::ScopedAStatus TunerService::getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) {
+ if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+ int id = TunerHelper::getResourceIdFromHandle(in_demuxHandle, DEMUX);
+ return mTuner->getDemuxInfo(id, _aidl_return);
+}
+
+::ndk::ScopedAStatus TunerService::getDemuxInfoList(vector<DemuxInfo>* _aidl_return) {
+ if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+ vector<DemuxInfo> demuxInfoList;
+ vector<int32_t> ids;
+ auto status = mTuner->getDemuxIds(&ids);
+ if (!status.isOk()) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+
+ for (int i = 0; i < ids.size(); i++) {
+ DemuxInfo demuxInfo;
+ auto res = mTuner->getDemuxInfo(ids[i], &demuxInfo);
+ if (!res.isOk()) {
+ continue;
+ }
+ demuxInfoList.push_back(demuxInfo);
+ }
+
+ if (demuxInfoList.size() > 0) {
+ *_aidl_return = demuxInfoList;
+ return ::ndk::ScopedAStatus::ok();
+ } else {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
}
::ndk::ScopedAStatus TunerService::getDemuxCaps(DemuxCapabilities* _aidl_return) {
@@ -230,7 +287,9 @@
}
void TunerService::updateTunerResources() {
- TunerHelper::updateTunerResources(getTRMFrontendInfos(), getTRMLnbHandles());
+ TunerHelper::updateTunerResources(getTRMFrontendInfos(),
+ getTRMDemuxInfos(),
+ getTRMLnbHandles());
}
vector<TunerFrontendInfo> TunerService::getTRMFrontendInfos() {
@@ -258,6 +317,32 @@
return infos;
}
+vector<TunerDemuxInfo> TunerService::getTRMDemuxInfos() {
+ vector<TunerDemuxInfo> infos;
+ vector<int32_t> ids;
+
+ if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
+ return infos;
+ }
+
+ auto status = mTuner->getDemuxIds(&ids);
+ if (!status.isOk()) {
+ return infos;
+ }
+
+ for (int i = 0; i < ids.size(); i++) {
+ DemuxInfo demuxInfo;
+ mTuner->getDemuxInfo(ids[i], &demuxInfo);
+ TunerDemuxInfo tunerDemuxInfo{
+ .handle = TunerHelper::getResourceHandleFromId((int)ids[i], DEMUX),
+ .filterTypes = static_cast<int>(demuxInfo.filterTypes)
+ };
+ infos.push_back(tunerDemuxInfo);
+ }
+
+ return infos;
+}
+
vector<int32_t> TunerService::getTRMLnbHandles() {
vector<int32_t> lnbHandles;
if (mTuner != nullptr) {
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index 517df4a..190ccd4 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -32,6 +32,7 @@
using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxInfo;
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
using ::aidl::android::hardware::tv::tuner::FrontendType;
using ::aidl::android::hardware::tv::tuner::ITuner;
@@ -71,6 +72,8 @@
::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) override;
::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
shared_ptr<ITunerDescrambler>* _aidl_return) override;
::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
@@ -90,6 +93,7 @@
private:
void updateTunerResources();
vector<TunerFrontendInfo> getTRMFrontendInfos();
+ vector<TunerDemuxInfo> getTRMDemuxInfos();
vector<int32_t> getTRMLnbHandles();
shared_ptr<ITuner> mTuner;
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index 8d285e3..932133e 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -17,6 +17,7 @@
package android.media.tv.tuner;
import android.hardware.tv.tuner.DemuxCapabilities;
+import android.hardware.tv.tuner.DemuxInfo;
import android.hardware.tv.tuner.FrontendInfo;
import android.hardware.tv.tuner.FrontendType;
import android.media.tv.tuner.ITunerDemux;
@@ -77,6 +78,21 @@
ITunerDemux openDemux(in int demuxHandle);
/**
+ * Retrieve the supported filter main types
+ *
+ * @param demuxHandle the handle of the demux to query demux info for
+ * @return the demux info
+ */
+ DemuxInfo getDemuxInfo(in int demuxHandle);
+
+ /**
+ * Retrieve the list of demux info for all the demuxes on the system
+ *
+ * @return the list of DemuxInfo
+ */
+ DemuxInfo[] getDemuxInfoList();
+
+ /**
* Retrieve the Tuner Demux capabilities.
*
* @return the demux’s capabilities.
diff --git a/services/tuner/hidl/TunerHidlService.cpp b/services/tuner/hidl/TunerHidlService.cpp
index 52005c2..6bc36be 100644
--- a/services/tuner/hidl/TunerHidlService.cpp
+++ b/services/tuner/hidl/TunerHidlService.cpp
@@ -123,6 +123,20 @@
return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
}
+::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int32_t /* in_demuxHandle */,
+ DemuxInfo* /* _aidl_return */) {
+ ALOGE("getDemuxInfo is not supported");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(HidlResult::UNAVAILABLE));
+}
+
+::ndk::ScopedAStatus TunerHidlService::getDemuxInfoList(
+ vector<DemuxInfo>* /* _aidle_return */) {
+ ALOGE("getDemuxInfoList is not supported");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(HidlResult::UNAVAILABLE));
+}
+
::ndk::ScopedAStatus TunerHidlService::getDemuxCaps(DemuxCapabilities* _aidl_return) {
ALOGV("getDemuxCaps");
HidlResult res;
diff --git a/services/tuner/hidl/TunerHidlService.h b/services/tuner/hidl/TunerHidlService.h
index 872aefc..526c5e6 100644
--- a/services/tuner/hidl/TunerHidlService.h
+++ b/services/tuner/hidl/TunerHidlService.h
@@ -33,6 +33,7 @@
using ::aidl::android::hardware::tv::tuner::DemuxCapabilities;
using ::aidl::android::hardware::tv::tuner::DemuxFilterEvent;
using ::aidl::android::hardware::tv::tuner::DemuxFilterStatus;
+using ::aidl::android::hardware::tv::tuner::DemuxInfo;
using ::aidl::android::hardware::tv::tuner::FrontendInfo;
using ::aidl::android::hardware::tv::tuner::FrontendType;
using ::aidl::android::media::tv::tuner::ITunerDemux;
@@ -83,6 +84,8 @@
::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) override;
::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
shared_ptr<ITunerDescrambler>* _aidl_return) override;
::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
diff --git a/services/tuner/main_tunerservice.cpp b/services/tuner/main_tunerservice.cpp
index f8311ff..90f1731 100644
--- a/services/tuner/main_tunerservice.cpp
+++ b/services/tuner/main_tunerservice.cpp
@@ -18,6 +18,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <utils/Log.h>
+#include <hidl/HidlTransportSupport.h>
#include "TunerService.h"
#include "hidl/TunerHidlService.h"
@@ -32,7 +33,8 @@
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
- ProcessState::self()->setThreadPoolMaxThreadCount(8);
+ hardware::configureRpcThreadpool(16, true);
+ ProcessState::self()->setThreadPoolMaxThreadCount(16);
// Check legacy HIDL HAL first. If it's not existed, use AIDL HAL.
binder_status_t status = TunerHidlService::instantiate();