Merge "Expose audioserver flags for static CTS inc" into main
diff --git a/camera/Android.mk b/camera/Android.mk
deleted file mode 100644
index d9068c0..0000000
--- a/camera/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-# Copyright 2010 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 $(call all-subdir-makefiles)
diff --git a/camera/CameraMetadata.cpp b/camera/CameraMetadata.cpp
index 2e808d1..424923a 100644
--- a/camera/CameraMetadata.cpp
+++ b/camera/CameraMetadata.cpp
@@ -880,7 +880,7 @@
return OK;
}
-metadata_vendor_id_t CameraMetadata::getVendorId() {
+metadata_vendor_id_t CameraMetadata::getVendorId() const {
return get_camera_metadata_vendor_id(mBuffer);
}
diff --git a/camera/VendorTagDescriptor.cpp b/camera/VendorTagDescriptor.cpp
index fb26f83..c12a1a1 100644
--- a/camera/VendorTagDescriptor.cpp
+++ b/camera/VendorTagDescriptor.cpp
@@ -466,7 +466,7 @@
int VendorTagDescriptorCache::getTagType(uint32_t tag,
metadata_vendor_id_t id) const {
- int ret = 0;
+ int ret = -1;
auto desc = mVendorMap.find(id);
if (desc != mVendorMap.end()) {
ret = desc->second->getTagType(tag);
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 8078cea..0eeeb7f 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -149,6 +149,18 @@
void remapCameraIds(in CameraIdRemapping cameraIdRemapping);
/**
+ * Inject Session Params into an existing camera session.
+ *
+ * @param cameraId the camera id session to inject session params into. Note that
+ * if there is no active session for the input cameraid, this operation
+ * will be a no-op. In addition, future camera sessions for cameraid will
+ * not be affected.
+ * @param sessionParams the session params to override for the existing session.
+ */
+ void injectSessionParams(@utf8InCpp String cameraId,
+ in CameraMetadataNative sessionParams);
+
+ /**
* Remove listener for changes to camera device and flashlight state.
*/
void removeListener(ICameraServiceListener listener);
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 8e1fcc0..843e0d4 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -99,6 +99,15 @@
*/
boolean isSessionConfigurationSupported(in SessionConfiguration sessionConfiguration);
+ /**
+ * Get the camera characteristics for a particular session configuration
+ *
+ * @param sessionConfiguration Specific session configuration for which the characteristics
+ * are fetched.
+ * @return - characteristics associated with the given session.
+ */
+ CameraMetadataNative getSessionCharacteristics(in SessionConfiguration sessionConfiguration);
+
void deleteStream(int streamId);
/**
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index f7deda1..076394d 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -62,3 +62,24 @@
description: "Enable session parameter injection via reconfiguration"
bug: "308984721"
}
+
+flag {
+ namespace: "camera_platform"
+ name: "camera_ae_mode_low_light_boost"
+ description: "An AE mode that enables increased brightening in low light scenes"
+ bug: "312803148"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "multiresolution_imagereader_usage_config"
+ description: "Enable creating MultiResolutionImageReader with usage flag configuration"
+ bug: "301588215"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "use_ro_board_api_level_for_vndk_version"
+ description: "Enable using ro.board.api_level instead of ro.vndk.version to get VNDK version"
+ bug: "312315580"
+}
diff --git a/camera/include/camera/CameraMetadata.h b/camera/include/camera/CameraMetadata.h
index c56ee6d..2903dfb 100644
--- a/camera/include/camera/CameraMetadata.h
+++ b/camera/include/camera/CameraMetadata.h
@@ -245,7 +245,7 @@
/**
* Return the current vendor tag id associated with this metadata.
*/
- metadata_vendor_id_t getVendorId();
+ metadata_vendor_id_t getVendorId() const;
private:
camera_metadata_t *mBuffer;
diff --git a/camera/include/camera/camera2/SessionConfiguration.h b/camera/include/camera/camera2/SessionConfiguration.h
index 120bf9e..22f8083 100644
--- a/camera/include/camera/camera2/SessionConfiguration.h
+++ b/camera/include/camera/camera2/SessionConfiguration.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
#define ANDROID_HARDWARE_CAMERA2_SESSIONCONFIGURATION_H
+#include "OutputConfiguration.h"
+
#include <binder/Parcelable.h>
#include <camera/CameraMetadata.h>
@@ -26,8 +28,6 @@
namespace camera2 {
namespace params {
-class OutputConfiguration;
-
class SessionConfiguration : public android::Parcelable {
public:
diff --git a/camera/ndk/Android.bp b/camera/ndk/Android.bp
index d4dd546..165395a 100644
--- a/camera/ndk/Android.bp
+++ b/camera/ndk/Android.bp
@@ -154,8 +154,8 @@
"libcamera_metadata",
"libmediandk",
"android.frameworks.cameraservice.common-V1-ndk",
- "android.frameworks.cameraservice.device-V1-ndk",
- "android.frameworks.cameraservice.service-V1-ndk",
+ "android.frameworks.cameraservice.device-V2-ndk",
+ "android.frameworks.cameraservice.service-V2-ndk",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
@@ -188,7 +188,6 @@
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
- "android.hidl.token@1.0",
],
cflags: [
"-D__ANDROID_VNDK__",
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 4387cc6..92de1e4 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -213,7 +213,7 @@
EXPORT
camera_status_t ACameraCaptureSession_prepareWindow(
ACameraCaptureSession* session,
- ACameraWindowType *window) {
+ ANativeWindow *window) {
ATRACE_CALL();
if (session == nullptr || window == nullptr) {
ALOGE("%s: Error: session %p / window %p is null", __FUNCTION__, session, window);
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index 8211671..f2ec573 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -124,7 +124,7 @@
EXPORT
camera_status_t ACaptureSessionOutput_create(
- ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
+ ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -137,7 +137,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_create(
- ACameraWindowType* window, /*out*/ACaptureSessionOutput** out) {
+ ANativeWindow* window, /*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || out == nullptr) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -150,7 +150,7 @@
EXPORT
camera_status_t ACaptureSessionPhysicalOutput_create(
- ACameraWindowType* window, const char* physicalId,
+ ANativeWindow* window, const char* physicalId,
/*out*/ACaptureSessionOutput** out) {
ATRACE_CALL();
if (window == nullptr || physicalId == nullptr || out == nullptr) {
@@ -164,7 +164,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *out,
- ACameraWindowType* window) {
+ ANativeWindow* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
@@ -190,7 +190,7 @@
EXPORT
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *out,
- ACameraWindowType* window) {
+ ANativeWindow* window) {
ATRACE_CALL();
if ((window == nullptr) || (out == nullptr)) {
ALOGE("%s: Error: bad argument. window %p, out %p",
diff --git a/camera/ndk/NdkCaptureRequest.cpp b/camera/ndk/NdkCaptureRequest.cpp
index 87de4a9..b851a1d 100644
--- a/camera/ndk/NdkCaptureRequest.cpp
+++ b/camera/ndk/NdkCaptureRequest.cpp
@@ -27,7 +27,7 @@
EXPORT
camera_status_t ACameraOutputTarget_create(
- ACameraWindowType* window, ACameraOutputTarget** out) {
+ ANativeWindow* window, ACameraOutputTarget** out) {
ATRACE_CALL();
if (window == nullptr) {
ALOGE("%s: Error: input window is null", __FUNCTION__);
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index 73439c7..449c0b4 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -146,7 +146,7 @@
return ret;
}
-camera_status_t ACameraCaptureSession::prepare(ACameraWindowType* window) {
+camera_status_t ACameraCaptureSession::prepare(ANativeWindow* window) {
#ifdef __ANDROID_VNDK__
std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
#else
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 88135ba..0d7a2c1 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -23,14 +23,14 @@
#ifdef __ANDROID_VNDK__
#include "ndk_vendor/impl/ACameraDevice.h"
-#include "ndk_vendor/impl/ACameraCaptureSessionVendor.h"
#else
#include "ACameraDevice.h"
+#endif
using namespace android;
struct ACaptureSessionOutput {
- explicit ACaptureSessionOutput(ACameraWindowType* window, bool isShared = false,
+ explicit ACaptureSessionOutput(ANativeWindow* window, bool isShared = false,
const char* physicalCameraId = "") :
mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
@@ -47,28 +47,27 @@
return mWindow > other.mWindow;
}
- inline bool isWindowEqual(ACameraWindowType* window) const {
+ inline bool isWindowEqual(ANativeWindow* window) const {
return mWindow == window;
}
// returns true if the window was successfully added, false otherwise.
- inline bool addSharedWindow(ACameraWindowType* window) {
+ inline bool addSharedWindow(ANativeWindow* window) {
auto ret = mSharedWindows.insert(window);
return ret.second;
}
// returns the number of elements removed.
- inline size_t removeSharedWindow(ACameraWindowType* window) {
+ inline size_t removeSharedWindow(ANativeWindow* window) {
return mSharedWindows.erase(window);
}
- ACameraWindowType* mWindow;
- std::set<ACameraWindowType *> mSharedWindows;
+ ANativeWindow* mWindow;
+ std::set<ANativeWindow*> mSharedWindows;
bool mIsShared;
int mRotation = CAMERA3_STREAM_ROTATION_0;
std::string mPhysicalCameraId;
};
-#endif
struct ACaptureSessionOutputContainer {
std::set<ACaptureSessionOutput> mOutputs;
@@ -147,7 +146,7 @@
mPreparedCb.context = context;
mPreparedCb.onWindowPrepared = cb;
}
- camera_status_t prepare(ACameraWindowType *window);
+ camera_status_t prepare(ANativeWindow *window);
ACameraDevice* getDevice();
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 97d65b0..1fa71f4 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -341,7 +341,7 @@
return ACAMERA_OK;
}
-camera_status_t CameraDevice::prepareLocked(ACameraWindowType *window) {
+camera_status_t CameraDevice::prepareLocked(ANativeWindow *window) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
return ret;
@@ -1097,7 +1097,7 @@
if (onWindowPrepared == nullptr) {
return;
}
- ACameraWindowType* anw;
+ ANativeWindow* anw;
found = msg->findPointer(kAnwKey, (void**) &anw);
if (!found) {
ALOGE("%s: Cannot find ANativeWindow: %d!", __FUNCTION__, __LINE__);
@@ -1823,7 +1823,7 @@
return ret;
}
// We've found the window corresponding to the surface id.
- ACameraWindowType *window = it->second.first;
+ ANativeWindow *window = it->second.first;
sp<AMessage> msg = new AMessage(kWhatPreparedCb, dev->mHandler);
msg->setPointer(kContextKey, session->mPreparedCb.context);
msg->setPointer(kAnwKey, window);
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index 4658d18..2b9f327 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -151,7 +151,7 @@
camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
- camera_status_t prepareLocked(ACameraWindowType *window);
+ camera_status_t prepareLocked(ANativeWindow *window);
camera_status_t allocateCaptureRequest(
const ACaptureRequest* request, sp<CaptureRequest>& outReq);
diff --git a/camera/ndk/impl/ACaptureRequest.h b/camera/ndk/impl/ACaptureRequest.h
index 2ffcafe..118c2a5 100644
--- a/camera/ndk/impl/ACaptureRequest.h
+++ b/camera/ndk/impl/ACaptureRequest.h
@@ -22,11 +22,8 @@
using namespace android;
-#ifdef __ANDROID_VNDK__
-#include "ndk_vendor/impl/ACaptureRequestVendor.h"
-#else
struct ACameraOutputTarget {
- explicit ACameraOutputTarget(ACameraWindowType* window) : mWindow(window) {};
+ explicit ACameraOutputTarget(ANativeWindow* window) : mWindow(window) {};
bool operator == (const ACameraOutputTarget& other) const {
return mWindow == other.mWindow;
@@ -41,9 +38,8 @@
return mWindow > other.mWindow;
}
- ACameraWindowType* mWindow;
+ ANativeWindow* mWindow;
};
-#endif
struct ACameraOutputTargets {
std::set<ACameraOutputTarget> mOutputs;
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 099c5c5..cf6b970 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -124,7 +124,7 @@
*/
typedef void (*ACameraCaptureSession_prepareCallback)(
void *context,
- ACameraWindowType *window,
+ ANativeWindow *window,
ACameraCaptureSession *session);
/// Enum for describing error reason in {@link ACameraCaptureFailure}
@@ -276,7 +276,7 @@
*/
typedef void (*ACameraCaptureSession_captureCallback_bufferLost)(
void* context, ACameraCaptureSession* session,
- ACaptureRequest* request, ACameraWindowType* window, int64_t frameNumber);
+ ACaptureRequest* request, ANativeWindow* window, int64_t frameNumber);
/**
* ACaptureCaptureSession_captureCallbacks structure used in
@@ -1088,7 +1088,7 @@
* and no pre-allocation is done.</p>
*
* @param session the {@link ACameraCaptureSession} that needs to prepare output buffers.
- * @param window the {@link ACameraWindowType} for which the output buffers need to be prepared.
+ * @param window the {@link ANativeWindow} for which the output buffers need to be prepared.
*
* @return <ul><li>
* {@link ACAMERA_OK} if the method succeeds</li>
@@ -1102,7 +1102,7 @@
*/
camera_status_t ACameraCaptureSession_prepareWindow(
ACameraCaptureSession* session,
- ACameraWindowType *window) __INTRODUCED_IN(34);
+ ANativeWindow *window) __INTRODUCED_IN(34);
__END_DECLS
#endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/include/camera/NdkCameraDevice.h b/camera/ndk/include/camera/NdkCameraDevice.h
index de10eb3..fbd0ee1 100644
--- a/camera/ndk/include/camera/NdkCameraDevice.h
+++ b/camera/ndk/include/camera/NdkCameraDevice.h
@@ -364,7 +364,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionOutput_create(
- ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(24);
+ ANativeWindow* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(24);
/**
* Free a ACaptureSessionOutput object.
@@ -705,7 +705,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionSharedOutput_create(
- ACameraWindowType* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(28);
+ ANativeWindow* anw, /*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(28);
/**
* Add a native window to shared ACaptureSessionOutput.
@@ -723,7 +723,7 @@
* ACaptureSessionOutput.</li></ul>
*/
camera_status_t ACaptureSessionSharedOutput_add(ACaptureSessionOutput *output,
- ACameraWindowType *anw) __INTRODUCED_IN(28);
+ ANativeWindow *anw) __INTRODUCED_IN(28);
/**
* Remove a native window from shared ACaptureSessionOutput.
@@ -739,7 +739,7 @@
* ACaptureSessionOutput.</li></ul>
*/
camera_status_t ACaptureSessionSharedOutput_remove(ACaptureSessionOutput *output,
- ACameraWindowType* anw) __INTRODUCED_IN(28);
+ ANativeWindow* anw) __INTRODUCED_IN(28);
/**
* Create a new camera capture session similar to {@link ACameraDevice_createCaptureSession}. This
@@ -797,7 +797,7 @@
* @see ACaptureSessionOutputContainer_add
*/
camera_status_t ACaptureSessionPhysicalOutput_create(
- ACameraWindowType* anw, const char* physicalId,
+ ANativeWindow* anw, const char* physicalId,
/*out*/ACaptureSessionOutput** output) __INTRODUCED_IN(29);
/**
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 3a483cc..2c68cef 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2244,6 +2244,39 @@
*/
ACAMERA_CONTROL_AUTOFRAMING_STATE = // byte (acamera_metadata_enum_android_control_autoframing_state_t)
ACAMERA_CONTROL_START + 54,
+ /**
+ * <p>The operating luminance range of low light boost measured in lux (lx).</p>
+ *
+ * <p>Type: float[2]</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraManager_getCameraCharacteristics</li>
+ * </ul></p>
+ *
+ */
+ ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE = // float[2]
+ ACAMERA_CONTROL_START + 55,
+ /**
+ * <p>Current state of the low light boost AE mode.</p>
+ *
+ * <p>Type: byte (acamera_metadata_enum_android_control_low_light_boost_state_t)</p>
+ *
+ * <p>This tag may appear in:
+ * <ul>
+ * <li>ACameraMetadata from ACameraCaptureSession_captureCallback_result callbacks</li>
+ * </ul></p>
+ *
+ * <p>When low light boost is enabled by setting the AE mode to
+ * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
+ * boost when the light level threshold is exceeded.</p>
+ * <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
+ * indicate when it is not being applied by returning 'INACTIVE'.</p>
+ * <p>This key will be absent from the CaptureResult if AE mode is not set to
+ * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
+ */
+ ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE = // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
+ ACAMERA_CONTROL_START + 56,
ACAMERA_CONTROL_END,
/**
@@ -4625,8 +4658,8 @@
* <p>The guaranteed stream combinations related to stream use case for a camera device with
* <a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE">CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_STREAM_USE_CASE</a>
* capability is documented in the camera device
- * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>. The application is strongly recommended to use one of the guaranteed stream
- * combinations.
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>.
+ * The application is strongly recommended to use one of the guaranteed stream combinations.
* If the application creates a session with a stream combination not in the guaranteed
* list, or with mixed DEFAULT and non-DEFAULT use cases within the same session,
* the camera device may ignore some stream use cases due to hardware constraints
@@ -8214,6 +8247,44 @@
*/
ACAMERA_CONTROL_AE_MODE_ON_EXTERNAL_FLASH = 5,
+ /**
+ * <p>Like 'ON' but applies additional brightness boost in low light scenes.</p>
+ * <p>When the scene lighting conditions are within the range defined by
+ * ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE this mode will apply additional
+ * brightness boost.</p>
+ * <p>This mode will automatically adjust the intensity of low light boost applied
+ * according to the scene lighting conditions. A darker scene will receive more boost
+ * while a brighter scene will receive less boost.</p>
+ * <p>This mode can ignore the set target frame rate to allow more light to be captured
+ * which can result in choppier motion. The frame rate can extend to lower than the
+ * ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES but will not go below 10 FPS. This mode
+ * can also increase the sensor sensitivity gain which can result in increased luma
+ * and chroma noise. The sensor sensitivity gain can extend to higher values beyond
+ * ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE. This mode may also apply additional
+ * processing to recover details in dark and bright areas of the image,and noise
+ * reduction at high sensitivity gain settings to manage the trade-off between light
+ * sensitivity and capture noise.</p>
+ * <p>This mode is restricted to two output surfaces. One output surface type can either
+ * be SurfaceView or TextureView. Another output surface type can either be MediaCodec
+ * or MediaRecorder. This mode cannot be used with a target FPS range higher than 30
+ * FPS.</p>
+ * <p>If the session configuration is not supported, the AE mode reported in the
+ * CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.</p>
+ * <p>The application can observe the CapturerResult field
+ * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
+ * 'INACTIVE'.</p>
+ * <p>The low light boost is 'ACTIVE' once the scene lighting condition is less than the
+ * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
+ * This mode will be 'INACTIVE' once the scene lighting condition is greater than the
+ * upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.</p>
+ *
+ * @see ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
+ * @see ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE
+ * @see ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE
+ * @see ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE
+ */
+ ACAMERA_CONTROL_AE_MODE_ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY = 6,
+
} acamera_metadata_enum_android_control_ae_mode_t;
// ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER
@@ -9215,6 +9286,20 @@
} acamera_metadata_enum_android_control_autoframing_state_t;
+// ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE
+typedef enum acamera_metadata_enum_acamera_control_low_light_boost_state {
+ /**
+ * <p>The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled but not applied.</p>
+ */
+ ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE_INACTIVE = 0,
+
+ /**
+ * <p>The AE mode 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY' is enabled and applied.</p>
+ */
+ ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE_ACTIVE = 1,
+
+} acamera_metadata_enum_android_control_low_light_boost_state_t;
+
// ACAMERA_EDGE_MODE
@@ -10090,8 +10175,8 @@
* </ul>
* <p><a href="https://developer.android.com/reference/android/hardware/camera2/CameraCharacteristics.html#SCALER_AVAILABLE_STREAM_USE_CASES">CameraCharacteristics#SCALER_AVAILABLE_STREAM_USE_CASES</a>
* lists all of the supported stream use cases.</p>
- * <p>Refer to
- * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice.html#stream-use-case-capability-additional-guaranteed-configurations">CameraDevice#stream-use-case-capability-additional-guaranteed-configurations</a>
+ * <p>Refer to the
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#stream-use-case-capability-additional-guaranteed-configurations">guideline</a>
* for the mandatory stream combinations involving stream use cases, which can also be
* queried via <a href="https://developer.android.com/reference/android/hardware/camera2/params/MandatoryStreamCombination.html">MandatoryStreamCombination</a>.</p>
*/
@@ -10952,9 +11037,9 @@
/**
* <p>This camera device does not have enough capabilities to qualify as a <code>FULL</code> device or
* better.</p>
- * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code> tables in the
- * {@link ACameraDevice_createCaptureSession }
- * documentation are guaranteed to be supported.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code> and <code>LIMITED</code>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#limited-level-additional-guaranteed-configurations">tables</a>
+ * in the documentation are guaranteed to be supported.</p>
* <p>All <code>LIMITED</code> devices support the <code>BACKWARDS_COMPATIBLE</code> capability, indicating basic
* support for color image capture. The only exception is that the device may
* alternatively support only the <code>DEPTH_OUTPUT</code> capability, if it can only output depth
@@ -10979,9 +11064,9 @@
/**
* <p>This camera device is capable of supporting advanced imaging applications.</p>
- * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code> tables in the
- * {@link ACameraDevice_createCaptureSession }
- * documentation are guaranteed to be supported.</p>
+ * <p>The stream configurations listed in the <code>FULL</code>, <code>LEGACY</code> and <code>LIMITED</code>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#full-level-additional-guaranteed-configurations">tables</a>
+ * in the documentation are guaranteed to be supported.</p>
* <p>A <code>FULL</code> device will support below capabilities:</p>
* <ul>
* <li><code>BURST_CAPTURE</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
@@ -11008,9 +11093,9 @@
/**
* <p>This camera device is running in backward compatibility mode.</p>
- * <p>Only the stream configurations listed in the <code>LEGACY</code> table in the
- * {@link ACameraDevice_createCaptureSession }
- * documentation are supported.</p>
+ * <p>Only the stream configurations listed in the <code>LEGACY</code>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#legacy-level-guaranteed-configurations">table</a>
+ * in the documentation are supported.</p>
* <p>A <code>LEGACY</code> device does not support per-frame control, manual sensor control, manual
* post-processing, arbitrary cropping regions, and has relaxed performance constraints.
* No additional capabilities beyond <code>BACKWARD_COMPATIBLE</code> will ever be listed by a
@@ -11032,9 +11117,9 @@
* <p>This camera device is capable of YUV reprocessing and RAW data capture, in addition to
* FULL-level capabilities.</p>
* <p>The stream configurations listed in the <code>LEVEL_3</code>, <code>RAW</code>, <code>FULL</code>, <code>LEGACY</code> and
- * <code>LIMITED</code> tables in the
- * {@link ACameraDevice_createCaptureSession }
- * documentation are guaranteed to be supported.</p>
+ * <code>LIMITED</code>
+ * <a href="https://developer.android.com/reference/android/hardware/camera2/CameraDevice#level-3-additional-guaranteed-configurations">tables</a>
+ * in the documentation are guaranteed to be supported.</p>
* <p>The following additional capabilities are guaranteed to be supported:</p>
* <ul>
* <li><code>YUV_REPROCESSING</code> capability (ACAMERA_REQUEST_AVAILABLE_CAPABILITIES contains
diff --git a/camera/ndk/include/camera/NdkCameraWindowType.h b/camera/ndk/include/camera/NdkCameraWindowType.h
index 0838fba..2217528 100644
--- a/camera/ndk/include/camera/NdkCameraWindowType.h
+++ b/camera/ndk/include/camera/NdkCameraWindowType.h
@@ -41,14 +41,11 @@
* camera2 NDK. This enables us to share the api definition headers and avoid
* code duplication (since the VNDK variant doesn't use ANativeWindow unlike the
* NDK variant).
+ * @deprecated No longer needed. Both NDK and VNDK use ANativeWindow now.
+ * Use ANativeWindow directly.
*/
-#ifdef __ANDROID_VNDK__
-#include <cutils/native_handle.h>
-typedef const native_handle_t ACameraWindowType;
-#else
#include <android/native_window.h>
typedef ANativeWindow ACameraWindowType;
-#endif
/** @} */
diff --git a/camera/ndk/include/camera/NdkCaptureRequest.h b/camera/ndk/include/camera/NdkCaptureRequest.h
index dc18544..5ccb510 100644
--- a/camera/ndk/include/camera/NdkCaptureRequest.h
+++ b/camera/ndk/include/camera/NdkCaptureRequest.h
@@ -99,7 +99,7 @@
*
* @see ACaptureRequest_addTarget
*/
-camera_status_t ACameraOutputTarget_create(ACameraWindowType* window,
+camera_status_t ACameraOutputTarget_create(ANativeWindow* window,
ACameraOutputTarget** output) __INTRODUCED_IN(24);
/**
diff --git a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h b/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
deleted file mode 100644
index 45098c3..0000000
--- a/camera/ndk/ndk_vendor/impl/ACameraCaptureSessionVendor.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2018 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 "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 = "") :
- mWindow(window), mIsShared(isShared), mPhysicalCameraId(physicalCameraId) {};
-
- bool operator == (const ACaptureSessionOutput& other) const {
- return (mWindow == other.mWindow);
- }
-
- bool operator != (const ACaptureSessionOutput& other) const {
- return mWindow != other.mWindow;
- }
-
- bool operator < (const ACaptureSessionOutput& other) const {
- return mWindow < other.mWindow;
- }
-
- bool operator > (const ACaptureSessionOutput& other) const {
- return mWindow > other.mWindow;
- }
-
- 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 87102e4..3325da6 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -26,7 +26,7 @@
#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 <android/native_window_aidl.h>
#include <inttypes.h>
#include <map>
#include <utility>
@@ -59,6 +59,7 @@
using AidlCameraMetadata = ::aidl::android::frameworks::cameraservice::device::CameraMetadata;
using ::aidl::android::frameworks::cameraservice::device::OutputConfiguration;
using ::aidl::android::frameworks::cameraservice::device::SessionConfiguration;
+using ::aidl::android::view::Surface;
using ::ndk::ScopedAStatus;
// Static member definitions
@@ -231,8 +232,9 @@
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));
+ auto& surfaces = outputStream.surfaces;
+ surfaces.reserve(output.mSharedWindows.size() + 1);
+ surfaces.emplace_back(output.mWindow);
outputStream.physicalCameraId = output.mPhysicalCameraId;
index++;
}
@@ -298,12 +300,12 @@
OutputConfiguration outConfig;
outConfig.rotation = utils::convertToAidl(output->mRotation);
- outConfig.windowHandles.resize(output->mSharedWindows.size() + 1);
- outConfig.windowHandles[0] = std::move(dupToAidl(output->mWindow));
+ auto& surfaces = outConfig.surfaces;
+ surfaces.reserve(output->mSharedWindows.size() + 1);
+ surfaces.emplace_back(output->mWindow);
outConfig.physicalCameraId = output->mPhysicalCameraId;
- int i = 1;
for (auto& anw : output->mSharedWindows) {
- outConfig.windowHandles[i++] = std::move(dupToAidl(anw));
+ surfaces.emplace_back(anw);
}
auto remoteRet = mRemote->updateOutputConfiguration(streamId,
@@ -340,7 +342,7 @@
return ACAMERA_OK;
}
-camera_status_t CameraDevice::prepareLocked(ACameraWindowType *window) {
+camera_status_t CameraDevice::prepareLocked(ANativeWindow *window) {
camera_status_t ret = checkCameraClosedOrErrorLocked();
if (ret != ACAMERA_OK) {
return ret;
@@ -387,18 +389,19 @@
std::vector<int32_t> requestSurfaceIdxList;
for (auto& outputTarget : request->targets->mOutputs) {
- native_handle_ptr_wrapper anw = outputTarget.mWindow;
+ ANativeWindow *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 OutputConfiguration& outConfig = kvPair.second.second;
- const auto& windowHandles = outConfig.windowHandles;
- for (int surfaceId = 0; surfaceId < (int) windowHandles.size(); surfaceId++) {
+ const auto& surfaces = outConfig.surfaces;
+ for (int surfaceId = 0; surfaceId < (int) surfaces.size(); surfaceId++) {
// If two window handles point to the same native window,
// they have the same surfaces.
- if (utils::isWindowNativeHandleEqual(anw, windowHandles[surfaceId])) {
+ auto& surface = surfaces[surfaceId];
+ if (anw == surface.get()) {
found = true;
requestStreamIdxList.push_back(streamId);
requestSurfaceIdxList.push_back(surfaceId);
@@ -410,7 +413,7 @@
}
}
if (!found) {
- ALOGE("Unconfigured output target %p in capture request!", anw.mWindow);
+ ALOGE("Unconfigured output target %p in capture request!", anw);
return ACAMERA_ERROR_INVALID_PARAMETER;
}
}
@@ -470,7 +473,7 @@
}
pRequest->targets = new ACameraOutputTargets();
for (size_t i = 0; i < req->mSurfaceList.size(); i++) {
- native_handle_ptr_wrapper anw = req->mSurfaceList[i];
+ ANativeWindow *anw = req->mSurfaceList[i];
ACameraOutputTarget outputTarget(anw);
pRequest->targets->mOutputs.insert(std::move(outputTarget));
}
@@ -637,20 +640,21 @@
return ret;
}
- std::map<native_handle_ptr_wrapper, OutputConfiguration> handleToConfig;
+ std::map<ANativeWindow *, OutputConfiguration> windowToConfig;
for (const auto& outConfig : outputs->mOutputs) {
- native_handle_ptr_wrapper anw = outConfig.mWindow;
+ ANativeWindow *anw = outConfig.mWindow;
OutputConfiguration outConfigInsert;
outConfigInsert.rotation = utils::convertToAidl(outConfig.mRotation);
outConfigInsert.windowGroupId = -1;
- outConfigInsert.windowHandles.resize(outConfig.mSharedWindows.size() + 1);
- outConfigInsert.windowHandles[0] = std::move(dupToAidl(anw));
+ auto& surfaces = outConfigInsert.surfaces;
+ surfaces.reserve(outConfig.mSharedWindows.size() + 1);
+ surfaces.emplace_back(anw);
outConfigInsert.physicalCameraId = outConfig.mPhysicalCameraId;
- handleToConfig.insert({anw, std::move(outConfigInsert)});
+ windowToConfig.insert({anw, std::move(outConfigInsert)});
}
- std::set<native_handle_ptr_wrapper> addSet;
- for (auto& kvPair : handleToConfig) {
+ std::set<ANativeWindow *> addSet;
+ for (auto& kvPair : windowToConfig) {
addSet.insert(kvPair.first);
}
@@ -663,8 +667,8 @@
auto& anw = outputPair.first;
auto& configuredOutput = outputPair.second;
- auto itr = handleToConfig.find(anw);
- if (itr != handleToConfig.end() && (itr->second) == configuredOutput) {
+ auto itr = windowToConfig.find(anw);
+ if (itr != windowToConfig.end() && (itr->second) == configuredOutput) {
deleteList.push_back(streamId);
} else {
addSet.erase(anw);
@@ -714,13 +718,13 @@
// add new streams
for (const auto &anw : addSet) {
int32_t streamId;
- auto itr = handleToConfig.find(anw);
+ auto itr = windowToConfig.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);
+ windowToConfig.erase(itr);
}
AidlCameraMetadata aidlParams;
@@ -867,9 +871,9 @@
// Get the surfaces corresponding to the error stream id, go through
// them and try to match the surfaces in the corresponding
// CaptureRequest.
- const auto& errorWindowHandles =
- outputPairIt->second.second.windowHandles;
- for (const auto& errorWindowHandle : errorWindowHandles) {
+ const auto& errorSurfaces =
+ outputPairIt->second.second.surfaces;
+ for (const auto& errorSurface : errorSurfaces) {
for (const auto &requestStreamAndWindowId :
request->mCaptureRequest.streamAndWindowIds) {
// Go through the surfaces in the capture request and see which
@@ -884,12 +888,11 @@
return;
}
- const auto &requestWindowHandles =
- requestSurfacePairIt->second.second.windowHandles;
+ const auto &requestSurfaces = requestSurfacePairIt->second.second.surfaces;
+ auto& requestSurface = requestSurfaces[requestWindowId];
- if (requestWindowHandles[requestWindowId] == errorWindowHandle) {
- const native_handle_t* anw = makeFromAidl(
- requestWindowHandles[requestWindowId]);
+ if (requestSurface == errorSurface) {
+ const ANativeWindow *anw = requestSurface.get();
ALOGV("Camera %s Lost output buffer for ANW %p frame %" PRId64,
getId(), anw, frameNumber);
@@ -1085,7 +1088,7 @@
if (onWindowPrepared == nullptr) {
return;
}
- native_handle_t* anw;
+ ANativeWindow* anw;
found = msg->findPointer(kAnwKey, (void**) &anw);
if (!found) {
ALOGE("%s: Cannot find ANativeWindow: %d!", __FUNCTION__, __LINE__);
@@ -1342,10 +1345,10 @@
return;
}
- native_handle_t* anw;
+ ANativeWindow* anw;
found = msg->findPointer(kAnwKey, (void**) &anw);
if (!found) {
- ALOGE("%s: Cannot find native_handle_t!", __FUNCTION__);
+ ALOGE("%s: Cannot find ANativeWindow!", __FUNCTION__);
return;
}
@@ -1359,7 +1362,6 @@
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;
}
}
@@ -1842,7 +1844,7 @@
return ScopedAStatus::ok();
}
// We've found the window corresponding to the surface id.
- const native_handle_t *anw = it->second.first.mWindow;
+ const ANativeWindow *anw = it->second.first;
sp<AMessage> msg = new AMessage(kWhatPreparedCb, dev->mHandler);
msg->setPointer(kContextKey, session->mPreparedCb.context);
msg->setPointer(kAnwKey, (void *)anw);
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 6e0c772..b771d47 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -66,7 +66,6 @@
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 ResultMetadataQueue = AidlMessageQueue<int8_t, SynchronizedReadWrite>;
@@ -197,7 +196,7 @@
camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
- camera_status_t prepareLocked(ACameraWindowType *window);
+ camera_status_t prepareLocked(ANativeWindow *window);
// Since this writes to ICameraDeviceUser's fmq, clients must take care that:
// a) This function is called serially.
@@ -236,7 +235,7 @@
// stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
// camera service)
- std::map<int, std::pair<native_handle_ptr_wrapper, OutputConfiguration>> mConfiguredOutputs;
+ std::map<int, std::pair<ANativeWindow *, OutputConfiguration>> mConfiguredOutputs;
// TODO: maybe a bool will suffice for synchronous implementation?
std::atomic_bool mClosing;
diff --git a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h b/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
deleted file mode 100644
index fcb7e34..0000000
--- a/camera/ndk/ndk_vendor/impl/ACaptureRequestVendor.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 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 "utils.h"
-
-using ::android::acam::utils::native_handle_ptr_wrapper;
-struct ACameraOutputTarget {
- explicit ACameraOutputTarget(const native_handle_t* window) : mWindow(window) {};
-
- bool operator == (const ACameraOutputTarget& other) const {
- return mWindow == other.mWindow;
- }
- bool operator != (const ACameraOutputTarget& other) const {
- return mWindow != other.mWindow;
- }
- bool operator < (const ACameraOutputTarget& other) const {
- return mWindow < other.mWindow;
- }
- bool operator > (const ACameraOutputTarget& other) const {
- return mWindow > other.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 73a527b..3971c73 100644
--- a/camera/ndk/ndk_vendor/impl/utils.cpp
+++ b/camera/ndk/ndk_vendor/impl/utils.cpp
@@ -18,7 +18,6 @@
#include "utils.h"
-#include <aidlcommonsupport/NativeHandle.h>
#include <utils/Log.h>
namespace android {
@@ -138,51 +137,6 @@
return ret;
}
-bool isWindowNativeHandleEqual(const native_handle_t *nh1, const native_handle_t *nh2) {
- if (nh1->numFds !=0 || nh2->numFds !=0) {
- ALOGE("Invalid window native handles being compared");
- return false;
- }
- if (nh1->version != nh2->version || nh1->numFds != nh2->numFds ||
- nh1->numInts != nh2->numInts) {
- return false;
- }
- for (int i = 0; i < nh1->numInts; i++) {
- if(nh1->data[i] != nh2->data[i]) {
- return false;
- }
- }
- 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;
- }
- if (nh1->numInts != nh2->numInts) {
- return nh1->numInts < nh2->numInts;
- }
-
- for (int i = 0; i < nh1->numInts; i++) {
- if (nh1->data[i] != nh2->data[i]) {
- return nh1->data[i] < nh2->data[i];
- }
- }
- return false;
-}
-
-bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2) {
- return !isWindowNativeHandleLessThan(nh1, nh2) && !isWindowNativeHandleEqual(nh1, nh2);
-}
-
} // 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 7ad74ad..d0dd2fc 100644
--- a/camera/ndk/ndk_vendor/impl/utils.h
+++ b/camera/ndk/ndk_vendor/impl/utils.h
@@ -38,53 +38,14 @@
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
-bool isWindowNativeHandleGreaterThan(const native_handle_t *nh1, const native_handle_t *nh2);
-
-// Utility class so the native_handle_t can be compared with its contents instead
-// of just raw pointer comparisons.
-struct native_handle_ptr_wrapper {
- const native_handle_t *mWindow = nullptr;
-
- native_handle_ptr_wrapper(const native_handle_t *nh) : mWindow(nh) { }
-
- native_handle_ptr_wrapper() = default;
-
- operator const native_handle_t *() const { return mWindow; }
-
- bool operator ==(const native_handle_ptr_wrapper other) const {
- return isWindowNativeHandleEqual(mWindow, other.mWindow);
- }
-
- bool operator != (const native_handle_ptr_wrapper& other) const {
- return !isWindowNativeHandleEqual(mWindow, other.mWindow);
- }
-
- bool operator < (const native_handle_ptr_wrapper& other) const {
- return isWindowNativeHandleLessThan(mWindow, other.mWindow);
- }
-
- bool operator > (const native_handle_ptr_wrapper& other) const {
- return !isWindowNativeHandleGreaterThan(mWindow, other.mWindow);
- }
-
-};
-
// Utility class so that CaptureRequest can be stored by sp<>
struct CaptureRequest: public RefBase {
AidlCaptureRequest mCaptureRequest;
- std::vector<native_handle_ptr_wrapper> mSurfaceList;
+ std::vector<ANativeWindow *> 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;
diff --git a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
index 74c6cad..0259359 100644
--- a/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
+++ b/camera/ndk/ndk_vendor/tests/AImageReaderVendorTest.cpp
@@ -31,8 +31,6 @@
#include <stdio.h>
#include <android/log.h>
-#include <android/hidl/manager/1.2/IServiceManager.h>
-#include <android/hidl/token/1.0/ITokenManager.h>
#include <camera/NdkCameraError.h>
#include <camera/NdkCameraManager.h>
#include <camera/NdkCameraDevice.h>
@@ -40,7 +38,6 @@
#include <hidl/ServiceManagement.h>
#include <media/NdkImage.h>
#include <media/NdkImageReader.h>
-#include <cutils/native_handle.h>
#include <VendorTagDescriptor.h>
namespace {
@@ -53,9 +50,7 @@
static constexpr int kTestImageFormat = AIMAGE_FORMAT_YUV_420_888;
using android::hardware::camera::common::V1_0::helper::VendorTagDescriptorCache;
-using android::hidl::manager::V1_0::IServiceManager;
-using android::hidl::token::V1_0::ITokenManager;
-using ConfiguredWindows = std::set<const native_handle_t *>;
+using ConfiguredWindows = std::set<ANativeWindow*>;
class CameraHelper {
public:
@@ -65,11 +60,11 @@
struct PhysicalImgReaderInfo {
const char* physicalCameraId;
- const native_handle_t* anw;
+ ANativeWindow* anw;
};
// Retaining the error code in case the caller needs to analyze it.
- std::variant<int, ConfiguredWindows> initCamera(const native_handle_t* imgReaderAnw,
+ std::variant<int, ConfiguredWindows> initCamera(ANativeWindow* imgReaderAnw,
const std::vector<PhysicalImgReaderInfo>& physicalImgReaders,
bool usePhysicalSettings, bool prepareWindows = false) {
ConfiguredWindows configuredWindows;
@@ -109,7 +104,7 @@
}
configuredWindows.insert(mImgReaderAnw);
std::vector<const char*> idPointerList;
- std::set<const native_handle_t*> physicalStreamMap;
+ std::set<ANativeWindow*> physicalStreamMap;
for (auto& physicalStream : physicalImgReaders) {
ACaptureSessionOutput* sessionOutput = nullptr;
ret = ACaptureSessionPhysicalOutput_create(physicalStream.anw,
@@ -301,7 +296,7 @@
private:
- static void onPreparedCb(void* obj, ACameraWindowType *anw, ACameraCaptureSession *session) {
+ static void onPreparedCb(void* obj, ANativeWindow *anw, ACameraCaptureSession *session) {
CameraHelper* thiz = reinterpret_cast<CameraHelper*>(obj);
thiz->handlePrepared(anw, session);
}
@@ -317,7 +312,7 @@
return ret;
}
- void handlePrepared(ACameraWindowType *anw, ACameraCaptureSession *session) {
+ void handlePrepared(ANativeWindow *anw, ACameraCaptureSession *session) {
// Reduce the pending prepared count of anw by 1. If count is 0, remove the key.
std::lock_guard<std::mutex> lock(mMutex);
if (session != mSession) {
@@ -334,7 +329,7 @@
mPendingPreparedCbs.erase(anw);
}
}
- void incPendingPrepared(ACameraWindowType *anw) {
+ void incPendingPrepared(ANativeWindow *anw) {
std::lock_guard<std::mutex> lock(mMutex);
if ((mPendingPreparedCbs.find(anw) == mPendingPreparedCbs.end())) {
mPendingPreparedCbs[anw] = 1;
@@ -344,13 +339,13 @@
}
// ANW -> pending prepared callbacks
- std::unordered_map<ACameraWindowType *, int> mPendingPreparedCbs;
+ std::unordered_map<ANativeWindow*, int> mPendingPreparedCbs;
ACameraDevice_StateCallbacks mDeviceCb{this, nullptr, nullptr};
ACameraCaptureSession_stateCallbacks mSessionCb{ this, nullptr, nullptr, nullptr};
ACameraCaptureSession_prepareCallback mPreparedCb = &onPreparedCb;
- const native_handle_t* mImgReaderAnw = nullptr; // not owned by us.
+ ANativeWindow* mImgReaderAnw = nullptr; // not owned by us.
// Camera device
ACameraDevice* mDevice = nullptr;
@@ -484,7 +479,7 @@
~ImageReaderTestCase() {
if (mImgReaderAnw) {
AImageReader_delete(mImgReader);
- // No need to call native_handle_t_release on imageReaderAnw
+ // No need to call AImageReader_release(mImgReaderAnw).
}
}
@@ -514,17 +509,18 @@
return ret;
}
- ret = AImageReader_getWindowNativeHandle(mImgReader, &mImgReaderAnw);
+
+ ret = AImageReader_getWindow(mImgReader, &mImgReaderAnw);
if (ret != AMEDIA_OK || mImgReaderAnw == nullptr) {
- ALOGE("Failed to get native_handle_t from AImageReader, ret=%d, mImgReaderAnw=%p.", ret,
- mImgReaderAnw);
+ ALOGE("Failed to get ANativeWindow* from AImageReader, ret=%d, mImgReader=%p.", ret,
+ mImgReader);
return -1;
}
return 0;
}
- const native_handle_t* getNativeWindow() { return mImgReaderAnw; }
+ ANativeWindow* getNativeWindow() { return mImgReaderAnw; }
int getAcquiredImageCount() {
std::lock_guard<std::mutex> lock(mMutex);
@@ -657,7 +653,7 @@
int mAcquiredImageCount{0};
AImageReader* mImgReader = nullptr;
- native_handle_t* mImgReaderAnw = nullptr;
+ ANativeWindow* mImgReaderAnw = nullptr;
AImageReader_ImageListener mReaderAvailableCb{this, onImageAvailable};
AImageReader_BufferRemovedListener mReaderDetachedCb{this, onBufferRemoved};
@@ -985,20 +981,12 @@
-TEST_F(AImageReaderVendorTest, CreateWindowNativeHandle) {
- auto transport = android::hardware::defaultServiceManager()->getTransport(ITokenManager::descriptor, "default");
- if (transport.isOk() && transport == IServiceManager::Transport::EMPTY) {
- GTEST_SKIP() << "This device no longer supports AImageReader_getWindowNativeHandle";
- }
+TEST_F(AImageReaderVendorTest, CreateANativeWindow) {
testBasicTakePictures(/*prepareSurfaces*/ false);
testBasicTakePictures(/*prepareSurfaces*/ true);
}
TEST_F(AImageReaderVendorTest, LogicalCameraPhysicalStream) {
- auto transport = android::hardware::defaultServiceManager()->getTransport(ITokenManager::descriptor, "default");
- if (transport.isOk() && transport == IServiceManager::Transport::EMPTY) {
- GTEST_SKIP() << "This device no longer supports AImageReader_getWindowNativeHandle";
- }
for (auto & v2 : {true, false}) {
testLogicalCameraPhysicalStream(false/*usePhysicalSettings*/, v2);
testLogicalCameraPhysicalStream(true/*usePhysicalSettings*/, v2);
diff --git a/camera/tests/Android.bp b/camera/tests/Android.bp
new file mode 100644
index 0000000..65b8b41
--- /dev/null
+++ b/camera/tests/Android.bp
@@ -0,0 +1,52 @@
+// Copyright 2013 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "frameworks_av_camera_license",
+ ],
+}
+
+cc_test {
+ name: "camera_client_test",
+ srcs: [
+ "VendorTagDescriptorTests.cpp",
+ "CameraBinderTests.cpp",
+ "CameraZSLTests.cpp",
+ "CameraCharacteristicsPermission.cpp",
+ ],
+ shared_libs: [
+ "liblog",
+ "libutils",
+ "libcutils",
+ "libcamera_metadata",
+ "libcamera_client",
+ "libgui",
+ "libsync",
+ "libui",
+ "libdl",
+ "libbinder",
+ ],
+ include_dirs: [
+ "system/media/private/camera/include",
+ "system/media/camera/tests",
+ "frameworks/av/services/camera/libcameraservice",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ ],
+}
diff --git a/camera/tests/Android.mk b/camera/tests/Android.mk
deleted file mode 100644
index 7f8078e..0000000
--- a/camera/tests/Android.mk
+++ /dev/null
@@ -1,50 +0,0 @@
-# Copyright 2013 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.
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-LOCAL_SRC_FILES:= \
- VendorTagDescriptorTests.cpp \
- CameraBinderTests.cpp \
- CameraZSLTests.cpp \
- CameraCharacteristicsPermission.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- liblog \
- libutils \
- libcutils \
- libcamera_metadata \
- libcamera_client \
- libgui \
- libsync \
- libui \
- libdl \
- libbinder
-
-LOCAL_C_INCLUDES += \
- system/media/private/camera/include \
- system/media/camera/tests \
- frameworks/av/services/camera/libcameraservice \
-
-LOCAL_CFLAGS += -Wall -Wextra -Werror
-
-LOCAL_MODULE:= camera_client_test
-LOCAL_LICENSE_KINDS:= SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS:= notice
-LOCAL_NOTICE_FILE:= $(LOCAL_PATH)/../NOTICE
-LOCAL_MODULE_TAGS := tests
-
-include $(BUILD_NATIVE_TEST)
diff --git a/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
index 07efc20..8371905 100644
--- a/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_Parameters_fuzzer.cpp
@@ -16,14 +16,19 @@
#include <CameraParameters.h>
#include <CameraParameters2.h>
+#include <camera/StringUtils.h>
#include <fcntl.h>
#include <fuzzer/FuzzedDataProvider.h>
#include <utils/String16.h>
#include <camera/StringUtils.h>
+#include <functional>
+
using namespace std;
using namespace android;
+constexpr int8_t kMaxBytes = 20;
+
string kValidFormats[] = {
CameraParameters::PIXEL_FORMAT_YUV422SP, CameraParameters::PIXEL_FORMAT_YUV420SP,
CameraParameters::PIXEL_FORMAT_YUV422I, CameraParameters::PIXEL_FORMAT_YUV420P,
@@ -34,26 +39,22 @@
class CameraParametersFuzzer {
public:
void process(const uint8_t* data, size_t size);
- ~CameraParametersFuzzer() {
- delete mCameraParameters;
- delete mCameraParameters2;
- }
private:
void invokeCameraParameters();
template <class type>
- void initCameraParameters(type** obj);
+ void initCameraParameters(unique_ptr<type>& obj);
template <class type>
- void cameraParametersCommon(type* obj);
- CameraParameters* mCameraParameters = nullptr;
- CameraParameters2* mCameraParameters2 = nullptr;
+ void callCameraParametersAPIs(unique_ptr<type>& obj);
+ unique_ptr<CameraParameters> mCameraParameters;
+ unique_ptr<CameraParameters2> mCameraParameters2;
FuzzedDataProvider* mFDP = nullptr;
};
template <class type>
-void CameraParametersFuzzer::initCameraParameters(type** obj) {
+void CameraParametersFuzzer::initCameraParameters(unique_ptr<type>& obj) {
if (mFDP->ConsumeBool()) {
- *obj = new type();
+ obj = make_unique<type>();
} else {
string params;
if (mFDP->ConsumeBool()) {
@@ -61,94 +62,176 @@
int32_t height = mFDP->ConsumeIntegral<int32_t>();
int32_t minFps = mFDP->ConsumeIntegral<int32_t>();
int32_t maxFps = mFDP->ConsumeIntegral<int32_t>();
- params = CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
+ params = mFDP->ConsumeBool() ? mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()
+ : CameraParameters::KEY_SUPPORTED_VIDEO_SIZES;
params += '=' + to_string(width) + 'x' + to_string(height) + ';';
if (mFDP->ConsumeBool()) {
- params += CameraParameters::KEY_PREVIEW_FPS_RANGE;
+ params += mFDP->ConsumeBool() ? mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()
+ : CameraParameters::KEY_PREVIEW_FPS_RANGE;
params += '=' + to_string(minFps) + ',' + to_string(maxFps) + ';';
}
if (mFDP->ConsumeBool()) {
- params += CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
+ params += mFDP->ConsumeBool() ? mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()
+ : CameraParameters::KEY_SUPPORTED_PICTURE_SIZES;
params += '=' + to_string(width) + 'x' + to_string(height) + ';';
}
if (mFDP->ConsumeBool()) {
- params += CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS;
- params += '=' + mFDP->PickValueInArray(kValidFormats) + ';';
+ params += mFDP->ConsumeBool() ? mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()
+ : CameraParameters::KEY_SUPPORTED_PREVIEW_FORMATS;
+ params += '=' +
+ (mFDP->ConsumeBool() ? mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()
+ : mFDP->PickValueInArray(kValidFormats)) + ';';
}
} else {
- params = mFDP->ConsumeRandomLengthString();
+ params = mFDP->ConsumeRandomLengthString(kMaxBytes);
}
- *obj = new type(toString8(params));
+ obj = make_unique<type>(toString8(params));
}
}
template <class type>
-void CameraParametersFuzzer::cameraParametersCommon(type* obj) {
- Vector<Size> supportedPreviewSizes;
- obj->getSupportedPreviewSizes(supportedPreviewSizes);
- int32_t previewWidth = mFDP->ConsumeIntegral<int32_t>();
- int32_t previewHeight = mFDP->ConsumeIntegral<int32_t>();
- obj->setPreviewSize(previewWidth, previewHeight);
- obj->getPreviewSize(&previewWidth, &previewHeight);
-
+void CameraParametersFuzzer::callCameraParametersAPIs(unique_ptr<type>& obj) {
Vector<Size> supportedVideoSizes;
- obj->getSupportedVideoSizes(supportedVideoSizes);
- if (supportedVideoSizes.size() != 0) {
- int32_t videoWidth, videoHeight, preferredVideoWidth, preferredVideoHeight;
- if (mFDP->ConsumeBool()) {
- int32_t idx = mFDP->ConsumeIntegralInRange<int32_t>(0, supportedVideoSizes.size() - 1);
- obj->setVideoSize(supportedVideoSizes[idx].width, supportedVideoSizes[idx].height);
- } else {
- videoWidth = mFDP->ConsumeIntegral<int32_t>();
- videoHeight = mFDP->ConsumeIntegral<int32_t>();
- obj->setVideoSize(videoWidth, videoHeight);
- }
- obj->getVideoSize(&videoWidth, &videoHeight);
- obj->getPreferredPreviewSizeForVideo(&preferredVideoWidth, &preferredVideoHeight);
- }
-
- int32_t fps = mFDP->ConsumeIntegral<int32_t>();
- obj->setPreviewFrameRate(fps);
- obj->getPreviewFrameRate();
- string previewFormat = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
- : mFDP->ConsumeRandomLengthString();
- obj->setPreviewFormat(previewFormat.c_str());
-
- int32_t pictureWidth = mFDP->ConsumeIntegral<int32_t>();
- int32_t pictureHeight = mFDP->ConsumeIntegral<int32_t>();
- Vector<Size> supportedPictureSizes;
- obj->setPictureSize(pictureWidth, pictureHeight);
- obj->getPictureSize(&pictureWidth, &pictureHeight);
- obj->getSupportedPictureSizes(supportedPictureSizes);
- string pictureFormat = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
- : mFDP->ConsumeRandomLengthString();
- obj->setPictureFormat(pictureFormat.c_str());
- obj->getPictureFormat();
-
- if (mFDP->ConsumeBool()) {
- obj->dump();
- } else {
- int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
- Vector<String16> args = {};
- obj->dump(fd, args);
- close(fd);
+ while (mFDP->remaining_bytes()) {
+ auto callCameraUtilsAPIs = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ Vector<Size> supportedPreviewSizes;
+ obj->getSupportedPreviewSizes(supportedPreviewSizes);
+ },
+ [&]() {
+ int32_t previewWidth = mFDP->ConsumeIntegral<int32_t>();
+ int32_t previewHeight = mFDP->ConsumeIntegral<int32_t>();
+ obj->setPreviewSize(previewWidth, previewHeight);
+ },
+ [&]() {
+ int32_t previewWidth, previewHeight;
+ obj->getPreviewSize(&previewWidth, &previewHeight);
+ },
+ [&]() { obj->getSupportedVideoSizes(supportedVideoSizes); },
+ [&]() {
+ int32_t videoWidth, videoHeight;
+ if (supportedVideoSizes.size()) {
+ int32_t idx = mFDP->ConsumeIntegralInRange<int32_t>(
+ 0, supportedVideoSizes.size() - 1);
+ videoWidth = mFDP->ConsumeBool() ? supportedVideoSizes[idx].width
+ : mFDP->ConsumeIntegral<int32_t>();
+ videoHeight = mFDP->ConsumeBool() ? supportedVideoSizes[idx].height
+ : mFDP->ConsumeIntegral<int32_t>();
+ obj->setVideoSize(videoWidth, videoHeight);
+ }
+ },
+ [&]() {
+ int32_t videoWidth, videoHeight;
+ obj->getVideoSize(&videoWidth, &videoHeight);
+ },
+ [&]() {
+ int32_t preferredVideoWidth, preferredVideoHeight;
+ obj->getPreferredPreviewSizeForVideo(&preferredVideoWidth,
+ &preferredVideoHeight);
+ },
+ [&]() {
+ int32_t fps = mFDP->ConsumeIntegral<int32_t>();
+ obj->setPreviewFrameRate(fps);
+ },
+ [&]() { obj->getPreviewFrameRate(); },
+ [&]() {
+ string previewFormat = mFDP->ConsumeBool()
+ ? mFDP->PickValueInArray(kValidFormats)
+ : mFDP->ConsumeRandomLengthString(kMaxBytes);
+ obj->setPreviewFormat(previewFormat.c_str());
+ },
+ [&]() {
+ int32_t pictureWidth = mFDP->ConsumeIntegral<int32_t>();
+ int32_t pictureHeight = mFDP->ConsumeIntegral<int32_t>();
+ obj->setPictureSize(pictureWidth, pictureHeight);
+ },
+ [&]() {
+ int32_t pictureWidth, pictureHeight;
+ obj->getPictureSize(&pictureWidth, &pictureHeight);
+ },
+ [&]() {
+ Vector<Size> supportedPictureSizes;
+ obj->getSupportedPictureSizes(supportedPictureSizes);
+ },
+ [&]() {
+ string pictureFormat = mFDP->ConsumeBool()
+ ? mFDP->PickValueInArray(kValidFormats)
+ : mFDP->ConsumeRandomLengthString(kMaxBytes);
+ obj->setPictureFormat(pictureFormat.c_str());
+ },
+ [&]() { obj->getPictureFormat(); },
+ [&]() {
+ if (mFDP->ConsumeBool()) {
+ obj->dump();
+ } else {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ Vector<String16> args = {};
+ obj->dump(fd, args);
+ close(fd);
+ }
+ },
+ [&]() { obj->flatten(); },
+ [&]() {
+ string key = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ float value = mFDP->ConsumeFloatingPoint<float>();
+ obj->setFloat(key.c_str(), value);
+ },
+ [&]() {
+ string key = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ obj->getFloat(key.c_str());
+ },
+ [&]() { obj->getPreviewFormat(); },
+ [&]() {
+ string key = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ obj->remove(key.c_str());
+ },
+ [&]() {
+ if (std::is_same_v<type, CameraParameters>) {
+ string format = mFDP->ConsumeBool()
+ ? mFDP->ConsumeRandomLengthString(kMaxBytes)
+ : mFDP->PickValueInArray(kValidFormats);
+ mCameraParameters->previewFormatToEnum(format.c_str());
+ }
+ },
+ [&]() {
+ if (std::is_same_v<type, CameraParameters>) {
+ mCameraParameters->isEmpty();
+ }
+ },
+ [&]() {
+ if (std::is_same_v<type, CameraParameters>) {
+ Vector<int32_t> formats;
+ mCameraParameters->getSupportedPreviewFormats(formats);
+ }
+ },
+ [&]() {
+ if (std::is_same_v<type, CameraParameters2>) {
+ string key1 = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ string key2 = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ int32_t order;
+ mCameraParameters2->compareSetOrder(key1.c_str(), key2.c_str(), &order);
+ }
+ },
+ [&]() {
+ if (std::is_same_v<type, CameraParameters2>) {
+ int32_t minFps = mFDP->ConsumeIntegral<int32_t>();
+ int32_t maxFps = mFDP->ConsumeIntegral<int32_t>();
+ mCameraParameters2->setPreviewFpsRange(minFps, maxFps);
+ }
+ },
+ });
+ callCameraUtilsAPIs();
}
}
void CameraParametersFuzzer::invokeCameraParameters() {
- initCameraParameters<CameraParameters>(&mCameraParameters);
- cameraParametersCommon<CameraParameters>(mCameraParameters);
- initCameraParameters<CameraParameters2>(&mCameraParameters2);
- cameraParametersCommon<CameraParameters2>(mCameraParameters2);
-
- int32_t minFPS, maxFPS;
- mCameraParameters->getPreviewFpsRange(&minFPS, &maxFPS);
- string format = mFDP->ConsumeBool() ? mFDP->PickValueInArray(kValidFormats)
- : mFDP->ConsumeRandomLengthString();
- mCameraParameters->previewFormatToEnum(format.c_str());
- mCameraParameters->isEmpty();
- Vector<int32_t> formats;
- mCameraParameters->getSupportedPreviewFormats(formats);
+ if (mFDP->ConsumeBool()) {
+ initCameraParameters<CameraParameters>(mCameraParameters);
+ callCameraParametersAPIs(mCameraParameters);
+ } else {
+ initCameraParameters<CameraParameters2>(mCameraParameters2);
+ callCameraParametersAPIs(mCameraParameters2);
+ }
}
void CameraParametersFuzzer::process(const uint8_t* data, size_t size) {
diff --git a/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
index 494ec1b..5ad9530 100644
--- a/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2CaptureRequest_fuzzer.cpp
@@ -44,7 +44,7 @@
}
for (size_t idx = 0; idx < physicalCameraSettingsSize; ++idx) {
- string id = fdp.ConsumeRandomLengthString();
+ string id = fdp.ConsumeRandomLengthString(kMaxBytes);
if (fdp.ConsumeBool()) {
parcelCamCaptureReq.writeString16(toString16(id));
}
@@ -120,7 +120,11 @@
}
}
- invokeReadWriteParcelsp<CaptureRequest>(captureRequest);
+ if (fdp.ConsumeBool()) {
+ invokeReadWriteParcelsp<CaptureRequest>(captureRequest);
+ } else {
+ invokeNewReadWriteParcelsp<CaptureRequest>(captureRequest, fdp);
+ }
invokeReadWriteNullParcelsp<CaptureRequest>(captureRequest);
parcelCamCaptureReq.setDataPosition(0);
captureRequest->readFromParcel(&parcelCamCaptureReq);
diff --git a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
index 2fe9a94..7046075 100644
--- a/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2OutputConfiguration_fuzzer.cpp
@@ -26,85 +26,122 @@
using namespace android;
using namespace android::hardware::camera2::params;
+constexpr int8_t kMaxLoopIterations = 100;
constexpr int32_t kSizeMin = 0;
constexpr int32_t kSizeMax = 1000;
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
- FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+class C2OutputConfigurationFuzzer {
+ public:
+ void process(const uint8_t* data, size_t size);
- OutputConfiguration* outputConfiguration = nullptr;
+ private:
+ void invokeC2OutputConfigFuzzer();
+ unique_ptr<OutputConfiguration> getC2OutputConfig();
+ sp<IGraphicBufferProducer> createIGraphicBufferProducer();
+ FuzzedDataProvider* mFDP = nullptr;
+};
- if (fdp.ConsumeBool()) {
- outputConfiguration = new OutputConfiguration();
+sp<IGraphicBufferProducer> C2OutputConfigurationFuzzer::createIGraphicBufferProducer() {
+ sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
+ sp<SurfaceControl> surfaceControl = composerClient->createSurface(
+ static_cast<String8>(mFDP->ConsumeRandomLengthString(kMaxBytes).c_str()) /* name */,
+ mFDP->ConsumeIntegral<uint32_t>() /* width */,
+ mFDP->ConsumeIntegral<uint32_t>() /* height */,
+ mFDP->ConsumeIntegral<int32_t>() /* format */,
+ mFDP->ConsumeIntegral<int32_t>() /* flags */);
+ if (surfaceControl) {
+ sp<Surface> surface = surfaceControl->getSurface();
+ return surface->getIGraphicBufferProducer();
} else {
- int32_t rotation = fdp.ConsumeIntegral<int32_t>();
- string physicalCameraId = fdp.ConsumeRandomLengthString();
- int32_t surfaceSetID = fdp.ConsumeIntegral<int32_t>();
- bool isShared = fdp.ConsumeBool();
-
- if (fdp.ConsumeBool()) {
- sp<IGraphicBufferProducer> iGBP = nullptr;
- sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
- sp<SurfaceControl> surfaceControl = composerClient->createSurface(
- static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()) /* name */,
- fdp.ConsumeIntegral<uint32_t>() /* width */,
- fdp.ConsumeIntegral<uint32_t>() /* height */,
- fdp.ConsumeIntegral<int32_t>() /* format */,
- fdp.ConsumeIntegral<int32_t>() /* flags */);
- if (surfaceControl) {
- sp<Surface> surface = surfaceControl->getSurface();
- iGBP = surface->getIGraphicBufferProducer();
- }
- outputConfiguration = new OutputConfiguration(iGBP, rotation, physicalCameraId,
- surfaceSetID, isShared);
- iGBP.clear();
- composerClient.clear();
- surfaceControl.clear();
- } else {
- size_t iGBPSize = fdp.ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
- vector<sp<IGraphicBufferProducer>> iGBPs;
- for (size_t idx = 0; idx < iGBPSize; ++idx) {
- sp<IGraphicBufferProducer> iGBP = nullptr;
- sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
- sp<SurfaceControl> surfaceControl = composerClient->createSurface(
- static_cast<String8>(fdp.ConsumeRandomLengthString().c_str()) /* name */,
- fdp.ConsumeIntegral<uint32_t>() /* width */,
- fdp.ConsumeIntegral<uint32_t>() /* height */,
- fdp.ConsumeIntegral<int32_t>() /* format */,
- fdp.ConsumeIntegral<int32_t>() /* flags */);
- if (surfaceControl) {
- sp<Surface> surface = surfaceControl->getSurface();
- iGBP = surface->getIGraphicBufferProducer();
- iGBPs.push_back(iGBP);
- }
- iGBP.clear();
- composerClient.clear();
- surfaceControl.clear();
- }
- outputConfiguration = new OutputConfiguration(iGBPs, rotation, physicalCameraId,
- surfaceSetID, isShared);
- }
+ sp<IGraphicBufferProducer> gbp;
+ return gbp;
}
+}
- outputConfiguration->getRotation();
- outputConfiguration->getSurfaceSetID();
- outputConfiguration->getSurfaceType();
- outputConfiguration->getWidth();
- outputConfiguration->getHeight();
- outputConfiguration->isDeferred();
- outputConfiguration->isShared();
- outputConfiguration->getPhysicalCameraId();
+unique_ptr<OutputConfiguration> C2OutputConfigurationFuzzer::getC2OutputConfig() {
+ unique_ptr<OutputConfiguration> outputConfiguration = nullptr;
+ auto selectOutputConfigurationConstructor =
+ mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { outputConfiguration = make_unique<OutputConfiguration>(); },
- OutputConfiguration outputConfiguration2;
- outputConfiguration->gbpsEqual(outputConfiguration2);
- outputConfiguration->sensorPixelModesUsedEqual(outputConfiguration2);
- outputConfiguration->gbpsLessThan(outputConfiguration2);
- outputConfiguration->sensorPixelModesUsedLessThan(outputConfiguration2);
- outputConfiguration->getGraphicBufferProducers();
- sp<IGraphicBufferProducer> gbp;
- outputConfiguration->addGraphicProducer(gbp);
- invokeReadWriteNullParcel<OutputConfiguration>(outputConfiguration);
- invokeReadWriteParcel<OutputConfiguration>(outputConfiguration);
- delete outputConfiguration;
+ [&]() {
+ int32_t rotation = mFDP->ConsumeIntegral<int32_t>();
+ string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
+ bool isShared = mFDP->ConsumeBool();
+ sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
+ outputConfiguration = make_unique<OutputConfiguration>(
+ iGBP, rotation, physicalCameraId, surfaceSetID, isShared);
+ },
+
+ [&]() {
+ int32_t rotation = mFDP->ConsumeIntegral<int32_t>();
+ string physicalCameraId = mFDP->ConsumeRandomLengthString(kMaxBytes);
+ int32_t surfaceSetID = mFDP->ConsumeIntegral<int32_t>();
+ bool isShared = mFDP->ConsumeBool();
+ size_t iGBPSize = mFDP->ConsumeIntegralInRange<size_t>(kSizeMin, kSizeMax);
+ vector<sp<IGraphicBufferProducer>> iGBPs;
+ for (size_t idx = 0; idx < iGBPSize; ++idx) {
+ sp<IGraphicBufferProducer> iGBP = createIGraphicBufferProducer();
+ iGBPs.push_back(iGBP);
+ }
+ outputConfiguration = make_unique<OutputConfiguration>(
+ iGBPs, rotation, physicalCameraId, surfaceSetID, isShared);
+ },
+ });
+ selectOutputConfigurationConstructor();
+ return outputConfiguration;
+}
+
+void C2OutputConfigurationFuzzer::invokeC2OutputConfigFuzzer() {
+ unique_ptr<OutputConfiguration> outputConfiguration = getC2OutputConfig();
+ int8_t count = kMaxLoopIterations;
+ while (--count > 0) {
+ unique_ptr<OutputConfiguration> outputConfiguration2 = getC2OutputConfig();
+ auto callC2OutputConfAPIs = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { outputConfiguration->getRotation(); },
+ [&]() { outputConfiguration->getSurfaceSetID(); },
+ [&]() { outputConfiguration->getSurfaceType(); },
+ [&]() { outputConfiguration->getWidth(); },
+ [&]() { outputConfiguration->getHeight(); },
+ [&]() { outputConfiguration->isDeferred(); },
+ [&]() { outputConfiguration->isShared(); },
+ [&]() { outputConfiguration->getPhysicalCameraId(); },
+ [&]() { outputConfiguration->gbpsEqual(*outputConfiguration2); },
+ [&]() { outputConfiguration->sensorPixelModesUsedEqual(*outputConfiguration2); },
+ [&]() { outputConfiguration->gbpsLessThan(*outputConfiguration2); },
+ [&]() { outputConfiguration->sensorPixelModesUsedLessThan(*outputConfiguration2); },
+ [&]() { outputConfiguration->getGraphicBufferProducers(); },
+ [&]() {
+ sp<IGraphicBufferProducer> gbp = createIGraphicBufferProducer();
+ outputConfiguration->addGraphicProducer(gbp);
+ },
+ [&]() { outputConfiguration->isMultiResolution(); },
+ [&]() { outputConfiguration->getColorSpace(); },
+ [&]() { outputConfiguration->getStreamUseCase(); },
+ [&]() { outputConfiguration->getTimestampBase(); },
+ [&]() { outputConfiguration->getMirrorMode(); },
+ [&]() { outputConfiguration->useReadoutTimestamp(); },
+ });
+ callC2OutputConfAPIs();
+ }
+ // Not keeping invokeReadWrite() APIs in while loop to avoid possible OOM.
+ invokeReadWriteNullParcel<OutputConfiguration>(outputConfiguration.get());
+ if (mFDP->ConsumeBool()) {
+ invokeReadWriteParcel<OutputConfiguration>(outputConfiguration.get());
+ } else {
+ invokeNewReadWriteParcel<OutputConfiguration>(outputConfiguration.get(), *mFDP);
+ }
+}
+
+void C2OutputConfigurationFuzzer::process(const uint8_t* data, size_t size) {
+ mFDP = new FuzzedDataProvider(data, size);
+ invokeC2OutputConfigFuzzer();
+ delete mFDP;
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ C2OutputConfigurationFuzzer c2OutputConfigurationFuzzer;
+ c2OutputConfigurationFuzzer.process(data, size);
return 0;
}
diff --git a/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
index dc40b0f..c588f11 100644
--- a/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_c2SubmitInfo_fuzzer.cpp
@@ -27,6 +27,10 @@
SubmitInfo submitInfo;
submitInfo.mRequestId = fdp.ConsumeIntegral<int32_t>();
submitInfo.mLastFrameNumber = fdp.ConsumeIntegral<int64_t>();
- invokeReadWriteParcel<SubmitInfo>(&submitInfo);
+ if (fdp.ConsumeBool()) {
+ invokeReadWriteParcel<SubmitInfo>(&submitInfo);
+ } else {
+ invokeNewReadWriteParcel<SubmitInfo>(&submitInfo, fdp);
+ }
return 0;
}
diff --git a/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
index e14d9ce..3131f1d 100644
--- a/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_vendorTagDescriptor_fuzzer.cpp
@@ -29,6 +29,8 @@
constexpr int32_t kRangeMin = 0;
constexpr int32_t kRangeMax = 1000;
constexpr int32_t kVendorTagDescriptorId = -1;
+constexpr int8_t kMinLoopIterations = 1;
+constexpr int8_t kMaxLoopIterations = 50;
extern "C" {
@@ -95,39 +97,63 @@
initVendorTagDescriptor();
sp<VendorTagDescriptor> vdesc = new VendorTagDescriptor();
- vdesc->copyFrom(*mVendorTagDescriptor);
- VendorTagDescriptor::setAsGlobalVendorTagDescriptor(mVendorTagDescriptor);
- VendorTagDescriptor::getGlobalVendorTagDescriptor();
- int32_t tagCount = mVendorTagDescriptor->getTagCount();
- if (tagCount > 0) {
- uint32_t tagArray[tagCount];
- mVendorTagDescriptor->getTagArray(tagArray);
- uint32_t tag;
- for (int32_t i = 0; i < tagCount; ++i) {
- tag = tagArray[i];
- get_local_camera_metadata_section_name_vendor_id(tag, kVendorTagDescriptorId);
- get_local_camera_metadata_tag_name_vendor_id(tag, kVendorTagDescriptorId);
- get_local_camera_metadata_tag_type_vendor_id(tag, kVendorTagDescriptorId);
- mVendorTagDescriptor->getSectionIndex(tag);
- }
- mVendorTagDescriptor->getAllSectionNames();
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ auto callVendorTagDescriptor = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() {
+ int32_t tagCount = mVendorTagDescriptor->getTagCount();
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptor->getTagArray(tagArray);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(
+ tag, kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_name_vendor_id(tag,
+ kVendorTagDescriptorId);
+ get_local_camera_metadata_tag_type_vendor_id(tag,
+ kVendorTagDescriptorId);
+ mVendorTagDescriptor->getSectionIndex(tag);
+ }
+ }
+ },
+ [&]() {
+ if (mVendorTagDescriptor->getTagCount() > 0) {
+ mVendorTagDescriptor->getAllSectionNames();
+ }
+ },
+ [&]() { vdesc->copyFrom(*mVendorTagDescriptor); },
+ [&]() {
+ VendorTagDescriptor::setAsGlobalVendorTagDescriptor(mVendorTagDescriptor);
+ },
+ [&]() { VendorTagDescriptor::getGlobalVendorTagDescriptor(); },
+ [&]() {
+ String8 name((mFDP->ConsumeRandomLengthString()).c_str());
+ String8 section((mFDP->ConsumeRandomLengthString()).c_str());
+ uint32_t lookupTag;
+ mVendorTagDescriptor->lookupTag(name, section, &lookupTag);
+ },
+ [&]() {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ int32_t indentation =
+ mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
+ mVendorTagDescriptor->dump(fd, verbosity, indentation);
+ close(fd);
+ },
+ });
+ callVendorTagDescriptor();
}
- String8 name((mFDP->ConsumeRandomLengthString()).c_str());
- String8 section((mFDP->ConsumeRandomLengthString()).c_str());
- uint32_t lookupTag;
- mVendorTagDescriptor->lookupTag(name, section, &lookupTag);
-
- int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
- int32_t verbosity = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
- int32_t indentation = mFDP->ConsumeIntegralInRange<int32_t>(kRangeMin, kRangeMax);
- mVendorTagDescriptor->dump(fd, verbosity, indentation);
-
- invokeReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor);
+ // Do not keep invokeReadWrite() APIs in while loop to avoid possible OOM.
+ if (mFDP->ConsumeBool()) {
+ invokeReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor);
+ } else {
+ invokeNewReadWriteParcelsp<VendorTagDescriptor>(mVendorTagDescriptor, *mFDP);
+ }
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- vdesc.clear();
- close(fd);
}
void VendorTagDescriptorFuzzer::invokeVendorTagDescriptorCache() {
@@ -135,36 +161,52 @@
uint64_t id = mFDP->ConsumeIntegral<uint64_t>();
initVendorTagDescriptor();
- mVendorTagDescriptorCache->addVendorDescriptor(id, mVendorTagDescriptor);
- VendorTagDescriptorCache::setAsGlobalVendorTagCache(mVendorTagDescriptorCache);
- VendorTagDescriptorCache::getGlobalVendorTagCache();
- sp<VendorTagDescriptor> tagDesc;
- mVendorTagDescriptorCache->getVendorTagDescriptor(id, &tagDesc);
-
- int32_t tagCount = mVendorTagDescriptorCache->getTagCount(id);
- if (tagCount > 0) {
- uint32_t tagArray[tagCount];
- mVendorTagDescriptorCache->getTagArray(tagArray, id);
- uint32_t tag;
- for (int32_t i = 0; i < tagCount; ++i) {
- tag = tagArray[i];
- get_local_camera_metadata_section_name_vendor_id(tag, id);
- get_local_camera_metadata_tag_name_vendor_id(tag, id);
- get_local_camera_metadata_tag_type_vendor_id(tag, id);
- }
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ auto callVendorTagDescriptorCache = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { mVendorTagDescriptorCache->addVendorDescriptor(id, mVendorTagDescriptor); },
+ [&]() {
+ VendorTagDescriptorCache::setAsGlobalVendorTagCache(mVendorTagDescriptorCache);
+ },
+ [&]() { VendorTagDescriptorCache::getGlobalVendorTagCache(); },
+ [&]() {
+ sp<VendorTagDescriptor> tagDesc;
+ mVendorTagDescriptorCache->getVendorTagDescriptor(id, &tagDesc);
+ },
+ [&]() {
+ int32_t tagCount = mVendorTagDescriptorCache->getTagCount(id);
+ if (tagCount > 0) {
+ uint32_t tagArray[tagCount];
+ mVendorTagDescriptorCache->getTagArray(tagArray, id);
+ uint32_t tag;
+ for (int32_t i = 0; i < tagCount; ++i) {
+ tag = tagArray[i];
+ get_local_camera_metadata_section_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_name_vendor_id(tag, id);
+ get_local_camera_metadata_tag_type_vendor_id(tag, id);
+ }
+ }
+ },
+ [&]() {
+ int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
+ int32_t verbosity = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ int32_t indentation = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
+ mVendorTagDescriptorCache->dump(fd, verbosity, indentation);
+ close(fd);
+ },
+ [&]() { VendorTagDescriptorCache::isVendorCachePresent(id); },
+ [&]() { mVendorTagDescriptorCache->getVendorIdsAndTagDescriptors(); },
+ });
+ callVendorTagDescriptorCache();
}
- int32_t fd = open("/dev/null", O_CLOEXEC | O_RDWR | O_CREAT);
- int32_t verbosity = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
- int32_t indentation = mFDP->ConsumeIntegralInRange<int>(kRangeMin, kRangeMax);
- mVendorTagDescriptorCache->dump(fd, verbosity, indentation);
-
- invokeReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache);
- VendorTagDescriptorCache::isVendorCachePresent(id);
- mVendorTagDescriptorCache->getVendorIdsAndTagDescriptors();
+ // Do not keep invokeReadWrite() APIs in while loop to avoid possible OOM.
+ if (mFDP->ConsumeBool()) {
+ invokeReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache);
+ } else {
+ invokeNewReadWriteParcelsp<VendorTagDescriptorCache>(mVendorTagDescriptorCache, *mFDP);
+ }
mVendorTagDescriptorCache->clearGlobalVendorTagCache();
- tagDesc.clear();
- close(fd);
}
void VendorTagDescriptorFuzzer::invokeVendorTagErrorConditions() {
@@ -177,26 +219,39 @@
VendorTagDescriptor::createDescriptorFromOps(/*vOps*/ NULL, vDesc);
} else {
VendorTagDescriptor::createDescriptorFromOps(&vOps, vDesc);
- int32_t tagCount = vDesc->getTagCount();
- uint32_t badTag = mFDP->ConsumeIntegral<uint32_t>();
- uint32_t badTagArray[tagCount + 1];
- vDesc->getTagArray(badTagArray);
- vDesc->getSectionName(badTag);
- vDesc->getTagName(badTag);
- vDesc->getTagType(badTag);
- VendorTagDescriptor::clearGlobalVendorTagDescriptor();
- VendorTagDescriptor::getGlobalVendorTagDescriptor();
- VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc);
+
+ int8_t count = mFDP->ConsumeIntegralInRange<int8_t>(kMinLoopIterations, kMaxLoopIterations);
+ while (--count > 0) {
+ int32_t tagCount = vDesc->getTagCount();
+ uint32_t badTag = mFDP->ConsumeIntegral<uint32_t>();
+ uint32_t badTagArray[tagCount + 1];
+ auto callVendorTagErrorConditions =
+ mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { vDesc->getTagArray(badTagArray); },
+ [&]() { vDesc->getSectionName(badTag); },
+ [&]() { vDesc->getTagName(badTag); },
+ [&]() { vDesc->getTagType(badTag); },
+ [&]() { VendorTagDescriptor::clearGlobalVendorTagDescriptor(); },
+ [&]() { VendorTagDescriptor::getGlobalVendorTagDescriptor(); },
+ [&]() { VendorTagDescriptor::setAsGlobalVendorTagDescriptor(vDesc); },
+ });
+ callVendorTagErrorConditions();
+ }
invokeReadWriteNullParcelsp<VendorTagDescriptor>(vDesc);
- vDesc.clear();
}
+ vDesc.clear();
}
void VendorTagDescriptorFuzzer::process(const uint8_t* data, size_t size) {
mFDP = new FuzzedDataProvider(data, size);
- invokeVendorTagDescriptor();
- invokeVendorTagDescriptorCache();
- invokeVendorTagErrorConditions();
+ while (mFDP->remaining_bytes()) {
+ auto invokeVendorTagDescriptorFuzzer = mFDP->PickValueInArray<const std::function<void()>>({
+ [&]() { invokeVendorTagDescriptor(); },
+ [&]() { invokeVendorTagDescriptorCache(); },
+ [&]() { invokeVendorTagErrorConditions(); },
+ });
+ invokeVendorTagDescriptorFuzzer();
+ }
delete mFDP;
}
diff --git a/media/aconfig/Android.bp b/media/aconfig/Android.bp
index 96bf4f5..ee25c03 100644
--- a/media/aconfig/Android.bp
+++ b/media/aconfig/Android.bp
@@ -1,22 +1,49 @@
+// deprecated
aconfig_declarations {
name: "aconfig_mediacodec_flags",
package: "com.android.media.codec.flags",
srcs: ["mediacodec_flags.aconfig"],
}
+// deprecated
java_aconfig_library {
name: "aconfig_mediacodec_flags_java_lib",
aconfig_declarations: "aconfig_mediacodec_flags",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
+// deprecated
cc_aconfig_library {
name: "aconfig_mediacodec_flags_c_lib",
min_sdk_version: "30",
vendor_available: true,
+ double_loadable: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media.swcodec",
+ ],
+ aconfig_declarations: "aconfig_mediacodec_flags",
+}
+
+aconfig_declarations {
+ name: "aconfig_codec_fwk_flags",
+ package: "android.media.codec",
+ srcs: ["codec_fwk.aconfig"],
+}
+
+java_aconfig_library {
+ name: "android.media.codec-aconfig-java",
+ aconfig_declarations: "aconfig_codec_fwk_flags",
+ defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
+
+cc_aconfig_library {
+ name: "android.media.codec-aconfig-cc",
+ min_sdk_version: "30",
+ vendor_available: true,
apex_available: [
"//apex_available:platform",
"com.android.media.swcodec",
],
- aconfig_declarations: "aconfig_mediacodec_flags",
+ aconfig_declarations: "aconfig_codec_fwk_flags",
}
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
new file mode 100644
index 0000000..183bd99
--- /dev/null
+++ b/media/aconfig/codec_fwk.aconfig
@@ -0,0 +1,26 @@
+# Codec framework feature flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+
+package: "android.media.codec"
+
+flag {
+ name: "dynamic_color_aspects"
+ namespace: "codec_fwk"
+ description: "Feature flag for dynamic color aspect support"
+ bug: "297914560"
+}
+
+flag {
+ name: "hlg_editing"
+ namespace: "codec_fwk"
+ description: "Feature flag for HLG editing support"
+ bug: "316397061"
+}
+
+flag {
+ name: "null_output_surface"
+ namespace: "codec_fwk"
+ description: "Feature flag for null output Surface support"
+ bug: "297920102"
+}
diff --git a/media/aconfig/mediacodec_flags.aconfig b/media/aconfig/mediacodec_flags.aconfig
index c82ad4d..be0fc5c 100644
--- a/media/aconfig/mediacodec_flags.aconfig
+++ b/media/aconfig/mediacodec_flags.aconfig
@@ -1,5 +1,10 @@
package: "com.android.media.codec.flags"
+# ******************************************************************
+# !!! DO NOT ADD FURTHER FLAGS TO THIS FILE !!!
+# !!! USE codec_fwk.aconfig INSTEAD !!!
+# ******************************************************************
+
flag {
name: "large_audio_frame"
namespace: "codec_fwk"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index 9e14e29..af97dac 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -43,6 +43,18 @@
name: "com.android.media.audio-aconfig-cc",
aconfig_declarations: "com.android.media.audio-aconfig",
defaults: ["audio-aconfig-cc-defaults"],
+ double_loadable: true,
+ host_supported: true,
+ product_available: true,
+ vendor_available: true,
+ // TODO(b/316909431) native_bridge_supported: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ "com.android.btservices",
+ ],
+ min_sdk_version: "29",
}
cc_aconfig_library {
@@ -70,21 +82,21 @@
name: "android.media.audio-aconfig",
package: "android.media.audio",
srcs: ["audio_framework.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
aconfig_declarations {
name: "android.media.audiopolicy-aconfig",
package: "android.media.audiopolicy",
srcs: ["audiopolicy_framework.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
aconfig_declarations {
name: "android.media.midi-aconfig",
package: "android.media.midi",
srcs: ["midi_flags.aconfig"],
- visibility: ["//visibility:private"],
+ visibility: ["//frameworks/base/api"],
}
java_aconfig_library {
@@ -97,6 +109,11 @@
name: "android.media.audiopolicy-aconfig-java",
aconfig_declarations: "android.media.audiopolicy-aconfig",
defaults: ["framework-minus-apex-aconfig-java-defaults"],
+ min_sdk_version: "VanillaIceCream",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.car.framework",
+ ],
}
java_aconfig_library {
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index 73cb8ca..0b2a5c4 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -37,8 +37,23 @@
}
flag {
+ name: "ringer_mode_affects_alarm"
+ namespace: "media_audio"
+ description:
+ "Support a configuration where ringer mode affects alarm stream"
+ bug: "312456558"
+}
+
+flag {
name: "spatializer_offload"
namespace: "media_audio"
description: "Enable spatializer offload"
bug: "307842941"
}
+
+flag {
+ name: "stereo_spatialization"
+ namespace: "media_audio"
+ description: "Enable stereo channel mask for spatialization."
+ bug: "303920722"
+}
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 294e67d..34c026a 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -21,6 +21,15 @@
bug: "302323921"
}
+flag {
+ name: "focus_exclusive_with_recording"
+ namespace: "media_audio"
+ description:
+ "Audio focus GAIN_TRANSIENT_EXCLUSIVE only mutes"
+ "notifications when the focus owner is also recording"
+ bug: "316414750"
+}
+
# TODO remove
flag {
name: "focus_freeze_test_api"
diff --git a/media/audio/aconfig/audiopolicy_framework.aconfig b/media/audio/aconfig/audiopolicy_framework.aconfig
index 833730a..b41c1c3 100644
--- a/media/audio/aconfig/audiopolicy_framework.aconfig
+++ b/media/audio/aconfig/audiopolicy_framework.aconfig
@@ -11,3 +11,17 @@
description: "Enable AudioPolicy.updateMixingRules API for hot-swapping audio mixing rules."
bug: "293874525"
}
+
+flag {
+ name: "enable_fade_manager_configuration"
+ namespace: "media_audio"
+ description: "Enable Fade Manager Configuration support to determine fade properties"
+ bug: "307354764"
+}
+
+flag {
+ name: "multi_zone_audio"
+ namespace: "media_audio"
+ description: "Enable multi-zone audio support in audio product strategies."
+ bug: "316643994"
+}
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 60b814e..1a6c7f1 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -28,7 +28,6 @@
#include "media/AidlConversionCppNdk.h"
-#include <media/ShmemCompat.h>
#include <media/stagefright/foundation/MediaDefs.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/media/audioaidlconversion/Android.bp b/media/audioaidlconversion/Android.bp
index d3a5755..07c59c7 100644
--- a/media/audioaidlconversion/Android.bp
+++ b/media/audioaidlconversion/Android.bp
@@ -56,6 +56,19 @@
}
cc_defaults {
+ name: "audio_aidl_conversion_common_default_cpp",
+ shared_libs: [
+ "libbinder",
+ "libshmemcompat",
+ "shared-file-region-aidl-cpp",
+ "framework-permission-aidl-cpp",
+ ],
+ export_shared_lib_headers: [
+ "shared-file-region-aidl-cpp",
+ ],
+}
+
+cc_defaults {
name: "audio_aidl_conversion_common_default",
export_include_dirs: ["include"],
host_supported: true,
@@ -67,17 +80,12 @@
],
shared_libs: [
"libbase",
- "libbinder",
"liblog",
- "libshmemcompat",
"libstagefright_foundation",
"libutils",
- "shared-file-region-aidl-cpp",
- "framework-permission-aidl-cpp",
],
export_shared_lib_headers: [
"libbase",
- "shared-file-region-aidl-cpp",
],
cflags: [
"-Wall",
@@ -113,6 +121,7 @@
],
defaults: [
"audio_aidl_conversion_common_default",
+ "audio_aidl_conversion_common_default_cpp",
"latest_android_media_audio_common_types_cpp_export_shared",
],
min_sdk_version: "29",
@@ -223,6 +232,7 @@
],
defaults: [
"audio_aidl_conversion_common_default",
+ "audio_aidl_conversion_common_default_cpp",
"audio_aidl_conversion_common_util_default",
"latest_android_media_audio_common_types_cpp_shared",
"latest_android_media_audio_common_types_ndk_shared",
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
index 656d76a..7cba011 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
@@ -25,12 +25,12 @@
#define AUDIO_AIDL_CONVERSION_AIDL_CONVERSION_UTIL_CPP
#endif // BACKEND_NDK_IMPL
+#include <functional>
#include <limits>
#include <type_traits>
#include <utility>
#include <android-base/expected.h>
-#include <binder/Status.h>
#if defined(BACKEND_NDK_IMPL)
#include <android/binder_auto_utils.h>
@@ -40,6 +40,7 @@
namespace aidl {
#else
#include <binder/Enums.h>
+#include <binder/Status.h>
#endif // BACKEND_NDK_IMPL
namespace android {
@@ -374,6 +375,30 @@
* Note: for EX_TRANSACTION_FAILED and EX_SERVICE_SPECIFIC a more detailed error code
* can be found from transactionError() or serviceSpecificErrorCode().
*/
+#if defined(BACKEND_NDK_IMPL)
+static inline ::android::status_t statusTFromExceptionCode(binder_exception_t exception) {
+ switch (exception) {
+ case EX_NONE:
+ return ::android::OK;
+ case EX_SECURITY: // Java SecurityException, rethrows locally in Java
+ return ::android::PERMISSION_DENIED;
+ case EX_BAD_PARCELABLE: // Java BadParcelableException, rethrows in Java
+ case EX_ILLEGAL_ARGUMENT: // Java IllegalArgumentException, rethrows in Java
+ case EX_NULL_POINTER: // Java NullPointerException, rethrows in Java
+ return ::android::BAD_VALUE;
+ case EX_ILLEGAL_STATE: // Java IllegalStateException, rethrows in Java
+ case EX_UNSUPPORTED_OPERATION: // Java UnsupportedOperationException, rethrows
+ return ::android::INVALID_OPERATION;
+ case EX_PARCELABLE: // Java bootclass loader (not standard exception), rethrows
+ case EX_NETWORK_MAIN_THREAD: // Java NetworkOnMainThreadException, rethrows
+ case EX_TRANSACTION_FAILED: // Native - see error code
+ case EX_SERVICE_SPECIFIC: // Java ServiceSpecificException,
+ // rethrows in Java with integer error code
+ return ::android::UNKNOWN_ERROR;
+ }
+ return ::android::UNKNOWN_ERROR;
+}
+#else
static inline ::android::status_t statusTFromExceptionCode(int32_t exceptionCode) {
using namespace ::android::binder;
switch (exceptionCode) {
@@ -398,6 +423,7 @@
}
return ::android::UNKNOWN_ERROR;
}
+#endif // BACKEND_NDK_IMPL
/**
* Return the equivalent Android ::android::status_t from a binder status.
@@ -410,6 +436,7 @@
*
* return_type method(type0 param0, ...)
*/
+#if !defined(BACKEND_NDK_IMPL)
static inline ::android::status_t statusTFromBinderStatus(const ::android::binder::Status &status) {
return status.isOk() ? ::android::OK // check ::android::OK,
: status.serviceSpecificErrorCode() // service-side error, not standard Java exception
@@ -418,6 +445,7 @@
?: statusTFromExceptionCode(status.exceptionCode()); // a service-side error with a
// standard Java exception (fromExceptionCode)
}
+#endif
#if defined(BACKEND_NDK_IMPL)
static inline ::android::status_t statusTFromBinderStatus(const ::ndk::ScopedAStatus &status) {
@@ -443,6 +471,7 @@
* This is used for methods not returning an explicit status_t,
* where Java callers expect an exception, not an integer return value.
*/
+#if !defined(BACKEND_NDK_IMPL)
static inline ::android::binder::Status binderStatusFromStatusT(
::android::status_t status, const char *optionalMessage = nullptr) {
const char * const emptyIfNull = optionalMessage == nullptr ? "" : optionalMessage;
@@ -470,6 +499,7 @@
// throw a ServiceSpecificException.
return Status::fromServiceSpecificError(status, emptyIfNull);
}
+#endif
} // namespace aidl_utils
diff --git a/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp b/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
index 60727b4..f78243e 100644
--- a/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
+++ b/media/audioaidlconversion/tests/audio_aidl_ndk_conversion_tests.cpp
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
+#define LOG_TAG "AidlConversionNdkTests"
#include <iostream>
#include <type_traits>
diff --git a/media/codec2/TEST_MAPPING b/media/codec2/TEST_MAPPING
index 8a894f3..b911e11 100644
--- a/media/codec2/TEST_MAPPING
+++ b/media/codec2/TEST_MAPPING
@@ -25,5 +25,8 @@
}
]
}
+ ],
+ "postsubmit": [
+ { "name": "c2aidl_gtracker_test"}
]
}
diff --git a/media/codec2/components/aom/C2SoftAomEnc.cpp b/media/codec2/components/aom/C2SoftAomEnc.cpp
index 71909e5..7c9d3e8 100644
--- a/media/codec2/components/aom/C2SoftAomEnc.cpp
+++ b/media/codec2/components/aom/C2SoftAomEnc.cpp
@@ -338,6 +338,19 @@
}
c2_status_t C2SoftAomEnc::onStop() {
+ IntfImpl::Lock lock = mIntf->lock();
+ std::shared_ptr<C2StreamRequestSyncFrameTuning::output> requestSync = mIntf->getRequestSync_l();
+ lock.unlock();
+ if (requestSync != mRequestSync) {
+ // we can handle IDR immediately
+ if (requestSync->value) {
+ // unset request
+ C2StreamRequestSyncFrameTuning::output clearSync(0u, C2_FALSE);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ mIntf->config({ &clearSync }, C2_MAY_BLOCK, &failures);
+ }
+ mRequestSync = requestSync;
+ }
onRelease();
return C2_OK;
}
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
index 3f96cb3..76680a3 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.cpp
@@ -42,6 +42,8 @@
constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
+constexpr uint32_t kOutputDelay = 4;
+
class C2SoftDav1dDec::IntfImpl : public SimpleInterface<void>::BaseParams {
public:
explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper>& helper)
@@ -239,6 +241,13 @@
.withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
.withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
.build());
+
+ addParameter(
+ DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
+ .withDefault(new C2PortActualDelayTuning::output(kOutputDelay))
+ .withFields({C2F(mActualOutputDelay, value).inRange(0, kOutputDelay)})
+ .withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
+ .build());
}
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output>& oldMe,
@@ -450,13 +459,6 @@
if (mDav1dCtx) {
Dav1dPicture p;
- while (mDecodedPictures.size() > 0) {
- p = mDecodedPictures.front();
- mDecodedPictures.pop_front();
-
- dav1d_picture_unref(&p);
- }
-
int res = 0;
while (true) {
memset(&p, 0, sizeof(p));
@@ -527,6 +529,8 @@
android::base::GetIntProperty(NUM_THREADS_DAV1D_PROPERTY, NUM_THREADS_DAV1D_DEFAULT);
if (numThreads > 0) lib_settings.n_threads = numThreads;
+ lib_settings.max_frame_delay = kOutputDelay;
+
int res = 0;
if ((res = dav1d_open(&mDav1dCtx, &lib_settings))) {
ALOGE("dav1d_open failed. status: %d.", res);
@@ -540,15 +544,6 @@
void C2SoftDav1dDec::destroyDecoder() {
if (mDav1dCtx) {
- Dav1dPicture p;
- while (mDecodedPictures.size() > 0) {
- memset(&p, 0, sizeof(p));
- p = mDecodedPictures.front();
- mDecodedPictures.pop_front();
-
- dav1d_picture_unref(&p);
- }
-
dav1d_close(&mDav1dCtx);
mDav1dCtx = nullptr;
mOutputBufferIndex = 0;
@@ -572,19 +567,24 @@
}
void C2SoftDav1dDec::finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
- const std::shared_ptr<C2GraphicBlock>& block) {
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const Dav1dPicture &img) {
std::shared_ptr<C2Buffer> buffer = createGraphicBuffer(block, C2Rect(mWidth, mHeight));
{
IntfImpl::Lock lock = mIntf->lock();
buffer->setInfo(mIntf->getColorAspects_l());
}
- auto fillWork = [buffer, index](const std::unique_ptr<C2Work>& work) {
+
+ auto fillWork = [buffer, index, img, this](const std::unique_ptr<C2Work>& work) {
uint32_t flags = 0;
if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) &&
(c2_cntr64_t(index) == work->input.ordinal.frameIndex)) {
flags |= C2FrameData::FLAG_END_OF_STREAM;
ALOGV("signalling end_of_stream.");
}
+ getHDRStaticParams(&img, work);
+ getHDR10PlusInfoData(&img, work);
+
work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
work->worklets.front()->output.buffers.clear();
work->worklets.front()->output.buffers.push_back(buffer);
@@ -598,10 +598,6 @@
}
}
-static void freeCallback(const uint8_t */*data*/, void */*cookie*/) {
- return;
-}
-
void C2SoftDav1dDec::process(const std::unique_ptr<C2Work>& work,
const std::shared_ptr<C2BlockPool>& pool) {
work->result = C2_OK;
@@ -652,19 +648,60 @@
if (res == 0) {
ALOGV("dav1d found a sequenceHeader (%dx%d) for in_frameIndex=%ld.", seq.max_width,
seq.max_height, (long)in_frameIndex);
+ if (seq.max_width != mWidth || seq.max_height != mHeight) {
+ drainInternal(DRAIN_COMPONENT_NO_EOS, pool, work);
+ mWidth = seq.max_width;
+ mHeight = seq.max_height;
+
+ C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
+ if (err == C2_OK) {
+ work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
+ } else {
+ ALOGE("Config update size failed");
+ mSignalledError = true;
+ work->result = C2_CORRUPTED;
+ work->workletsProcessed = 1u;
+ return;
+ }
+ }
}
+ // insert OBU TD if it is not present.
+ // TODO: b/286852962
+ uint8_t obu_type = (bitstream[0] >> 3) & 0xf;
Dav1dData data;
- res = dav1d_data_wrap(&data, bitstream, inSize, freeCallback, nullptr);
- if (res != 0) {
- ALOGE("Decoder wrap error %s!", strerror(DAV1D_ERR(res)));
+ uint8_t* ptr = (obu_type == DAV1D_OBU_TD) ? dav1d_data_create(&data, inSize)
+ : dav1d_data_create(&data, inSize + 2);
+ if (ptr == nullptr) {
+ ALOGE("dav1d_data_create failed!");
i_ret = -1;
+
} else {
data.m.timestamp = in_frameIndex;
- // ALOGV("inSize=%ld, in_frameIndex=%ld, timestamp=%ld",
- // inSize, frameIndex, data.m.timestamp);
+ int new_Size;
+ if (obu_type != DAV1D_OBU_TD) {
+ new_Size = (int)(inSize + 2);
+
+ // OBU TD
+ ptr[0] = 0x12;
+ ptr[1] = 0;
+
+ memcpy(ptr + 2, bitstream, inSize);
+ } else {
+ new_Size = (int)(inSize);
+ // TODO: b/277797541 - investigate how to wrap this pointer in Dav1dData to
+ // avoid memcopy operations.
+ memcpy(ptr, bitstream, new_Size);
+ }
+
+ // ALOGV("memcpy(ptr,bitstream,inSize=%ld,new_Size=%d,in_frameIndex=%ld,timestamp=%ld,"
+ // "ptr[0,1,2,3,4]=%x,%x,%x,%x,%x)",
+ // inSize, new_Size, frameIndex, data.m.timestamp, ptr[0], ptr[1], ptr[2],
+ // ptr[3], ptr[4]);
// Dump the bitstream data (inputBuffer) if dumping is enabled.
#ifdef FILE_DUMP_ENABLE
@@ -672,6 +709,7 @@
#endif
bool b_draining = false;
+ int res;
do {
res = dav1d_send_data(mDav1dCtx, &data);
@@ -685,39 +723,9 @@
break;
}
- bool b_output_error = false;
+ outputBuffer(pool, work);
- do {
- Dav1dPicture img;
- memset(&img, 0, sizeof(img));
-
- res = dav1d_get_picture(mDav1dCtx, &img);
- if (res == 0) {
- mDecodedPictures.push_back(img);
-
- if (!end_of_stream) break;
- } else if (res == DAV1D_ERR(EAGAIN)) {
- /* the decoder needs more data to be able to output something.
- * if there is more data pending, continue the loop below or
- * otherwise break */
- if (data.sz != 0) res = 0;
- break;
- } else {
- ALOGE("warning! Decoder error %d!", res);
- b_output_error = true;
- break;
- }
- } while (res == 0);
-
- if (b_output_error) break;
-
- /* on drain, we must ignore the 1st EAGAIN */
- if (!b_draining && (res == DAV1D_ERR(EAGAIN) || res == 0) &&
- (end_of_stream)) {
- b_draining = true;
- res = 0;
- }
- } while (res == 0 && ((data.sz != 0) || b_draining));
+ } while (res == DAV1D_ERR(EAGAIN));
if (data.sz > 0) {
ALOGE("unexpected data.sz=%zu after dav1d_send_data", data.sz);
@@ -739,8 +747,6 @@
}
}
- (void)outputBuffer(pool, work);
-
if (end_of_stream) {
drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
mSignalledOutputEos = true;
@@ -749,7 +755,7 @@
}
}
-void C2SoftDav1dDec::getHDRStaticParams(Dav1dPicture* picture,
+void C2SoftDav1dDec::getHDRStaticParams(const Dav1dPicture* picture,
const std::unique_ptr<C2Work>& work) {
C2StreamHdrStaticMetadataInfo::output hdrStaticMetadataInfo{};
bool infoPresent = false;
@@ -813,7 +819,7 @@
}
}
-void C2SoftDav1dDec::getHDR10PlusInfoData(Dav1dPicture* picture,
+void C2SoftDav1dDec::getHDR10PlusInfoData(const Dav1dPicture* picture,
const std::unique_ptr<C2Work>& work) {
if (picture != nullptr) {
if (picture->itut_t35 != nullptr) {
@@ -853,7 +859,7 @@
}
}
-void C2SoftDav1dDec::getVuiParams(Dav1dPicture* picture) {
+void C2SoftDav1dDec::getVuiParams(const Dav1dPicture* picture) {
VuiColorAspects vuiColorAspects;
if (picture) {
@@ -924,53 +930,16 @@
memset(&img, 0, sizeof(img));
int res = 0;
- if (mDecodedPictures.size() > 0) {
- img = mDecodedPictures.front();
- mDecodedPictures.pop_front();
- // ALOGD("Got a picture(out_frameIndex=%ld,timestamp=%ld) from the deque for
- // outputBuffer.",img.m.timestamp,img.m.timestamp);
- } else {
- res = dav1d_get_picture(mDav1dCtx, &img);
- if (res == 0) {
- // ALOGD("Got a picture(out_frameIndex=%ld,timestamp=%ld) from dav1d for
- // outputBuffer.",img.m.timestamp,img.m.timestamp);
- } else {
- ALOGE("failed to get a picture from dav1d for outputBuffer.");
- }
- }
-
+ res = dav1d_get_picture(mDav1dCtx, &img);
if (res == DAV1D_ERR(EAGAIN)) {
- ALOGD("Not enough data to output a picture.");
+ ALOGV("Not enough data to output a picture.");
return false;
- }
- if (res != 0) {
+ } else if (res != 0) {
ALOGE("The AV1 decoder failed to get a picture (res=%s).", strerror(DAV1D_ERR(res)));
return false;
}
- const int width = img.p.w;
- const int height = img.p.h;
- if (width != mWidth || height != mHeight) {
- mWidth = width;
- mHeight = height;
-
- C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
- std::vector<std::unique_ptr<C2SettingResult>> failures;
- c2_status_t err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
- if (err == C2_OK) {
- work->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
- } else {
- ALOGE("Config update size failed");
- mSignalledError = true;
- work->result = C2_CORRUPTED;
- work->workletsProcessed = 1u;
- return false;
- }
- }
-
getVuiParams(&img);
- getHDRStaticParams(&img, work);
- getHDR10PlusInfoData(&img, work);
// out_frameIndex that the decoded picture returns from dav1d.
int64_t out_frameIndex = img.m.timestamp;
@@ -1156,9 +1125,8 @@
convFormat);
}
+ finishWork(out_frameIndex, work, std::move(block), img);
dav1d_picture_unref(&img);
-
- finishWork(out_frameIndex, work, std::move(block));
block = nullptr;
return true;
}
diff --git a/media/codec2/components/dav1d/C2SoftDav1dDec.h b/media/codec2/components/dav1d/C2SoftDav1dDec.h
index e3d2a93..5d2a725 100644
--- a/media/codec2/components/dav1d/C2SoftDav1dDec.h
+++ b/media/codec2/components/dav1d/C2SoftDav1dDec.h
@@ -58,7 +58,6 @@
int mOutputBufferIndex = 0;
Dav1dContext* mDav1dCtx = nullptr;
- std::deque<Dav1dPicture> mDecodedPictures;
// configurations used by component in process
// (TODO: keep this in intf but make them internal only)
@@ -101,12 +100,13 @@
nsecs_t mTimeEnd = 0; // Time at the end of decode()
bool initDecoder();
- void getHDRStaticParams(Dav1dPicture* picture, const std::unique_ptr<C2Work>& work);
- void getHDR10PlusInfoData(Dav1dPicture* picture, const std::unique_ptr<C2Work>& work);
- void getVuiParams(Dav1dPicture* picture);
+ void getHDRStaticParams(const Dav1dPicture* picture, const std::unique_ptr<C2Work>& work);
+ void getHDR10PlusInfoData(const Dav1dPicture* picture, const std::unique_ptr<C2Work>& work);
+ void getVuiParams(const Dav1dPicture* picture);
void destroyDecoder();
void finishWork(uint64_t index, const std::unique_ptr<C2Work>& work,
- const std::shared_ptr<C2GraphicBlock>& block);
+ const std::shared_ptr<C2GraphicBlock>& block,
+ const Dav1dPicture &img);
// Sets |work->result| and mSignalledError. Returns false.
void setError(const std::unique_ptr<C2Work>& work, c2_status_t error);
bool allocTmpFrameBuffer(size_t size);
diff --git a/media/codec2/components/raw/C2SoftRawDec.cpp b/media/codec2/components/raw/C2SoftRawDec.cpp
index a03d4e2..ea13071 100644
--- a/media/codec2/components/raw/C2SoftRawDec.cpp
+++ b/media/codec2/components/raw/C2SoftRawDec.cpp
@@ -65,7 +65,7 @@
addParameter(
DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
.withDefault(new C2StreamChannelCountInfo::output(0u, 2))
- .withFields({C2F(mChannelCount, value).inRange(1, 8)})
+ .withFields({C2F(mChannelCount, value).inRange(1, 12)})
.withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
.build());
diff --git a/media/codec2/components/vpx/C2SoftVpxEnc.cpp b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
index e903069..76e74ec 100644
--- a/media/codec2/components/vpx/C2SoftVpxEnc.cpp
+++ b/media/codec2/components/vpx/C2SoftVpxEnc.cpp
@@ -964,7 +964,7 @@
memcpy(wView.data(), encoded_packet->data.frame.buf, encoded_packet->data.frame.sz);
++mNumInputFrames;
- ALOGD("bytes generated %zu", encoded_packet->data.frame.sz);
+ ALOGV("bytes generated %zu", encoded_packet->data.frame.sz);
uint32_t flags = 0;
if (eos) {
flags |= C2FrameData::FLAG_END_OF_STREAM;
diff --git a/media/codec2/core/include/C2Config.h b/media/codec2/core/include/C2Config.h
index 9a3399d..785cdf2 100644
--- a/media/codec2/core/include/C2Config.h
+++ b/media/codec2/core/include/C2Config.h
@@ -160,6 +160,10 @@
kParamIndexSecureMode,
kParamIndexEncryptedBuffer, // info-buffer, used with SM_READ_PROTECTED_WITH_ENCRYPTED
+ /* multiple access unit support */
+ kParamIndexLargeFrame,
+ kParamIndexAccessUnitInfos, // struct
+
// deprecated
kParamIndexDelayRequest = kParamIndexDelay | C2Param::CoreIndex::IS_REQUEST_FLAG,
@@ -1114,6 +1118,36 @@
constexpr char C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE[] = "input.buffers.max-size";
constexpr char C2_PARAMKEY_OUTPUT_MAX_BUFFER_SIZE[] = "output.buffers.max-size";
+/**
+ * Large frame struct
+ *
+ * This structure describes the size limits for large frames (frames with multiple
+ * access units.)
+ */
+struct C2LargeFrameStruct {
+ uint32_t maxSize; ///< maximum size of the buffer in bytes
+ uint32_t thresholdSize; ///< size threshold for the buffer in bytes. The buffer is considered
+ ///< full as soon as its size reaches or surpasses this limit.
+ C2LargeFrameStruct()
+ : maxSize(0),
+ thresholdSize(0) {}
+
+ C2LargeFrameStruct(uint32_t maxSize_, uint32_t thresholdSize_)
+ : maxSize(maxSize_), thresholdSize(thresholdSize_) {}
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(LargeFrame)
+ C2FIELD(maxSize, "max-size")
+ C2FIELD(thresholdSize, "threshold-size")
+};
+
+/**
+ * This tuning controls the size limits for large output frames for the component.
+ * The default value for this tuning is platform specific.
+ */
+typedef C2StreamParam<C2Tuning, C2LargeFrameStruct, kParamIndexLargeFrame>
+ C2LargeFrame;
+constexpr char C2_PARAMKEY_OUTPUT_LARGE_FRAME[] = "output.large-frame";
+
/* ---------------------------------------- misc. state ---------------------------------------- */
/**
@@ -2146,6 +2180,49 @@
C2StreamAudioFrameSizeInfo;
constexpr char C2_PARAMKEY_AUDIO_FRAME_SIZE[] = "raw.audio-frame-size";
+/**
+ * Information for an access unit in a large frame (containing multiple access units)
+ */
+struct C2AccessUnitInfosStruct {
+
+ inline C2AccessUnitInfosStruct() {
+ memset(this, 0, sizeof(*this));
+ }
+
+ inline C2AccessUnitInfosStruct(
+ uint32_t flags_,
+ uint32_t size_,
+ int64_t timestamp_)
+ : flags(flags_),
+ size(size_),
+ timestamp(timestamp_) { }
+
+ uint32_t flags; ///<flags for the access-unit
+ uint32_t size; ///<size of access-unit
+ int64_t timestamp; ///<timestamp in us for the access-unit
+
+ DEFINE_AND_DESCRIBE_C2STRUCT(AccessUnitInfos)
+ C2FIELD(flags, "flags")
+ C2FIELD(size, "size")
+ C2FIELD(timestamp, "timestamp")
+};
+
+/**
+ * Multiple access unit support (e.g large audio frames)
+ *
+ * If supported by a component, multiple access units may be contained
+ * in a single work item. For now this is only defined for linear buffers.
+ * The metadata indicates the access-unit boundaries in a single buffer.
+ * The boundary of each access-units are marked by its size, immediately
+ * followed by the next access-unit.
+ */
+typedef C2StreamParam<C2Info, C2SimpleArrayStruct<C2AccessUnitInfosStruct>,
+ kParamIndexAccessUnitInfos>
+ C2AccessUnitInfos;
+
+constexpr char C2_PARAMKEY_INPUT_ACCESS_UNIT_INFOS[] = "input.access-unit-infos";
+constexpr char C2_PARAMKEY_OUTPUT_ACCESS_UNIT_INFOS[] = "output.access-unit-infos";
+
/* --------------------------------------- AAC components --------------------------------------- */
/**
diff --git a/media/codec2/core/include/C2ParamDef.h b/media/codec2/core/include/C2ParamDef.h
index d578820..86dfe65 100644
--- a/media/codec2/core/include/C2ParamDef.h
+++ b/media/codec2/core/include/C2ParamDef.h
@@ -404,6 +404,7 @@
/// Specialization for an input port parameter.
struct input : public T, public S,
public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+ using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Wrapper around base structure's constructor.
template<typename ...Args>
@@ -416,6 +417,7 @@
/// Specialization for an output port parameter.
struct output : public T, public S,
public _C2StructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+ using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Wrapper around base structure's constructor.
template<typename ...Args>
@@ -470,6 +472,7 @@
/// Specialization for an input port parameter.
struct input : public T,
public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_INPUT> {
+ using T::operator!=;
private:
/// Wrapper around base structure's constructor while also specifying port/direction.
template<typename ...Args>
@@ -486,6 +489,7 @@
/// Specialization for an output port parameter.
struct output : public T,
public _C2FlexStructCheck<S, ParamIndex, T::PARAM_KIND | T::Index::DIR_OUTPUT> {
+ using T::operator!=;
private:
/// Wrapper around base structure's constructor while also specifying port/direction.
template<typename ...Args>
@@ -549,6 +553,7 @@
struct input : public T, public S,
public _C2StructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
+ using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Default constructor. Stream-ID is undefined.
@@ -567,6 +572,7 @@
struct output : public T, public S,
public _C2StructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
+ using T::operator!=;
_C2_CORE_INDEX_OVERRIDE(ParamIndex)
/// Default constructor. Stream-ID is undefined.
@@ -634,6 +640,7 @@
struct input : public T,
public _C2FlexStructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_INPUT> {
+ using T::operator!=;
private:
/// Default constructor. Stream-ID is undefined.
inline input(size_t flexCount) : T(_Type::CalcSize(flexCount), input::PARAM_TYPE) { }
@@ -656,6 +663,7 @@
struct output : public T,
public _C2FlexStructCheck<S, ParamIndex,
T::PARAM_KIND | T::Index::IS_STREAM_FLAG | T::Type::DIR_OUTPUT> {
+ using T::operator!=;
private:
/// Default constructor. Stream-ID is undefined.
inline output(size_t flexCount) : T(_Type::CalcSize(flexCount), output::PARAM_TYPE) { }
diff --git a/media/codec2/hal/aidl/Android.bp b/media/codec2/hal/aidl/Android.bp
index 7a9af18..48b6e21 100644
--- a/media/codec2/hal/aidl/Android.bp
+++ b/media/codec2/hal/aidl/Android.bp
@@ -24,7 +24,7 @@
shared_libs: [
"android.hardware.common-V2-ndk",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbinder_ndk",
"libbase",
@@ -84,7 +84,7 @@
shared_libs: [
"android.hardware.common-V2-ndk",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder_ndk",
diff --git a/media/codec2/hal/aidl/BufferTypes.cpp b/media/codec2/hal/aidl/BufferTypes.cpp
index bc4948b..a0e6aa5 100644
--- a/media/codec2/hal/aidl/BufferTypes.cpp
+++ b/media/codec2/hal/aidl/BufferTypes.cpp
@@ -302,7 +302,7 @@
"invalid receiver connection id (0).";
return bufferpool2::ResultStatus::CRITICAL_ERROR;
} else {
- if (isNewConnection) {
+ if (foundConnection == mConnections.end()) {
foundConnection = mConnections.try_emplace(
connectionId, receiverConnectionId, now).first;
} else {
diff --git a/media/codec2/hal/aidl/Component.cpp b/media/codec2/hal/aidl/Component.cpp
index 4605af3..bdc560f 100644
--- a/media/codec2/hal/aidl/Component.cpp
+++ b/media/codec2/hal/aidl/Component.cpp
@@ -289,30 +289,22 @@
const IComponent::BlockPoolAllocator &allocator,
IComponent::BlockPool *blockPool) {
std::shared_ptr<C2BlockPool> c2BlockPool;
- static constexpr IComponent::BlockPoolAllocator::Tag ALLOCATOR_ID =
- IComponent::BlockPoolAllocator::allocatorId;
- static constexpr IComponent::BlockPoolAllocator::Tag IGBA =
- IComponent::BlockPoolAllocator::allocator;
c2_status_t status = C2_OK;
::android::C2PlatformAllocatorDesc allocatorParam;
- switch (allocator.getTag()) {
- case ALLOCATOR_ID: {
- allocatorParam.allocatorId =
- allocator.get<IComponent::BlockPoolAllocator::allocatorId>();
- }
- break;
- case IGBA: {
- allocatorParam.allocatorId = ::android::C2PlatformAllocatorStore::IGBA;
- allocatorParam.igba =
- allocator.get<IComponent::BlockPoolAllocator::allocator>().igba;
+ allocatorParam.allocatorId = allocator.allocatorId;
+ switch (allocator.allocatorId) {
+ case ::android::C2PlatformAllocatorStore::IGBA: {
+ allocatorParam.igba = allocator.gbAllocator->igba;
allocatorParam.waitableFd.reset(
- allocator.get<IComponent::BlockPoolAllocator::allocator>()
- .waitableFd.dup().release());
+ allocator.gbAllocator->waitableFd.dup().release());
}
break;
- default:
- return ScopedAStatus::fromServiceSpecificError(C2_CORRUPTED);
+ default: {
+ // no-op
+ }
+ break;
}
+
#ifdef __ANDROID_APEX__
status = ::android::CreateCodec2BlockPool(
allocatorParam,
@@ -403,6 +395,22 @@
return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
}
+ScopedAStatus Component::connectToInputSurface(
+ const std::shared_ptr<IInputSurface>& inputSurface,
+ std::shared_ptr<IInputSurfaceConnection> *connection) {
+ // TODO
+ (void)inputSurface;
+ (void)connection;
+ return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
+ScopedAStatus Component::asInputSink(
+ std::shared_ptr<IInputSink> *sink) {
+ // TODO
+ (void)sink;
+ return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
void Component::initListener(const std::shared_ptr<Component>& self) {
if (__builtin_available(android __ANDROID_API_T__, *)) {
std::shared_ptr<C2Component::Listener> c2listener =
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index 58407d1..f0a1490 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -273,6 +273,13 @@
return ScopedAStatus::ok();
}
+ScopedAStatus ComponentStore::createInputSurface(
+ std::shared_ptr<IInputSurface> *inputSurface) {
+ // TODO
+ (void)inputSurface;
+ return ScopedAStatus::fromServiceSpecificError(Status::OMITTED);
+}
+
void ComponentStore::onInterfaceLoaded(const std::shared_ptr<C2ComponentInterface> &intf) {
// invalidate unsupported struct descriptors if a new interface is loaded as it may have
// exposed new descriptors
diff --git a/media/codec2/hal/aidl/Configurable.cpp b/media/codec2/hal/aidl/Configurable.cpp
index 0326263..2daaac2 100644
--- a/media/codec2/hal/aidl/Configurable.cpp
+++ b/media/codec2/hal/aidl/Configurable.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
+#include <android-base/hex.h>
#include <codec2/aidl/Configurable.h>
#include <codec2/aidl/ParamTypes.h>
@@ -61,7 +62,7 @@
ScopedAStatus CachedConfigurable::query(
const std::vector<int32_t>& indices,
bool mayBlock,
- Params* params) {
+ QueryResult *queryResult) {
typedef C2Param::Index Index;
std::vector<Index> c2heapParamIndices(
(Index*)indices.data(),
@@ -72,13 +73,11 @@
mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK,
&c2heapParams);
- if (!CreateParamsBlob(params, c2heapParams)) {
+ if (!CreateParamsBlob(&(queryResult->params), c2heapParams)) {
LOG(WARNING) << "query -- invalid output params.";
}
- if (c2res == C2_OK) {
- return ScopedAStatus::ok();
- }
- return ScopedAStatus::fromServiceSpecificError(c2res);
+ queryResult->status.status = c2res;
+ return ScopedAStatus::ok();
}
ScopedAStatus CachedConfigurable::config(
@@ -115,10 +114,8 @@
if (!CreateParamsBlob(&result->params, c2params)) {
LOG(DEBUG) << "config -- invalid output params.";
}
- if (c2res == C2_OK) {
- return ScopedAStatus::ok();
- }
- return ScopedAStatus::fromServiceSpecificError(c2res);
+ result->status.status = c2res;
+ return ScopedAStatus::ok();
}
ScopedAStatus CachedConfigurable::querySupportedParams(
@@ -139,8 +136,6 @@
LOG(WARNING) << "querySupportedParams -- invalid output params.";
break;
}
- } else {
- res = Status::BAD_INDEX;
}
}
paramDesc->resize(dstIx);
@@ -153,7 +148,7 @@
ScopedAStatus CachedConfigurable::querySupportedValues(
const std::vector<FieldSupportedValuesQuery>& fields,
bool mayBlock,
- std::vector<FieldSupportedValuesQueryResult>* result) {
+ QuerySupportedValuesResult *queryValues) {
std::vector<C2FieldSupportedValuesQuery> c2fields;
{
// C2FieldSupportedValuesQuery objects are restricted in that some
@@ -173,22 +168,20 @@
c2_status_t c2res = mIntf->querySupportedValues(
c2fields,
mayBlock ? C2_MAY_BLOCK : C2_DONT_BLOCK);
- result->resize(fields.size());
+ queryValues->values.resize(fields.size());
size_t dstIx = 0;
for (const C2FieldSupportedValuesQuery &res : c2fields) {
- if (ToAidl(&(*result)[dstIx], res)) {
+ if (ToAidl(&(queryValues->values[dstIx]), res)) {
++dstIx;
} else {
- result->resize(dstIx);
+ queryValues->values.resize(dstIx);
c2res = C2_CORRUPTED;
LOG(WARNING) << "querySupportedValues -- invalid output params.";
break;
}
}
- if (c2res == C2_OK) {
- return ScopedAStatus::ok();
- }
- return ScopedAStatus::fromServiceSpecificError(c2res);
+ queryValues->status.status = c2res;
+ return ScopedAStatus::ok();
}
} // namespace utils
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Component.h b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
index 4a090e9..94b760f 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/Component.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Component.h
@@ -27,6 +27,9 @@
#include <aidl/android/hardware/media/c2/IComponentInterface.h>
#include <aidl/android/hardware/media/c2/IComponentListener.h>
#include <aidl/android/hardware/media/c2/IComponentStore.h>
+#include <aidl/android/hardware/media/c2/IInputSink.h>
+#include <aidl/android/hardware/media/c2/IInputSurface.h>
+#include <aidl/android/hardware/media/c2/IInputSurfaceConnection.h>
#include <C2Component.h>
#include <C2Buffer.h>
@@ -71,6 +74,11 @@
::ndk::ScopedAStatus configureVideoTunnel(
int32_t avSyncHwId,
common::NativeHandle* handle) override;
+ ::ndk::ScopedAStatus connectToInputSurface(
+ const std::shared_ptr<IInputSurface>& inputSurface,
+ std::shared_ptr<IInputSurfaceConnection> *connection) override;
+ ::ndk::ScopedAStatus asInputSink(
+ std::shared_ptr<IInputSink> *sink) override;
protected:
c2_status_t mInit;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index b3c97d5..0698b0f 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -23,6 +23,7 @@
#include <aidl/android/hardware/media/bufferpool2/IClientManager.h>
#include <aidl/android/hardware/media/c2/BnComponentStore.h>
+#include <aidl/android/hardware/media/c2/IInputSurface.h>
#include <C2Component.h>
#include <C2Param.h>
@@ -85,6 +86,8 @@
std::shared_ptr<IComponentInterface> *intf) override;
virtual ::ndk::ScopedAStatus listComponents(
std::vector<IComponentStore::ComponentTraits>* traits) override;
+ virtual ::ndk::ScopedAStatus createInputSurface(
+ std::shared_ptr<IInputSurface> *inputSurface) override;
virtual ::ndk::ScopedAStatus getStructDescriptors(
const std::vector<int32_t>& indices,
std::vector<StructDescriptor> *descs) override;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
index 6cc2c1b..96d3516 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/Configurable.h
@@ -111,7 +111,7 @@
virtual ::ndk::ScopedAStatus query(
const std::vector<int32_t>& indices,
bool mayBlock,
- Params* params) override;
+ QueryResult* result) override;
virtual ::ndk::ScopedAStatus config(
const ::aidl::android::hardware::media::c2::Params& params,
@@ -126,7 +126,7 @@
virtual ::ndk::ScopedAStatus querySupportedValues(
const std::vector<FieldSupportedValuesQuery>& fields,
bool mayBlock,
- std::vector<FieldSupportedValuesQueryResult>* result) override;
+ QuerySupportedValuesResult* result) override;
protected:
// Common Codec2.0 interface wrapper
diff --git a/media/codec2/hal/client/Android.bp b/media/codec2/hal/client/Android.bp
index 0b5b940..af6f4ae 100644
--- a/media/codec2/hal/client/Android.bp
+++ b/media/codec2/hal/client/Android.bp
@@ -43,7 +43,7 @@
"android.hardware.media.c2@1.0",
"android.hardware.media.c2@1.1",
"android.hardware.media.c2@1.2",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder",
diff --git a/media/codec2/hal/client/GraphicsTracker.cpp b/media/codec2/hal/client/GraphicsTracker.cpp
index 0848fc6..01b0678 100644
--- a/media/codec2/hal/client/GraphicsTracker.cpp
+++ b/media/codec2/hal/client/GraphicsTracker.cpp
@@ -174,20 +174,16 @@
GraphicsTracker::GraphicsTracker(int maxDequeueCount)
: mBufferCache(new BufferCache()), mMaxDequeue{maxDequeueCount},
- mMaxDequeueRequested{maxDequeueCount},
mMaxDequeueCommitted{maxDequeueCount},
- mMaxDequeueRequestedSeqId{0UL}, mMaxDequeueCommittedSeqId{0ULL},
mDequeueable{maxDequeueCount},
mTotalDequeued{0}, mTotalCancelled{0}, mTotalDropped{0}, mTotalReleased{0},
mInConfig{false}, mStopped{false} {
if (maxDequeueCount < kMaxDequeueMin) {
mMaxDequeue = kMaxDequeueMin;
- mMaxDequeueRequested = kMaxDequeueMin;
mMaxDequeueCommitted = kMaxDequeueMin;
mDequeueable = kMaxDequeueMin;
} else if(maxDequeueCount > kMaxDequeueMax) {
mMaxDequeue = kMaxDequeueMax;
- mMaxDequeueRequested = kMaxDequeueMax;
mMaxDequeueCommitted = kMaxDequeueMax;
mDequeueable = kMaxDequeueMax;
}
@@ -197,34 +193,36 @@
mReadPipeFd.reset(pipefd[0]);
mWritePipeFd.reset(pipefd[1]);
- mEventQueueThread = std::thread([this](){processEvent();});
- writeIncDequeueable(mDequeueable);
+ // ctor does not require lock to be held.
+ writeIncDequeueableLocked(mDequeueable);
CHECK(ret >= 0);
- CHECK(mEventQueueThread.joinable());
}
GraphicsTracker::~GraphicsTracker() {
stop();
- if (mEventQueueThread.joinable()) {
- mEventQueueThread.join();
- }
}
bool GraphicsTracker::adjustDequeueConfLocked(bool *updateDequeue) {
// TODO: can't we adjust during config? not committing it may safe?
*updateDequeue = false;
- if (!mInConfig && mMaxDequeueRequested < mMaxDequeue) {
- int delta = mMaxDequeue - mMaxDequeueRequested;
+ if (!mInConfig && mMaxDequeueRequested.has_value() && mMaxDequeueRequested < mMaxDequeue) {
+ int delta = mMaxDequeue - mMaxDequeueRequested.value();
+ int drained = 0;
// Since we are supposed to increase mDequeuable by one already
int adjustable = mDequeueable + 1;
if (adjustable >= delta) {
- mMaxDequeue = mMaxDequeueRequested;
+ mMaxDequeue = mMaxDequeueRequested.value();
mDequeueable -= (delta - 1);
+ drained = delta - 1;
} else {
mMaxDequeue -= adjustable;
+ drained = mDequeueable;
mDequeueable = 0;
}
+ if (drained > 0) {
+ drainDequeueableLocked(drained);
+ }
if (mMaxDequeueRequested == mMaxDequeue && mMaxDequeueRequested != mMaxDequeueCommitted) {
*updateDequeue = true;
}
@@ -235,6 +233,7 @@
c2_status_t GraphicsTracker::configureGraphics(
const sp<IGraphicBufferProducer>& igbp, uint32_t generation) {
+ // TODO: wait until operations to previous IGBP is completed.
std::shared_ptr<BufferCache> prevCache;
int prevDequeueCommitted;
@@ -254,14 +253,28 @@
if (igbp) {
ret = igbp->getUniqueId(&bqId);
}
- if (ret != ::android::OK || prevCache->mGeneration == generation || prevCache->mBqId == bqId) {
+ if (ret != ::android::OK ||
+ prevCache->mGeneration == generation) {
+ ALOGE("new surface configure fail due to wrong or same bqId or same generation:"
+ "igbp(%d:%llu -> %llu), gen(%lu -> %lu)", (bool)igbp,
+ (unsigned long long)prevCache->mBqId, (unsigned long long)bqId,
+ (unsigned long)prevCache->mGeneration, (unsigned long)generation);
+ std::unique_lock<std::mutex> l(mLock);
+ mInConfig = false;
return C2_BAD_VALUE;
}
- ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
- if (ret != ::android::OK) {
- // TODO: sort out the error from igbp and return an error accordingly.
- return C2_CORRUPTED;
+ if (igbp) {
+ ret = igbp->setMaxDequeuedBufferCount(prevDequeueCommitted);
+ if (ret != ::android::OK) {
+ ALOGE("new surface maxDequeueBufferCount configure fail");
+ // TODO: sort out the error from igbp and return an error accordingly.
+ std::unique_lock<std::mutex> l(mLock);
+ mInConfig = false;
+ return C2_CORRUPTED;
+ }
}
+ ALOGD("new surface configured with id:%llu gen:%lu maxDequeue:%d",
+ (unsigned long long)bqId, (unsigned long)generation, prevDequeueCommitted);
std::shared_ptr<BufferCache> newCache = std::make_shared<BufferCache>(bqId, generation, igbp);
{
std::unique_lock<std::mutex> l(mLock);
@@ -283,59 +296,74 @@
// (Sometimes maxDequeueCount cannot be committed if the number of
// dequeued buffer count is bigger.)
int maxDequeueToCommit;
- // max dequeue count which is committed to IGBP currently
- // (actually mMaxDequeueCommitted, but needs to be read outside lock.)
- int curMaxDequeueCommitted;
std::unique_lock<std::mutex> cl(mConfigLock);
{
std::unique_lock<std::mutex> l(mLock);
- if (mMaxDequeueRequested == maxDequeueCount) {
+ if (mMaxDequeueRequested.has_value()) {
+ if (mMaxDequeueRequested == maxDequeueCount) {
+ ALOGD("maxDequeueCount requested with %d already", maxDequeueCount);
+ return C2_OK;
+ }
+ } else if (mMaxDequeue == maxDequeueCount) {
+ ALOGD("maxDequeueCount is already %d", maxDequeueCount);
return C2_OK;
}
mInConfig = true;
mMaxDequeueRequested = maxDequeueCount;
cache = mBufferCache;
- curMaxDequeueCommitted = mMaxDequeueCommitted;
if (mMaxDequeue <= maxDequeueCount) {
maxDequeueToCommit = maxDequeueCount;
} else {
// Since mDequeuable is decreasing,
// a delievered ready to allocate event may not be fulfilled.
// Another waiting via a waitable object may be necessary in the case.
- int delta = mMaxDequeue - maxDequeueCount;
- if (delta <= mDequeueable) {
- maxDequeueToCommit = maxDequeueCount;
- mDequeueable -= delta;
- } else {
- maxDequeueToCommit = mMaxDequeue - mDequeueable;
- mDequeueable = 0;
+ int delta = std::min(mMaxDequeue - maxDequeueCount, mDequeueable);
+ maxDequeueToCommit = mMaxDequeue - delta;
+ mDequeueable -= delta;
+ if (delta > 0) {
+ drainDequeueableLocked(delta);
}
}
}
bool committed = true;
- if (cache->mIgbp && maxDequeueToCommit != curMaxDequeueCommitted) {
+ if (cache->mIgbp && maxDequeueToCommit != mMaxDequeueCommitted) {
::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(maxDequeueToCommit);
committed = (ret == ::android::OK);
- if (!committed) {
+ if (committed) {
+ ALOGD("maxDequeueCount committed to IGBP: %d", maxDequeueToCommit);
+ } else {
// This should not happen.
- ALOGE("dequeueCount failed with error(%d)", (int)ret);
+ ALOGE("maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
}
}
+ int oldMaxDequeue = 0;
+ int requested = 0;
{
std::unique_lock<std::mutex> l(mLock);
mInConfig = false;
+ oldMaxDequeue = mMaxDequeue;
+ mMaxDequeue = maxDequeueToCommit; // we already drained dequeueable
if (committed) {
+ clearCacheIfNecessaryLocked(cache, maxDequeueToCommit);
mMaxDequeueCommitted = maxDequeueToCommit;
- int delta = mMaxDequeueCommitted - mMaxDequeue;
+ if (mMaxDequeueRequested == mMaxDequeueCommitted &&
+ mMaxDequeueRequested == mMaxDequeue) {
+ mMaxDequeueRequested.reset();
+ }
+ if (mMaxDequeueRequested.has_value()) {
+ requested = mMaxDequeueRequested.value();
+ }
+ int delta = mMaxDequeueCommitted - oldMaxDequeue;
if (delta > 0) {
mDequeueable += delta;
- l.unlock();
- writeIncDequeueable(delta);
+ writeIncDequeueableLocked(delta);
}
}
}
+ ALOGD("maxDqueueCount change %d -> %d: pending: %d",
+ oldMaxDequeue, maxDequeueToCommit, requested);
if (!committed) {
return C2_CORRUPTED;
@@ -350,48 +378,60 @@
std::unique_lock<std::mutex> cl(mConfigLock);
{
std::unique_lock<std::mutex> l(mLock);
- if (mMaxDequeue == mMaxDequeueRequested && mMaxDequeueCommitted != mMaxDequeueRequested) {
- dequeueCommit = mMaxDequeue;
- mInConfig = true;
- cache = mBufferCache;
- } else {
+ if (!mMaxDequeueRequested.has_value() || mMaxDequeue != mMaxDequeueRequested) {
return;
}
+ if (mMaxDequeueCommitted == mMaxDequeueRequested) {
+ // already committed. may not happen.
+ mMaxDequeueRequested.reset();
+ return;
+ }
+ dequeueCommit = mMaxDequeue;
+ mInConfig = true;
+ cache = mBufferCache;
}
bool committed = true;
if (cache->mIgbp) {
::android::status_t ret = cache->mIgbp->setMaxDequeuedBufferCount(dequeueCommit);
committed = (ret == ::android::OK);
- if (!committed) {
+ if (committed) {
+ ALOGD("delayed maxDequeueCount update to IGBP: %d", dequeueCommit);
+ } else {
// This should not happen.
- ALOGE("dequeueCount failed with error(%d)", (int)ret);
+ ALOGE("delayed maxdequeueCount update to IGBP failed with error(%d)", (int)ret);
}
}
- int cleared = 0;
{
// cache == mCache here, since we locked config.
std::unique_lock<std::mutex> l(mLock);
mInConfig = false;
if (committed) {
- if (cache->mIgbp && dequeueCommit < mMaxDequeueCommitted) {
- // we are shrinking # of buffers, so clearing the cache.
- for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
- uint64_t bid = it->second->mId;
- if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
- ++cleared;
- it = cache->mBuffers.erase(it);
- } else {
- ++it;
- }
- }
- }
+ clearCacheIfNecessaryLocked(cache, dequeueCommit);
mMaxDequeueCommitted = dequeueCommit;
}
+ mMaxDequeueRequested.reset();
}
- if (cleared > 0) {
- ALOGD("%d buffers are cleared from cache, due to IGBP capacity change", cleared);
- }
+}
+void GraphicsTracker::clearCacheIfNecessaryLocked(const std::shared_ptr<BufferCache> &cache,
+ int maxDequeueCommitted) {
+ int cleared = 0;
+ size_t origCacheSize = cache->mBuffers.size();
+ if (cache->mIgbp && maxDequeueCommitted < mMaxDequeueCommitted) {
+ // we are shrinking # of buffers in the case, so evict the previous
+ // cached buffers.
+ for (auto it = cache->mBuffers.begin(); it != cache->mBuffers.end();) {
+ uint64_t bid = it->second->mId;
+ if (mDequeued.count(bid) == 0 || mDeallocating.count(bid) > 0) {
+ ++cleared;
+ it = cache->mBuffers.erase(it);
+ } else {
+ ++it;
+ }
+ }
+ }
+ ALOGD("Cache size %zu -> %zu: maybe_cleared(%d), dequeued(%zu)",
+ origCacheSize, cache->mBuffers.size(), cleared, mDequeued.size());
}
int GraphicsTracker::getCurDequeueable() {
@@ -400,70 +440,58 @@
}
void GraphicsTracker::stop() {
- bool expected = false;
- std::unique_lock<std::mutex> l(mEventLock);
- bool updated = mStopped.compare_exchange_strong(expected, true);
- if (updated) {
- int writeFd = mWritePipeFd.release();
+ // TODO: wait until all operation to current IGBP
+ // being completed.
+ std::unique_lock<std::mutex> l(mLock);
+ if (mStopped) {
+ return;
+ }
+ mStopped = true;
+ int writeFd = mWritePipeFd.release();
+ if (writeFd >= 0) {
::close(writeFd);
- int readFd = mReadPipeFd.release();
- ::close(readFd);
- mEventCv.notify_one();
}
}
-void GraphicsTracker::writeIncDequeueable(int inc) {
+void GraphicsTracker::writeIncDequeueableLocked(int inc) {
CHECK(inc > 0 && inc < kMaxDequeueMax);
thread_local char buf[kMaxDequeueMax];
- int diff = 0;
- {
- std::unique_lock<std::mutex> l(mEventLock);
- if (mStopped) {
- return;
- }
- CHECK(mWritePipeFd.get() >= 0);
- int ret = ::write(mWritePipeFd.get(), buf, inc);
- if (ret == inc) {
- return;
- }
- diff = ret < 0 ? inc : inc - ret;
-
- // Partial write or EINTR. This will not happen in a real scenario.
- mIncDequeueable += diff;
- if (mIncDequeueable > 0) {
- l.unlock();
- mEventCv.notify_one();
- ALOGW("updating dequeueable to pipefd pending");
- }
+ if (mStopped) { // reading end closed;
+ return;
}
+ int writeFd = mWritePipeFd.get();
+ if (writeFd < 0) {
+ // initialization fail and not valid though.
+ return;
+ }
+ int ret = ::write(writeFd, buf, inc);
+ // Since this is non-blocking i/o, it never returns EINTR.
+ //
+ // ::write() to pipe guarantee to succeed atomically if it writes less than
+ // the given PIPE_BUF. And the buffer size in pipe/fifo is at least 4K and our total
+ // max pending buffer size is 64. So it never returns EAGAIN here either.
+ // See pipe(7) for further information.
+ //
+ // Other errors are serious errors and we cannot synchronize mDequeueable to
+ // length of pending buffer in pipe/fifo anymore. So better to abort here.
+ // TODO: do not abort here. (b/318717399)
+ CHECK(ret == inc);
}
-void GraphicsTracker::processEvent() {
- // This is for partial/failed writes to the writing end.
- // This may not happen in the real scenario.
+void GraphicsTracker::drainDequeueableLocked(int dec) {
+ CHECK(dec > 0 && dec < kMaxDequeueMax);
thread_local char buf[kMaxDequeueMax];
- while (true) {
- std::unique_lock<std::mutex> l(mEventLock);
- if (mStopped) {
- break;
- }
- if (mIncDequeueable > 0) {
- int inc = mIncDequeueable > kMaxDequeueMax ? kMaxDequeueMax : mIncDequeueable;
- int ret = ::write(mWritePipeFd.get(), buf, inc);
- int written = ret <= 0 ? 0 : ret;
- mIncDequeueable -= written;
- if (mIncDequeueable > 0) {
- l.unlock();
- if (ret < 0) {
- ALOGE("write to writing end failed %d", errno);
- } else {
- ALOGW("partial write %d(%d)", inc, written);
- }
- continue;
- }
- }
- mEventCv.wait(l);
+ if (mStopped) {
+ return;
}
+ int readFd = mReadPipeFd.get();
+ if (readFd < 0) {
+ // initializationf fail and not valid though.
+ return;
+ }
+ int ret = ::read(readFd, buf, dec);
+ // TODO: no dot abort here. (b/318717399)
+ CHECK(ret == dec);
}
c2_status_t GraphicsTracker::getWaitableFd(int *pipeFd) {
@@ -539,8 +567,7 @@
return;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
}
@@ -715,14 +742,13 @@
return C2_OK;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
return C2_OK;
}
void GraphicsTracker::commitDeallocate(
- std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid) {
+ std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid, bool *updateDequeue) {
std::unique_lock<std::mutex> l(mLock);
size_t del1 = mDequeued.erase(bid);
size_t del2 = mDeallocating.erase(bid);
@@ -730,9 +756,11 @@
if (cache) {
cache->unblockSlot(slotId);
}
+ if (adjustDequeueConfLocked(updateDequeue)) {
+ return;
+ }
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
@@ -758,7 +786,10 @@
// cache->mIgbp is not null, if completed is false.
(void)cache->mIgbp->cancelBuffer(slotId, rFence);
- commitDeallocate(cache, slotId, bid);
+ commitDeallocate(cache, slotId, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_OK;
}
@@ -785,8 +816,7 @@
return C2_BAD_STATE;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
return C2_BAD_STATE;
}
std::shared_ptr<BufferItem> buffer = it->second;
@@ -828,8 +858,7 @@
return;
}
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
return;
}
}
@@ -843,6 +872,9 @@
ALOGE("retrieving AHB-ID for GraphicBlock failed");
return C2_CORRUPTED;
}
+ std::shared_ptr<_C2BlockPoolData> poolData =
+ _C2BlockFactory::GetGraphicBlockPoolData(blk);
+ _C2BlockFactory::DisownIgbaBlock(poolData);
std::shared_ptr<BufferCache> cache;
std::shared_ptr<BufferItem> buffer;
std::shared_ptr<BufferItem> oldBuffer;
@@ -870,13 +902,19 @@
if (!gb) {
ALOGE("render: realloc-ing a new buffer for migration failed");
std::shared_ptr<BufferCache> nullCache;
- commitDeallocate(nullCache, -1, bid);
+ commitDeallocate(nullCache, -1, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
if (cache->mIgbp->attachBuffer(&(newBuffer->mSlot), gb) != ::android::OK) {
ALOGE("render: attaching a new buffer to IGBP failed");
std::shared_ptr<BufferCache> nullCache;
- commitDeallocate(nullCache, -1, bid);
+ commitDeallocate(nullCache, -1, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
cache->waitOnSlot(newBuffer->mSlot);
@@ -890,11 +928,13 @@
CHECK(renderRes != ::android::BAD_VALUE);
ALOGE("render: failed to queueBuffer() err = %d", renderRes);
(void) cache->mIgbp->cancelBuffer(buffer->mSlot, input.fence);
- commitDeallocate(cache, buffer->mSlot, bid);
+ commitDeallocate(cache, buffer->mSlot, bid, &updateDequeue);
+ if (updateDequeue) {
+ updateDequeueConf();
+ }
return C2_REFUSED;
}
- updateDequeue = false;
commitRender(cache, buffer, oldBuffer, output->bufferReplaced, &updateDequeue);
if (updateDequeue) {
updateDequeueConf();
@@ -909,8 +949,7 @@
if (mBufferCache->mGeneration == generation) {
if (!adjustDequeueConfLocked(&updateDequeue)) {
mDequeueable++;
- l.unlock();
- writeIncDequeueable(1);
+ writeIncDequeueableLocked(1);
}
}
}
diff --git a/media/codec2/hal/client/client.cpp b/media/codec2/hal/client/client.cpp
index 2d19ecc..9ed9458 100644
--- a/media/codec2/hal/client/client.cpp
+++ b/media/codec2/hal/client/client.cpp
@@ -635,21 +635,22 @@
if (heapParams) {
heapParams->reserve(heapParams->size() + numIndices);
}
- c2_aidl::Params result;
+ c2_aidl::IConfigurable::QueryResult result;
ndk::ScopedAStatus transStatus = mBase->query(indices, (mayBlock == C2_MAY_BLOCK), &result);
c2_status_t status = GetC2Status(transStatus, "query");
if (status != C2_OK) {
return status;
}
+ status = static_cast<c2_status_t>(result.status.status);
std::vector<C2Param*> paramPointers;
- if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, result)) {
+ if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, result.params)) {
LOG(ERROR) << "query -- error while parsing params.";
return C2_CORRUPTED;
}
size_t i = 0;
- for (auto it = paramPointers.begin();
- it != paramPointers.end(); ) {
+ size_t numUpdatedStackParams = 0;
+ for (auto it = paramPointers.begin(); it != paramPointers.end(); ) {
C2Param* paramPointer = *it;
if (numStackIndices > 0) {
--numStackIndices;
@@ -676,7 +677,9 @@
status = C2_BAD_INDEX;
continue;
}
- if (!stackParams[i++]->updateFrom(*paramPointer)) {
+ if (stackParams[i++]->updateFrom(*paramPointer)) {
+ ++numUpdatedStackParams;
+ } else {
LOG(WARNING) << "query -- param update failed: "
"index = "
<< paramPointer->index() << ".";
@@ -696,6 +699,13 @@
}
++it;
}
+ size_t numQueried = numUpdatedStackParams;
+ if (heapParams) {
+ numQueried += heapParams->size();
+ }
+ if (status == C2_OK && indices.size() != numQueried) {
+ status = C2_BAD_INDEX;
+ }
return status;
}
@@ -714,6 +724,7 @@
if (status != C2_OK) {
return status;
}
+ status = static_cast<c2_status_t>(result.status.status);
size_t i = failures->size();
failures->resize(i + result.failures.size());
for (const c2_aidl::SettingResult& sf : result.failures) {
@@ -764,21 +775,23 @@
}
}
- std::vector<c2_aidl::FieldSupportedValuesQueryResult> result;
+ c2_aidl::IConfigurable::QuerySupportedValuesResult result;
+
ndk::ScopedAStatus transStatus = mBase->querySupportedValues(
inFields, (mayBlock == C2_MAY_BLOCK), &result);
c2_status_t status = GetC2Status(transStatus, "querySupportedValues");
if (status != C2_OK) {
return status;
}
- if (result.size() != fields.size()) {
+ status = static_cast<c2_status_t>(result.status.status);
+ if (result.values.size() != fields.size()) {
LOG(ERROR) << "querySupportedValues -- "
"input and output lists "
"have different sizes.";
return C2_CORRUPTED;
}
for (size_t i = 0; i < fields.size(); ++i) {
- if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result[i])) {
+ if (!c2_aidl::utils::FromAidl(&fields[i], inFields[i], result.values[i])) {
LOG(ERROR) << "querySupportedValues -- "
"invalid returned value.";
return C2_CORRUPTED;
@@ -2059,6 +2072,8 @@
id = id == C2PlatformAllocatorStore::BUFFERQUEUE ?
C2PlatformAllocatorStore::IGBA : id;
+ c2_aidl::IComponent::BlockPoolAllocator allocator;
+ allocator.allocatorId = id;
if (id == C2PlatformAllocatorStore::IGBA) {
std::shared_ptr<AidlGraphicBufferAllocator> gba =
mGraphicBufferAllocators->create();
@@ -2068,12 +2083,11 @@
if (status != C2_OK) {
return status;
}
- c2_aidl::IComponent::BlockPoolAllocator allocator;
- allocator.set<c2_aidl::IComponent::BlockPoolAllocator::allocator>();
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().igba =
+ c2_aidl::IComponent::GbAllocator gbAllocator;
+ gbAllocator.waitableFd = std::move(waitableFd);
+ gbAllocator.igba =
c2_aidl::IGraphicBufferAllocator::fromBinder(gba->asBinder());
- allocator.get<c2_aidl::IComponent::BlockPoolAllocator::allocator>().waitableFd =
- std::move(waitableFd);
+ allocator.gbAllocator = std::move(gbAllocator);
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
@@ -2083,7 +2097,7 @@
mGraphicBufferAllocators->setCurrentId(aidlBlockPool.blockPoolId);
} else {
::ndk::ScopedAStatus transStatus = mAidlBase->createBlockPool(
- static_cast<int32_t>(id), &aidlBlockPool);
+ allocator, &aidlBlockPool);
status = GetC2Status(transStatus, "createBlockPool");
if (status != C2_OK) {
return status;
diff --git a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
index 4640243..dd6c869 100644
--- a/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
+++ b/media/codec2/hal/client/include/codec2/aidl/GraphicsTracker.h
@@ -27,6 +27,7 @@
#include <mutex>
#include <set>
#include <thread>
+#include <optional>
#include <C2Buffer.h>
@@ -234,12 +235,14 @@
std::map<uint64_t, std::shared_ptr<BufferItem>> mDequeued;
std::set<uint64_t> mDeallocating;
+ // These member variables are read and modified accessed as follows.
+ // 1. mConfigLock being held
+ // Set mInConfig true with mLock in the beginning
+ // Clear mInConfig with mLock in the end
+ // 2. mLock is held and mInConfig is false.
int mMaxDequeue;
- int mMaxDequeueRequested;
int mMaxDequeueCommitted;
-
- uint32_t mMaxDequeueRequestedSeqId;
- uint32_t mMaxDequeueCommittedSeqId;
+ std::optional<int> mMaxDequeueRequested;
int mDequeueable;
@@ -271,13 +274,6 @@
::android::base::unique_fd mWritePipeFd; // The writing end file descriptor
std::atomic<bool> mStopped;
- std::thread mEventQueueThread; // Thread to handle interrupted
- // writes to the writing end.
- std::mutex mEventLock;
- std::condition_variable mEventCv;
-
- bool mStopEventThread;
- int mIncDequeueable; // pending # of write to increase dequeueable eventfd
private:
explicit GraphicsTracker(int maxDequeueCount);
@@ -289,6 +285,9 @@
bool adjustDequeueConfLocked(bool *updateDequeueConf);
void updateDequeueConf();
+ void clearCacheIfNecessaryLocked(
+ const std::shared_ptr<BufferCache> &cache,
+ int maxDequeueCommitted);
c2_status_t requestAllocate(std::shared_ptr<BufferCache> *cache);
c2_status_t requestDeallocate(uint64_t bid, const sp<Fence> &fence,
@@ -305,7 +304,9 @@
bool cached, int slotId, const sp<Fence> &fence,
std::shared_ptr<BufferItem> *buffer,
bool *updateDequeue);
- void commitDeallocate(std::shared_ptr<BufferCache> &cache, int slotId, uint64_t bid);
+ void commitDeallocate(std::shared_ptr<BufferCache> &cache,
+ int slotId, uint64_t bid,
+ bool *updateDequeue);
void commitRender(const std::shared_ptr<BufferCache> &cache,
const std::shared_ptr<BufferItem> &buffer,
const std::shared_ptr<BufferItem> &oldBuffer,
@@ -318,8 +319,8 @@
bool *cached, int *rSlotId, sp<Fence> *rFence,
std::shared_ptr<BufferItem> *buffer);
- void writeIncDequeueable(int inc);
- void processEvent();
+ void writeIncDequeueableLocked(int inc);
+ void drainDequeueableLocked(int dec);
};
} // namespace aidl::android::hardware::media::c2::implementation
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
index 1c5c7d6..2054fe6 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/Android.bp
@@ -44,6 +44,7 @@
"res/bbb_opus_stereo_128kbps_48000hz.info",
"res/bbb_opus_stereo_128kbps_48000hz.opus",
"res/bbb_raw_1ch_8khz_s32le.info",
+ "res/bbb_raw_1ch_8khz_s32le_largeframe.info",
"res/bbb_raw_1ch_8khz_s32le.raw",
"res/bbb_vorbis_stereo_128kbps_48000hz.info",
"res/bbb_vorbis_stereo_128kbps_48000hz.vorbis",
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
index ce9fc39..0c30d95 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.cpp
@@ -32,7 +32,11 @@
#include <codec2/hidl/client.h>
#include "media_c2_hidl_test_common.h"
-using DecodeTestParameters = std::tuple<std::string, std::string, uint32_t, bool>;
+
+using DecodeTestParameters = std::tuple<std::string /*instance_name*/,
+ std::string /*component_name*/,
+ uint32_t /*stream_index*/,
+ bool /*signal end-of-stream nor not*/>;
static std::vector<DecodeTestParameters> gDecodeTestParameters;
using CsdFlushTestParameters = std::tuple<std::string, std::string, bool>;
@@ -56,6 +60,7 @@
{"g711-mlaw", "bbb_g711mulaw_1ch_8khz.raw", "bbb_g711mulaw_1ch_8khz.info"},
{"gsm", "bbb_gsm_1ch_8khz_13kbps.raw", "bbb_gsm_1ch_8khz_13kbps.info"},
{"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le.info"},
+ {"raw", "bbb_raw_1ch_8khz_s32le.raw", "bbb_raw_1ch_8khz_s32le_largeframe.info"},
{"flac", "bbb_flac_stereo_680kbps_48000hz.flac", "bbb_flac_stereo_680kbps_48000hz.info"},
};
@@ -90,8 +95,8 @@
std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
- mLinearPool = std::make_shared<C2PooledBlockPool>(
- mLinearAllocator, mBlockPoolId++, getBufferPoolVer());
+ mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++,
+ getBufferPoolVer());
ASSERT_NE(mLinearPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
@@ -137,6 +142,9 @@
struct outputMetaData {
uint64_t timestampUs;
uint32_t rangeLength;
+ // The following is used only if C2AccessUnitInfos::output
+ // is present as part of C2Buffer.
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
// callback function to process onWorkDone received by Listener
void handleWorkDone(std::list<std::unique_ptr<C2Work>>& workItems) {
@@ -161,8 +169,18 @@
.capacity();
// List of timestamp values and output size to calculate timestamp
if (mTimestampDevTest) {
- outputMetaData meta = {mTimestampUs, rangeLength};
+ outputMetaData meta = {mTimestampUs, rangeLength, {}};
oBufferMetaData.push_back(meta);
+ std::shared_ptr<const C2AccessUnitInfos::output> inBufferInfo =
+ std::static_pointer_cast<const C2AccessUnitInfos::output>(
+ work->worklets.front()->output.buffers[0]->getInfo(
+ C2AccessUnitInfos::output::PARAM_TYPE));
+ if (inBufferInfo) {
+ for (int nMeta = 0; nMeta < inBufferInfo->flexCount(); nMeta++) {
+ oBufferMetaData.back().largeFrameInfo.push_back(
+ inBufferInfo->m.values[nMeta]);
+ }
+ }
}
}
bool mCsd = false;
@@ -203,6 +221,12 @@
std::string mInfoFile;
size_t mStreamIndex = 0;
+ // These are used only with large frame codec
+ // Specifies the maximum output size in bytes.
+ uint32_t mMaxOutputSize;
+ //Specifies the threshold output size in bytes.
+ uint32_t mOutputThresholdSize;
+
protected:
static void description(const std::string& description) {
RecordProperty("description", description);
@@ -249,6 +273,96 @@
ALOGV("Component Valid");
}
+bool isLargeAudioFrameSupported(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ std::vector<C2FieldSupportedValues>& supportedValues) {
+ C2LargeFrame::output largeFrameParams;
+ std::vector<C2FieldSupportedValuesQuery> validValueInfos = {
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams, &C2LargeFrame::maxSize)),
+ C2FieldSupportedValuesQuery::Current(
+ C2ParamField(&largeFrameParams,
+ &C2LargeFrame::thresholdSize))};
+ c2_status_t c2err = comp->querySupportedValues(validValueInfos, C2_DONT_BLOCK);
+ if (c2err != C2_OK || validValueInfos.size() != 2) {
+ return false;
+ }
+ supportedValues.clear();
+ for (int i = 0; i < 2; i++) {
+ if (validValueInfos[i].values.type == C2FieldSupportedValues::EMPTY) {
+ return false;
+ }
+ supportedValues.push_back(validValueInfos[i].values);
+ }
+ return true;
+}
+
+c2_status_t configureLargeFrameParams(const std::shared_ptr<android::Codec2Client::Component> &comp,
+ uint32_t& maxOutput, uint32_t& outputThreshold,
+ const std::vector<C2FieldSupportedValues>& supportedValues) {
+
+ if (supportedValues.empty()) {
+ ALOGE("Error: No supported values in large audio frame params");
+ return C2_BAD_VALUE;
+ }
+
+ auto boundBySupportedValues = [](const C2FieldSupportedValues& supportedValues, uint32_t& value)
+ -> c2_status_t {
+ uint32_t oBufMin = 0, oBufMax = 0;
+ switch (supportedValues.type) {
+ case C2FieldSupportedValues::type_t::RANGE:
+ {
+ const auto& range = supportedValues.range;
+ oBufMax = (uint32_t)(range.max).ref<uint32_t>();
+ oBufMin = (uint32_t)(range.min).ref<uint32_t>();
+ value = (value > oBufMax) ? oBufMax :
+ (value < oBufMin) ? oBufMin : value;
+ break;
+ }
+
+ case C2FieldSupportedValues::type_t::VALUES:
+ {
+ uint32_t lastValue;
+ for (const C2Value::Primitive& prim : supportedValues.values) {
+ lastValue = (uint32_t)prim.ref<uint32_t>();
+ if (lastValue > value) {
+ value = lastValue;
+ break;
+ }
+ }
+ if (value > lastValue) {
+ value = lastValue;
+ }
+ break;
+ }
+
+ default:
+ return C2_BAD_VALUE;
+ }
+ return C2_OK;
+ };
+ c2_status_t c2_err = boundBySupportedValues(supportedValues[0], maxOutput);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ c2_err = boundBySupportedValues(supportedValues[1], outputThreshold);
+ if (c2_err != C2_OK) {
+ return c2_err;
+ }
+ if (outputThreshold > maxOutput) {
+ outputThreshold = maxOutput;
+ }
+ ALOGV("Setting large frame format : Max: %d - Threshold: %d", maxOutput, outputThreshold);
+ std::vector<std::unique_ptr<C2SettingResult>> failures;
+ C2LargeFrame::output largeFrameParams(0u, maxOutput, outputThreshold);
+ std::vector<C2Param*> configParam{&largeFrameParams};
+ c2_status_t status = comp->config(configParam, C2_DONT_BLOCK, &failures);
+ if (status != C2_OK || failures.size() != 0u) {
+ ALOGE("Large frame Audio configuration failed for maxSize: %d, thresholdSize: %d",
+ maxOutput, outputThreshold);
+ }
+ return status;
+}
+
// Set Default config param.
bool setupConfigParam(const std::shared_ptr<android::Codec2Client::Component>& component,
int32_t* bitStreamInfo) {
@@ -317,6 +431,10 @@
typedef std::unique_lock<std::mutex> ULock;
int frameID = offset;
int maxRetry = 0;
+ std::shared_ptr<C2Buffer> buffer;
+ std::vector<C2FieldSupportedValues> largeFrameValues;
+ bool isComponentSupportsLargeAudioFrame = isLargeAudioFrameSupported(component,
+ largeFrameValues);
while (1) {
if (frameID == (int)Info->size() || frameID == (offset + range)) break;
uint32_t flags = 0;
@@ -336,7 +454,9 @@
ASSERT_TRUE(false) << "Wait for generating C2Work exceeded timeout";
}
int64_t timestamp = (*Info)[frameID].timestamp;
- flags = ((*Info)[frameID].flags == FLAG_CONFIG_DATA) ? C2FrameData::FLAG_CODEC_CONFIG : 0;
+ flags = ((*Info)[frameID].vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME))
+ ? C2FrameData::FLAG_CODEC_CONFIG
+ : 0;
if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
flags |= C2FrameData::FLAG_END_OF_STREAM;
@@ -374,7 +494,17 @@
memcpy(view.base(), data, size);
- work->input.buffers.emplace_back(new LinearBuffer(block));
+ buffer.reset(new LinearBuffer(block));
+ if (!(*Info)[frameID].largeFrameInfo.empty() && isComponentSupportsLargeAudioFrame) {
+ const std::vector<C2AccessUnitInfosStruct>& meta =
+ (*Info)[frameID].largeFrameInfo;
+ ALOGV("Large Audio frame supported for %s, frameID: %d, size: %zu",
+ component->getName().c_str(), frameID, meta.size());
+ const std::shared_ptr<C2AccessUnitInfos::input> largeFrame =
+ C2AccessUnitInfos::input::AllocShared(meta.size(), 0u, meta);
+ buffer->setInfo(largeFrame);
+ }
+ work->input.buffers.push_back(buffer);
free(data);
}
work->worklets.clear();
@@ -401,9 +531,37 @@
auto itOut = oBufferMetaData.begin();
EXPECT_EQ(*itIn, itOut->timestampUs);
uint64_t expectedTimeStamp = *itIn;
- while (itOut != oBufferMetaData.end()) {
+ bool err= false;
+ while (!err && itOut != oBufferMetaData.end()) {
EXPECT_EQ(expectedTimeStamp, itOut->timestampUs);
if (expectedTimeStamp != itOut->timestampUs) break;
+ if (!itOut->largeFrameInfo.empty()) {
+ // checking large audio frame metadata
+ if (itOut->largeFrameInfo[0].timestamp != itOut->timestampUs) {
+ ALOGE("Metadata first time stamp doesn't match");
+ err = true;
+ break;
+ }
+ uint64_t totalSize = 0;
+ uint64_t sampleSize = 0;
+ int64_t nextTimestamp = itOut->timestampUs;
+ for (auto& meta : itOut->largeFrameInfo) {
+ if (nextTimestamp != meta.timestamp) {
+ ALOGE("Metadata timestamp error: expect: %lld, got: %lld",
+ (long long)nextTimestamp, (long long)meta.timestamp);
+ err = true;
+ break;
+ }
+ totalSize += meta.size;
+ sampleSize = (meta.size / (nChannels * 2));
+ nextTimestamp += sampleSize * 1000000ll / nSampleRate;
+ }
+ if (totalSize != itOut->rangeLength) {
+ ALOGE("Metadata size error: expected:%lld, got: %d",
+ (long long)totalSize, itOut->rangeLength);
+ err = true;
+ }
+ }
// buffer samples = ((total bytes) / (ac * (bits per sample / 8))
samplesReceived += ((itOut->rangeLength) / (nChannels * 2));
expectedTimeStamp = samplesReceived * 1000000ll / nSampleRate;
@@ -451,7 +609,8 @@
android::Vector<FrameInfo> Info;
int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
- ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
+ ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile <<
+ " #CSD " << numCsds;
// Reset total no of frames received
mFramesReceived = 0;
@@ -472,10 +631,23 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
+
ASSERT_NO_FATAL_FAILURE(decodeNFrames(mComponent, mQueueLock, mQueueCondition, mWorkQueue,
mFlushedIndices, mLinearPool, eleStream, &Info, 0,
(int)Info.size(), signalEOS));
@@ -527,18 +699,26 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// request EOS for thumbnail
// signal EOS flag with last frame
- size_t i = -1;
- uint32_t flags;
- do {
- i++;
- flags = 0;
- if (Info[i].flags) flags = 1u << (Info[i].flags - 1);
-
- } while (!(flags & SYNC_FRAME));
+ size_t i;
+ for (i = 0; i < Info.size(); i++) {
+ if (Info[i].vtsFlags & (1 << VTS_BIT_FLAG_SYNC_FRAME)) break;
+ }
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
@@ -613,6 +793,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
// flush
std::list<std::unique_ptr<C2Work>> flushedWork;
@@ -643,14 +835,11 @@
mFlushedIndices.clear();
int index = numFramesFlushed;
bool keyFrame = false;
- uint32_t flags = 0;
while (index < (int)Info.size()) {
- if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
- if ((flags & SYNC_FRAME) == SYNC_FRAME) {
+ if (Info[index].vtsFlags & (1 << VTS_BIT_FLAG_SYNC_FRAME)) {
keyFrame = true;
break;
}
- flags = 0;
eleStream.ignore(Info[index].bytesCount);
index++;
}
@@ -684,24 +873,38 @@
int bytesCount = 0;
uint32_t frameId = 0;
uint32_t flags = 0;
+ uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
bool codecConfig = false;
// This test introduces empty CSD after every 20th frame
// and empty input frames at an interval of 5 frames.
while (1) {
if (!(frameId % 5)) {
- if (!(frameId % 20))
- flags = 32;
- else
- flags = 0;
+ vtsFlags = !(frameId % 20) ? (1 << VTS_BIT_FLAG_CSD_FRAME) : 0;
bytesCount = 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
} else {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
- codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+ codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
+ if ((vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) != 0) {
+ eleInfo >> nLargeFrames;
+ // this is a large audio frame.
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ Info.editItemAt(Info.size() - 1).largeFrameInfo.push_back(
+ {(uint32_t)bytesCount, vtsFlags, timestamp});
+ }
+ }
}
- Info.push_back({bytesCount, flags, timestamp});
frameId++;
}
eleInfo.close();
@@ -716,6 +919,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
@@ -771,7 +986,18 @@
std::cout << "[ WARN ] Test Skipped \n";
return;
}
-
+ getInputChannelInfo(mComponent, mMime, bitStreamInfo);
+ std::vector<C2FieldSupportedValues> supportedValues;
+ if (!Info.top().largeFrameInfo.empty()) {
+ if (!isLargeAudioFrameSupported(mComponent, supportedValues)) {
+ GTEST_SKIP() << "As component does not support large frame";
+ }
+ // time_sec * sample_rate * channel_count * 2 (bytes_per_channel)
+ mMaxOutputSize = 60 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ mOutputThresholdSize = 50 * bitStreamInfo[0] * bitStreamInfo[1] * 2;
+ ASSERT_EQ(configureLargeFrameParams(mComponent, mMaxOutputSize,
+ mOutputThresholdSize, supportedValues), C2_OK);
+ }
ASSERT_EQ(mComponent->start(), C2_OK);
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
@@ -869,4 +1095,4 @@
::testing::InitGoogleTest(&argc, argv);
ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
-}
+}
\ No newline at end of file
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
index 6c04683..9b9c62f 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
+++ b/media/codec2/hal/hidl/1.0/vts/functional/audio/VtsHalMediaC2V1_0TargetAudioDecTest.xml
@@ -38,6 +38,8 @@
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_opus_stereo_128kbps_48000hz.opus" value="/data/local/tmp/media/bbb_opus_stereo_128kbps_48000hz.opus" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.info" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.info" />
+ <option name="push-file" key="bbb_raw_1ch_8khz_s32le_largeframe.info"
+ value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le_largeframe.info" />
<option name="push-file" key="bbb_raw_1ch_8khz_s32le.raw" value="/data/local/tmp/media/bbb_raw_1ch_8khz_s32le.raw" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.info" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.info" />
<option name="push-file" key="bbb_vorbis_stereo_128kbps_48000hz.vorbis" value="/data/local/tmp/media/bbb_vorbis_stereo_128kbps_48000hz.vorbis" />
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
index f36bc41..92b0bf5 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.cpp
@@ -233,18 +233,36 @@
int32_t numCsds = 0;
int32_t bytesCount = 0;
uint32_t flags = 0;
+ uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
+ uint32_t nLargeFrames = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ if (vtsFlags == 0xFF) {
+ ALOGE("unrecognized flag(0x%x) entry in info file %s", flags, info.c_str());
+ return -1;
+ }
eleInfo >> timestamp;
- bool codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+ bool codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0 ;
if (codecConfig) numCsds++;
- bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
+ bool nonDisplayFrame = (vtsFlags & (1 << VTS_BIT_FLAG_NO_SHOW_FRAME)) != 0;
if (timestampDevTest && !codecConfig && !nonDisplayFrame) {
timestampUslist->push_back(timestamp);
}
- frameInfo->push_back({bytesCount, flags, timestamp});
+ frameInfo->push_back({bytesCount, vtsFlags, timestamp, {}});
+ if (vtsFlags & (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME)) {
+ eleInfo >> nLargeFrames;
+ while(nLargeFrames-- > 0) {
+ eleInfo >> bytesCount;
+ eleInfo >> flags;
+ eleInfo >> timestamp;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ frameInfo->editItemAt(frameInfo->size() - 1).largeFrameInfo.push_back(
+ {vtsFlags, static_cast<uint32_t>(bytesCount), timestamp});
+ }
+ }
}
ALOGV("numCsds : %d", numCsds);
eleInfo.close();
@@ -273,3 +291,12 @@
ASSERT_EQ(flushedIndices.empty(), true);
flushedWork.clear();
}
+
+int mapInfoFlagstoVtsFlags(int infoFlags) {
+ if (infoFlags == 0) return 0;
+ else if (infoFlags == 0x1) return (1 << VTS_BIT_FLAG_SYNC_FRAME);
+ else if (infoFlags == 0x10) return (1 << VTS_BIT_FLAG_NO_SHOW_FRAME);
+ else if (infoFlags == 0x20) return (1 << VTS_BIT_FLAG_CSD_FRAME);
+ else if (infoFlags == 0x40) return (1 << VTS_BIT_FLAG_LARGE_AUDIO_FRAME);
+ return 0xFF;
+}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
index 48e80a4..708fe15 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
+++ b/media/codec2/hal/hidl/1.0/vts/functional/common/media_c2_hidl_test_common.h
@@ -29,9 +29,6 @@
#include <chrono>
#include <fstream>
-#define FLAG_NON_DISPLAY_FRAME (1 << 4)
-#define FLAG_CONFIG_DATA (1 << 5)
-
#define MAX_RETRY 20
#define TIME_OUT 400ms
#define MAX_INPUT_BUFFERS 8
@@ -53,10 +50,20 @@
// Component name prefix
extern std::string sComponentNamePrefix;
+enum c2_vts_flags_t {
+ VTS_BIT_FLAG_SYNC_FRAME = 1,
+ VTS_BIT_FLAG_NO_SHOW_FRAME = 2,
+ VTS_BIT_FLAG_CSD_FRAME = 3,
+ VTS_BIT_FLAG_LARGE_AUDIO_FRAME = 4,
+};
+
struct FrameInfo {
int bytesCount;
- uint32_t flags;
+ uint32_t vtsFlags;
int64_t timestamp;
+ // This is used when access-units are marked with
+ // VTS_BIT_FLAG_LARGE_AUDIO_FRAME
+ std::vector<C2AccessUnitInfosStruct> largeFrameInfo;
};
template <typename... T>
@@ -83,7 +90,6 @@
virtual void onWorkDone(const std::weak_ptr<android::Codec2Client::Component>& comp,
std::list<std::unique_ptr<C2Work>>& workItems) override {
/* TODO */
- ALOGD("onWorkDone called");
(void)comp;
if (callBack) callBack(workItems);
}
@@ -100,7 +106,6 @@
uint32_t errorCode) override {
/* TODO */
(void)comp;
- ALOGD("onError called");
if (errorCode != 0) ALOGE("Error : %u", errorCode);
}
@@ -165,4 +170,7 @@
void verifyFlushOutput(std::list<std::unique_ptr<C2Work>>& flushedWork,
std::list<std::unique_ptr<C2Work>>& workQueue,
std::list<uint64_t>& flushedIndices, std::mutex& queueLock);
+
+int mapInfoFlagstoVtsFlags(int infoFlags);
+
#endif // MEDIA_C2_HIDL_TEST_COMMON_H
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
new file mode 100644
index 0000000..291e323
--- /dev/null
+++ b/media/codec2/hal/hidl/1.0/vts/functional/res/bbb_raw_1ch_8khz_s32le_largeframe.info
@@ -0,0 +1,5 @@
+16384 64 0 1 16384 1 0
+49152 64 1024000 3 16384 1 1024000 16384 1 2048000 16384 1 3072000
+32768 64 4096000 2 16384 1 4096000 16384 1 5120000
+49152 64 6144000 3 16384 1 6144000 16384 1 7168000 16384 1 8192000
+10924 64 9216000 1 10924 1 9216000
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
index 2cf0d6e..f8fd425 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoDecTest.cpp
@@ -29,6 +29,7 @@
#include <C2BufferPriv.h>
#include <C2Config.h>
#include <C2Debug.h>
+#include <codec2/common/HalSelection.h>
#include <codec2/hidl/client.h>
#include <gui/BufferQueue.h>
#include <gui/IConsumerListener.h>
@@ -120,8 +121,8 @@
std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_LINEAR, &mLinearAllocator), C2_OK);
- mLinearPool = std::make_shared<C2PooledBlockPool>(
- mLinearAllocator, mBlockPoolId++, getBufferPoolVer());
+ mLinearPool = std::make_shared<C2PooledBlockPool>(mLinearAllocator, mBlockPoolId++,
+ getBufferPoolVer());
ASSERT_NE(mLinearPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
@@ -407,30 +408,45 @@
surfaceMode_t surfMode) {
using namespace android;
sp<IGraphicBufferProducer> producer = nullptr;
+ sp<IGraphicBufferConsumer> consumer = nullptr;
+ sp<GLConsumer> texture = nullptr;
+ sp<ANativeWindow> surface = nullptr;
static std::atomic_uint32_t surfaceGeneration{0};
uint32_t generation =
(getpid() << 10) |
((surfaceGeneration.fetch_add(1, std::memory_order_relaxed) + 1) & ((1 << 10) - 1));
int32_t maxDequeueBuffers = kSmoothnessFactor + kRenderingDepth;
+ C2BlockPool::local_id_t poolId = C2BlockPool::BASIC_GRAPHIC;
+ std::shared_ptr<Codec2Client::Configurable> configurable;
+ bool aidl = ::android::IsCodec2AidlHalSelected();
+ if (aidl) {
+ // AIDL does not support blockpool-less mode.
+ c2_status_t poolRet = component->createBlockPool(
+ C2PlatformAllocatorStore::IGBA, &poolId, &configurable);
+ ASSERT_EQ(poolRet, C2_OK) << "setOutputSurface failed";
+ }
+
if (surfMode == SURFACE) {
- sp<IGraphicBufferConsumer> consumer = nullptr;
BufferQueue::createBufferQueue(&producer, &consumer);
ASSERT_NE(producer, nullptr) << "createBufferQueue returned invalid producer";
ASSERT_NE(consumer, nullptr) << "createBufferQueue returned invalid consumer";
- sp<GLConsumer> texture =
+ texture =
new GLConsumer(consumer, 0 /* tex */, GLConsumer::TEXTURE_EXTERNAL,
true /* useFenceSync */, false /* isControlledByApp */);
- sp<ANativeWindow> gSurface = new Surface(producer);
- ASSERT_NE(gSurface, nullptr) << "getSurface failed";
+ surface = new Surface(producer);
+ ASSERT_NE(surface, nullptr) << "failed to create Surface object";
producer->setGenerationNumber(generation);
}
- c2_status_t err = component->setOutputSurface(C2BlockPool::BASIC_GRAPHIC, producer, generation,
+ c2_status_t err = component->setOutputSurface(poolId, producer, generation,
maxDequeueBuffers);
- ASSERT_EQ(err, C2_OK) << "setOutputSurface failed";
+ std::string surfStr = surfMode == NO_SURFACE ? "NO_SURFACE" :
+ (surfMode == NULL_SURFACE ? "NULL_SURFACE" : "WITH_SURFACE");
+
+ ASSERT_EQ(err, C2_OK) << "setOutputSurface failed, surfMode: " << surfStr;
}
void decodeNFrames(const std::shared_ptr<android::Codec2Client::Component>& component,
@@ -463,7 +479,9 @@
}
int64_t timestamp = (*Info)[frameID].timestamp;
- flags = ((*Info)[frameID].flags == FLAG_CONFIG_DATA) ? C2FrameData::FLAG_CODEC_CONFIG : 0;
+ flags = ((*Info)[frameID].vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME))
+ ? C2FrameData::FLAG_CODEC_CONFIG
+ : 0;
if (signalEOS && ((frameID == (int)Info->size() - 1) || (frameID == (offset + range - 1))))
flags |= C2FrameData::FLAG_END_OF_STREAM;
@@ -711,17 +729,19 @@
ASSERT_EQ(eleInfo.is_open(), true) << mInputFile << " - file not found";
int bytesCount = 0;
uint32_t flags = 0;
+ uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
uint32_t timestampMax = 0;
while (1) {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
timestamp += timestampOffset;
- Info.push_back({bytesCount, flags, timestamp});
- bool codecConfig =
- flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
- bool nonDisplayFrame = ((flags & FLAG_NON_DISPLAY_FRAME) != 0);
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
+ bool codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
+ bool nonDisplayFrame = (vtsFlags & (1 << VTS_BIT_FLAG_NO_SHOW_FRAME)) != 0;
{
ULock l(mQueueLock);
@@ -795,20 +815,15 @@
int32_t numCsds = populateInfoVector(mInfoFile, &Info, mTimestampDevTest, &mTimestampUslist);
ASSERT_GE(numCsds, 0) << "Error in parsing input info file: " << mInfoFile;
- uint32_t flags = 0;
for (size_t i = 0; i < MAX_ITERATIONS; i++) {
ASSERT_EQ(mComponent->start(), C2_OK);
// request EOS for thumbnail
// signal EOS flag with last frame
size_t j = -1;
- do {
- j++;
- flags = 0;
- if (Info[j].flags) flags = 1u << (Info[j].flags - 1);
-
- } while (!(flags & SYNC_FRAME));
-
+ for (j = 0; j < Info.size(); j++) {
+ if (Info[j].vtsFlags & (1 << VTS_BIT_FLAG_SYNC_FRAME)) break;
+ }
std::ifstream eleStream;
eleStream.open(mInputFile, std::ifstream::binary);
ASSERT_EQ(eleStream.is_open(), true);
@@ -908,14 +923,11 @@
// Seek to next key frame and start decoding till the end
int index = numFramesFlushed;
bool keyFrame = false;
- uint32_t flags = 0;
while (index < (int)Info.size()) {
- if (Info[index].flags) flags = 1u << (Info[index].flags - 1);
- if ((flags & SYNC_FRAME) == SYNC_FRAME) {
+ if (Info[index].vtsFlags & (1 << VTS_BIT_FLAG_SYNC_FRAME)) {
keyFrame = true;
break;
}
- flags = 0;
eleStream.ignore(Info[index].bytesCount);
index++;
}
@@ -949,24 +961,24 @@
int bytesCount = 0;
uint32_t frameId = 0;
uint32_t flags = 0;
+ uint32_t vtsFlags = 0;
uint32_t timestamp = 0;
bool codecConfig = false;
// This test introduces empty CSD after every 20th frame
// and empty input frames at an interval of 5 frames.
while (1) {
if (!(frameId % 5)) {
- if (!(frameId % 20))
- flags = 32;
- else
- flags = 0;
+ vtsFlags = !(frameId % 20) ? (1 << VTS_BIT_FLAG_CSD_FRAME) : 0;
bytesCount = 0;
} else {
if (!(eleInfo >> bytesCount)) break;
eleInfo >> flags;
+ vtsFlags = mapInfoFlagstoVtsFlags(flags);
+ ASSERT_NE(vtsFlags, 0xFF) << "unrecognized flag entry in info file: " << mInfoFile;
eleInfo >> timestamp;
- codecConfig = flags ? ((1 << (flags - 1)) & C2FrameData::FLAG_CODEC_CONFIG) != 0 : 0;
+ codecConfig = (vtsFlags & (1 << VTS_BIT_FLAG_CSD_FRAME)) != 0;
}
- Info.push_back({bytesCount, flags, timestamp});
+ Info.push_back({bytesCount, vtsFlags, timestamp, {}});
frameId++;
}
eleInfo.close();
@@ -1046,12 +1058,9 @@
}
int offset = framesToDecode;
- uint32_t flags = 0;
while (1) {
while (offset < (int)Info.size()) {
- flags = 0;
- if (Info[offset].flags) flags = 1u << (Info[offset].flags - 1);
- if (flags & SYNC_FRAME) {
+ if (Info[offset].vtsFlags & (1 << VTS_BIT_FLAG_SYNC_FRAME)) {
keyFrame = true;
break;
}
diff --git a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
index fbb4f18..8ecb9c0 100644
--- a/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
+++ b/media/codec2/hal/hidl/1.0/vts/functional/video/VtsHalMediaC2V1_0TargetVideoEncTest.cpp
@@ -19,6 +19,7 @@
#include <android-base/logging.h>
#include <android/binder_process.h>
+#include <codec2/common/HalSelection.h>
#include <gtest/gtest.h>
#include <hidl/GtestPrinter.h>
#include <stdio.h>
@@ -71,7 +72,9 @@
std::shared_ptr<C2AllocatorStore> store = android::GetCodec2PlatformAllocatorStore();
CHECK_EQ(store->fetchAllocator(C2AllocatorStore::DEFAULT_GRAPHIC, &mGraphicAllocator),
C2_OK);
- mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++);
+ C2PooledBlockPool::BufferPoolVer ver = ::android::IsCodec2AidlHalSelected() ?
+ C2PooledBlockPool::VER_AIDL2 : C2PooledBlockPool::VER_HIDL;
+ mGraphicPool = std::make_shared<C2PooledBlockPool>(mGraphicAllocator, mBlockPoolId++, ver);
ASSERT_NE(mGraphicPool, nullptr);
std::vector<std::unique_ptr<C2Param>> queried;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 3bb6593..5c1755e 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -1049,7 +1049,11 @@
// Unwrap raw buffer handle from the C2Handle
native_handle_t *nh = UnwrapNativeCodec2GrallocHandle(handle);
if (!nh) {
- return;
+ nh = UnwrapNativeCodec2AhwbHandle(handle);
+ if (!nh) {
+ ALOGE("handle is not compatible to neither C2HandleGralloc nor C2HandleAhwb");
+ return;
+ }
}
// Import the raw handle so IMapper can use the buffer. The imported
// handle must be freed when the client is done with the buffer.
diff --git a/media/codec2/tests/aidl/Android.bp b/media/codec2/tests/aidl/Android.bp
new file mode 100644
index 0000000..2ad245c
--- /dev/null
+++ b/media/codec2/tests/aidl/Android.bp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // 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_test {
+ name: "c2aidl_gtracker_test",
+ test_suites: ["device-tests"],
+ defaults: [
+ "libcodec2-aidl-client-defaults",
+ ],
+
+ header_libs: [
+ "libcodec2_client_headers",
+ "libcodec2_internal",
+ "libcodec2_vndk_headers",
+ ],
+
+ srcs: [
+ "GraphicsTracker_test.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libcodec2_client",
+ "libgui",
+ "libnativewindow",
+ "libui",
+ ],
+}
diff --git a/media/codec2/tests/aidl/GraphicsTracker_test.cpp b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
new file mode 100644
index 0000000..9008086
--- /dev/null
+++ b/media/codec2/tests/aidl/GraphicsTracker_test.cpp
@@ -0,0 +1,820 @@
+/*
+ * 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_NDEBUG 0
+#define LOG_TAG "GraphicsTracker_test"
+#include <unistd.h>
+
+#include <android/hardware_buffer.h>
+#include <codec2/aidl/GraphicsTracker.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <gtest/gtest.h>
+#include <gui/BufferQueue.h>
+#include <gui/IProducerListener.h>
+#include <gui/IConsumerListener.h>
+#include <gui/Surface.h>
+#include <private/android/AHardwareBufferHelpers.h>
+
+#include <C2BlockInternal.h>
+#include <C2FenceFactory.h>
+
+#include <atomic>
+#include <memory>
+#include <iostream>
+#include <thread>
+
+using ::aidl::android::hardware::media::c2::implementation::GraphicsTracker;
+using ::android::BufferItem;
+using ::android::BufferQueue;
+using ::android::Fence;
+using ::android::GraphicBuffer;
+using ::android::IGraphicBufferProducer;
+using ::android::IGraphicBufferConsumer;
+using ::android::IProducerListener;
+using ::android::IConsumerListener;
+using ::android::OK;
+using ::android::sp;
+using ::android::wp;
+
+namespace {
+struct BqStatistics {
+ std::atomic<int> mDequeued;
+ std::atomic<int> mQueued;
+ std::atomic<int> mBlocked;
+ std::atomic<int> mDropped;
+ std::atomic<int> mDiscarded;
+ std::atomic<int> mReleased;
+
+ void log() {
+ ALOGD("Dequeued: %d, Queued: %d, Blocked: %d, "
+ "Dropped: %d, Discarded %d, Released %d",
+ (int)mDequeued, (int)mQueued, (int)mBlocked,
+ (int)mDropped, (int)mDiscarded, (int)mReleased);
+ }
+
+ void clear() {
+ mDequeued = 0;
+ mQueued = 0;
+ mBlocked = 0;
+ mDropped = 0;
+ mDiscarded = 0;
+ mReleased = 0;
+ }
+};
+
+struct DummyConsumerListener : public android::BnConsumerListener {
+ void onFrameAvailable(const BufferItem& /* item */) override {}
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+};
+
+struct TestConsumerListener : public android::BnConsumerListener {
+ TestConsumerListener(const sp<IGraphicBufferConsumer> &consumer)
+ : BnConsumerListener(), mConsumer(consumer) {}
+ void onFrameAvailable(const BufferItem&) override {
+ constexpr static int kRenderDelayUs = 1000000/30; // 30fps
+ BufferItem buffer;
+ // consume buffer
+ sp<IGraphicBufferConsumer> consumer = mConsumer.promote();
+ if (consumer != nullptr && consumer->acquireBuffer(&buffer, 0) == android::NO_ERROR) {
+ ::usleep(kRenderDelayUs);
+ consumer->releaseBuffer(buffer.mSlot, buffer.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, buffer.mFence);
+ }
+ }
+ void onBuffersReleased() override {}
+ void onSidebandStreamChanged() override {}
+
+ wp<IGraphicBufferConsumer> mConsumer;
+};
+
+struct TestProducerListener : public android::BnProducerListener {
+ TestProducerListener(std::shared_ptr<GraphicsTracker> tracker,
+ std::shared_ptr<BqStatistics> &stat,
+ uint32_t generation) : BnProducerListener(),
+ mTracker(tracker), mStat(stat), mGeneration(generation) {}
+ virtual void onBufferReleased() override {
+ auto tracker = mTracker.lock();
+ if (tracker) {
+ mStat->mReleased++;
+ tracker->onReleased(mGeneration);
+ }
+ }
+ virtual bool needsReleaseNotify() override { return true; }
+ virtual void onBuffersDiscarded(const std::vector<int32_t>&) override {}
+
+ std::weak_ptr<GraphicsTracker> mTracker;
+ std::shared_ptr<BqStatistics> mStat;
+ uint32_t mGeneration;
+};
+
+struct Frame {
+ AHardwareBuffer *buffer_;
+ sp<Fence> fence_;
+
+ Frame() : buffer_{nullptr}, fence_{nullptr} {}
+ Frame(AHardwareBuffer *buffer, sp<Fence> fence)
+ : buffer_(buffer), fence_(fence) {}
+ ~Frame() {
+ if (buffer_) {
+ AHardwareBuffer_release(buffer_);
+ }
+ }
+};
+
+struct FrameQueue {
+ bool mStopped;
+ bool mDrain;
+ std::queue<std::shared_ptr<Frame>> mQueue;
+ std::mutex mMutex;
+ std::condition_variable mCond;
+
+ FrameQueue() : mStopped{false}, mDrain{false} {}
+
+ bool queueItem(AHardwareBuffer *buffer, sp<Fence> fence) {
+ std::shared_ptr<Frame> frame = std::make_shared<Frame>(buffer, fence);
+ if (mStopped) {
+ return false;
+ }
+ if (!frame) {
+ return false;
+ }
+ std::unique_lock<std::mutex> l(mMutex);
+ mQueue.emplace(frame);
+ l.unlock();
+ mCond.notify_all();
+ return true;
+ }
+
+ void stop(bool drain = false) {
+ bool stopped = false;
+ {
+ std::unique_lock<std::mutex> l(mMutex);
+ if (!mStopped) {
+ mStopped = true;
+ mDrain = drain;
+ stopped = true;
+ }
+ l.unlock();
+ if (stopped) {
+ mCond.notify_all();
+ }
+ }
+ }
+
+ bool waitItem(std::shared_ptr<Frame> *frame) {
+ while(true) {
+ std::unique_lock<std::mutex> l(mMutex);
+ if (!mDrain && mStopped) {
+ // stop without consuming the queue.
+ return false;
+ }
+ if (!mQueue.empty()) {
+ *frame = mQueue.front();
+ mQueue.pop();
+ return true;
+ } else if (mStopped) {
+ // stop after consuming the queue.
+ return false;
+ }
+ mCond.wait(l);
+ }
+ }
+};
+
+} // namespace anonymous
+
+class GraphicsTrackerTest : public ::testing::Test {
+public:
+ const uint64_t kTestUsageFlag = GRALLOC_USAGE_SW_WRITE_OFTEN;
+
+ void queueBuffer(FrameQueue *queue) {
+ while (true) {
+ std::shared_ptr<Frame> frame;
+ if (!queue->waitItem(&frame)) {
+ break;
+ }
+ uint64_t bid;
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ if (AHardwareBuffer_getId(frame->buffer_, &bid) !=
+ android::NO_ERROR) {
+ break;
+ }
+ } else {
+ break;
+ }
+ android::status_t ret = frame->fence_->wait(-1);
+ if (ret != android::NO_ERROR) {
+ mTracker->deallocate(bid, frame->fence_);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+
+ std::shared_ptr<C2GraphicBlock> blk =
+ _C2BlockFactory::CreateGraphicBlock(frame->buffer_);
+ if (!blk) {
+ mTracker->deallocate(bid, Fence::NO_FENCE);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+ IGraphicBufferProducer::QueueBufferInput input(
+ 0, false,
+ HAL_DATASPACE_UNKNOWN, android::Rect(0, 0, 1, 1),
+ NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, Fence::NO_FENCE);
+ IGraphicBufferProducer::QueueBufferOutput output{};
+ c2_status_t res = mTracker->render(
+ blk->share(C2Rect(1, 1), C2Fence()),
+ input, &output);
+ if (res != C2_OK) {
+ mTracker->deallocate(bid, Fence::NO_FENCE);
+ mBqStat->mDiscarded++;
+ continue;
+ }
+ if (output.bufferReplaced) {
+ mBqStat->mDropped++;
+ }
+ mBqStat->mQueued++;
+ }
+ }
+
+ void stopTrackerAfterUs(int us) {
+ ::usleep(us);
+ mTracker->stop();
+ }
+
+protected:
+ bool init(int maxDequeueCount) {
+ mTracker = GraphicsTracker::CreateGraphicsTracker(maxDequeueCount);
+ if (!mTracker) {
+ return false;
+ }
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ if (!mProducer || !mConsumer) {
+ return false;
+ }
+ return true;
+ }
+ bool configure(sp<IProducerListener> producerListener,
+ sp<IConsumerListener> consumerListener,
+ int maxAcquiredCount = 1, bool controlledByApp = true) {
+ if (mConsumer->consumerConnect(
+ consumerListener, controlledByApp) != ::android::NO_ERROR) {
+ return false;
+ }
+ if (mConsumer->setMaxAcquiredBufferCount(maxAcquiredCount) != ::android::NO_ERROR) {
+ return false;
+ }
+ IGraphicBufferProducer::QueueBufferOutput qbo{};
+ if (mProducer->connect(producerListener,
+ NATIVE_WINDOW_API_MEDIA, true, &qbo) != ::android::NO_ERROR) {
+ return false;
+ }
+ if (mProducer->setDequeueTimeout(0) != ::android::NO_ERROR) {
+ return false;
+ }
+ return true;
+ }
+
+ virtual void TearDown() override {
+ mBqStat->log();
+ mBqStat->clear();
+
+ if (mTracker) {
+ mTracker->stop();
+ mTracker.reset();
+ }
+ if (mProducer) {
+ mProducer->disconnect(NATIVE_WINDOW_API_MEDIA);
+ }
+ mProducer.clear();
+ mConsumer.clear();
+ }
+
+protected:
+ std::shared_ptr<BqStatistics> mBqStat = std::make_shared<BqStatistics>();
+ sp<IGraphicBufferProducer> mProducer;
+ sp<IGraphicBufferConsumer> mConsumer;
+ std::shared_ptr<GraphicsTracker> mTracker;
+};
+
+
+TEST_F(GraphicsTrackerTest, AllocateAndBlockedTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bid;
+
+ // Allocate and check dequeueable
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - (i + 1), mTracker->getCurDequeueable());
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+ ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+ AHardwareBuffer_release(buf);
+ }
+ } else {
+ GTEST_SKIP();
+ }
+
+ // Allocate should be blocked
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ALOGD("alloc : err(%d, %d)", ret, C2_BLOCKING);
+ ASSERT_EQ(C2_BLOCKING, ret);
+ mBqStat->mBlocked++;
+ ASSERT_EQ(0, mTracker->getCurDequeueable());
+}
+
+TEST_F(GraphicsTrackerTest, AllocateAndDeallocateTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bid;
+ std::vector<uint64_t> bids;
+
+ // Allocate and store buffer id
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bid));
+ bids.push_back(bid);
+ ALOGD("alloced : bufferId: %llu", (unsigned long long)bid);
+ AHardwareBuffer_release(buf);
+ }
+ } else {
+ GTEST_SKIP();
+ }
+
+ // Deallocate and check dequeueable
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ALOGD("dealloc : bufferId: %llu", (unsigned long long)bids[i]);
+ ret = mTracker->deallocate(bids[i], Fence::NO_FENCE);
+ ASSERT_EQ(C2_OK, ret);
+ ASSERT_EQ(i + 1, mTracker->getCurDequeueable());
+ mBqStat->mDiscarded++;
+ }
+}
+
+TEST_F(GraphicsTrackerTest, DropAndReleaseTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new DummyConsumerListener()));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ c2_status_t ret = mTracker->configureGraphics(mProducer, generation);
+ ASSERT_EQ(C2_OK, ret);
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+ AHardwareBuffer *buf1, *buf2;
+ sp<Fence> fence1, fence2;
+
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence1);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+ ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence2);
+ ASSERT_EQ(C2_OK, ret);
+ mBqStat->mDequeued++;
+ ASSERT_EQ(maxDequeueCount - 2, mTracker->getCurDequeueable());
+
+ // Queue two buffers without consuming, one should be dropped
+ ASSERT_TRUE(frameQueue.queueItem(buf1, fence1));
+ ASSERT_TRUE(frameQueue.queueItem(buf2, fence2));
+
+ frameQueue.stop(true);
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+
+ ASSERT_EQ(maxDequeueCount - 1, mTracker->getCurDequeueable());
+
+ // Consume one buffer and release
+ BufferItem item;
+ ASSERT_EQ(OK, mConsumer->acquireBuffer(&item, 0));
+ ASSERT_EQ(OK, mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, item.mFence));
+ // Nothing to consume
+ ASSERT_NE(OK, mConsumer->acquireBuffer(&item, 0));
+
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+ ASSERT_EQ(1, mBqStat->mReleased);
+ ASSERT_EQ(1, mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, RenderTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+ const int maxNumAlloc = 20;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+
+ int numAlloc = 0;
+
+ while (numAlloc < maxNumAlloc) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ if (!frameQueue.queueItem(buf, fence)) {
+ ALOGE("queue to render failed");
+ break;
+ }
+ ++numAlloc;
+ }
+
+ frameQueue.stop(true);
+ // Wait more than enough time(1 sec) to render all queued frames for sure.
+ ::usleep(1000000);
+
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+ ASSERT_EQ(numAlloc, maxNumAlloc);
+ ASSERT_EQ(numAlloc, mBqStat->mDequeued);
+ ASSERT_EQ(mBqStat->mDequeued, mBqStat->mQueued);
+ ASSERT_EQ(mBqStat->mDequeued, mBqStat->mReleased + mBqStat->mDropped);
+}
+
+TEST_F(GraphicsTrackerTest, StopAndWaitTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 2;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf1, *buf2;
+ sp<Fence> fence;
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf1, &fence));
+ mBqStat->mDequeued++;
+ AHardwareBuffer_release(buf1);
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf2, &fence));
+ mBqStat->mDequeued++;
+ AHardwareBuffer_release(buf2);
+
+ ASSERT_EQ(0, mTracker->getCurDequeueable());
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(3000000000));
+
+ std::thread stopThread(&GraphicsTrackerTest::stopTrackerAfterUs, this, 500000);
+ ASSERT_EQ(C2_BAD_STATE, waitFence.wait(3000000000));
+
+ if (stopThread.joinable()) {
+ stopThread.join();
+ }
+}
+
+TEST_F(GraphicsTrackerTest, SurfaceChangeTest) {
+ uint32_t generation = 1;
+ const int maxDequeueCount = 10;
+
+ const int maxNumAlloc = 20;
+
+ const int firstPassAlloc = 12;
+ const int firstPassRender = 8;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *bufs[maxNumAlloc];
+ sp<Fence> fences[maxNumAlloc];
+
+ FrameQueue frameQueue;
+ std::thread queueThread(&GraphicsTrackerTest::queueBuffer, this, &frameQueue);
+ int numAlloc = 0;
+
+ for (int i = 0; i < firstPassRender; ++i) {
+ ASSERT_EQ(C2_OK, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[i], &fences[i]));
+ mBqStat->mDequeued++;
+ numAlloc++;
+ ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+ }
+
+ while (numAlloc < firstPassAlloc) {
+ c2_status_t ret = mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[numAlloc], &fences[numAlloc]);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(numAlloc, firstPassAlloc);
+
+ // switching surface
+ sp<IGraphicBufferProducer> oldProducer = mProducer;
+ sp<IGraphicBufferConsumer> oldConsumer = mConsumer;
+ mProducer.clear();
+ mConsumer.clear();
+ BufferQueue::createBufferQueue(&mProducer, &mConsumer);
+ ASSERT_TRUE((bool)mProducer && (bool)mConsumer);
+
+ generation += 1;
+
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+
+ ASSERT_EQ(OK, oldProducer->disconnect(NATIVE_WINDOW_API_MEDIA));
+ oldProducer.clear();
+ oldConsumer.clear();
+
+ for (int i = firstPassRender ; i < firstPassAlloc; ++i) {
+ ASSERT_EQ(true, frameQueue.queueItem(bufs[i], fences[i]));
+ }
+
+ while (numAlloc < maxNumAlloc) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ c2_status_t ret = mTracker->allocate(0, 0, 0, kTestUsageFlag, &buf, &fence);
+ if (ret == C2_BLOCKING) {
+ mBqStat->mBlocked++;
+ c2_status_t waitRes = waitFence.wait(3000000000);
+ if (waitRes == C2_TIMED_OUT || waitRes == C2_OK) {
+ continue;
+ }
+ ALOGE("alloc wait failed: c2_err(%d)", waitRes);
+ break;
+ }
+ if (ret != C2_OK) {
+ ALOGE("alloc error: c2_err(%d)", ret);
+ break;
+ }
+ mBqStat->mDequeued++;
+ if (!frameQueue.queueItem(buf, fence)) {
+ ALOGE("queue to render failed");
+ break;
+ }
+ ++numAlloc;
+ }
+
+ ASSERT_EQ(numAlloc, maxNumAlloc);
+
+ frameQueue.stop(true);
+ // Wait more than enough time(1 sec) to render all queued frames for sure.
+ ::usleep(1000000);
+
+ if (queueThread.joinable()) {
+ queueThread.join();
+ }
+ // mReleased should not be checked. IProducerListener::onBufferReleased()
+ // from the previous Surface could be missing after a new Surface was
+ // configured. Instead check # of dequeueable and queueBuffer() calls.
+ ASSERT_EQ(numAlloc, mBqStat->mQueued);
+ ASSERT_EQ(maxDequeueCount, mTracker->getCurDequeueable());
+
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+
+ ASSERT_EQ(C2_OK, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate(
+ 0, 0, 0, kTestUsageFlag, &bufs[0], &fences[0]));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueIncreaseTest) {
+ uint32_t generation = 1;
+ int maxDequeueCount = 10;
+ int dequeueIncrease = 4;
+
+ int numAlloc = 0;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bids[maxDequeueCount];
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ } else {
+ GTEST_SKIP();
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[0], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+
+ maxDequeueCount += dequeueIncrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueIncrease + 1; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[1], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+
+ maxDequeueCount += dequeueIncrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueIncrease + 1; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+}
+
+TEST_F(GraphicsTrackerTest, maxDequeueDecreaseTest) {
+ uint32_t generation = 1;
+ int maxDequeueCount = 12;
+ int dequeueDecrease = 4;
+
+ int numAlloc = 0;
+
+ ASSERT_TRUE(init(maxDequeueCount));
+ ASSERT_TRUE(configure(new TestProducerListener(mTracker, mBqStat, generation),
+ new TestConsumerListener(mConsumer), 1, false));
+
+ ASSERT_EQ(OK, mProducer->setGenerationNumber(generation));
+ ASSERT_EQ(C2_OK, mTracker->configureGraphics(mProducer, generation));
+
+ int waitFd = -1;
+ ASSERT_EQ(C2_OK, mTracker->getWaitableFd(&waitFd));
+ C2Fence waitFence = _C2FenceFactory::CreatePipeFence(waitFd);
+
+ AHardwareBuffer *buf;
+ sp<Fence> fence;
+ uint64_t bids[maxDequeueCount];
+ if (__builtin_available(android __ANDROID_API_T__, *)) {
+ for (int i = 0; i < maxDequeueCount; ++i) {
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(OK, AHardwareBuffer_getId(buf, &bids[i]));
+ AHardwareBuffer_release(buf);
+ mBqStat->mDequeued++;
+ numAlloc++;
+ }
+ } else {
+ GTEST_SKIP();
+ }
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+
+ int discardIdx = 0;
+ maxDequeueCount -= dequeueDecrease;
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueDecrease + 1; ++i) {
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ }
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ mBqStat->mDequeued++;
+
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ maxDequeueCount -= dequeueDecrease;
+
+ ASSERT_EQ(C2_OK, mTracker->configureMaxDequeueCount(maxDequeueCount));
+ for (int i = 0; i < dequeueDecrease - 1; ++i) {
+ ASSERT_EQ(C2_TIMED_OUT, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_BLOCKING, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ ASSERT_EQ(C2_OK, mTracker->deallocate(bids[discardIdx++], Fence::NO_FENCE));
+ mBqStat->mDiscarded++;
+ }
+ ASSERT_EQ(C2_OK, waitFence.wait(1000000000));
+ ASSERT_EQ(C2_OK, mTracker->allocate( 0, 0, 0, kTestUsageFlag, &buf, &fence));
+ mBqStat->mDequeued++;
+}
diff --git a/media/codec2/vndk/Android.bp b/media/codec2/vndk/Android.bp
index af2683b..9f57bfd 100644
--- a/media/codec2/vndk/Android.bp
+++ b/media/codec2/vndk/Android.bp
@@ -84,7 +84,7 @@
"libbase",
"libdmabufheap",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
],
local_include_dirs: [
@@ -102,7 +102,7 @@
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
"android.hardware.media.bufferpool@2.0",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
"libbase",
"libbinder_ndk",
@@ -162,11 +162,12 @@
"android.hardware.graphics.bufferqueue@2.0",
"android.hardware.common-V2-ndk",
"android.hardware.common.fmq-V1-ndk",
- "android.hardware.media.bufferpool2-V1-ndk",
+ "android.hardware.media.bufferpool2-V2-ndk",
"android.hardware.media.c2-V1-ndk",
],
shared_libs: [
+ "libbinder",
"libbinder_ndk",
"libui",
"libdl",
diff --git a/media/codec2/vndk/C2AllocatorGralloc.cpp b/media/codec2/vndk/C2AllocatorGralloc.cpp
index 107ce89..60b5b29 100644
--- a/media/codec2/vndk/C2AllocatorGralloc.cpp
+++ b/media/codec2/vndk/C2AllocatorGralloc.cpp
@@ -383,7 +383,7 @@
}
uint8_t *pointer = nullptr;
- err = mapper.lock(handle, usage, bounds, (void **)&pointer, nullptr, nullptr);
+ err = mapper.lock(handle, usage, bounds, (void **)&pointer);
if (err != NO_ERROR || pointer == nullptr) {
return C2_CORRUPTED;
}
diff --git a/media/codec2/vndk/C2Fence.cpp b/media/codec2/vndk/C2Fence.cpp
index 52ebe25..5d50fc3 100644
--- a/media/codec2/vndk/C2Fence.cpp
+++ b/media/codec2/vndk/C2Fence.cpp
@@ -335,7 +335,8 @@
p.reset();
}
} else {
- ALOGE("Create sync fence from invalid fd");
+ ALOGV("Create sync fence from invalid fd");
+ return C2Fence();
}
return C2Fence(p);
}
@@ -531,7 +532,9 @@
p = SyncFenceImpl::CreateFromNativeHandle(handle);
break;
default:
- ALOGD("Unsupported fence type %d", type);
+ ALOGV("Unsupported fence type %d", type);
+ // If this is malformed-handle close the handle here.
+ (void) native_handle_close(handle);
// return a null-fence in this case
break;
}
diff --git a/media/codec2/vndk/include/C2SurfaceSyncObj.h b/media/codec2/vndk/include/C2SurfaceSyncObj.h
index b193b4a..7c1a405 100644
--- a/media/codec2/vndk/include/C2SurfaceSyncObj.h
+++ b/media/codec2/vndk/include/C2SurfaceSyncObj.h
@@ -117,6 +117,16 @@
*/
void notifyAll();
+ /**
+ * Invalide current sync variables on the death of the other process.
+ */
+ void invalidate();
+
+ /**
+ * If a dead process holds the lock, clear the lock.
+ */
+ void clearLockIfNecessary();
+
C2SyncVariables() {}
private:
@@ -135,6 +145,11 @@
*/
int wait();
+ /**
+ * try lock for the specified duration.
+ */
+ bool tryLockFor(size_t ms);
+
std::atomic<uint32_t> mLock;
std::atomic<uint32_t> mCond;
int32_t mMaxDequeueCount;
diff --git a/media/codec2/vndk/platform/C2BqBuffer.cpp b/media/codec2/vndk/platform/C2BqBuffer.cpp
index 62b0ab5..48157c8 100644
--- a/media/codec2/vndk/platform/C2BqBuffer.cpp
+++ b/media/codec2/vndk/platform/C2BqBuffer.cpp
@@ -396,6 +396,12 @@
if (c2Fence) {
*c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
}
+ if (mInvalidated) {
+ if (c2Fence) {
+ *c2Fence = C2Fence();
+ }
+ return C2_BAD_STATE;
+ }
return C2_BLOCKING;
}
if (syncVar->getSyncStatusLocked() != C2SyncVariables::STATUS_ACTIVE) {
@@ -404,6 +410,12 @@
if (c2Fence) {
*c2Fence = _C2FenceFactory::CreateSurfaceFence(mSyncMem, waitId);
}
+ if (mInvalidated) {
+ if (c2Fence) {
+ *c2Fence = C2Fence();
+ }
+ return C2_BAD_STATE;
+ }
return C2_BLOCKING;
}
syncVar->notifyDequeuedLocked();
@@ -690,7 +702,6 @@
}
}
int migrated = 0;
- std::shared_ptr<C2SurfaceSyncMemory> oldMem;
// poolDatas dtor should not be called during lock is held.
std::shared_ptr<C2BufferQueueBlockPoolData>
poolDatas[NUM_BUFFER_SLOTS];
@@ -708,8 +719,22 @@
mGeneration = 0;
ALOGD("configuring null producer: igbp_information(%d)", bqInformation);
}
- oldMem = mSyncMem; // preven destruction while locked.
- mSyncMem = c2SyncMem;
+ if (mInvalidated) {
+ return;
+ }
+ {
+ std::unique_lock<std::mutex> memLock(mSyncMemMutex);
+ mOldMem = mSyncMem; // prevent destruction while locked.
+ // The waiters from the old memory will be
+ // woken up by the client after this
+ // configuration from HAL being finished.
+ // But we will keep this in case of the
+ // client being dead in between.
+ // In the case the death listener will wake
+ // up the wiators for the old memory using
+ // mOldMem here.
+ mSyncMem = c2SyncMem;
+ }
C2SyncVariables *syncVar = mSyncMem ? mSyncMem->mem() : nullptr;
if (syncVar) {
syncVar->lock();
@@ -736,6 +761,9 @@
// is no longer valid.
mIgbpValidityToken = std::make_shared<int>(0);
}
+ if (mInvalidated) {
+ mIgbpValidityToken = std::make_shared<int>(0);
+ }
for (int i = 0; i < NUM_BUFFER_SLOTS; ++i) {
mBuffers[i] = buffers[i];
mPoolDatas[i] = poolDatas[i];
@@ -754,8 +782,33 @@
}
void invalidate() {
- mInvalidated = true;
+ std::shared_ptr<C2SurfaceSyncMemory> syncMem;
+ std::shared_ptr<C2SurfaceSyncMemory> oldMem;
+ {
+ std::unique_lock<std::mutex> l(mSyncMemMutex);
+ bool old = mInvalidated.exchange(true);
+ if (old) {
+ return;
+ }
+ syncMem = mSyncMem;
+ oldMem = mOldMem;
+ }
mIgbpValidityToken.reset();
+ C2SyncVariables *syncVar = syncMem ? syncMem->mem(): nullptr;
+ if (syncVar) {
+ syncVar->invalidate();
+ }
+ C2SyncVariables *oldVar = oldMem ? oldMem->mem(): nullptr;
+ if (oldVar) {
+ oldVar->invalidate();
+ }
+ // invalidate pending lock from a dead process if any
+ if (syncVar) {
+ syncVar->clearLockIfNecessary();
+ }
+ if (oldVar) {
+ oldVar->clearLockIfNecessary();
+ }
}
private:
@@ -780,7 +833,9 @@
sp<GraphicBuffer> mBuffers[NUM_BUFFER_SLOTS];
std::weak_ptr<C2BufferQueueBlockPoolData> mPoolDatas[NUM_BUFFER_SLOTS];
+ std::mutex mSyncMemMutex;
std::shared_ptr<C2SurfaceSyncMemory> mSyncMem;
+ std::shared_ptr<C2SurfaceSyncMemory> mOldMem;
// IGBP invalidation notification token.
// The buffers(C2BufferQueueBlockPoolData) has the reference to the IGBP where
diff --git a/media/codec2/vndk/platform/C2IgbaBuffer.cpp b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
index 2051e8f..eafdb22 100644
--- a/media/codec2/vndk/platform/C2IgbaBuffer.cpp
+++ b/media/codec2/vndk/platform/C2IgbaBuffer.cpp
@@ -193,7 +193,7 @@
width, height, format, usage, kBlockingFetchTimeoutNs, &origId, block, &fence);
if (res == C2_BLOCKING) {
- return C2_TIMED_OUT;
+ return C2_BLOCKING;
}
if (res != C2_OK) {
return res;
diff --git a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
index d8c2292..41d16b5 100644
--- a/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
+++ b/media/codec2/vndk/platform/C2SurfaceSyncObj.cpp
@@ -26,6 +26,33 @@
#include <chrono>
#include <C2SurfaceSyncObj.h>
+namespace {
+static inline void timespec_add_ms(timespec& ts, size_t ms) {
+ constexpr int kNanoSecondsPerSec = 1000000000;
+ ts.tv_sec += ms / 1000;
+ ts.tv_nsec += (ms % 1000) * 1000000;
+ if (ts.tv_nsec >= kNanoSecondsPerSec) {
+ ts.tv_sec++;
+ ts.tv_nsec -= kNanoSecondsPerSec;
+ }
+}
+
+/*
+ * lhs < rhs: return <0
+ * lhs == rhs: return 0
+ * lhs > rhs: return >0
+ */
+static inline int timespec_compare(const timespec& lhs, const timespec& rhs) {
+ if (lhs.tv_sec < rhs.tv_sec) {
+ return -1;
+ }
+ if (lhs.tv_sec > rhs.tv_sec) {
+ return 1;
+ }
+ return lhs.tv_nsec - rhs.tv_nsec;
+}
+}
+
const native_handle_t C2SurfaceSyncMemory::HandleSyncMem::cHeader = {
C2SurfaceSyncMemory::HandleSyncMem::version,
C2SurfaceSyncMemory::HandleSyncMem::numFds,
@@ -284,6 +311,26 @@
this->unlock();
}
+void C2SyncVariables::invalidate() {
+ mCond++;
+ (void) syscall(__NR_futex, &mCond, FUTEX_REQUEUE, INT_MAX, (void *)INT_MAX, &mLock, 0);
+}
+
+void C2SyncVariables::clearLockIfNecessary() {
+ // Note: After waiting for 30ms without acquiring the lock,
+ // we will consider the lock is dangling.
+ // Since the lock duration is very brief to manage the counter,
+ // waiting for 30ms should be more than enough.
+ constexpr size_t kTestLockDurationMs = 30;
+
+ bool locked = tryLockFor(kTestLockDurationMs);
+ unlock();
+
+ if (!locked) {
+ ALOGW("A dead process might be holding the lock");
+ }
+}
+
int C2SyncVariables::signal() {
mCond++;
@@ -308,3 +355,35 @@
}
return 0;
}
+
+bool C2SyncVariables::tryLockFor(size_t ms) {
+ uint32_t old = FUTEX_UNLOCKED;
+
+ if (mLock.compare_exchange_strong(old, FUTEX_LOCKED_UNCONTENDED)) {
+ return true;
+ }
+
+ if (old == FUTEX_LOCKED_UNCONTENDED) {
+ old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+ }
+
+ struct timespec wait{
+ static_cast<time_t>(ms / 1000),
+ static_cast<long>((ms % 1000) * 1000000)};
+ struct timespec end;
+ clock_gettime(CLOCK_REALTIME, &end);
+ timespec_add_ms(end, ms);
+
+ while (old != FUTEX_UNLOCKED) { // case of EINTR being returned;
+ (void)syscall(__NR_futex, &mLock, FUTEX_WAIT, FUTEX_LOCKED_CONTENDED, &wait, NULL, 0);
+ old = mLock.exchange(FUTEX_LOCKED_CONTENDED);
+
+ struct timespec now;
+ clock_gettime(CLOCK_REALTIME, &now);
+ if (timespec_compare(now, end) >= 0) {
+ break;
+ }
+ }
+
+ return old == FUTEX_UNLOCKED;
+}
diff --git a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
index e1ff3eb..1b06ea7 100644
--- a/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
+++ b/media/libaaudio/fuzzer/libaaudio_fuzzer.cpp
@@ -19,6 +19,8 @@
#include "aaudio/AAudioTesting.h"
#include <fuzzer/FuzzedDataProvider.h>
+#include <functional>
+
constexpr int32_t kRandomStringLength = 256;
constexpr int32_t kMaxRuns = 100;
constexpr int64_t kNanosPerMillisecond = 1000 * 1000;
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index c3b32e6..9d9b574 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -2011,10 +2011,20 @@
__INTRODUCED_IN(28);
/**
- * Passes back the time at which a particular frame was presented.
+ * Returns the time at which a particular frame was played on a speaker or headset,
+ * or was recorded on a microphone.
+ *
* This can be used to synchronize audio with video or MIDI.
* It can also be used to align a recorded stream with a playback stream.
*
+ * The framePosition is an index into the stream of audio data.
+ * The first frame played or recorded is at framePosition 0.
+ *
+ * These framePositions are the same units that you get from AAudioStream_getFramesRead()
+ * or AAudioStream_getFramesWritten().
+ * A "frame" is a set of audio sample values that are played simultaneously.
+ * For example, a stereo stream has two samples in a frame, left and right.
+ *
* Timestamps are only valid when the stream is in {@link #AAUDIO_STREAM_STATE_STARTED}.
* {@link #AAUDIO_ERROR_INVALID_STATE} will be returned if the stream is not started.
* Note that because requestStart() is asynchronous, timestamps will not be valid until
@@ -2030,8 +2040,8 @@
*
* @param stream reference provided by AAudioStreamBuilder_openStream()
* @param clockid CLOCK_MONOTONIC or CLOCK_BOOTTIME
- * @param framePosition pointer to a variable to receive the position
- * @param timeNanoseconds pointer to a variable to receive the time
+ * @param[out] framePosition pointer to a variable to receive the position
+ * @param[out] 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* _Nonnull stream,
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 886603d..fcb376c 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -41,10 +41,10 @@
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
- // "modernize-use-nodiscard", // found in aidl generated files
+ "modernize-use-nodiscard",
"modernize-use-noexcept",
"modernize-use-nullptr",
- // "modernize-use-override", // found in aidl generated files
+ "modernize-use-override",
// "modernize-use-trailing-return-type", // not necessarily more readable
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
@@ -225,10 +225,12 @@
"flowgraph/SinkI16.cpp",
"flowgraph/SinkI24.cpp",
"flowgraph/SinkI32.cpp",
+ "flowgraph/SinkI8_24.cpp",
"flowgraph/SourceFloat.cpp",
"flowgraph/SourceI16.cpp",
"flowgraph/SourceI24.cpp",
"flowgraph/SourceI32.cpp",
+ "flowgraph/SourceI8_24.cpp",
"flowgraph/resampler/IntegerRatio.cpp",
"flowgraph/resampler/LinearResampler.cpp",
"flowgraph/resampler/MultiChannelResampler.cpp",
diff --git a/media/libaaudio/src/binding/AudioEndpointParcelable.h b/media/libaaudio/src/binding/AudioEndpointParcelable.h
index 722dd14..12cc42e 100644
--- a/media/libaaudio/src/binding/AudioEndpointParcelable.h
+++ b/media/libaaudio/src/binding/AudioEndpointParcelable.h
@@ -53,7 +53,7 @@
int32_t addFileDescriptor(const android::base::unique_fd& fd, int32_t sizeInBytes);
/**
- * Close current data file descriptor. The duplicated file descriptor will be close.
+ * Close current data file descriptor. The duplicated file descriptor will be closed.
*/
void closeDataFileDescriptor();
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.cpp b/media/libaaudio/src/client/AAudioFlowGraph.cpp
index b7e0ae6..14e2007 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.cpp
+++ b/media/libaaudio/src/client/AAudioFlowGraph.cpp
@@ -30,10 +30,12 @@
#include <flowgraph/SinkI16.h>
#include <flowgraph/SinkI24.h>
#include <flowgraph/SinkI32.h>
+#include <flowgraph/SinkI8_24.h>
#include <flowgraph/SourceFloat.h>
#include <flowgraph/SourceI16.h>
#include <flowgraph/SourceI24.h>
#include <flowgraph/SourceI32.h>
+#include <flowgraph/SourceI8_24.h>
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -68,6 +70,9 @@
case AUDIO_FORMAT_PCM_32_BIT:
mSource = std::make_unique<SourceI32>(sourceChannelCount);
break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ mSource = std::make_unique<SourceI8_24>(sourceChannelCount);
+ break;
default:
ALOGE("%s() Unsupported source format = %d", __func__, sourceFormat);
return AAUDIO_ERROR_UNIMPLEMENTED;
@@ -139,6 +144,9 @@
case AUDIO_FORMAT_PCM_32_BIT:
mSink = std::make_unique<SinkI32>(sinkChannelCount);
break;
+ case AUDIO_FORMAT_PCM_8_24_BIT:
+ mSink = std::make_unique<SinkI8_24>(sinkChannelCount);
+ break;
default:
ALOGE("%s() Unsupported sink format = %d", __func__, sinkFormat);
return AAUDIO_ERROR_UNIMPLEMENTED;
diff --git a/media/libaaudio/src/client/AAudioFlowGraph.h b/media/libaaudio/src/client/AAudioFlowGraph.h
index e1d517e..0c55fca 100644
--- a/media/libaaudio/src/client/AAudioFlowGraph.h
+++ b/media/libaaudio/src/client/AAudioFlowGraph.h
@@ -72,6 +72,12 @@
*/
int32_t pull(void *destination, int32_t targetFramesToRead);
+ // Reset the entire graph so that volume ramps start at their
+ // target value and sample rate converters start with no phase offset.
+ void reset() {
+ mSink->pullReset();
+ }
+
/**
* Set numFramesToWrite frames from the source into the flowgraph.
* Then, attempt to read targetFramesToRead from the flowgraph.
diff --git a/media/libaaudio/src/client/AudioEndpoint.h b/media/libaaudio/src/client/AudioEndpoint.h
index 2c23e1d..b117572 100644
--- a/media/libaaudio/src/client/AudioEndpoint.h
+++ b/media/libaaudio/src/client/AudioEndpoint.h
@@ -107,7 +107,7 @@
*/
void eraseDataMemory();
- void freeDataQueue();
+ void freeDataQueue() { mDataQueue.reset(); }
void dump() const;
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index f431da8..7648e25 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -199,6 +199,7 @@
if (getSampleRate() != getDeviceSampleRate()) {
ALOGD("%s - skipping sample rate converter. SR = %d, Device SR = %d", __func__,
getSampleRate(), getDeviceSampleRate());
+ result = AAUDIO_ERROR_INVALID_RATE;
goto error;
}
}
@@ -399,6 +400,12 @@
uint8_t buffer[getDeviceBufferCapacity() * getBytesPerFrame()];
android::fifo_frames_t fullFramesAvailable = mAudioEndpoint->read(buffer,
getDeviceBufferCapacity());
+ // Before releasing the data queue, update the frames read and written.
+ getFramesRead();
+ getFramesWritten();
+ // Call freeDataQueue() here because the following call to
+ // closeDataFileDescriptor() will invalidate the pointers used by the data queue.
+ mAudioEndpoint->freeDataQueue();
mEndPointParcelable.closeDataFileDescriptor();
aaudio_result_t result = mServiceInterface.exitStandby(
mServiceStreamHandleInfo, endpointParcelable);
diff --git a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
index d9b75da..68c9156 100644
--- a/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalCapture.cpp
@@ -273,7 +273,8 @@
int64_t AudioStreamInternalCapture::getFramesRead() {
if (mAudioEndpoint) {
- mLastFramesRead = mAudioEndpoint->getDataReadCounter() + mFramesOffsetFromService;
+ mLastFramesRead = std::max(mLastFramesRead,
+ mAudioEndpoint->getDataReadCounter() + mFramesOffsetFromService);
}
return mLastFramesRead;
}
@@ -295,8 +296,10 @@
if ((result != mCallbackFrames)) {
ALOGE("callbackLoop: read() returned %d", result);
if (result >= 0) {
- // Only read some of the frames requested. Must have timed out.
- result = AAUDIO_ERROR_TIMEOUT;
+ // Only read some of the frames requested. The stream can be disconnected
+ // or timed out.
+ processCommands();
+ result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
}
maybeCallErrorCallback(result);
break;
diff --git a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
index 3badb0b..5d4c3d4 100644
--- a/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternalPlay.cpp
@@ -100,6 +100,10 @@
}
void AudioStreamInternalPlay::prepareBuffersForStart() {
+ // Reset volume ramps to avoid a starting noise.
+ // This was called here instead of AudioStreamInternal so that
+ // it will be easier to backport.
+ mFlowGraph.reset();
// Prevent stale data from being played.
mAudioEndpoint->eraseDataMemory();
}
@@ -329,8 +333,9 @@
int64_t AudioStreamInternalPlay::getFramesWritten() {
if (mAudioEndpoint) {
- mLastFramesWritten = mAudioEndpoint->getDataWriteCounter()
- + mFramesOffsetFromService;
+ mLastFramesWritten = std::max(
+ mLastFramesWritten,
+ mAudioEndpoint->getDataWriteCounter() + mFramesOffsetFromService);
}
return mLastFramesWritten;
}
@@ -353,8 +358,10 @@
result = write(mCallbackBuffer.get(), mCallbackFrames, timeoutNanos);
if ((result != mCallbackFrames)) {
if (result >= 0) {
- // Only wrote some of the frames requested. Must have timed out.
- result = AAUDIO_ERROR_TIMEOUT;
+ // Only wrote some of the frames requested. The stream can be disconnected
+ // or timed out.
+ processCommands();
+ result = isDisconnected() ? AAUDIO_ERROR_DISCONNECTED : AAUDIO_ERROR_TIMEOUT;
}
maybeCallErrorCallback(result);
break;
diff --git a/media/libaaudio/src/core/AAudioStreamParameters.cpp b/media/libaaudio/src/core/AAudioStreamParameters.cpp
index 1db62f3..3e51575 100644
--- a/media/libaaudio/src/core/AAudioStreamParameters.cpp
+++ b/media/libaaudio/src/core/AAudioStreamParameters.cpp
@@ -61,6 +61,7 @@
case AUDIO_FORMAT_PCM_32_BIT:
case AUDIO_FORMAT_PCM_FLOAT:
case AUDIO_FORMAT_PCM_24_BIT_PACKED:
+ case AUDIO_FORMAT_PCM_8_24_BIT:
case AUDIO_FORMAT_IEC61937:
break; // valid
default:
diff --git a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
index 5e90588..e277d6e 100644
--- a/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
+++ b/media/libaaudio/src/flowgraph/FlowgraphUtilities.h
@@ -17,6 +17,7 @@
#ifndef FLOWGRAPH_UTILITIES_H
#define FLOWGRAPH_UTILITIES_H
+#include <math.h>
#include <unistd.h>
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -50,6 +51,20 @@
return f > 0 ? f + 0.5 : f - 0.5;
}
+/**
+ * Convert a single-precision floating point value to a Q0.23 integer value, stored in a
+ * 32 bit signed integer (technically stored as Q8.23, but clamped to Q0.23).
+ *
+ * Values outside the range [-1.0, 1.0) are properly clamped to -8388608 and 8388607,
+ * including -Inf and +Inf. NaN values are considered undefined, and behavior may change
+ * depending on hardware and future implementation of this function.
+ */
+static int32_t clamp24FromFloat(float f)
+{
+ static const float scale = 1 << 23;
+ return (int32_t) lroundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+}
+
};
#endif // FLOWGRAPH_UTILITIES_H
diff --git a/media/libaaudio/src/flowgraph/SinkI8_24.cpp b/media/libaaudio/src/flowgraph/SinkI8_24.cpp
new file mode 100644
index 0000000..d5e4b80
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI8_24.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright 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 "FlowGraphNode.h"
+#include "FlowgraphUtilities.h"
+#include "SinkI8_24.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SinkI8_24::SinkI8_24(int32_t channelCount)
+ : FlowGraphSink(channelCount) {}
+
+int32_t SinkI8_24::read(void *data, int32_t numFrames) {
+ int32_t *intData = (int32_t *) data;
+ const int32_t channelCount = input.getSamplesPerFrame();
+
+ int32_t framesLeft = numFrames;
+ while (framesLeft > 0) {
+ // Run the graph and pull data through the input port.
+ int32_t framesRead = pullData(framesLeft);
+ if (framesRead <= 0) {
+ break;
+ }
+ const float *signal = input.getBuffer();
+ int32_t numSamples = framesRead * channelCount;
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_q8_23_from_float_with_clamp(intData, signal, numSamples);
+ intData += numSamples;
+ signal += numSamples;
+#else
+ for (int i = 0; i < numSamples; i++) {
+ *intData++ = FlowgraphUtilities::clamp24FromFloat(*signal++);
+ }
+#endif
+ framesLeft -= framesRead;
+ }
+ return numFrames - framesLeft;
+}
diff --git a/media/libaaudio/src/flowgraph/SinkI8_24.h b/media/libaaudio/src/flowgraph/SinkI8_24.h
new file mode 100644
index 0000000..aa96918
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SinkI8_24.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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 FLOWGRAPH_SINK_I8_24_H
+#define FLOWGRAPH_SINK_I8_24_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SinkI8_24 : public FlowGraphSink {
+public:
+ explicit SinkI8_24(int32_t channelCount);
+ ~SinkI8_24() override = default;
+
+ int32_t read(void *data, int32_t numFrames) override;
+
+ const char *getName() override {
+ return "SinkI8_24";
+ }
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SINK_I8_24_H
diff --git a/media/libaaudio/src/flowgraph/SourceI8_24.cpp b/media/libaaudio/src/flowgraph/SourceI8_24.cpp
new file mode 100644
index 0000000..684446c
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI8_24.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 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 <algorithm>
+#include <unistd.h>
+
+#include "FlowGraphNode.h"
+#include "SourceI8_24.h"
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+#include <audio_utils/primitives.h>
+#endif
+
+using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
+
+SourceI8_24::SourceI8_24(int32_t channelCount)
+ : FlowGraphSourceBuffered(channelCount) {
+}
+
+int32_t SourceI8_24::onProcess(int32_t numFrames) {
+ float *floatData = output.getBuffer();
+ const int32_t channelCount = output.getSamplesPerFrame();
+
+ const int32_t framesLeft = mSizeInFrames - mFrameIndex;
+ const int32_t framesToProcess = std::min(numFrames, framesLeft);
+ const int32_t numSamples = framesToProcess * channelCount;
+
+ const int32_t *intBase = static_cast<const int32_t *>(mData);
+ const int32_t *intData = &intBase[mFrameIndex * channelCount];
+
+#if FLOWGRAPH_ANDROID_INTERNAL
+ memcpy_to_float_from_q8_23(floatData, intData, numSamples);
+#else
+ for (int i = 0; i < numSamples; i++) {
+ *floatData++ = *intData++ * kScale;
+ }
+#endif
+
+ mFrameIndex += framesToProcess;
+ return framesToProcess;
+}
diff --git a/media/libaaudio/src/flowgraph/SourceI8_24.h b/media/libaaudio/src/flowgraph/SourceI8_24.h
new file mode 100644
index 0000000..91c756c
--- /dev/null
+++ b/media/libaaudio/src/flowgraph/SourceI8_24.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 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 FLOWGRAPH_SOURCE_I8_24_H
+#define FLOWGRAPH_SOURCE_I8_24_H
+
+#include <stdint.h>
+
+#include "FlowGraphNode.h"
+
+namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph {
+
+class SourceI8_24 : public FlowGraphSourceBuffered {
+public:
+ explicit SourceI8_24(int32_t channelCount);
+ ~SourceI8_24() override = default;
+
+ int32_t onProcess(int32_t numFrames) override;
+
+ const char *getName() override {
+ return "SourceI8_24";
+ }
+private:
+ static constexpr float kScale = 1.0 / (1UL << 23);
+};
+
+} /* namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph */
+
+#endif //FLOWGRAPH_SOURCE_I8_24_H
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 59fdabc..d729047 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -69,16 +69,24 @@
audio_channel_mask_t channelMask =
AAudio_getChannelMaskForOpen(getChannelMask(), getSamplesPerFrame(), false /*isInput*/);
+ // Set flags based on selected parameters.
audio_output_flags_t flags;
aaudio_performance_mode_t perfMode = getPerformanceMode();
switch(perfMode) {
- case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
+ case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY: {
// Bypass the normal mixer and go straight to the FAST mixer.
- // If the app asks for a sessionId then it means they want to use effects.
- // So don't use RAW flag.
- flags = (audio_output_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
- ? (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)
- : (AUDIO_OUTPUT_FLAG_FAST));
+ // Some Usages need RAW mode so they can get the lowest possible latency.
+ // Other Usages should avoid RAW because it can interfere with
+ // dual sink routing or other features.
+ bool usageBenefitsFromRaw = getUsage() == AAUDIO_USAGE_GAME ||
+ getUsage() == AAUDIO_USAGE_MEDIA;
+ // If an app does not ask for a sessionId then there will be no effects.
+ // So we can use the use RAW flag.
+ flags = (audio_output_flags_t) (((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+ && usageBenefitsFromRaw)
+ ? (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)
+ : (AUDIO_OUTPUT_FLAG_FAST));
+ }
break;
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
index 1129ced..d59afef 100644
--- a/media/libaaudio/tests/Android.bp
+++ b/media/libaaudio/tests/Android.bp
@@ -241,3 +241,10 @@
"libaaudio_internal",
],
}
+
+cc_binary {
+ name: "test_idle_disconnected_shared_stream",
+ defaults: ["libaaudio_tests_defaults"],
+ srcs: ["test_idle_disconnected_shared_stream.cpp"],
+ shared_libs: ["libaaudio"],
+}
diff --git a/media/libaaudio/tests/test_flowgraph.cpp b/media/libaaudio/tests/test_flowgraph.cpp
index 7eb8b0d..f20a4bb 100644
--- a/media/libaaudio/tests/test_flowgraph.cpp
+++ b/media/libaaudio/tests/test_flowgraph.cpp
@@ -31,14 +31,16 @@
#include "flowgraph/Limiter.h"
#include "flowgraph/MonoBlend.h"
#include "flowgraph/MonoToMultiConverter.h"
-#include "flowgraph/SourceFloat.h"
#include "flowgraph/RampLinear.h"
#include "flowgraph/SinkFloat.h"
#include "flowgraph/SinkI16.h"
#include "flowgraph/SinkI24.h"
#include "flowgraph/SinkI32.h"
+#include "flowgraph/SinkI8_24.h"
+#include "flowgraph/SourceFloat.h"
#include "flowgraph/SourceI16.h"
#include "flowgraph/SourceI24.h"
+#include "flowgraph/SourceI8_24.h"
#include "flowgraph/resampler/IntegerRatio.h"
using namespace FLOWGRAPH_OUTER_NAMESPACE::flowgraph;
@@ -52,6 +54,9 @@
PARAM_RESAMPLER_QUALITY
};
+constexpr int kInt24Min = 0xff800000;
+constexpr int kInt24Max = 0x007fffff;
+
constexpr int kBytesPerI24Packed = 3;
constexpr int kNumSamples = 8;
@@ -59,15 +64,19 @@
1.0f, 0.5f, -0.25f, -1.0f,
0.0f, 53.9f, -87.2f, -1.02f};
-// Corresponding PCM values as integers.
-constexpr std::array<int16_t, kNumSamples> kExpectedI16 = {
+// Corresponding PCM values as integers.
+constexpr std::array<int16_t, kNumSamples> kExpectedI16 = {
INT16_MAX, 1 << 14, INT16_MIN / 4, INT16_MIN,
0, INT16_MAX, INT16_MIN, INT16_MIN};
-constexpr std::array<int32_t, kNumSamples> kExpectedI32 = {
+constexpr std::array<int32_t, kNumSamples> kExpectedI32 = {
INT32_MAX, 1 << 30, INT32_MIN / 4, INT32_MIN,
0, INT32_MAX, INT32_MIN, INT32_MIN};
+constexpr std::array<int32_t, kNumSamples> kExpectedI8_24 = {
+ kInt24Max, 1 << 22, kInt24Min / 4, kInt24Min,
+ 0, kInt24Max, kInt24Min, kInt24Min};
+
// =================================== FLOAT to I16 ==============
// Simple test that tries to reproduce a Clang compiler bug.
@@ -215,6 +224,8 @@
EXPECT_EQ(input[0], output[1]);
EXPECT_EQ(input[1], output[2]);
EXPECT_EQ(input[1], output[3]);
+ EXPECT_EQ(input[2], output[4]);
+ EXPECT_EQ(input[2], output[5]);
}
TEST(test_flowgraph, module_ramp_linear) {
@@ -434,6 +445,70 @@
}
}
+// =================================== FLOAT to Q8.23 ==============
+__attribute__((noinline))
+static int32_t clamp24FromFloat(float f)
+{
+ static const float scale = 1 << 23;
+ return (int32_t) lroundf(fmaxf(fminf(f * scale, scale - 1.f), -scale));
+}
+
+void local_convert_float_to_i8_24(const float *input,
+ int32_t *output,
+ int count) {
+ for (int i = 0; i < count; i++) {
+ *output++ = clamp24FromFloat(*input++);
+ }
+}
+
+TEST(test_flowgraph, local_convert_float_to_i8_24) {
+ std::array<int32_t, kNumSamples> output;
+ // Convert audio signal using the function.
+ output.fill(777);
+ local_convert_float_to_i8_24(kInputFloat.data(), output.data(), kNumSamples);
+ for (int i = 0; i < kNumSamples; i++) {
+ EXPECT_EQ(kExpectedI8_24.at(i), output.at(i)) << ", i = " << i;
+ }
+}
+
+TEST(test_flowgraph, module_sinkI8_24) {
+ std::array<int32_t, kNumSamples + 10> output; // larger than input
+
+ SourceFloat sourceFloat{2};
+ SinkI8_24 sinkI8_24{2};
+
+ sourceFloat.setData(kInputFloat.data(), kNumSamples);
+ sourceFloat.output.connect(&sinkI8_24.input);
+
+ output.fill(777);
+ int32_t numRead = sinkI8_24.read(output.data(), output.size());
+ ASSERT_EQ(kNumSamples, numRead);
+ for (int i = 0; i < numRead; i++) {
+ EXPECT_EQ(kExpectedI8_24.at(i), output.at(i)) << ", i = " << i;
+ }
+}
+
+TEST(test_flowgraph, module_sourceI8_24) {
+ static const int32_t input[] = {1 << 23, 1 << 22, -(1 << 21), -(1 << 23), 0, 1 << 25,
+ -(1 << 25)};
+ static const float expected[] = {1.0f, 0.5f, -0.25f, -1.0f, 0.0f, 4.0f, -4.0f};
+ float output[100];
+
+ SourceI8_24 sourceI8_24{1};
+ SinkFloat sinkFloat{1};
+
+ int numSamples = std::size(input);
+
+ sourceI8_24.setData(input, numSamples);
+ sourceI8_24.output.connect(&sinkFloat.input);
+
+ int32_t numRead = sinkFloat.read(output, numSamples);
+ ASSERT_EQ(numSamples, numRead);
+ for (int i = 0; i < numRead; i++) {
+ EXPECT_EQ(expected[i], output[i]) << ", i = " << i;
+ }
+}
+
void checkSampleRateConversionVariedSizes(int32_t sourceSampleRate,
int32_t sinkSampleRate,
MultiChannelResampler::Quality resamplerQuality) {
diff --git a/media/libaaudio/tests/test_idle_disconnected_shared_stream.cpp b/media/libaaudio/tests/test_idle_disconnected_shared_stream.cpp
new file mode 100644
index 0000000..2e24b6b
--- /dev/null
+++ b/media/libaaudio/tests/test_idle_disconnected_shared_stream.cpp
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+// When receive disconnect event, ignore it and leave the shared stream at OPEN
+// state. It should be possible to open another shared stream and start it.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <aaudio/AAudio.h>
+#include <aaudio/AAudioTesting.h>
+
+static constexpr unsigned int ONE_SECOND = 1e6;
+static constexpr unsigned int WAIT_TIME_MS = 10 * ONE_SECOND;
+#define MMAP_POLICY AAUDIO_POLICY_ALWAYS
+
+AAudioStream* openStream() {
+ AAudioStreamBuilder *aaudioBuilder = nullptr;
+ aaudio_result_t result = AAudio_createStreamBuilder(&aaudioBuilder);
+ if (result != AAUDIO_OK) {
+ printf("Failed to create stream builder, result=%d, %s\n",
+ result, AAudio_convertResultToText(result));
+ return nullptr;
+ }
+ AAudioStreamBuilder_setSharingMode(aaudioBuilder, AAUDIO_SHARING_MODE_SHARED);
+ AAudioStreamBuilder_setPerformanceMode(aaudioBuilder, AAUDIO_PERFORMANCE_MODE_LOW_LATENCY);
+ AAudioStream* aaudioStream;
+ result = AAudioStreamBuilder_openStream(aaudioBuilder, &aaudioStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR could not open AAudio stream, %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+ AAudioStreamBuilder_delete(aaudioBuilder);
+ return aaudioStream;
+}
+
+aaudio_result_t testNoCloseSharedStreamAfterRoutingChanged(bool stopFirstStream) {
+ aaudio_result_t result = AAUDIO_OK;
+ printf("Please connect external device that supports MMAP playback, will wait 10 seconds\n");
+ usleep(WAIT_TIME_MS);
+
+ // Open first shared stream
+ printf("Open first shared stream\n");
+ AAudioStream* firstStream = openStream();
+ if (firstStream == nullptr) {
+ return 1;
+ }
+ result = AAudioStream_requestStart(firstStream);
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+
+ if (stopFirstStream) {
+ printf("Stop first shared stream\n");
+ result = AAudioStream_requestStop(firstStream);
+ if (result != AAUDIO_OK) {
+ return result;
+ }
+ printf("Wait to make sure the stream is stopped\n");
+ usleep(ONE_SECOND * 3);
+ }
+
+ printf("Please disconnect and reconnect the external device, will wait 10 second\n");
+ usleep(WAIT_TIME_MS);
+
+ // Open second stream after the first shared stream was reconnected
+ printf("Open second shared stream\n");
+ AAudioStream* secondStream = openStream();
+ if (secondStream == nullptr) {
+ result = 1;
+ goto exit;
+ }
+
+ // Starting second stream should be successful
+ printf("Start second shared stream\n");
+ result = AAudioStream_requestStart(secondStream);
+ if (result != AAUDIO_OK) {
+ printf("ERROR could not start second stream, %d %s\n",
+ result, AAudio_convertResultToText(result));
+ }
+
+exit:
+ // Close all streams
+ AAudioStream_close(firstStream);
+ AAudioStream_close(secondStream);
+ return result;
+}
+
+int main(int argc, char **argv) {
+ (void) argc; // unused
+ (void) argv; // unused
+
+ aaudio_policy_t originalPolicy = AAudio_getMMapPolicy();
+ AAudio_setMMapPolicy(MMAP_POLICY);
+
+ printf("Run first test. The first stream is started when routing changed.\n");
+ aaudio_result_t result = testNoCloseSharedStreamAfterRoutingChanged(false /*stopFirstStream*/);
+
+ if (result != AAUDIO_OK) {
+ goto exit;
+ }
+
+ printf("First test passed\n");
+ printf("----------------------------------------------------------------\n");
+ printf("Run second test. The first stream is stopped when routing changed.\n");
+ if (testNoCloseSharedStreamAfterRoutingChanged(true /*stopFirstStream*/) == AAUDIO_OK) {
+ printf("Second test passed\n");
+ }
+
+exit:
+ AAudio_setMMapPolicy(originalPolicy);
+
+ return result != AAUDIO_OK ? EXIT_FAILURE : EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 658bf63..51a679b 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -217,6 +217,7 @@
],
defaults: [
"audio_aidl_conversion_common_default",
+ "audio_aidl_conversion_common_default_cpp",
"latest_android_media_audio_common_types_cpp_export_shared",
],
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 58e0486..565427b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1704,10 +1704,14 @@
__func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
- if (mStatus == NO_ERROR && mSelectedDeviceId != mRoutedDeviceId) {
+ if (mStatus == NO_ERROR) {
+ // allow track invalidation when track is not playing to propagate
+ // the updated mSelectedDeviceId
if (isPlaying_l()) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
+ if (mSelectedDeviceId != mRoutedDeviceId) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ mProxy->interrupt();
+ }
} else {
// if the track is idle, try to restore now and
// defer to next start if not possible
@@ -2855,7 +2859,9 @@
if (isOffloadedOrDirect_l() || mDoNotReconnect) {
// FIXME re-creation of offloaded and direct tracks is not yet implemented;
- // reconsider enabling for linear PCM encodings when position can be preserved.
+ // Disabled since (1) timestamp correction is not implemented for non-PCM and
+ // (2) We pre-empt existing direct tracks on resource constraint, so these tracks
+ // shouldn't reconnect.
result = DEAD_OBJECT;
return result;
}
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index 60bb4f0..234e858 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -43,8 +43,17 @@
}
],
"postsubmit": [
+ // TODO(b/302036943): Enable once we make it pass with AIDL HAL on CF.
+ // {
+ // "name": "audioeffect_analysis"
+ // },
{
- "name": "audioeffect_analysis"
+ "name": "CtsVirtualDevicesTestCases",
+ "options" : [
+ {
+ "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
+ }
+ ]
}
]
}
diff --git a/media/libaudioclient/tests/audioeffect_tests.cpp b/media/libaudioclient/tests/audioeffect_tests.cpp
index 26121cd..e12ae23 100644
--- a/media/libaudioclient/tests/audioeffect_tests.cpp
+++ b/media/libaudioclient/tests/audioeffect_tests.cpp
@@ -80,7 +80,7 @@
uint32_t numEffects = AudioEffect::kMaxPreProcessing;
status_t ret = AudioEffect::queryDefaultPreProcessing(audioRecord->getSessionId(), descriptors,
&numEffects);
- if (ret != OK) {
+ if (ret != OK || numEffects > AudioEffect::kMaxPreProcessing) {
return false;
}
for (int i = 0; i < numEffects; i++) {
@@ -247,6 +247,7 @@
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
+ ASSERT_NE(capture->getAudioRecordHandle(), nullptr);
if (!isEffectDefaultOnRecord(&descriptors[i].type, &descriptors[i].uuid,
capture->getAudioRecordHandle())) {
selectedEffect = i;
@@ -265,6 +266,7 @@
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
+ ASSERT_NE(capture->getAudioRecordHandle(), nullptr);
EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
@@ -287,6 +289,7 @@
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
+ ASSERT_NE(capture->getAudioRecordHandle(), nullptr);
EXPECT_TRUE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
capture->getAudioRecordHandle()))
<< "Effect should have been default on record. " << type;
@@ -304,6 +307,7 @@
ASSERT_NE(capture, nullptr) << "Unable to create Record Application";
EXPECT_EQ(NO_ERROR, capture->create());
EXPECT_EQ(NO_ERROR, capture->start());
+ ASSERT_NE(capture->getAudioRecordHandle(), nullptr);
EXPECT_FALSE(isEffectDefaultOnRecord(selectedEffectType, selectedEffectUuid,
capture->getAudioRecordHandle()))
<< "Effect should not have been default on record. " << type;
diff --git a/media/libaudioclient/tests/audiorecord_tests.cpp b/media/libaudioclient/tests/audiorecord_tests.cpp
index 8c63a6d..61edd4d 100644
--- a/media/libaudioclient/tests/audiorecord_tests.cpp
+++ b/media/libaudioclient/tests/audiorecord_tests.cpp
@@ -14,9 +14,13 @@
* limitations under the License.
*/
+#include <sstream>
+
//#define LOG_NDEBUG 0
#define LOG_TAG "AudioRecordTest"
+#include <android-base/logging.h>
+#include <binder/ProcessState.h>
#include <gtest/gtest.h>
#include "audio_test_utils.h"
@@ -25,32 +29,40 @@
class AudioRecordTest : public ::testing::Test {
public:
- virtual void SetUp() override {
+ void SetUp() override {
mAC = new AudioCapture(AUDIO_SOURCE_DEFAULT, 44100, AUDIO_FORMAT_PCM_16_BIT,
AUDIO_CHANNEL_IN_FRONT);
ASSERT_NE(nullptr, mAC);
ASSERT_EQ(OK, mAC->create()) << "record creation failed";
}
- virtual void TearDown() override {
+ void TearDown() override {
if (mAC) ASSERT_EQ(OK, mAC->stop());
}
sp<AudioCapture> mAC;
};
-class AudioRecordCreateTest
- : public ::testing::TestWithParam<
- std::tuple<uint32_t, audio_format_t, audio_channel_mask_t, audio_input_flags_t,
- audio_session_t, audio_source_t>> {
+using RecordCreateTestParam = std::tuple<uint32_t, audio_format_t, audio_channel_mask_t,
+ audio_input_flags_t, audio_session_t, audio_source_t>;
+enum {
+ RECORD_PARAM_SAMPLE_RATE,
+ RECORD_PARAM_FORMAT,
+ RECORD_PARAM_CHANNEL_MASK,
+ RECORD_PARAM_FLAGS,
+ RECORD_PARAM_SESSION_ID,
+ RECORD_PARAM_INPUT_SOURCE
+};
+
+class AudioRecordCreateTest : public ::testing::TestWithParam<RecordCreateTestParam> {
public:
AudioRecordCreateTest()
- : mSampleRate(std::get<0>(GetParam())),
- mFormat(std::get<1>(GetParam())),
- mChannelMask(std::get<2>(GetParam())),
- mFlags(std::get<3>(GetParam())),
- mSessionId(std::get<4>(GetParam())),
- mInputSource(std::get<5>(GetParam())){};
+ : mSampleRate(std::get<RECORD_PARAM_SAMPLE_RATE>(GetParam())),
+ mFormat(std::get<RECORD_PARAM_FORMAT>(GetParam())),
+ mChannelMask(std::get<RECORD_PARAM_CHANNEL_MASK>(GetParam())),
+ mFlags(std::get<RECORD_PARAM_FLAGS>(GetParam())),
+ mSessionId(std::get<RECORD_PARAM_SESSION_ID>(GetParam())),
+ mInputSource(std::get<RECORD_PARAM_INPUT_SOURCE>(GetParam())){};
const uint32_t mSampleRate;
const audio_format_t mFormat;
@@ -62,14 +74,14 @@
sp<AudioCapture> mAC;
- virtual void SetUp() override {
+ void SetUp() override {
mAC = new AudioCapture(mInputSource, mSampleRate, mFormat, mChannelMask, mFlags, mSessionId,
mTransferType);
ASSERT_NE(nullptr, mAC);
ASSERT_EQ(OK, mAC->create()) << "record creation failed";
}
- virtual void TearDown() override {
+ void TearDown() override {
if (mAC) ASSERT_EQ(OK, mAC->stop());
}
};
@@ -197,6 +209,18 @@
EXPECT_EQ(OK, mAC->audioProcess()) << "audioProcess failed";
}
+static std::string GetRecordTestName(const testing::TestParamInfo<RecordCreateTestParam>& info) {
+ const auto& p = info.param;
+ std::ostringstream s;
+ s << std::get<RECORD_PARAM_SAMPLE_RATE>(p) << "_"
+ << audio_format_to_string(std::get<RECORD_PARAM_FORMAT>(p)) << "__"
+ << audio_channel_mask_to_string(std::get<RECORD_PARAM_CHANNEL_MASK>(p)) << "__"
+ << "Flags_0x" << std::hex << std::get<RECORD_PARAM_FLAGS>(p) << std::dec << "__"
+ << "Session_" << std::get<RECORD_PARAM_SESSION_ID>(p) << "__"
+ << audio_source_to_string(std::get<RECORD_PARAM_INPUT_SOURCE>(p));
+ return s.str();
+}
+
// for port primary input
INSTANTIATE_TEST_SUITE_P(AudioRecordPrimaryInput, AudioRecordCreateTest,
::testing::Combine(::testing::Values(8000, 11025, 12000, 16000, 22050,
@@ -207,7 +231,8 @@
AUDIO_CHANNEL_IN_FRONT_BACK),
::testing::Values(AUDIO_INPUT_FLAG_NONE),
::testing::Values(AUDIO_SESSION_NONE),
- ::testing::Values(AUDIO_SOURCE_DEFAULT)));
+ ::testing::Values(AUDIO_SOURCE_DEFAULT)),
+ GetRecordTestName);
// for port fast input
INSTANTIATE_TEST_SUITE_P(AudioRecordFastInput, AudioRecordCreateTest,
@@ -219,7 +244,8 @@
AUDIO_CHANNEL_IN_FRONT_BACK),
::testing::Values(AUDIO_INPUT_FLAG_FAST),
::testing::Values(AUDIO_SESSION_NONE),
- ::testing::Values(AUDIO_SOURCE_DEFAULT)));
+ ::testing::Values(AUDIO_SOURCE_DEFAULT)),
+ GetRecordTestName);
// misc
INSTANTIATE_TEST_SUITE_P(AudioRecordMiscInput, AudioRecordCreateTest,
@@ -232,4 +258,35 @@
AUDIO_SOURCE_CAMCORDER,
AUDIO_SOURCE_VOICE_RECOGNITION,
AUDIO_SOURCE_VOICE_COMMUNICATION,
- AUDIO_SOURCE_UNPROCESSED)));
+ AUDIO_SOURCE_UNPROCESSED)),
+ GetRecordTestName);
+
+namespace {
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Started", test_info);
+ }
+ void OnTestEnd(const ::testing::TestInfo& test_info) override {
+ TraceTestState("Finished", test_info);
+ }
+ void OnTestPartResult(const ::testing::TestPartResult& result) override { LOG(INFO) << result; }
+
+ private:
+ static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info) {
+ LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+ }
+};
+
+} // namespace
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ android::base::SetMinimumLogSeverity(::android::base::DEBUG);
+ // This is for death handlers instantiated by the framework code.
+ android::ProcessState::self()->setThreadPoolMaxThreadCount(1);
+ android::ProcessState::self()->startThreadPool();
+ return RUN_ALL_TESTS();
+}
diff --git a/media/libaudiohal/FactoryHal.cpp b/media/libaudiohal/FactoryHal.cpp
index f88915d..c414e19 100644
--- a/media/libaudiohal/FactoryHal.cpp
+++ b/media/libaudiohal/FactoryHal.cpp
@@ -50,9 +50,8 @@
* This list need to keep sync with AudioHalVersionInfo.VERSIONS in
* media/java/android/media/AudioHalVersionInfo.java.
*/
-static const std::array<AudioHalVersionInfo, 5> sAudioHALVersions = {
- // TODO: remove this comment to get AIDL
- // AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, 1, 0),
+static const std::array<AudioHalVersionInfo, 6> sAudioHALVersions = {
+ AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, 1, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 6, 0),
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 6a6557c..db9a9b1 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -451,6 +451,7 @@
}
*config = VALUE_OR_RETURN_STATUS(
::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
+ if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
args.portConfigId = mixPortConfig.id;
const bool isOffload = isBitPositionFlagSet(
@@ -523,6 +524,7 @@
}
*config = VALUE_OR_RETURN_STATUS(
::aidl::android::aidl2legacy_AudioConfig_audio_config_t(aidlConfig, isInput));
+ if (mixPortConfig.id == 0) return BAD_VALUE; // HAL suggests a different config.
::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
args.portConfigId = mixPortConfig.id;
RecordTrackMetadata aidlTrackMetadata{
@@ -707,8 +709,7 @@
*config, isInput, 0 /*portId*/));
AudioPortConfig portConfig;
std::lock_guard l(mLock);
- return mMapper.findOrCreatePortConfig(
- requestedPortConfig, std::set<int32_t>(), &portConfig);
+ return mMapper.setPortConfig(requestedPortConfig, std::set<int32_t>(), &portConfig);
}
MicrophoneInfoProvider::Info const* DeviceHalAidl::getMicrophoneInfo() {
@@ -780,7 +781,7 @@
Hal2AidlMapper::Cleanups cleanups(mMapperAccessor);
{
std::lock_guard l(mLock);
- RETURN_STATUS_IF_ERROR(mMapper.findOrCreatePortConfig(
+ RETURN_STATUS_IF_ERROR(mMapper.setPortConfig(
requestedPortConfig, {} /*destinationPortIds*/, &devicePortConfig, &cleanups));
}
auto aidlEffect = sp<effect::EffectHalAidl>::cast(effect);
@@ -913,15 +914,39 @@
}
status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_port_v7* port) {
- // There is not AIDL API defined for `prepareToDisconnectExternalDevice`.
- // Call `setConnectedState` instead.
- // TODO(b/279824103): call prepareToDisconnectExternalDevice when it is added.
- RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
- std::lock_guard l(mLock);
- mDeviceDisconnectionNotified.insert(port->id);
- // Return that there was no error as otherwise the disconnection procedure will not be
- // considered complete for upper layers, and 'setConnectedState' will not be called again
- return OK;
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (mModule == nullptr) return NO_INIT;
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ const bool isInput = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::portDirection(port->role, port->type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ AudioPort aidlPort = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_v7_AudioPort(*port, isInput));
+ if (aidlPort.ext.getTag() != AudioPortExt::device) {
+ ALOGE("%s: provided port is not a device port (module %s): %s",
+ __func__, mInstance.c_str(), aidlPort.toString().c_str());
+ return BAD_VALUE;
+ }
+ status_t status = NO_ERROR;
+ {
+ std::lock_guard l(mLock);
+ status = mMapper.prepareToDisconnectExternalDevice(aidlPort);
+ }
+ if (status == UNKNOWN_TRANSACTION) {
+ // If there is not AIDL API defined for `prepareToDisconnectExternalDevice`.
+ // Call `setConnectedState` instead.
+ RETURN_STATUS_IF_ERROR(setConnectedState(port, false /*connected*/));
+ std::lock_guard l(mLock);
+ mDeviceDisconnectionNotified.insert(port->id);
+ // Return that there was no error as otherwise the disconnection procedure will not be
+ // considered complete for upper layers, and 'setConnectedState' will not be called again
+ return OK;
+ } else {
+ return status;
+ }
}
status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
@@ -935,11 +960,10 @@
std::lock_guard l(mLock);
if (mDeviceDisconnectionNotified.erase(port->id) > 0) {
// For device disconnection, APM will first call `prepareToDisconnectExternalDevice`
- // and then call `setConnectedState`. However, there is no API for
- // `prepareToDisconnectExternalDevice` yet. In that case, `setConnectedState` will be
- // called when calling `prepareToDisconnectExternalDevice`. Do not call to the HAL if
- // previous call is successful. Also remove the cache here to avoid a large cache after
- // a long run.
+ // and then call `setConnectedState`. If `prepareToDisconnectExternalDevice` doesn't
+ // exit, `setConnectedState` will be called when calling
+ // `prepareToDisconnectExternalDevice`. Do not call to the HAL if previous call is
+ // successful. Also remove the cache here to avoid a large cache after a long run.
return OK;
}
}
@@ -961,7 +985,7 @@
if (mModule == nullptr) return NO_INIT;
{
std::lock_guard l(mLock);
- mMapper.resetUnusedPatchesAndPortConfigs();
+ mMapper.resetUnusedPatchesPortConfigsAndPorts();
}
ModuleDebug debug{ .simulateDeviceConnections = enabled };
status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
index a8f9f7e..3dbc14a 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.cpp
@@ -24,7 +24,6 @@
#include <aidl/android/hardware/audio/core/IModule.h>
#include <android/binder_manager.h>
-#include <binder/IServiceManager.h>
#include <media/AidlConversionNdkCpp.h>
#include <media/AidlConversionUtil.h>
#include <utils/Log.h>
@@ -115,29 +114,6 @@
return OK;
}
-status_t DevicesFactoryHalAidl::getHalPids(std::vector<pid_t> *pids) {
- if (pids == nullptr) {
- return BAD_VALUE;
- }
- // 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) {
// Dynamic registration of module instances is not supported. The functionality
// in the audio server which is related to this callback can be removed together
diff --git a/media/libaudiohal/impl/DevicesFactoryHalAidl.h b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
index 97e3796..17bfe43 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalAidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalAidl.h
@@ -35,8 +35,6 @@
// necessary to release references to the returned object.
status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
- status_t getHalPids(std::vector<pid_t> *pids) override;
-
status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
android::detail::AudioHalVersionInfo getHalVersion() const override;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
index eef60b5..1cac9da 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
@@ -163,29 +163,6 @@
return BAD_VALUE;
}
-status_t DevicesFactoryHalHidl::getHalPids(std::vector<pid_t> *pids) {
- std::set<pid_t> pidsSet;
- auto factories = copyDeviceFactories();
- for (const auto& factory : factories) {
- using ::android::hidl::base::V1_0::DebugInfo;
-
- DebugInfo debugInfo;
- auto ret = factory->getDebugInfo([&] (const auto &info) {
- debugInfo = info;
- });
- if (!ret.isOk()) {
- return INVALID_OPERATION;
- }
- if (debugInfo.pid == (int)IServiceManager::PidConstant::NO_PID) {
- continue;
- }
- pidsSet.insert(debugInfo.pid);
- }
-
- *pids = {pidsSet.begin(), pidsSet.end()};
- return NO_ERROR;
-}
-
status_t DevicesFactoryHalHidl::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
ALOG_ASSERT(callback != nullptr);
bool needToCallCallback = false;
diff --git a/media/libaudiohal/impl/DevicesFactoryHalHidl.h b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
index 3285af7..e38d86d 100644
--- a/media/libaudiohal/impl/DevicesFactoryHalHidl.h
+++ b/media/libaudiohal/impl/DevicesFactoryHalHidl.h
@@ -43,8 +43,6 @@
// necessary to release references to the returned object.
status_t openDevice(const char *name, sp<DeviceHalInterface> *device) override;
- status_t getHalPids(std::vector<pid_t> *pids) override;
-
status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) override;
android::detail::AudioHalVersionInfo getHalVersion() const override;
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 196b432..39999a5 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -180,18 +180,6 @@
State state;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getState(&state)));
- // in case of buffer/ioHandle re-configure for an opened effect, close it and re-open
- if (state != State::INIT && mCommon != common) {
- ALOGI("%s at state %s, common parameter change from %s to %s, closing effect", __func__,
- android::internal::ToString(state).c_str(), mCommon.toString().c_str(),
- common.toString().c_str());
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->close()));
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getState(&state)));
- mStatusQ.reset();
- mInputQ.reset();
- mOutputQ.reset();
- }
-
if (state == State::INIT) {
ALOGI("%s at state %s, opening effect with input %s output %s", __func__,
android::internal::ToString(state).c_str(), common.input.toString().c_str(),
@@ -199,16 +187,7 @@
IEffect::OpenEffectReturn openReturn;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
-
- if (mIsProxyEffect) {
- mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
- mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
- mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
- } else {
- mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
- mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
- mOutputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
- }
+ updateMqs(openReturn);
if (status_t status = updateEventFlags(); status != OK) {
ALOGV("%s closing at status %d", __func__, status);
@@ -225,6 +204,18 @@
return *static_cast<int32_t*>(pReplyData) = OK;
}
+void EffectConversionHelperAidl::updateMqs(const IEffect::OpenEffectReturn& ret) {
+ if (mIsProxyEffect) {
+ mStatusQ = std::static_pointer_cast<EffectProxy>(mEffect)->getStatusMQ();
+ mInputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getInputMQ();
+ mOutputQ = std::static_pointer_cast<EffectProxy>(mEffect)->getOutputMQ();
+ } else {
+ mStatusQ = std::make_shared<StatusMQ>(ret.statusMQ);
+ mInputQ = std::make_shared<DataMQ>(ret.inputDataMQ);
+ mOutputQ = std::make_shared<DataMQ>(ret.outputDataMQ);
+ }
+}
+
status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
const void* pCmdData __unused,
uint32_t* replySize, void* pReplyData) {
@@ -517,5 +508,13 @@
return desc;
}
+status_t EffectConversionHelperAidl::reopen() {
+ IEffect::OpenEffectReturn openReturn;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->reopen(&openReturn)));
+
+ updateMqs(openReturn);
+ return OK;
+}
+
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 5db334c..8b9efb3 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -47,6 +47,7 @@
bool isBypassingOrTunnel() const;
::aidl::android::hardware::audio::effect::Descriptor getDescriptor() const;
+ status_t reopen();
protected:
const int32_t mSessionId;
@@ -108,6 +109,8 @@
std::shared_ptr<android::hardware::EventFlag> mEfGroup = nullptr;
status_t updateEventFlags();
+ void updateMqs(const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn& ret);
+
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,
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index f26444c..2836727 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -56,6 +56,7 @@
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::kEventFlagDataMqUpdate;
using ::aidl::android::hardware::audio::effect::State;
namespace android {
@@ -165,26 +166,37 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
+ const std::string effectName = mConversion->getDescriptor().common.name;
State state = State::INIT;
if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
state != State::PROCESSING) {
- ALOGI("%s skipping %s process because it's %s", __func__,
- mConversion->getDescriptor().common.name.c_str(),
+ ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
mConversion->isBypassing()
? "bypassing"
: aidl::android::hardware::audio::effect::toString(state).c_str());
return -ENODATA;
}
+ // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+ auto efGroup = mConversion->getEventFlagGroup();
+ if (!efGroup) {
+ ALOGE("%s invalid efGroup", __func__);
+ return INVALID_OPERATION;
+ }
+
+ if (uint32_t efState = 0;
+ ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState, 1 /* ns */,
+ true /* retry */)) {
+ ALOGI("%s %s receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str());
+ mConversion->reopen();
+ }
auto statusQ = mConversion->getStatusMQ();
auto inputQ = mConversion->getInputMQ();
auto outputQ = mConversion->getOutputMQ();
- auto efGroup = mConversion->getEventFlagGroup();
if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
- !outputQ->isValid() || !efGroup) {
- ALOGE("%s invalid FMQ [Status %d I %d O %d] efGroup %p", __func__,
- statusQ ? statusQ->isValid() : 0, inputQ ? inputQ->isValid() : 0,
- outputQ ? outputQ->isValid() : 0, efGroup.get());
+ !outputQ->isValid()) {
+ ALOGE("%s invalid FMQ [Status %d I %d O %d]", __func__, statusQ ? statusQ->isValid() : 0,
+ inputQ ? inputQ->isValid() : 0, outputQ ? outputQ->isValid() : 0);
return INVALID_OPERATION;
}
@@ -225,8 +237,8 @@
return INVALID_OPERATION;
}
- ALOGD("%s %s consumed %zu produced %zu", __func__,
- mConversion->getDescriptor().common.name.c_str(), floatsToWrite, floatsToRead);
+ ALOGD("%s %s consumed %zu produced %zu", __func__, effectName.c_str(), floatsToWrite,
+ floatsToRead);
return OK;
}
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
index aee42a9..d440ef8 100644
--- a/media/libaudiohal/impl/EffectProxy.cpp
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -106,8 +106,8 @@
ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
IEffect::OpenEffectReturn* ret __unused) {
- ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage(
- EX_ILLEGAL_ARGUMENT, "nullEffectHandle");
+ ndk::ScopedAStatus status =
+ ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "nullEffectHandle");
for (auto& sub : mSubEffects) {
IEffect::OpenEffectReturn openReturn;
if (!sub.handle || !(status = sub.handle->open(common, specific, &openReturn)).isOk()) {
@@ -130,7 +130,33 @@
return status;
}
+ndk::ScopedAStatus EffectProxy::reopen(OpenEffectReturn* ret __unused) {
+ ndk::ScopedAStatus status =
+ ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_STATE, "nullEffectHandle");
+ for (auto& sub : mSubEffects) {
+ IEffect::OpenEffectReturn openReturn;
+ if (!sub.handle || !(status = sub.handle->reopen(&openReturn)).isOk()) {
+ ALOGE("%s: failed to open %p UUID %s", __func__, sub.handle.get(),
+ ::android::audio::utils::toString(sub.descriptor.common.id.uuid).c_str());
+ break;
+ }
+ sub.effectMq.statusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
+ sub.effectMq.inputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
+ sub.effectMq.outputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
+ }
+
+ // close all opened effects if failure
+ if (!status.isOk()) {
+ ALOGE("%s: closing all sub-effects with error %s", __func__,
+ status.getDescription().c_str());
+ close();
+ }
+
+ return status;
+}
+
ndk::ScopedAStatus EffectProxy::close() {
+ command(CommandId::STOP);
return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
return effect->close();
});
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
index 0d62642..9b9e8f1 100644
--- a/media/libaudiohal/impl/EffectProxy.h
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -62,6 +62,8 @@
specific,
::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn* ret) override;
ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus reopen(
+ ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn* ret) override;
ndk::ScopedAStatus getDescriptor(
::aidl::android::hardware::audio::effect::Descriptor* desc) override;
ndk::ScopedAStatus command(::aidl::android::hardware::audio::effect::CommandId id) override;
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index 47fcd27..2b7f298 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -30,11 +30,13 @@
using aidl::android::aidl_utils::statusTFromBinderStatus;
using aidl::android::media::audio::common::AudioChannelLayout;
using aidl::android::media::audio::common::AudioConfig;
+using aidl::android::media::audio::common::AudioConfigBase;
using aidl::android::media::audio::common::AudioDevice;
using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioDeviceDescription;
using aidl::android::media::audio::common::AudioDeviceType;
using aidl::android::media::audio::common::AudioFormatDescription;
+using aidl::android::media::audio::common::AudioFormatType;
using aidl::android::media::audio::common::AudioInputFlags;
using aidl::android::media::audio::common::AudioIoFlags;
using aidl::android::media::audio::common::AudioOutputFlags;
@@ -64,10 +66,11 @@
portConfig.format.value() == config.base.format;
}
-void setConfigFromPortConfig(AudioConfig* config, const AudioPortConfig& portConfig) {
+AudioConfig* 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();
+ return config;
}
void setPortConfigFromConfig(AudioPortConfig* portConfig, const AudioConfig& config) {
@@ -142,8 +145,33 @@
std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
for (const auto& s : configs) {
AudioPortConfig portConfig;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
- s, destinationPortIds, &portConfig, cleanups));
+ if (status_t status = setPortConfig(
+ s, destinationPortIds, &portConfig, cleanups); status != OK) {
+ if (s.ext.getTag() == AudioPortExt::mix) {
+ // See b/315528763. Despite that the framework knows the actual format of
+ // the mix port, it still uses the original format. Luckily, there is
+ // the I/O handle which can be used to find the mix port.
+ ALOGI("fillPortConfigs: retrying to find a mix port config with default "
+ "configuration");
+ if (auto it = findPortConfig(std::nullopt, s.flags,
+ s.ext.get<AudioPortExt::mix>().handle);
+ it != mPortConfigs.end()) {
+ portConfig = it->second;
+ } else {
+ const std::string flags = s.flags.has_value() ?
+ s.flags->toString() : "<unspecified>";
+ ALOGE("fillPortConfigs: existing port config for flags %s, handle %d "
+ "not found in module %s", flags.c_str(),
+ s.ext.get<AudioPortExt::mix>().handle, mInstance.c_str());
+ return BAD_VALUE;
+ }
+ } else {
+ return status;
+ }
+ }
+ LOG_ALWAYS_FATAL_IF(portConfig.id == 0,
+ "fillPortConfigs: initial config: %s, port config: %s",
+ s.toString().c_str(), portConfig.toString().c_str());
ids->push_back(portConfig.id);
if (portIds != nullptr) {
portIds->insert(portConfig.portId);
@@ -189,34 +217,50 @@
}
status_t Hal2AidlMapper::createOrUpdatePortConfig(
- const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
- AudioPortConfig appliedPortConfig;
+ const AudioPortConfig& requestedPortConfig, AudioPortConfig* result, bool* created) {
bool applied = false;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->setAudioPortConfig(
- requestedPortConfig, &appliedPortConfig, &applied)));
+ requestedPortConfig, result, &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;
- }
+ result->id = 0;
+ *created = false;
+ return OK;
}
- int32_t id = appliedPortConfig.id;
+ int32_t id = result->id;
if (requestedPortConfig.id != 0 && requestedPortConfig.id != id) {
LOG_ALWAYS_FATAL("%s: requested port config id %d changed to %d", __func__,
requestedPortConfig.id, id);
}
- auto [it, inserted] = mPortConfigs.insert_or_assign(std::move(id),
- std::move(appliedPortConfig));
- *result = it;
+ auto [_, inserted] = mPortConfigs.insert_or_assign(id, *result);
*created = inserted;
return OK;
}
+status_t Hal2AidlMapper::createOrUpdatePortConfigRetry(
+ const AudioPortConfig& requestedPortConfig, AudioPortConfig* result, bool* created) {
+ AudioPortConfig suggestedOrAppliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig,
+ &suggestedOrAppliedPortConfig, created));
+ if (suggestedOrAppliedPortConfig.id == 0) {
+ // Try again with the suggested config
+ suggestedOrAppliedPortConfig.id = requestedPortConfig.id;
+ AudioPortConfig appliedPortConfig;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(suggestedOrAppliedPortConfig,
+ &appliedPortConfig, created));
+ if (appliedPortConfig.id == 0) {
+ ALOGE("%s: module %s did not apply suggested config %s", __func__,
+ mInstance.c_str(), suggestedOrAppliedPortConfig.toString().c_str());
+ return NO_INIT;
+ }
+ *result = appliedPortConfig;
+ } else {
+ *result = suggestedOrAppliedPortConfig;
+ }
+ return OK;
+}
+
void Hal2AidlMapper::eraseConnectedPort(int32_t portId) {
mPorts.erase(portId);
mConnectedPorts.erase(portId);
@@ -226,6 +270,7 @@
ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str());
mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>();
}
+ updateDynamicMixPorts();
}
status_t Hal2AidlMapper::findOrCreatePatch(
@@ -258,11 +303,10 @@
return OK;
}
-status_t Hal2AidlMapper::findOrCreatePortConfig(
+status_t Hal2AidlMapper::findOrCreateDevicePortConfig(
const AudioDevice& device, const AudioConfig* config, AudioPortConfig* portConfig,
bool* created) {
- auto portConfigIt = findPortConfig(device);
- if (portConfigIt == mPortConfigs.end()) {
+ if (auto portConfigIt = findPortConfig(device); 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",
@@ -274,24 +318,32 @@
if (config != nullptr) {
setPortConfigFromConfig(&requestedPortConfig, *config);
}
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
+ return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
} else {
- *created = false;
+ AudioPortConfig requestedPortConfig = portConfigIt->second;
+ if (config != nullptr) {
+ setPortConfigFromConfig(&requestedPortConfig, *config);
+ }
+
+ if (requestedPortConfig != portConfigIt->second) {
+ return createOrUpdatePortConfigRetry(requestedPortConfig, portConfig, created);
+ } else {
+ *portConfig = portConfigIt->second;
+ *created = false;
+ }
}
- *portConfig = portConfigIt->second;
return OK;
}
-status_t Hal2AidlMapper::findOrCreatePortConfig(
+status_t Hal2AidlMapper::findOrCreateMixPortConfig(
const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
AudioSource source, const std::set<int32_t>& destinationPortIds,
AudioPortConfig* portConfig, bool* created) {
// These flags get removed one by one in this order when retrying port finding.
static const std::vector<AudioInputFlags> kOptionalInputFlags{
AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
- auto portConfigIt = findPortConfig(config, flags, ioHandle);
- if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
+ if (auto portConfigIt = findPortConfig(config, flags, ioHandle);
+ portConfigIt == mPortConfigs.end() && flags.has_value()) {
auto optionalInputFlagsIt = kOptionalInputFlags.begin();
AudioIoFlags matchFlags = flags.value();
auto portsIt = findPort(config, matchFlags, destinationPortIds);
@@ -319,14 +371,14 @@
AudioPortConfig requestedPortConfig;
requestedPortConfig.portId = portsIt->first;
setPortConfigFromConfig(&requestedPortConfig, config);
+ requestedPortConfig.flags = portsIt->second.flags;
requestedPortConfig.ext = AudioPortMixExt{ .handle = ioHandle };
if (matchFlags.getTag() == AudioIoFlags::Tag::input
&& source != AudioSource::SYS_RESERVED_INVALID) {
requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
}
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
+ return createOrUpdatePortConfig(requestedPortConfig, portConfig, created);
} else if (portConfigIt == mPortConfigs.end() && !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",
@@ -334,22 +386,21 @@
return BAD_VALUE;
} else {
AudioPortConfig requestedPortConfig = portConfigIt->second;
- if (requestedPortConfig.ext.getTag() == AudioPortExt::Tag::mix) {
- AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
- if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
- source != AudioSource::SYS_RESERVED_INVALID) {
- mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
- }
+ setPortConfigFromConfig(&requestedPortConfig, config);
+
+ AudioPortMixExt& mixExt = requestedPortConfig.ext.get<AudioPortExt::Tag::mix>();
+ if (mixExt.usecase.getTag() == AudioPortMixExtUseCase::Tag::source &&
+ source != AudioSource::SYS_RESERVED_INVALID) {
+ mixExt.usecase.get<AudioPortMixExtUseCase::Tag::source>() = source;
}
if (requestedPortConfig != portConfigIt->second) {
- RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
- created));
+ return createOrUpdatePortConfig(requestedPortConfig, portConfig, created);
} else {
+ *portConfig = portConfigIt->second;
*created = false;
}
}
- *portConfig = portConfigIt->second;
return OK;
}
@@ -371,31 +422,29 @@
AudioPortMixExtUseCase::Tag::source ?
requestedPortConfig.ext.get<Tag::mix>().usecase.
get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
- return findOrCreatePortConfig(config, requestedPortConfig.flags,
+ return findOrCreateMixPortConfig(config, requestedPortConfig.flags,
requestedPortConfig.ext.get<Tag::mix>().handle, source, destinationPortIds,
portConfig, created);
} else if (requestedPortConfig.ext.getTag() == Tag::device) {
- return findOrCreatePortConfig(
- requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
- portConfig, created);
+ if (const auto& p = requestedPortConfig;
+ p.sampleRate.has_value() && p.channelMask.has_value() &&
+ p.format.has_value()) {
+ AudioConfig config;
+ setConfigFromPortConfig(&config, requestedPortConfig);
+ return findOrCreateDevicePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, &config,
+ portConfig, created);
+ } else {
+ return findOrCreateDevicePortConfig(
+ requestedPortConfig.ext.get<Tag::device>().device, nullptr /*config*/,
+ portConfig, created);
+ }
}
ALOGW("%s: unsupported audio port config: %s",
__func__, requestedPortConfig.toString().c_str());
return BAD_VALUE;
}
-status_t Hal2AidlMapper::findOrCreatePortConfig(
- const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
- AudioPortConfig* portConfig, Cleanups* cleanups) {
- bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
- requestedPortConfig, destinationPortIds, portConfig, &created));
- if (created && cleanups != nullptr) {
- cleanups->add(&Hal2AidlMapper::resetPortConfig, portConfig->id);
- }
- return OK;
-}
-
status_t Hal2AidlMapper::findPortConfig(const AudioDevice& device, AudioPortConfig* portConfig) {
if (auto it = findPortConfig(device); it != mPortConfigs.end()) {
*portConfig = it->second;
@@ -665,6 +714,14 @@
return false;
}
+status_t Hal2AidlMapper::prepareToDisconnectExternalDevice(const AudioPort& devicePort) {
+ auto portsIt = findPort(devicePort.ext.get<AudioPortExt::device>().device);
+ if (portsIt == mPorts.end()) {
+ return BAD_VALUE;
+ }
+ return statusTFromBinderStatus(mModule->prepareToDisconnectExternalDevice(portsIt->second.id));
+}
+
status_t Hal2AidlMapper::prepareToOpenStream(
int32_t ioHandle, const AudioDevice& device, const AudioIoFlags& flags,
AudioSource source, Cleanups* cleanups, AudioConfig* config,
@@ -673,29 +730,93 @@
this, __func__, ioHandle, device.toString().c_str(),
flags.toString().c_str(), toString(source).c_str(),
config->toString().c_str(), mixPortConfig->toString().c_str());
- resetUnusedPatchesAndPortConfigs();
- const bool isInput = flags.getTag() == AudioIoFlags::Tag::input;
+ resetUnusedPatchesPortConfigsAndPorts();
+ const AudioConfig initialConfig = *config;
// 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(device, config,
- &devicePortConfig, &created));
+ RETURN_STATUS_IF_ERROR(findOrCreateDevicePortConfig(device, config,
+ &devicePortConfig, &created));
+ LOG_ALWAYS_FATAL_IF(devicePortConfig.id == 0);
if (created) {
cleanups->add(&Hal2AidlMapper::resetPortConfig, devicePortConfig.id);
}
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*config, flags, ioHandle, source,
- std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
+ status_t status = prepareToOpenStreamHelper(ioHandle, devicePortConfig.portId,
+ devicePortConfig.id, flags, source, initialConfig, cleanups, config,
+ mixPortConfig, patch);
+ if (status != OK) {
+ // If using the client-provided config did not work out for establishing a mix port config
+ // or patching, try with the device port config. Note that in general device port config and
+ // mix port config are not required to be the same, however they must match if the HAL
+ // module can't perform audio stream conversions.
+ AudioConfig deviceConfig = initialConfig;
+ if (setConfigFromPortConfig(&deviceConfig, devicePortConfig)->base != initialConfig.base) {
+ ALOGD("%s: retrying with device port config: %s", __func__,
+ devicePortConfig.toString().c_str());
+ status = prepareToOpenStreamHelper(ioHandle, devicePortConfig.portId,
+ devicePortConfig.id, flags, source, initialConfig, cleanups,
+ &deviceConfig, mixPortConfig, patch);
+ if (status == OK) {
+ *config = deviceConfig;
+ }
+ }
+ }
+ return status;
+}
+
+status_t Hal2AidlMapper::prepareToOpenStreamHelper(
+ int32_t ioHandle, int32_t devicePortId, int32_t devicePortConfigId,
+ const AudioIoFlags& flags, AudioSource source, const AudioConfig& initialConfig,
+ Cleanups* cleanups, AudioConfig* config, AudioPortConfig* mixPortConfig,
+ AudioPatch* patch) {
+ const bool isInput = flags.getTag() == AudioIoFlags::Tag::input;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreateMixPortConfig(*config, flags, ioHandle, source,
+ std::set<int32_t>{devicePortId}, mixPortConfig, &created));
if (created) {
cleanups->add(&Hal2AidlMapper::resetPortConfig, mixPortConfig->id);
}
setConfigFromPortConfig(config, *mixPortConfig);
+ bool retryWithSuggestedConfig = false; // By default, let the framework to retry.
+ if (mixPortConfig->id == 0 && config->base == AudioConfigBase{}) {
+ // The HAL proposes a default config, can retry here.
+ retryWithSuggestedConfig = true;
+ } else if (isInput && config->base != initialConfig.base) {
+ // If the resulting config is different, we must stop and provide the config to the
+ // framework so that it can retry.
+ mixPortConfig->id = 0;
+ } else if (!isInput && mixPortConfig->id == 0 &&
+ (initialConfig.base.format.type == AudioFormatType::PCM ||
+ !isBitPositionFlagSet(flags.get<AudioIoFlags::output>(),
+ AudioOutputFlags::DIRECT) ||
+ isBitPositionFlagSet(flags.get<AudioIoFlags::output>(),
+ AudioOutputFlags::COMPRESS_OFFLOAD))) {
+ // The framework does not retry opening non-direct PCM and IEC61937 outputs, need to retry
+ // here (see 'AudioHwDevice::openOutputStream').
+ retryWithSuggestedConfig = true;
+ }
+ if (mixPortConfig->id == 0 && retryWithSuggestedConfig) {
+ ALOGD("%s: retrying to find/create a mix port config using config %s", __func__,
+ config->toString().c_str());
+ RETURN_STATUS_IF_ERROR(findOrCreateMixPortConfig(*config, flags, ioHandle, source,
+ std::set<int32_t>{devicePortId}, mixPortConfig, &created));
+ if (created) {
+ cleanups->add(&Hal2AidlMapper::resetPortConfig, mixPortConfig->id);
+ }
+ setConfigFromPortConfig(config, *mixPortConfig);
+ }
+ if (mixPortConfig->id == 0) {
+ ALOGD("%p %s: returning suggested config for the stream: %s", this, __func__,
+ config->toString().c_str());
+ return OK;
+ }
if (isInput) {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {devicePortConfig.id}, {mixPortConfig->id}, patch, &created));
+ {devicePortConfigId}, {mixPortConfig->id}, patch, &created));
} else {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {mixPortConfig->id}, {devicePortConfig.id}, patch, &created));
+ {mixPortConfig->id}, {devicePortConfigId}, patch, &created));
}
if (created) {
cleanups->add(&Hal2AidlMapper::resetPatch, patch->id);
@@ -706,6 +827,18 @@
return OK;
}
+status_t Hal2AidlMapper::setPortConfig(
+ const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+ AudioPortConfig* portConfig, Cleanups* cleanups) {
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+ requestedPortConfig, destinationPortIds, portConfig, &created));
+ if (created && cleanups != nullptr) {
+ cleanups->add(&Hal2AidlMapper::resetPortConfig, portConfig->id);
+ }
+ return OK;
+}
+
status_t Hal2AidlMapper::releaseAudioPatch(int32_t patchId) {
return releaseAudioPatches({patchId});
}
@@ -725,7 +858,7 @@
result = BAD_VALUE;
}
}
- resetUnusedPortConfigs();
+ resetUnusedPortConfigsAndPorts();
return result;
}
@@ -742,7 +875,7 @@
ALOGE("%s: port config id %d not found", __func__, portConfigId);
}
-void Hal2AidlMapper::resetUnusedPatchesAndPortConfigs() {
+void Hal2AidlMapper::resetUnusedPatchesPortConfigsAndPorts() {
// Since patches can be created independently of streams via 'createOrUpdatePatch',
// here we only clean up patches for released streams.
std::set<int32_t> patchesToRelease;
@@ -756,11 +889,11 @@
it = mStreams.erase(it);
}
}
- // 'releaseAudioPatches' also resets unused port configs.
+ // 'releaseAudioPatches' also resets unused port configs and ports.
releaseAudioPatches(patchesToRelease);
}
-void Hal2AidlMapper::resetUnusedPortConfigs() {
+void Hal2AidlMapper::resetUnusedPortConfigsAndPorts() {
// The assumption is that port configs are used to create patches
// (or to open streams, but that involves creation of patches, too). Thus,
// orphaned port configs can and should be reset.
@@ -801,6 +934,7 @@
}
status_t Hal2AidlMapper::setDevicePortConnectedState(const AudioPort& devicePort, bool connected) {
+ resetUnusedPatchesPortConfigsAndPorts();
if (connected) {
AudioDevice matchDevice = devicePort.ext.get<AudioPortExt::device>().device;
std::optional<AudioPort> templatePort;
@@ -835,7 +969,6 @@
}
templatePort = portsIt->second;
}
- resetUnusedPatchesAndPortConfigs();
// Use the ID of the "template" port, use all the information from the provided port.
AudioPort connectedPort = devicePort;
@@ -862,7 +995,6 @@
ALOGD("%s: device port for device %s found in the module %s",
__func__, matchDevice.toString().c_str(), mInstance.c_str());
}
- resetUnusedPatchesAndPortConfigs();
// Disconnection of remote submix out with address "0" is a special case. We need to replace
// the connected port entry with the "augmented template".
@@ -895,6 +1027,9 @@
if (status == OK) {
auto portIt = mPorts.find(portId);
if (portIt != mPorts.end()) {
+ if (port->ext.getTag() == AudioPortExt::Tag::mix && portIt->second != *port) {
+ mDynamicMixPortIds.insert(portId);
+ }
portIt->second = *port;
} else {
ALOGW("%s, port(%d) returned successfully from the HAL but not it is not cached",
@@ -943,4 +1078,15 @@
return OK;
}
+void Hal2AidlMapper::updateDynamicMixPorts() {
+ for (int32_t portId : mDynamicMixPortIds) {
+ if (auto it = mPorts.find(portId); it != mPorts.end()) {
+ updateAudioPort(portId, &it->second);
+ } else {
+ // This must not happen
+ ALOGE("%s, cannot find port for id=%d", __func__, portId);
+ }
+ }
+}
+
} // namespace android
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.h b/media/libaudiohal/impl/Hal2AidlMapper.h
index 70a2bd7..f937173 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.h
+++ b/media/libaudiohal/impl/Hal2AidlMapper.h
@@ -36,6 +36,11 @@
// structures directly. Mapper does the job of translating the "legacy" way of identifying ports
// and port configs (by device addresses and I/O handles) into AIDL IDs. Once the framework will
// be updated to provide these IDs directly to libaudiohal, the need for the mapper will cease.
+//
+// Note that unlike DeviceHalInterface, which sometimes allows a method to return an error,
+// but still consider some of the outputs to be valid (for example, in 'open{Input|Output}Stream'),
+// 'Hal2AidlMapper' follows the Binder convention. It means that if a method returns an error,
+// the outputs may not be initialized at all and should not be considered by the caller.
class Hal2AidlMapper {
public:
using Cleanups = Cleanups<Hal2AidlMapper>;
@@ -49,27 +54,6 @@
const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources,
const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks,
int32_t* patchId, Cleanups* cleanups);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioDevice& device,
- const ::aidl::android::media::audio::common::AudioConfig* config,
- ::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::AudioSource source,
- const std::set<int32_t>& destinationPortIds,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- const std::set<int32_t>& destinationPortIds,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
- status_t findOrCreatePortConfig(
- const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- const std::set<int32_t>& destinationPortIds,
- ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
- Cleanups* cleanups = nullptr);
status_t findPortConfig(
const ::aidl::android::media::audio::common::AudioDevice& device,
::aidl::android::media::audio::common::AudioPortConfig* portConfig);
@@ -88,6 +72,10 @@
return ::aidl::android::convertContainer(mRoutes, routes, converter);
}
status_t initialize();
+ status_t prepareToDisconnectExternalDevice(
+ const ::aidl::android::media::audio::common::AudioPort& devicePort);
+ // If the resulting 'mixPortConfig->id' is 0, that means the stream was not created,
+ // and 'config' is a suggested config.
status_t prepareToOpenStream(
int32_t ioHandle,
const ::aidl::android::media::audio::common::AudioDevice& device,
@@ -97,8 +85,13 @@
::aidl::android::media::audio::common::AudioConfig* config,
::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
::aidl::android::hardware::audio::core::AudioPatch* patch);
+ status_t setPortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ const std::set<int32_t>& destinationPortIds,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+ Cleanups* cleanups = nullptr);
status_t releaseAudioPatch(int32_t patchId);
- void resetUnusedPatchesAndPortConfigs();
+ void resetUnusedPatchesPortConfigsAndPorts();
status_t setDevicePortConnectedState(
const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected);
@@ -128,9 +121,14 @@
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);
+ // If the 'result->id' is 0, that means, the config was not created/updated,
+ // and the 'result' is a suggestion from the HAL.
status_t createOrUpdatePortConfig(
const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- PortConfigs::iterator* result, bool *created);
+ ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
+ status_t createOrUpdatePortConfigRetry(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created);
void eraseConnectedPort(int32_t portId);
status_t findOrCreatePatch(
const std::set<int32_t>& sourcePortConfigIds,
@@ -139,6 +137,24 @@
status_t findOrCreatePatch(
const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch,
::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created);
+ status_t findOrCreateDevicePortConfig(
+ const ::aidl::android::media::audio::common::AudioDevice& device,
+ const ::aidl::android::media::audio::common::AudioConfig* config,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig,
+ bool* created);
+ // If the resulting 'portConfig->id' is 0, that means the config was not created,
+ // and 'portConfig' is a suggested config.
+ status_t findOrCreateMixPortConfig(
+ 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::AudioSource source,
+ const std::set<int32_t>& destinationPortIds,
+ ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created);
+ status_t findOrCreatePortConfig(
+ const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
+ const std::set<int32_t>& destinationPortIds,
+ ::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);
@@ -153,6 +169,14 @@
const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
int32_t ioHandle);
bool isPortBeingHeld(int32_t portId);
+ status_t prepareToOpenStreamHelper(
+ int32_t ioHandle, int32_t devicePortId, int32_t devicePortConfigId,
+ const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+ ::aidl::android::media::audio::common::AudioSource source,
+ const ::aidl::android::media::audio::common::AudioConfig& initialConfig,
+ Cleanups* cleanups, ::aidl::android::media::audio::common::AudioConfig* config,
+ ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
+ ::aidl::android::hardware::audio::core::AudioPatch* patch);
bool portConfigBelongsToPort(int32_t portConfigId, int32_t portId) {
auto it = mPortConfigs.find(portConfigId);
return it != mPortConfigs.end() && it->second.portId == portId;
@@ -160,10 +184,11 @@
status_t releaseAudioPatches(const std::set<int32_t>& patchIds);
void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); }
void resetPortConfig(int32_t portConfigId);
- void resetUnusedPortConfigs();
+ void resetUnusedPortConfigsAndPorts();
status_t updateAudioPort(
int32_t portId, ::aidl::android::media::audio::common::AudioPort* port);
status_t updateRoutes();
+ void updateDynamicMixPorts();
Ports mPorts;
// Remote submix "template" ports (no address specified, no profiles).
@@ -181,6 +206,7 @@
ConnectedPorts mConnectedPorts;
std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort>
mDisconnectedPortReplacement;
+ std::set<int32_t> mDynamicMixPortIds;
};
} // namespace android
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 378d919..5f525d7 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -234,7 +234,9 @@
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 status = mStream->dump(fd, Args(args).args(), args.size());
+ mStreamPowerLog.dump(fd);
+ return status;
}
status_t StreamHalAidl::start() {
@@ -808,6 +810,7 @@
mOffloadMetadata.channelMask = VALUE_OR_RETURN_STATUS(
::aidl::android::legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
channel_mask, false /*isInput*/));
+ return OK;
}
return BAD_VALUE;
}))) {
diff --git a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
index 8397e9b..c34a671 100644
--- a/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DevicesFactoryHalInterface.h
@@ -42,8 +42,6 @@
// necessary to release references to the returned object.
virtual status_t openDevice(const char *name, sp<DeviceHalInterface> *device) = 0;
- virtual status_t getHalPids(std::vector<pid_t> *pids) = 0;
-
// Sets a DevicesFactoryHalCallback to notify the client.
// The callback can be only set once.
virtual status_t setCallbackOnce(sp<DevicesFactoryHalCallback> callback) = 0;
diff --git a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
index adff110..1204a3b 100644
--- a/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
+++ b/media/libaudiohal/tests/CoreAudioHalAidl_test.cpp
@@ -201,6 +201,9 @@
ndk::ScopedAStatus getAAudioHardwareBurstMinUsec(int32_t*) override {
return ndk::ScopedAStatus::ok();
}
+ ndk::ScopedAStatus prepareToDisconnectExternalDevice(int32_t) override {
+ return ndk::ScopedAStatus::ok();
+ }
bool mIsScreenTurnedOn = false;
ScreenRotation mScreenRotation = ScreenRotation::DEG_0;
diff --git a/media/libeffects/downmix/Android.bp b/media/libeffects/downmix/Android.bp
index a5259aa..b56872c 100644
--- a/media/libeffects/downmix/Android.bp
+++ b/media/libeffects/downmix/Android.bp
@@ -56,9 +56,7 @@
":effectCommonFile",
],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
],
header_libs: [
"libaudioeffects",
@@ -71,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/downmix/aidl/DownmixContext.cpp b/media/libeffects/downmix/aidl/DownmixContext.cpp
index 0e76d1d..5fb44b5 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.cpp
+++ b/media/libeffects/downmix/aidl/DownmixContext.cpp
@@ -20,12 +20,60 @@
#include "DownmixContext.h"
-using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::hardware::audio::common::getChannelCount;
+using aidl::android::hardware::audio::effect::IEffect;
using aidl::android::media::audio::common::AudioChannelLayout;
+using aidl::android::media::audio::common::AudioConfig;
namespace aidl::android::hardware::audio::effect {
+namespace {
+
+inline bool isChannelMaskValid(const 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;
+}
+
+inline bool isStereoChannelMask(const AudioChannelLayout& channelMask) {
+ if (channelMask.getTag() != AudioChannelLayout::layoutMask) return false;
+
+ return channelMask.get<AudioChannelLayout::layoutMask>() == AudioChannelLayout::LAYOUT_STEREO;
+}
+
+} // namespace
+
+bool DownmixContext::validateCommonConfig(const Parameter::Common& common) {
+ const AudioConfig& input = common.input;
+ const AudioConfig& output = common.output;
+ if (input.base.sampleRate != output.base.sampleRate) {
+ LOG(ERROR) << __func__ << ": SRC not supported, input: " << input.toString()
+ << " output: " << output.toString();
+ return false;
+ }
+
+ if (!isStereoChannelMask(output.base.channelMask)) {
+ LOG(ERROR) << __func__ << ": output should be stereo, not "
+ << output.base.channelMask.toString();
+ return false;
+ }
+
+ if (!isChannelMaskValid(input.base.channelMask)) {
+ LOG(ERROR) << __func__ << ": invalid input channel, " << input.base.channelMask.toString();
+ return false;
+ }
+
+ return true;
+}
+
DownmixContext::DownmixContext(int statusDepth, const Parameter::Common& common)
: EffectContext(statusDepth, common) {
LOG(DEBUG) << __func__;
@@ -62,8 +110,7 @@
resetBuffer();
}
-IEffect::Status DownmixContext::lvmProcess(float* in, float* out, int samples) {
- LOG(DEBUG) << __func__ << " in " << in << " out " << out << " sample " << samples;
+IEffect::Status DownmixContext::downmixProcess(float* in, float* out, int samples) {
IEffect::Status status = {EX_ILLEGAL_ARGUMENT, 0, 0};
if (in == nullptr || out == nullptr ||
@@ -84,7 +131,6 @@
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);
@@ -93,7 +139,7 @@
out[0] = in[0];
out[1] = in[1];
}
- in += inputChannelCount;
+ in += mInputChannelCount;
out += 2;
frames--;
}
@@ -105,8 +151,11 @@
return status;
}
}
- LOG(DEBUG) << __func__ << " done processing";
- return {STATUS_OK, samples, samples};
+ int producedSamples = (samples / mInputChannelCount) << 1;
+ LOG(DEBUG) << __func__ << " done processing " << samples << " samples, generated "
+ << producedSamples << " frameSize: " << getInputFrameSize() << " - "
+ << getOutputFrameSize();
+ return {STATUS_OK, samples, producedSamples};
}
void DownmixContext::init_params(const Parameter::Common& common) {
@@ -122,18 +171,4 @@
}
}
-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
index 1571c38..a381d7f 100644
--- a/media/libeffects/downmix/aidl/DownmixContext.h
+++ b/media/libeffects/downmix/aidl/DownmixContext.h
@@ -50,7 +50,9 @@
return RetCode::SUCCESS;
}
- IEffect::Status lvmProcess(float* in, float* out, int samples);
+ IEffect::Status downmixProcess(float* in, float* out, int samples);
+
+ static bool validateCommonConfig(const Parameter::Common& common);
private:
DownmixState mState;
@@ -60,7 +62,6 @@
// 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
index 7068c5c..c82c23b 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.cpp
+++ b/media/libeffects/downmix/aidl/EffectDownmix.cpp
@@ -71,42 +71,6 @@
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) {
@@ -193,6 +157,8 @@
return mContext;
}
+ if (!DownmixContext::validateCommonConfig(common)) return nullptr;
+
mContext = std::make_shared<DownmixContext>(1 /* statusFmqDepth */, common);
return mContext;
}
@@ -204,13 +170,50 @@
return RetCode::SUCCESS;
}
+void DownmixImpl::process() {
+ /**
+ * wait for the EventFlag without lock, it's ok because the mEfGroup pointer will not change
+ * in the life cycle of workerThread (threadLoop).
+ */
+ uint32_t efState = 0;
+ if (!mEventFlag || ::android::OK != mEventFlag->wait(kEventFlagNotEmpty, &efState)) {
+ LOG(ERROR) << getEffectName() << __func__ << ": StatusEventFlag invalid";
+ }
+
+ {
+ std::lock_guard lg(mImplMutex);
+ RETURN_VALUE_IF(!mImplContext, void(), "nullContext");
+ auto statusMQ = mImplContext->getStatusFmq();
+ auto inputMQ = mImplContext->getInputDataFmq();
+ auto outputMQ = mImplContext->getOutputDataFmq();
+ auto buffer = mImplContext->getWorkBuffer();
+ if (!inputMQ || !outputMQ) {
+ return;
+ }
+
+ const auto availableToRead = inputMQ->availableToRead();
+ const auto availableToWrite = outputMQ->availableToWrite() *
+ mImplContext->getInputFrameSize() /
+ mImplContext->getOutputFrameSize();
+ auto processSamples = std::min(availableToRead, availableToWrite);
+ if (processSamples) {
+ inputMQ->read(buffer, processSamples);
+ IEffect::Status status = effectProcessImpl(buffer, buffer, processSamples);
+ outputMQ->write(buffer, status.fmqProduced);
+ statusMQ->writeBlocking(&status, 1);
+ LOG(VERBOSE) << getEffectName() << __func__ << ": done processing, effect consumed "
+ << status.fmqConsumed << " produced " << status.fmqProduced;
+ }
+ }
+}
+
// 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);
+ return mContext->downmixProcess(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
index 812d26b..54557dc 100644
--- a/media/libeffects/downmix/aidl/EffectDownmix.h
+++ b/media/libeffects/downmix/aidl/EffectDownmix.h
@@ -34,21 +34,26 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) 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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
+ // downmix override the process because of different input/output sample size requirement
+ void process() override;
+
private:
- std::shared_ptr<DownmixContext> mContext;
- ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific);
+ std::shared_ptr<DownmixContext> mContext GUARDED_BY(mImplMutex);
+ ndk::ScopedAStatus getParameterDownmix(const Downmix::Tag& tag, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 7838117..e93a4e6 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -86,9 +86,7 @@
],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
"dynamicsprocessingdefaults",
],
@@ -97,6 +95,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index 85ea53a..1fedea4 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -211,11 +211,12 @@
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");
+ std::lock_guard lg(mImplMutex);
RETURN_OK_IF(mState != State::INIT);
- auto context = createContext(common);
- RETURN_IF(!context, EX_NULL_POINTER, "createContextFailed");
+ mImplContext = createContext(common);
+ RETURN_IF(!mContext || !mImplContext, EX_NULL_POINTER, "createContextFailed");
+ mEventFlag = mImplContext->getStatusEventFlag();
- RETURN_IF_ASTATUS_NOT_OK(setParameterCommon(common), "setCommParamErr");
if (specific.has_value()) {
RETURN_IF_ASTATUS_NOT_OK(setParameterSpecific(specific.value()), "setSpecParamErr");
} else {
@@ -227,8 +228,8 @@
}
mState = State::IDLE;
- context->dupeFmq(ret);
- RETURN_IF(createThread(context, getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
+ mContext->dupeFmq(ret);
+ RETURN_IF(createThread(getEffectName()) != RetCode::SUCCESS, EX_UNSUPPORTED_OPERATION,
"FailedToCreateWorker");
return ndk::ScopedAStatus::ok();
}
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index 1e1e72e..4897888 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -39,22 +39,25 @@
ndk::ScopedAStatus open(const Parameter::Common& common,
const std::optional<Parameter::Specific>& specific,
OpenEffectReturn* ret) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) 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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
- std::shared_ptr<DynamicsProcessingContext> mContext;
+ std::shared_ptr<DynamicsProcessingContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
bool isParamInRange(const Parameter::Specific& specific);
};
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index e5e5368..042b063 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -63,6 +63,9 @@
}
RetCode DynamicsProcessingContext::setCommon(const Parameter::Common& common) {
+ if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+ return ret;
+ }
mCommon = common;
init();
LOG(INFO) << __func__ << common.toString();
@@ -312,9 +315,11 @@
void DynamicsProcessingContext::init() {
std::lock_guard lg(mMutex);
- mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
- mChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
- mCommon.input.base.channelMask);
+ if (mState == DYNAMICS_PROCESSING_STATE_UNINITIALIZED) {
+ mState = DYNAMICS_PROCESSING_STATE_INITIALIZED;
+ }
+ mChannelCount = static_cast<int>(::aidl::android::hardware::audio::common::getChannelCount(
+ mCommon.input.base.channelMask));
}
dp_fx::DPChannel* DynamicsProcessingContext::getChannel_l(int channel) {
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
index ced7f19..839c6dd 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -74,7 +74,7 @@
static constexpr float kPreferredProcessingDurationMs = 10.0f;
static constexpr int kBandCount = 5;
std::mutex mMutex;
- size_t mChannelCount GUARDED_BY(mMutex) = 0;
+ int 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;
diff --git a/media/libeffects/hapticgenerator/Android.bp b/media/libeffects/hapticgenerator/Android.bp
index fc80211..7d96b53 100644
--- a/media/libeffects/hapticgenerator/Android.bp
+++ b/media/libeffects/hapticgenerator/Android.bp
@@ -75,9 +75,7 @@
],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
"hapticgeneratordefaults",
],
@@ -86,6 +84,6 @@
],
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
index fe9616a..53dcd49 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.h
@@ -33,16 +33,18 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) 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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index de44e05..354ee00 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include <cstddef>
#define LOG_TAG "AHAL_HapticGeneratorContext"
#include <Utils.h>
@@ -162,8 +163,8 @@
}
// 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) {
+ for (int64_t i = 0; i < mFrameCount; ++i) {
+ for (int j = 0; j < mParams.mHapticChannelCount; ++j) {
mInputBuffer[i * mParams.mHapticChannelCount + j] =
in[i * mParams.mAudioChannelCount + mParams.mHapticChannelSource[j]];
}
@@ -180,8 +181,7 @@
// 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) {
+ for (size_t i = 0; i < hapticSampleCount; ++i) {
in[samples + i] = hapticOutBuffer[i];
}
return {STATUS_OK, samples, static_cast<int32_t>(samples + hapticSampleCount)};
@@ -199,7 +199,7 @@
mParams.mHapticChannelCount = ::aidl::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) {
+ for (int i = 0; i < mParams.mHapticChannelCount; ++i) {
// By default, use the first audio channel to generate haptic channels.
mParams.mHapticChannelSource[i] = 0;
}
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
index a0a0a4c..26e69e4 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.h
@@ -92,7 +92,7 @@
HapticGeneratorState mState;
HapticGeneratorParam mParams GUARDED_BY(mMutex);
int mSampleRate;
- int mFrameCount = 0;
+ int64_t mFrameCount = 0;
// A cache for all shared pointers of the HapticGenerator
struct HapticGeneratorProcessorsRecord mProcessorsRecord;
diff --git a/media/libeffects/loudness/Android.bp b/media/libeffects/loudness/Android.bp
index 7acba11..46e4669 100644
--- a/media/libeffects/loudness/Android.bp
+++ b/media/libeffects/loudness/Android.bp
@@ -54,9 +54,7 @@
":effectCommonFile",
],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
],
header_libs: [
"libaudioeffects",
@@ -71,6 +69,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
index 5b9e924..e2e716c 100644
--- a/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
+++ b/media/libeffects/loudness/aidl/EffectLoudnessEnhancer.h
@@ -33,22 +33,25 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) 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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
- std::shared_ptr<LoudnessEnhancerContext> mContext;
+ std::shared_ptr<LoudnessEnhancerContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterLoudnessEnhancer(const LoudnessEnhancer::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
index 578f58a..33f6779 100644
--- a/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
+++ b/media/libeffects/loudness/dsp/core/dynamic_range_compression.cpp
@@ -89,8 +89,7 @@
} else {
state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
}
- compressor_gain_ *=
- math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+ compressor_gain_ *= expf(state_ - prev_state);
x *= compressor_gain_;
if (x > kFixedPointLimit) {
return kFixedPointLimit;
@@ -118,8 +117,7 @@
} else {
state_ = alpha_release_ * state_ + (1.0f - alpha_release_) * cv;
}
- compressor_gain_ *=
- math::ExpApproximationViaTaylorExpansionOrder5(state_ - prev_state);
+ compressor_gain_ *= expf(state_ - prev_state);
*x1 *= compressor_gain_;
if (*x1 > kFixedPointLimit) {
*x1 = kFixedPointLimit;
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index a163f4b..bb7e4c6 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "BundleContext"
#include <android-base/logging.h>
#include <audio_utils/power.h>
+#include <media/AidlConversionCppNdk.h>
#include <Utils.h>
#include "BundleContext.h"
@@ -36,9 +37,10 @@
const lvm::BundleEffectType& type)
: EffectContext(statusDepth, common), mType(type) {
LOG(DEBUG) << __func__ << type;
- int channelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+
+ int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
common.input.base.channelMask);
- mSamplesPerSecond = common.input.base.sampleRate * channelCount;
+ mSamplesPerSecond = common.input.base.sampleRate * inputChannelCount;
}
BundleContext::~BundleContext() {
@@ -50,9 +52,15 @@
std::lock_guard lg(mMutex);
// init with pre-defined preset NORMAL
for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- mBandGainMdB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
+ mBandGainmB[i] = lvm::kSoftPresets[0 /* normal */][i] * 100;
}
+ // Initialise control params
+ LVM_ControlParams_t controlParams;
+ RetCode retStatus = initControlParameter(controlParams);
+ RETURN_VALUE_IF(retStatus != RetCode::SUCCESS, RetCode::ERROR_ILLEGAL_PARAMETER,
+ " UnsupportedParams");
+
// allocate lvm instance
LVM_ReturnStatus_en status;
LVM_InstParams_t params = {.BufferMode = LVM_UNMANAGED_BUFFERS,
@@ -63,8 +71,6 @@
GOTO_IF_LVM_ERROR(status, deinit, "LVM_GetInstanceHandleFailed");
// set control
- LVM_ControlParams_t controlParams;
- initControlParameter(controlParams);
status = LVM_SetControlParameters(mInstance, &controlParams);
GOTO_IF_LVM_ERROR(status, deinit, "LVM_SetControlParametersFailed");
@@ -227,8 +233,8 @@
bool viEnabled = params.VirtualizerOperatingMode == LVM_MODE_ON;
if (eqEnabled) {
- for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- float bandFactor = mBandGainMdB[i] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ float bandFactor = mBandGainmB[i] / 1500.0;
float bandCoefficient = lvm::kBandEnergyCoefficient[i];
float bandEnergy = bandFactor * bandCoefficient * bandCoefficient;
if (bandEnergy > 0) energyContribution += bandEnergy;
@@ -236,9 +242,9 @@
// cross EQ coefficients
float bandFactorSum = 0;
- for (int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
- float bandFactor1 = mBandGainMdB[i] / 1500.0;
- float bandFactor2 = mBandGainMdB[i + 1] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS - 1; i++) {
+ float bandFactor1 = mBandGainmB[i] / 1500.0;
+ float bandFactor2 = mBandGainmB[i + 1] / 1500.0;
if (bandFactor1 > 0 && bandFactor2 > 0) {
float crossEnergy =
@@ -259,8 +265,8 @@
energyContribution += boostFactor * boostCoefficient * boostCoefficient;
if (eqEnabled) {
- for (int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- float bandFactor = mBandGainMdB[i] / 1500.0;
+ for (unsigned int i = 0; i < lvm::MAX_NUM_BANDS; i++) {
+ float bandFactor = mBandGainmB[i] / 1500.0;
float bandCrossCoefficient = lvm::kBassBoostEnergyCrossCoefficient[i];
float bandEnergy = boostFactor * bandFactor * bandCrossCoefficient;
if (bandEnergy > 0) energyBassBoost += bandEnergy;
@@ -312,7 +318,9 @@
device != AudioDeviceDescription{AudioDeviceType::OUT_CARKIT,
AudioDeviceDescription::CONNECTION_BT_SCO} &&
device != AudioDeviceDescription{AudioDeviceType::OUT_SPEAKER,
- AudioDeviceDescription::CONNECTION_BT_A2DP}) {
+ AudioDeviceDescription::CONNECTION_BT_A2DP} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+ AudioDeviceDescription::CONNECTION_VIRTUAL}) {
return false;
}
}
@@ -329,7 +337,9 @@
device != AudioDeviceDescription{AudioDeviceType::OUT_HEADPHONE,
AudioDeviceDescription::CONNECTION_BT_A2DP} &&
device != AudioDeviceDescription{AudioDeviceType::OUT_HEADSET,
- AudioDeviceDescription::CONNECTION_USB}) {
+ AudioDeviceDescription::CONNECTION_USB} &&
+ device != AudioDeviceDescription{AudioDeviceType::OUT_SUBMIX,
+ AudioDeviceDescription::CONNECTION_VIRTUAL}) {
return false;
}
}
@@ -421,7 +431,6 @@
RetCode BundleContext::setVolumeStereo(const Parameter::VolumeStereo& volume) {
LVM_ControlParams_t params;
- LVM_ReturnStatus_en status = LVM_SUCCESS;
// Convert volume to dB
float leftdB = VolToDb(volume.left);
@@ -470,6 +479,7 @@
RetCode BundleContext::setEqualizerBandLevels(const std::vector<Equalizer::BandLevel>& bandLevels) {
RETURN_VALUE_IF(bandLevels.size() > lvm::MAX_NUM_BANDS || bandLevels.empty(),
RetCode::ERROR_ILLEGAL_PARAMETER, "sizeExceedMax");
+
RetCode ret = updateControlParameter(bandLevels);
if (RetCode::SUCCESS == ret) {
mCurPresetIdx = lvm::PRESET_CUSTOM;
@@ -484,15 +494,13 @@
std::vector<Equalizer::BandLevel> bandLevels;
bandLevels.reserve(lvm::MAX_NUM_BANDS);
for (std::size_t i = 0; i < lvm::MAX_NUM_BANDS; i++) {
- bandLevels.emplace_back(
- Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainMdB[i]});
+ bandLevels.emplace_back(Equalizer::BandLevel{static_cast<int32_t>(i), mBandGainmB[i]});
}
return bandLevels;
}
std::vector<int32_t> BundleContext::getEqualizerCenterFreqs() {
std::vector<int32_t> freqs;
-
LVM_ControlParams_t params;
{
std::lock_guard lg(mMutex);
@@ -512,14 +520,14 @@
const auto [min, max] =
std::minmax_element(bandLevels.begin(), bandLevels.end(),
[](const auto& a, const auto& b) { return a.index < b.index; });
- return min->index >= 0 && max->index < lvm::MAX_NUM_BANDS;
+ return min->index >= 0 && static_cast<size_t>(max->index) < lvm::MAX_NUM_BANDS;
}
RetCode BundleContext::updateControlParameter(const std::vector<Equalizer::BandLevel>& bandLevels) {
RETURN_VALUE_IF(!isBandLevelIndexInRange(bandLevels), RetCode::ERROR_ILLEGAL_PARAMETER,
"indexOutOfRange");
- std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainMdB);
+ std::array<int, lvm::MAX_NUM_BANDS> tempLevel(mBandGainmB);
for (const auto& it : bandLevels) {
tempLevel[it.index] = it.levelMb;
}
@@ -540,8 +548,8 @@
RETURN_VALUE_IF(LVM_SUCCESS != LVM_SetControlParameters(mInstance, ¶ms),
RetCode::ERROR_EFFECT_LIB_ERROR, " setControlParamFailed");
}
- mBandGainMdB = tempLevel;
- LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainMdB)
+ mBandGainmB = tempLevel;
+ LOG(DEBUG) << __func__ << " update bandGain to " << ::android::internal::ToString(mBandGainmB)
<< "mdB";
return RetCode::SUCCESS;
@@ -619,11 +627,30 @@
return RetCode::SUCCESS;
}
-void BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+RetCode BundleContext::initControlParameter(LVM_ControlParams_t& params) const {
+ int outputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+ mCommon.output.base.channelMask);
+ auto outputChannelMaskConv = aidl2legacy_AudioChannelLayout_audio_channel_mask_t(
+ mCommon.output.base.channelMask, /*isInput*/ false);
+ RETURN_VALUE_IF(!outputChannelMaskConv.ok(), RetCode::ERROR_ILLEGAL_PARAMETER,
+ " outputChannelMaskNotValid");
+
+ params.NrChannels = outputChannelCount;
+ params.ChMask = outputChannelMaskConv.value();
+ params.SampleRate = lvmFsForSampleRate(mCommon.input.base.sampleRate);
+
+ int inputChannelCount = ::aidl::android::hardware::audio::common::getChannelCount(
+ mCommon.input.base.channelMask);
+ if (inputChannelCount == 1) {
+ params.SourceFormat = LVM_MONO;
+ } else if (inputChannelCount == 2) {
+ params.SourceFormat = LVM_STEREO;
+ } else if (inputChannelCount > 2 && inputChannelCount <= LVM_MAX_CHANNELS) {
+ params.SourceFormat = LVM_MULTICHANNEL;
+ }
+
/* General parameters */
params.OperatingMode = LVM_MODE_ON;
- params.SampleRate = LVM_FS_44100;
- params.SourceFormat = LVM_STEREO;
params.SpeakerType = LVM_HEADPHONES;
/* Concert Sound parameters */
@@ -658,13 +685,7 @@
params.PSA_Enable = LVM_PSA_OFF;
params.PSA_PeakDecayRate = LVM_PSA_SPEED_MEDIUM;
- /* TE Control parameters */
- params.TE_OperatingMode = LVM_TE_OFF;
- params.TE_EffectLevel = 0;
-
- params.NrChannels = audio_channel_count_from_out_mask(AUDIO_CHANNEL_OUT_STEREO);
- params.ChMask = AUDIO_CHANNEL_OUT_STEREO;
- params.SourceFormat = LVM_STEREO;
+ return RetCode::SUCCESS;
}
void BundleContext::initHeadroomParameter(LVM_HeadroomParams_t& params) const {
@@ -833,13 +854,13 @@
LOG(DEBUG) << "Effect_process() processing last frame";
}
mNumberEffectsCalled = 0;
- LVM_UINT16 frames = samples * sizeof(float) / frameSize;
float* outTmp = (accumulate ? getWorkBuffer() : out);
/* Process the samples */
LVM_ReturnStatus_en lvmStatus;
{
std::lock_guard lg(mMutex);
- lvmStatus = LVM_Process(mInstance, in, outTmp, frames, 0);
+
+ lvmStatus = LVM_Process(mInstance, in, outTmp, inputFrameCount, 0);
if (lvmStatus != LVM_SUCCESS) {
LOG(ERROR) << __func__ << lvmStatus;
return {EX_UNSUPPORTED_OPERATION, 0, 0};
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index 779d53a..809f402 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -41,15 +41,6 @@
RetCode disable();
RetCode disableOperatingMode();
- void setSampleRate(const int sampleRate) { mSampleRate = sampleRate; }
- int getSampleRate() const { return mSampleRate; }
-
- void setChannelMask(const aidl::android::media::audio::common::AudioChannelLayout& chMask) {
- mChMask = chMask;
- }
- aidl::android::media::audio::common::AudioChannelLayout getChannelMask() const {
- return mChMask;
- }
bool isDeviceSupportedBassBoost(
const std::vector<aidl::android::media::audio::common::AudioDeviceDescription>&
devices);
@@ -105,9 +96,7 @@
LVM_Handle_t mInstance GUARDED_BY(mMutex);
aidl::android::media::audio::common::AudioDeviceDescription mVirtualizerForcedDevice;
- aidl::android::media::audio::common::AudioChannelLayout mChMask;
- int mSampleRate = LVM_FS_44100;
int mSamplesPerSecond = 0;
int mSamplesToExitCountEq = 0;
int mSamplesToExitCountBb = 0;
@@ -129,7 +118,7 @@
int mBassStrengthSaved = 0;
// Equalizer
int mCurPresetIdx = lvm::PRESET_CUSTOM; /* Current preset being used */
- std::array<int, lvm::MAX_NUM_BANDS> mBandGainMdB; /* band gain in millibels */
+ std::array<int, lvm::MAX_NUM_BANDS> mBandGainmB; /* band gain in millibels */
// Virtualizer
int mVirtStrengthSaved = 0; /* Conversion between Get/Set */
bool mVirtualizerTempDisabled = false;
@@ -139,7 +128,7 @@
float mVolume = 0;
bool mMuteEnabled = false; /* Must store as mute = -96dB level */
- void initControlParameter(LVM_ControlParams_t& params) const;
+ RetCode initControlParameter(LVM_ControlParams_t& params) const;
void initHeadroomParameter(LVM_HeadroomParams_t& params) const;
RetCode limitLevel();
static float VolToDb(float vol);
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
index 3148d36..257e972 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.cpp
@@ -425,10 +425,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectBundleAidl::getContext() {
- return mContext;
-}
-
RetCode EffectBundleAidl::releaseContext() {
if (mContext) {
GlobalSession::getGlobalSession().releaseSession(mType, mContext->getSessionId());
diff --git a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
index ec1abe8..429e941 100644
--- a/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
+++ b/media/libeffects/lvm/wrapper/Aidl/EffectBundleAidl.h
@@ -36,41 +36,47 @@
~EffectBundleAidl() 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;
+ ndk::ScopedAStatus setParameterCommon(const Parameter& param) REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<BundleContext> mContext;
+ std::shared_ptr<BundleContext> mContext GUARDED_BY(mImplMutex);
const Descriptor* mDescriptor;
const std::string* mEffectName;
lvm::BundleEffectType mType = lvm::BundleEffectType::EQUALIZER;
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 setParameterBassBoost(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterBassBoost(const BassBoost::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- 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 setParameterEqualizer(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterEqualizer(const Equalizer::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus setParameterVolume(const Parameter::Specific& specific) REQUIRES(mImplMutex);
+ ndk::ScopedAStatus getParameterVolume(const Volume::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
+ ndk::ScopedAStatus setParameterVirtualizer(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterVirtualizer(const Virtualizer::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific) REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index fa300d2..a50ba93 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -110,9 +110,7 @@
],
static_libs: ["libmusicbundle"],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
],
local_include_dirs: ["Aidl"],
header_libs: [
@@ -120,14 +118,19 @@
"libhardware_headers",
],
shared_libs: [
+ "libaudio_aidl_conversion_common_ndk",
+ "libaudioutils",
+ "libbinder",
"liblog",
+ "libstagefright_foundation",
],
cflags: [
"-Wthread-safety",
+ "-DBACKEND_NDK",
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
@@ -140,9 +143,7 @@
],
static_libs: ["libreverb"],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
],
local_include_dirs: ["Reverb/aidl"],
header_libs: [
@@ -160,6 +161,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
index b49d109..f9afe69 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.cpp
@@ -358,10 +358,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectReverb::getContext() {
- return mContext;
-}
-
RetCode EffectReverb::releaseContext() {
if (mContext) {
mContext.reset();
diff --git a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
index d7d2bbd..e0771a1 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/EffectReverb.h
@@ -30,35 +30,41 @@
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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<ReverbContext> mContext;
+ std::shared_ptr<ReverbContext> mContext GUARDED_BY(mImplMutex);
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 setParameterPresetReverb(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterPresetReverb(const PresetReverb::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterEnvironmentalReverb(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterEnvironmentalReverb(const EnvironmentalReverb::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // 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
index 79e67f2..468b268 100644
--- a/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/aidl/ReverbContext.cpp
@@ -329,7 +329,7 @@
*/
int ReverbContext::convertLevel(int level) {
- for (int i = 0; i < kLevelMapping.size(); i++) {
+ for (std::size_t i = 0; i < kLevelMapping.size(); i++) {
if (level <= kLevelMapping[i]) {
return i;
}
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index d018c47..994b061 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -67,9 +67,7 @@
":effectCommonFile",
],
defaults: [
- "aidlaudioservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
+ "aidlaudioeffectservice_defaults",
],
local_include_dirs: ["aidl"],
shared_libs: [
@@ -91,6 +89,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
index e8ae8b3..7552804 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.cpp
@@ -412,10 +412,6 @@
return mContext;
}
-std::shared_ptr<EffectContext> EffectPreProcessing::getContext() {
- return mContext;
-}
-
RetCode EffectPreProcessing::releaseContext() {
if (mContext) {
PreProcessingSession::getPreProcessingSession().releaseSession(mType,
diff --git a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
index fad848a..9ce5597 100644
--- a/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
+++ b/media/libeffects/preprocessing/aidl/EffectPreProcessing.h
@@ -31,41 +31,51 @@
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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> createContext(const Parameter::Common& common) override;
- std::shared_ptr<EffectContext> getContext() override;
- RetCode releaseContext() override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- IEffect::Status effectProcessImpl(float* in, float* out, int samples) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int samples)
+ REQUIRES(mImplMutex) override;
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) override;
std::string getEffectName() override { return *mEffectName; }
private:
- std::shared_ptr<PreProcessingContext> mContext;
+ std::shared_ptr<PreProcessingContext> mContext GUARDED_BY(mImplMutex);
const Descriptor* mDescriptor;
const std::string* mEffectName;
PreProcessingEffectType mType;
- ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAcousticEchoCanceler(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAcousticEchoCanceler(const AcousticEchoCanceler::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAutomaticGainControlV1(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAutomaticGainControlV1(const AutomaticGainControlV1::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterAutomaticGainControlV2(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterAutomaticGainControlV2(const AutomaticGainControlV2::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
- ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific);
+ ndk::ScopedAStatus setParameterNoiseSuppression(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex);
ndk::ScopedAStatus getParameterNoiseSuppression(const NoiseSuppression::Id& id,
- Parameter::Specific* specific);
+ Parameter::Specific* specific)
+ REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
index c1e4eda..2c44e5c 100644
--- a/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
+++ b/media/libeffects/preprocessing/aidl/PreProcessingContext.cpp
@@ -141,6 +141,9 @@
}
RetCode PreProcessingContext::setCommon(const Parameter::Common& common) {
+ if(auto ret = updateIOFrameSize(common); ret != RetCode::SUCCESS) {
+ return ret;
+ }
mCommon = common;
updateConfigs(common);
return RetCode::SUCCESS;
diff --git a/media/libeffects/visualizer/Android.bp b/media/libeffects/visualizer/Android.bp
index cf782f7..66ceadf 100644
--- a/media/libeffects/visualizer/Android.bp
+++ b/media/libeffects/visualizer/Android.bp
@@ -60,8 +60,6 @@
],
defaults: [
"aidlaudioeffectservice_defaults",
- "latest_android_hardware_audio_effect_ndk_shared",
- "latest_android_media_audio_common_types_ndk_shared",
"visualizer_defaults",
],
cflags: [
@@ -72,6 +70,6 @@
],
relative_install_path: "soundfx",
visibility: [
- "//hardware/interfaces/audio/aidl/default",
+ "//hardware/interfaces/audio/aidl/default:__subpackages__",
],
}
diff --git a/media/libeffects/visualizer/aidl/Visualizer.h b/media/libeffects/visualizer/aidl/Visualizer.h
index ec725db..b48c85e 100644
--- a/media/libeffects/visualizer/aidl/Visualizer.h
+++ b/media/libeffects/visualizer/aidl/Visualizer.h
@@ -35,23 +35,25 @@
LOG(DEBUG) << __func__;
}
- ndk::ScopedAStatus commandImpl(CommandId command) override;
+ ndk::ScopedAStatus commandImpl(CommandId command) REQUIRES(mImplMutex) 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;
+ ndk::ScopedAStatus setParameterSpecific(const Parameter::Specific& specific)
+ REQUIRES(mImplMutex) override;
+ ndk::ScopedAStatus getParameterSpecific(const Parameter::Id& id, Parameter::Specific* specific)
+ REQUIRES(mImplMutex) override;
+ IEffect::Status effectProcessImpl(float* in, float* out, int process)
+ REQUIRES(mImplMutex) override;
+ std::shared_ptr<EffectContext> createContext(const Parameter::Common& common)
+ REQUIRES(mImplMutex) override;
+ RetCode releaseContext() REQUIRES(mImplMutex) override;
- std::shared_ptr<EffectContext> getContext() override { return mContext; }
std::string getEffectName() override { return kEffectName; }
private:
static const std::vector<Range::VisualizerRange> kRanges;
- std::shared_ptr<VisualizerContext> mContext;
+ std::shared_ptr<VisualizerContext> mContext GUARDED_BY(mImplMutex);
ndk::ScopedAStatus getParameterVisualizer(const Visualizer::Tag& tag,
- Parameter::Specific* specific);
+ Parameter::Specific* specific) REQUIRES(mImplMutex);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libmedia/CharacterEncodingDetector.cpp b/media/libmedia/CharacterEncodingDetector.cpp
index e33cc0f..4436fb9 100644
--- a/media/libmedia/CharacterEncodingDetector.cpp
+++ b/media/libmedia/CharacterEncodingDetector.cpp
@@ -198,7 +198,9 @@
ALOGV("@@@ checking %s", name);
const char *s = mValues.getEntry(i);
int32_t inputLength = strlen(s);
- const char *enc;
+ // Use encoding determined from the combination of artist/album/title etc.
+ // as default if there is no better match found.
+ const char *enc = combinedenc;
if (!allprintable && (!strcmp(name, "artist") ||
!strcmp(name, "albumartist") ||
@@ -216,13 +218,12 @@
const UCharsetMatch** ucma = ucsdet_detectAll(csd, &matches, &status);
const UCharsetMatch* bestSingleMatch = getPreferred(s, inputLength,
ucma, matches, &goodmatchSingle, &highestSingle);
- if (goodmatchSingle || highestSingle > highest)
- enc = ucsdet_getName(bestSingleMatch, &status);
- else
- enc = combinedenc;
- } else {
- // use encoding determined from the combination of artist/album/title etc.
- enc = combinedenc;
+ // getPreferred could return a null. Check for null before calling
+ // ucsdet_getName.
+ if (bestSingleMatch != NULL) {
+ if (goodmatchSingle || highestSingle > highest)
+ enc = ucsdet_getName(bestSingleMatch, &status);
+ }
}
} else {
if (isPrintableAscii(s, inputLength)) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a625893..bb49b5a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1977,6 +1977,8 @@
if (rate > 0) {
format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
}
+
+ format->setInt32("android._video-scaling", mVideoScalingMode);
}
Mutex::Autolock autoLock(mDecoderLock);
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index 0af9d12..712b405 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -137,7 +137,7 @@
cflags: [
"-DDISABLE_AUDIO_SYSTEM_OFFLOAD",
],
- }
+ },
},
}
@@ -273,7 +273,7 @@
"VideoFrameSchedulerBase.cpp",
"VideoFrameScheduler.cpp",
"VideoRenderQualityTracker.cpp",
- ],
+ ],
shared_libs: [
"libstagefright_framecapture_utils",
@@ -330,7 +330,7 @@
"libmedia_ndkformatpriv",
],
- header_libs:[
+ header_libs: [
"libmediadrm_headers",
"libnativeloader-headers",
"libstagefright_xmlparser_headers",
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 1a0bb7f..0ab954f 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -102,6 +102,13 @@
displayTop = 0;
}
}
+ if (displayWidth > width) {
+ displayWidth = width;
+ }
+ if (displayHeight > height) {
+ displayHeight = height;
+ }
+
if (allocRotated) {
if (rotationAngle == 90 || rotationAngle == 270) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ee66622..3c80f28 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -318,8 +318,8 @@
return Status::fromStatus(STATUS_INVALID_OPERATION);
}
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(this)};
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(this)};
service->removeClient(clientInfo);
*_aidl_return = true;
return Status::ok();
@@ -396,6 +396,10 @@
mCodecName = name;
}
+ inline void setImportance(int importance) {
+ mImportance = importance;
+ }
+
private:
// To get the binder interface to ResourceManagerService.
void getService() {
@@ -435,12 +439,30 @@
mGetServiceFuture = std::async(std::launch::async, [this] { getService(); });
}
+ /**
+ * Get the ClientInfo to communicate with the ResourceManager.
+ *
+ * ClientInfo includes:
+ * - {pid, uid} of the process
+ * - identifier for the client
+ * - name of the client/codec
+ * - importance associated with the client
+ */
+ inline ClientInfoParcel getClientInfo() const {
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
+ .uid = static_cast<int32_t>(mUid),
+ .id = getId(mClient),
+ .name = mCodecName,
+ .importance = mImportance};
+ return std::move(clientInfo);
+ }
private:
- std::mutex mLock;
- pid_t mPid;
- uid_t mUid;
- bool mBinderDied = false;
+ std::mutex mLock;
+ bool mBinderDied = false;
+ pid_t mPid;
+ uid_t mUid;
+ int mImportance = 0;
std::string mCodecName;
/**
* Reconnecting with the ResourceManagerService, after its binder interface dies,
@@ -548,11 +570,7 @@
std::vector<MediaResourceParcel> resources;
std::copy(mMediaResourceParcel.begin(), mMediaResourceParcel.end(),
std::back_inserter(resources));
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- mService->addResource(clientInfo, mClient, resources);
+ mService->addResource(getClientInfo(), mClient, resources);
}
void MediaCodec::ResourceManagerServiceProxy::BinderDiedCallback(void* cookie) {
@@ -585,11 +603,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->addResource(clientInfo, mClient, resources);
+ service->addResource(getClientInfo(), mClient, resources);
mMediaResourceParcel.emplace(resource);
}
@@ -603,11 +617,7 @@
}
std::vector<MediaResourceParcel> resources;
resources.push_back(resource);
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeResource(clientInfo, resources);
+ service->removeResource(getClientInfo(), resources);
mMediaResourceParcel.erase(resource);
}
@@ -618,11 +628,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->removeClient(clientInfo);
+ service->removeClient(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -633,11 +639,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->markClientForPendingRemoval(clientInfo);
+ service->markClientForPendingRemoval(getClientInfo());
mMediaResourceParcel.clear();
}
@@ -650,11 +652,7 @@
return false;
}
bool success;
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- Status status = service->reclaimResource(clientInfo, resources, &success);
+ Status status = service->reclaimResource(getClientInfo(), resources, &success);
return status.isOk() && success;
}
@@ -665,11 +663,7 @@
ALOGW("Service isn't available");
return;
}
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
- .uid = static_cast<int32_t>(mUid),
- .id = getId(mClient),
- .name = mCodecName};
- service->notifyClientCreated(clientInfo);
+ service->notifyClientCreated(getClientInfo());
}
void MediaCodec::ResourceManagerServiceProxy::notifyClientStarted(
@@ -680,10 +674,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStarted(clientConfig);
}
@@ -695,10 +686,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientStopped(clientConfig);
}
@@ -710,10 +698,7 @@
ALOGW("Service isn't available");
return;
}
- clientConfig.clientInfo.pid = static_cast<int32_t>(mPid);
- clientConfig.clientInfo.uid = static_cast<int32_t>(mUid);
- clientConfig.clientInfo.id = getId(mClient);
- clientConfig.clientInfo.name = mCodecName;
+ clientConfig.clientInfo = getClientInfo();
service->notifyClientConfigChanged(clientConfig);
}
@@ -1197,6 +1182,7 @@
mTunneledInputHeight(0),
mTunneled(false),
mTunnelPeekState(TunnelPeekState::kLegacyMode),
+ mTunnelPeekEnabled(false),
mHaveInputSurface(false),
mHavePendingInputBuffers(false),
mCpuBoostRequested(false),
@@ -1713,6 +1699,21 @@
}
}
+void MediaCodec::updateCodecImportance(const sp<AMessage>& msg) {
+ // Update the codec importance.
+ int32_t importance = 0;
+ if (msg->findInt32(KEY_IMPORTANCE, &importance)) {
+ // Ignoring the negative importance.
+ if (importance >= 0) {
+ // Notify RM about the change in the importance.
+ mResourceManagerProxy->setImportance(importance);
+ ClientConfigParcel clientConfig;
+ initClientConfigParcel(clientConfig);
+ mResourceManagerProxy->notifyClientConfigChanged(clientConfig);
+ }
+ }
+}
+
constexpr const char *MediaCodec::asString(TunnelPeekState state, const char *default_string){
switch(state) {
case TunnelPeekState::kLegacyMode:
@@ -1742,6 +1743,7 @@
TunnelPeekState previousState = mTunnelPeekState;
if(tunnelPeek == 0){
+ mTunnelPeekEnabled = false;
switch (mTunnelPeekState) {
case TunnelPeekState::kLegacyMode:
msg->setInt32("android._tunnel-peek-set-legacy", 0);
@@ -1757,6 +1759,7 @@
return;
}
} else {
+ mTunnelPeekEnabled = true;
switch (mTunnelPeekState) {
case TunnelPeekState::kLegacyMode:
msg->setInt32("android._tunnel-peek-set-legacy", 0);
@@ -2219,23 +2222,9 @@
static void mapFormat(AString componentName, const sp<AMessage> &format, const char *kind,
bool reverse);
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &nativeWindow,
- const sp<ICrypto> &crypto,
- uint32_t flags) {
- return configure(format, nativeWindow, crypto, NULL, flags);
-}
-
-status_t MediaCodec::configure(
- const sp<AMessage> &format,
- const sp<Surface> &surface,
- const sp<ICrypto> &crypto,
- const sp<IDescrambler> &descrambler,
- uint32_t flags) {
-
- sp<AMessage> msg = new AMessage(kWhatConfigure, this);
+mediametrics_handle_t MediaCodec::createMediaMetrics(const sp<AMessage>& format, uint32_t flags) {
mediametrics_handle_t nextMetricsHandle = mediametrics_create(kCodecKeyName);
+ bool isEncoder = (flags & CONFIGURE_FLAG_ENCODE);
// TODO: validity check log-session-id: it should be a 32-hex-digit.
format->findString("log-session-id", &mLogSessionId);
@@ -2250,8 +2239,7 @@
if (format->findInt32("level", &level)) {
mediametrics_setInt32(nextMetricsHandle, kCodecLevel, level);
}
- mediametrics_setInt32(nextMetricsHandle, kCodecEncoder,
- (flags & CONFIGURE_FLAG_ENCODE) ? 1 : 0);
+ mediametrics_setInt32(nextMetricsHandle, kCodecEncoder, isEncoder);
if (!mLogSessionId.empty()) {
mediametrics_setCString(nextMetricsHandle, kCodecLogSessionId, mLogSessionId.c_str());
@@ -2330,7 +2318,7 @@
}
}
- if (flags & CONFIGURE_FLAG_ENCODE) {
+ if (isEncoder) {
int8_t enableShaping = property_get_bool(enableMediaFormatShapingProperty,
enableMediaFormatShapingDefault);
if (!enableShaping) {
@@ -2375,6 +2363,31 @@
updateLowLatency(format);
+ return nextMetricsHandle;
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &nativeWindow,
+ const sp<ICrypto> &crypto,
+ uint32_t flags) {
+ return configure(format, nativeWindow, crypto, NULL, flags);
+}
+
+status_t MediaCodec::configure(
+ const sp<AMessage> &format,
+ const sp<Surface> &surface,
+ const sp<ICrypto> &crypto,
+ const sp<IDescrambler> &descrambler,
+ uint32_t flags) {
+
+ // Update the codec importance.
+ updateCodecImportance(format);
+
+ // Create and set up metrics for this codec.
+ mediametrics_handle_t nextMetricsHandle = createMediaMetrics(format, flags);
+
+ sp<AMessage> msg = new AMessage(kWhatConfigure, this);
msg->setMessage("format", format);
msg->setInt32("flags", flags);
msg->setObject("surface", surface);
@@ -4943,10 +4956,11 @@
CHECK(msg->senderAwaitsResponse(&replyID));
TunnelPeekState previousState = mTunnelPeekState;
if (previousState != TunnelPeekState::kLegacyMode) {
- mTunnelPeekState = TunnelPeekState::kEnabledNoBuffer;
+ mTunnelPeekState = mTunnelPeekEnabled ? TunnelPeekState::kEnabledNoBuffer :
+ TunnelPeekState::kDisabledNoBuffer;
ALOGV("TunnelPeekState: %s -> %s",
asString(previousState),
- asString(TunnelPeekState::kEnabledNoBuffer));
+ asString(mTunnelPeekState));
}
mReplyID = replyID;
@@ -5445,10 +5459,11 @@
returnBuffersToCodec();
TunnelPeekState previousState = mTunnelPeekState;
if (previousState != TunnelPeekState::kLegacyMode) {
- mTunnelPeekState = TunnelPeekState::kEnabledNoBuffer;
+ mTunnelPeekState = mTunnelPeekEnabled ? TunnelPeekState::kEnabledNoBuffer :
+ TunnelPeekState::kDisabledNoBuffer;
ALOGV("TunnelPeekState: %s -> %s",
asString(previousState),
- asString(TunnelPeekState::kEnabledNoBuffer));
+ asString(mTunnelPeekState));
}
break;
}
@@ -5991,7 +6006,7 @@
if (isBufferDecodeOnly) {
buffer->meta()->setInt32("decode-only", true);
}
- if (mTunneled && !isBufferDecodeOnly) {
+ if (mTunneled && !isBufferDecodeOnly && !(flags & BUFFER_FLAG_CODECCONFIG)) {
TunnelPeekState previousState = mTunnelPeekState;
switch(mTunnelPeekState){
case TunnelPeekState::kEnabledNoBuffer:
@@ -6584,6 +6599,7 @@
return NO_INIT;
}
updateLowLatency(params);
+ updateCodecImportance(params);
mapFormat(mComponentName, params, nullptr, false);
updateTunnelPeek(params);
mCodec->signalSetParameters(params);
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
index f16e635..604dcb0 100644
--- a/media/libstagefright/SurfaceUtils.cpp
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -298,6 +298,11 @@
ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
break;
}
+ if (img == nullptr) {
+ (void)buf->unlock(); // Since lock() was successful.
+ ALOGE("error pushing blank frames: lock succeeded: buf mapping is nullptr");
+ break;
+ }
*img = 0;
diff --git a/media/libstagefright/colorconversion/fuzzer/Android.bp b/media/libstagefright/colorconversion/fuzzer/Android.bp
index 76b054a..237e715 100644
--- a/media/libstagefright/colorconversion/fuzzer/Android.bp
+++ b/media/libstagefright/colorconversion/fuzzer/Android.bp
@@ -47,9 +47,15 @@
],
fuzz_config: {
cc: [
- "android-media-fuzzing-reports@google.com",
+ "android-fwk-video@google.com",
],
- componentid: 155276,
+ componentid: 42195,
+ hotlists: ["4593311"],
+ description: "The fuzzer targets the APIs of libstagefright_color_conversion",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libstagefright/data/media_codecs_google_c2_audio.xml b/media/libstagefright/data/media_codecs_google_c2_audio.xml
index 509f7a9..0d9e0ec 100644
--- a/media/libstagefright/data/media_codecs_google_c2_audio.xml
+++ b/media/libstagefright/data/media_codecs_google_c2_audio.xml
@@ -66,7 +66,7 @@
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
<Alias name="OMX.google.raw.decoder" />
- <Limit name="channel-count" max="8" />
+ <Limit name="channel-count" max="12" />
<Limit name="sample-rate" ranges="8000-192000" />
<Limit name="bitrate" range="1-10000000" />
</MediaCodec>
diff --git a/media/libstagefright/data/media_codecs_sw.xml b/media/libstagefright/data/media_codecs_sw.xml
index ee41867..24020d1 100644
--- a/media/libstagefright/data/media_codecs_sw.xml
+++ b/media/libstagefright/data/media_codecs_sw.xml
@@ -80,7 +80,7 @@
</MediaCodec>
<MediaCodec name="c2.android.raw.decoder" type="audio/raw">
<Alias name="OMX.google.raw.decoder" />
- <Limit name="channel-count" max="8" />
+ <Limit name="channel-count" max="12" />
<Limit name="sample-rate" ranges="8000-192000" />
<Limit name="bitrate" range="1-10000000" />
<Attribute name="software-codec" />
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index f99a78b..2f94e5e 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -320,6 +320,9 @@
status_t reclaim(bool force = false);
friend struct ResourceManagerClient;
+ // to create the metrics associated with this codec.
+ mediametrics_handle_t createMediaMetrics(const sp<AMessage>& format, uint32_t flags);
+
private:
enum State {
UNINITIALIZED,
@@ -462,6 +465,7 @@
void resetMetricsFields();
void updateEphemeralMediametrics(mediametrics_handle_t item);
void updateLowLatency(const sp<AMessage> &msg);
+ void updateCodecImportance(const sp<AMessage>& msg);
void onGetMetrics(const sp<AMessage>& msg);
constexpr const char *asString(TunnelPeekState state, const char *default_string="?");
void updateTunnelPeek(const sp<AMessage> &msg);
@@ -560,6 +564,7 @@
int32_t mTunneledInputHeight;
bool mTunneled;
TunnelPeekState mTunnelPeekState;
+ bool mTunnelPeekEnabled;
sp<IDescrambler> mDescrambler;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
index 7334639..f4c40e1 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodecConstants.h
@@ -794,6 +794,7 @@
inline constexpr char KEY_HDR10_PLUS_INFO[] = "hdr10-plus-info";
inline constexpr char KEY_HEIGHT[] = "height";
inline constexpr char KEY_I_FRAME_INTERVAL[] = "i-frame-interval";
+inline constexpr char KEY_IMPORTANCE[] = "importance";
inline constexpr char KEY_INTRA_REFRESH_PERIOD[] = "intra-refresh-period";
inline constexpr char KEY_IS_ADTS[] = "is-adts";
inline constexpr char KEY_IS_AUTOSELECT[] = "is-autoselect";
@@ -809,6 +810,9 @@
inline constexpr char KEY_MAX_FPS_TO_ENCODER[] = "max-fps-to-encoder";
inline constexpr char KEY_MAX_HEIGHT[] = "max-height";
inline constexpr char KEY_MAX_INPUT_SIZE[] = "max-input-size";
+inline constexpr char KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE[] = "buffer-batch-max-output-size";
+inline constexpr char KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE[] =
+ "buffer-batch-threshold-output-size";
inline constexpr char KEY_MAX_OUTPUT_CHANNEL_COUNT[] = "max-output-channel-count";
inline constexpr char KEY_MAX_PTS_GAP_TO_ENCODER[] = "max-pts-gap-to-encoder";
inline constexpr char KEY_MAX_WIDTH[] = "max-width";
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 54c5697..79ab009 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -184,6 +184,9 @@
cc_defaults {
name: "libstagefright_softomx-defaults",
+ // TODO (b/316432618) Software OMX codecs are no longer used, disable building them till
+ // this code is removed completely.
+ enabled: false,
vendor_available: true,
cflags: [
diff --git a/media/module/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/module/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index e8fea73..fb9f1e9 100644
--- a/media/module/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/module/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -310,26 +310,31 @@
}
// Check if the input is valid by checking if it contains a sync word
-static bool isInputValid(uint8 *buf, uint32 inSize)
+static ERROR_CODE validate_input(uint8 *buf, uint32 inSize)
{
- // Buffer needs to contain at least 4 bytes which is the size of
- // the header
- if (inSize < 4) return false;
+ /*
+ * Verify that at least the header is complete
+ * Note that SYNC_WORD_LNGTH is in unit of bits, but inSize is in unit of bytes.
+ */
+ if (inSize < ((SYNC_WORD_LNGTH + 21) >> 3))
+ {
+ return NO_ENOUGH_MAIN_DATA_ERROR;
+ }
size_t totalInSize = 0;
size_t frameSize = 0;
while (totalInSize <= (inSize - 4)) {
if (!parseHeader(U32_AT(buf + totalInSize), &frameSize)) {
- return false;
+ return SYNCH_LOST_ERROR;
}
// Buffer needs to be large enough to include complete frame
if ((frameSize > inSize) || (totalInSize > (inSize - frameSize))) {
- return false;
+ return SYNCH_LOST_ERROR;
}
totalInSize += frameSize;
}
- return true;
+ return NO_DECODING_ERROR;
}
ERROR_CODE pvmp3_framedecoder(tPVMP3DecoderExternal *pExt,
@@ -348,10 +353,11 @@
mp3Header info_data;
mp3Header *info = &info_data;
- if (!isInputValid(pExt->pInputBuffer, pExt->inputBufferCurrentLength))
+ errorCode = validate_input(pExt->pInputBuffer, pExt->inputBufferCurrentLength);
+ if (errorCode != NO_DECODING_ERROR)
{
pExt->outputFrameSize = 0;
- return SYNCH_LOST_ERROR;
+ return errorCode;
}
pVars->inputStream.pBuffer = pExt->pInputBuffer;
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 65d537b..f95fc4d 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -148,6 +148,11 @@
return C2_TRANSACTION_FAILED;
}
}
+ status = static_cast<c2_status_t>(configResult.status.status);
+ if (status != C2_BAD_INDEX) {
+ LOG(DEBUG) << "config -- call failed: "
+ << status << ".";
+ }
size_t i = failures->size();
failures->resize(i + configResult.failures.size());
for (const c2_aidl::SettingResult& sf : configResult.failures) {
@@ -320,8 +325,8 @@
heapParams->reserve(heapParams->size() + numIndices);
}
c2_status_t status = C2_OK;
- c2_aidl::Params aidlParams;
- ScopedAStatus transResult = mAidlConfigurable->query(indices, true, &aidlParams);
+ c2_aidl::IConfigurable::QueryResult aidlResult;
+ ScopedAStatus transResult = mAidlConfigurable->query(indices, true, &aidlResult);
if (!transResult.isOk()) {
if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
status = c2_status_t(transResult.getServiceSpecificError());
@@ -332,8 +337,12 @@
return C2_TRANSACTION_FAILED;
}
}
+ status = static_cast<c2_status_t>(aidlResult.status.status);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "query -- call failed: " << status << ".";
+ }
std::vector<C2Param*> paramPointers;
- if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, aidlParams)) {
+ if (!c2_aidl::utils::ParseParamsBlob(¶mPointers, aidlResult.params)) {
LOG(ERROR) << "query -- error while parsing params.";
return C2_CORRUPTED;
}
@@ -488,9 +497,9 @@
}
c2_status_t status = C2_OK;
- std::vector<c2_aidl::FieldSupportedValuesQueryResult> queryResults;
+ c2_aidl::IConfigurable::QuerySupportedValuesResult queryResult;
ScopedAStatus transResult = mAidlConfigurable->querySupportedValues(
- aidlFields, true, &queryResults);
+ aidlFields, true, &queryResult);
if (!transResult.isOk()) {
if (transResult.getExceptionCode() == EX_SERVICE_SPECIFIC) {
status = c2_status_t(transResult.getServiceSpecificError());
@@ -502,14 +511,19 @@
return C2_TRANSACTION_FAILED;
}
}
- if (queryResults.size() != fields.size()) {
+ status = static_cast<c2_status_t>(queryResult.status.status);
+ if (status != C2_OK) {
+ LOG(DEBUG) << "querySupportedValues -- call failed: "
+ << status << ".";
+ }
+ if (queryResult.values.size() != fields.size()) {
LOG(ERROR) << "querySupportedValues -- "
"input and output lists "
"have different sizes.";
return C2_CORRUPTED;
}
for (size_t i = 0; i < fields.size(); ++i) {
- if (!c2_aidl::utils::FromAidl(&fields[i], aidlFields[i], queryResults[i])) {
+ if (!c2_aidl::utils::FromAidl(&fields[i], aidlFields[i], queryResult.values[i])) {
LOG(ERROR) << "querySupportedValues -- "
"invalid returned value.";
return C2_CORRUPTED;
@@ -803,6 +817,7 @@
}
}
+ bool registered = false;
if (platformVersion >= __ANDROID_API_V__) {
if (!aidlStore) {
aidlStore = ::ndk::SharedRefBase::make<c2_aidl::utils::ComponentStore>(
@@ -812,23 +827,27 @@
std::string(c2_aidl::IComponentStore::descriptor) + "/software";
binder_exception_t ex = AServiceManager_addService(
aidlStore->asBinder().get(), serviceName.c_str());
- if (ex != EX_NONE) {
+ if (ex == EX_NONE) {
+ registered = true;
+ } else {
LOG(ERROR) << "Cannot register software Codec2 AIDL service.";
- return;
}
}
if (!hidlStore) {
- hidlStore = ::android::sp<V1_0::utils::ComponentStore>::make(
+ hidlStore = ::android::sp<V1_2::utils::ComponentStore>::make(
std::make_shared<H2C2ComponentStore>(nullptr));
- hidlVer = "1.0";
+ hidlVer = "1.2";
}
- if (hidlStore->registerAsService("software") != android::OK) {
+ if (hidlStore->registerAsService("software") == android::OK) {
+ registered = true;
+ } else {
LOG(ERROR) << "Cannot register software Codec2 v" << hidlVer << " service.";
- return;
}
- LOG(INFO) << "Software Codec2 service created and registered.";
+ if (registered) {
+ LOG(INFO) << "Software Codec2 service created and registered.";
+ }
ABinderProcess_joinThreadPool();
::android::hardware::joinRpcThreadpool();
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 0a8d2ab..d096d63 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -189,6 +189,8 @@
],
dictionary: "mkv_extractor_fuzzer.dict",
+
+ corpus: ["corpus/*"],
}
cc_fuzz {
diff --git a/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
new file mode 100755
index 0000000..8b31683
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/103c24dec0f5da3638a771e451cecfe38339b29c
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
new file mode 100755
index 0000000..f4d475d
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/2e532f8eb60e1c757f4399377e8f563a3cf3abf2e
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3 b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
new file mode 100755
index 0000000..8438e66
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/45e6a4014883a7e1f1200e2a53eabb4f0109aec3
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69 b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
new file mode 100755
index 0000000..2f622cd
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/465b39984b71d8b4c2b80072993fb7ec73b4af69
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600 b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
new file mode 100755
index 0000000..f053c01
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/4ef9546eab199719aadead2d26d3c1d72f42e600
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65 b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
new file mode 100755
index 0000000..872451c
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/6b35d5a3af88baf240293ff1b8adf0b774055e65
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8 b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
new file mode 100755
index 0000000..2f7e3ea
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/7e798d68a1bf154e079227ee43e69ea27844b7e8
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687 b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
new file mode 100755
index 0000000..10b5f9a
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d2fd225343c99872f5a825f7f06b8c1dac0e8687
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620 b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
new file mode 100755
index 0000000..969b7a2
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/d5602e69abf068ed8f1277e412149b8664d06620
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498 b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
new file mode 100755
index 0000000..bd146b1
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/e73fa90346e7287b7e923b0ebf07ce8988d94498
Binary files differ
diff --git a/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
new file mode 100755
index 0000000..7cf844e
--- /dev/null
+++ b/media/module/extractors/fuzzers/corpus/f1ee160337d3a467402a2217897477f0fab15da
Binary files differ
diff --git a/media/module/extractors/mp4/ItemTable.cpp b/media/module/extractors/mp4/ItemTable.cpp
index cf3df62..c6586fc 100644
--- a/media/module/extractors/mp4/ItemTable.cpp
+++ b/media/module/extractors/mp4/ItemTable.cpp
@@ -1501,9 +1501,9 @@
info.isExif(), (long long)offset, (long long)size);
if ((info.isExif() && size > 4) || (info.isXmp() && size > 0)) {
ExternalMetaItem metaItem = {
- .isExif = info.isExif(),
.offset = offset,
.size = size,
+ .isExif = info.isExif(),
};
mItemIdToMetaMap.add(info.itemId, metaItem);
}
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index 559927a..b3707c8 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -522,7 +522,7 @@
return AMEDIA_ERROR_UNKNOWN;
}
- [=] {
+ [this, &track] {
int64_t duration;
int32_t samplerate;
// Only for audio track.
diff --git a/media/module/extractors/wav/WAVExtractor.cpp b/media/module/extractors/wav/WAVExtractor.cpp
index 9c3bac6..d278103 100644
--- a/media/module/extractors/wav/WAVExtractor.cpp
+++ b/media/module/extractors/wav/WAVExtractor.cpp
@@ -219,7 +219,7 @@
mNumChannels = U16_LE_AT(&formatSpec[2]);
- if (mNumChannels < 1 || mNumChannels > FCC_8) {
+ if (mNumChannels < 1 || mNumChannels > FCC_12) {
ALOGE("Unsupported number of channels (%d)", mNumChannels);
return AMEDIA_ERROR_UNSUPPORTED;
}
diff --git a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
index c3a0ced..f8906dc 100644
--- a/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
+++ b/media/module/libmediatranscoding/transcoder/tests/AndroidTestTemplate.xml
@@ -15,6 +15,7 @@
-->
<configuration description="Unit test configuration for {MODULE}">
<option name="test-suite-tag" value="TranscoderTests" />
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer" />
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="false" />
<option name="push-file" key="TranscodingTestAssets" value="/data/local/tmp/TranscodingTestAssets" />
diff --git a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
index 88c3fd3..fed8fc9 100644
--- a/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
+++ b/media/module/libmediatranscoding/transcoder/tests/VideoTrackTranscoderTests.cpp
@@ -20,6 +20,7 @@
#define LOG_TAG "VideoTrackTranscoderTests"
#include <android-base/logging.h>
+#include <android/binder_process.h>
#include <fcntl.h>
#include <gtest/gtest.h>
#include <media/MediaSampleReaderNDK.h>
@@ -221,5 +222,6 @@
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
+ ABinderProcess_startThreadPool();
return RUN_ALL_TESTS();
}
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 42e9078..a2b1c5e 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -427,6 +427,9 @@
}
void MtpDataPacket::putString(const uint16_t* string) {
+ if (string == NULL) {
+ return;
+ }
int count = 0;
for (int i = 0; i <= MTP_STRING_MAX_CHARACTER_NUMBER; i++) {
if (string[i])
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
index 111485c..aa632a4 100644
--- a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -45,18 +45,18 @@
pkt.size());
// packet is bigger than what the caller can handle,
- if (pkt.size() > len) {
+ if (pkt.size() - mPacketOffset > len) {
memcpy(data, pkt.data() + mPacketOffset, len);
mPacketOffset += len;
readAmt = len;
// packet is equal or smaller than the caller buffer
} else {
- memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size() - mPacketOffset);
mPacketNumber++;
mPacketOffset = 0;
- readAmt = pkt.size();
+ readAmt = pkt.size() - mPacketOffset;
}
return readAmt;
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 8b9dde3..9ec7700 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -208,19 +208,21 @@
}
cc_test {
- name: "AImageReaderWindowHandleTest",
+ name: "AImageReaderWindowTest",
test_suites: ["device-tests"],
- srcs: ["tests/AImageReaderWindowHandleTest.cpp"],
+ srcs: ["tests/AImageReaderWindowTest.cpp"],
shared_libs: [
"libbinder",
"libmediandk",
"libmediautils",
"libnativewindow",
"libgui",
+ "libhidlbase",
"libutils",
"libui",
"libcutils",
"android.hardware.graphics.bufferqueue@1.0",
+ "android.hidl.token@1.0",
],
header_libs: [
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 161b5e3..a26681e 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -428,6 +428,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_HDR10_PLUS_INFO = "hdr10-plus-info";
EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
EXPORT const char* AMEDIAFORMAT_KEY_ICC_PROFILE = "icc-profile";
+EXPORT const char* AMEDIAFORMAT_KEY_IMPORTANCE = "importance";
EXPORT const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD = "intra-refresh-period";
EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
@@ -449,6 +450,10 @@
EXPORT const char* AMEDIAFORMAT_KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE =
+ "buffer-batch-max-output-size";
+EXPORT const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE =
+ "buffer-batch-threshold-output-size";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_PTS_GAP_TO_ENCODER = "max-pts-gap-to-encoder";
EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
diff --git a/media/ndk/TEST_MAPPING b/media/ndk/TEST_MAPPING
index e420812..1a15728 100644
--- a/media/ndk/TEST_MAPPING
+++ b/media/ndk/TEST_MAPPING
@@ -1,7 +1,7 @@
// mappings for frameworks/av/media/ndk
{
"presubmit": [
- { "name": "AImageReaderWindowHandleTest" },
+ { "name": "AImageReaderWindowTest" },
{ "name": "libmediandk_test" }
]
}
diff --git a/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp b/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
index 304879d..e6c1338 100644
--- a/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
+++ b/media/ndk/fuzzer/ndk_crypto_fuzzer.cpp
@@ -18,6 +18,8 @@
#include <media/NdkMediaCrypto.h>
#include <functional>
+#include <functional>
+
constexpr size_t kMaxString = 256;
constexpr size_t kMinBytes = 0;
constexpr size_t kMaxBytes = 1000;
diff --git a/media/ndk/include/media/NdkImageReader.h b/media/ndk/include/media/NdkImageReader.h
index b722b74..4fc9918 100644
--- a/media/ndk/include/media/NdkImageReader.h
+++ b/media/ndk/include/media/NdkImageReader.h
@@ -534,7 +534,8 @@
* Get the native_handle_t corresponding to the ANativeWindow owned by the
* AImageReader provided.
*
- * This is deprecated in API level 35 and will return AMEDIA_ERROR_UNKNOWN.
+ * This is deprecated on devices with vendor API level greater than 34 and
+ * will return AMEDIA_ERROR_UNKNOWN on those devices.
* The native_handle_t is no longer used with AIDL interfaces and
* ANativeWindow is used directly instead.
* Use AImageRead_getWindow to get the ANativeWindow and use that object.
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index b2cdf8d..cc1dd9f 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -168,6 +168,7 @@
extern const char* AMEDIAFORMAT_KEY_GRID_ROWS __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HDR_STATIC_INFO __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_HEIGHT __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_IMPORTANCE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_INTRA_REFRESH_PERIOD __INTRODUCED_IN(28);
extern const char* AMEDIAFORMAT_KEY_IS_ADTS __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT __INTRODUCED_IN(21);
@@ -186,6 +187,8 @@
extern const char* AMEDIAFORMAT_KEY_MAX_B_FRAMES __INTRODUCED_IN(34);
extern const char* AMEDIAFORMAT_KEY_MAX_HEIGHT __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE __INTRODUCED_IN(21);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE __INTRODUCED_IN(35);
+extern const char* AMEDIAFORMAT_KEY_BUFFER_BATCH_THRESHOLD_OUTPUT_SIZE __INTRODUCED_IN(35);
extern const char* AMEDIAFORMAT_KEY_MAX_WIDTH __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MIME __INTRODUCED_IN(21);
extern const char* AMEDIAFORMAT_KEY_MPEG_USER_DATA __INTRODUCED_IN(28);
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 4f045fd..262c169 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -185,11 +185,11 @@
AMediaCodecCryptoInfo_setPattern; # introduced=24
AMediaCodec_configure;
AMediaCodec_createCodecByName;
- AMediaCodec_createCodecByNameForClient; # systemapi # introduced=31
+ AMediaCodec_createCodecByNameForClient; # systemapi introduced=31
AMediaCodec_createDecoderByType;
- AMediaCodec_createDecoderByTypeForClient; # systemapi # introduced=31
+ AMediaCodec_createDecoderByTypeForClient; # systemapi introduced=31
AMediaCodec_createEncoderByType;
- AMediaCodec_createEncoderByTypeForClient; # systemapi # introduced=31
+ AMediaCodec_createEncoderByTypeForClient; # systemapi introduced=31
AMediaCodec_delete;
AMediaCodec_dequeueInputBuffer;
AMediaCodec_dequeueOutputBuffer;
diff --git a/media/ndk/tests/AImageReaderWindowHandleTest.cpp b/media/ndk/tests/AImageReaderWindowHandleTest.cpp
deleted file mode 100644
index 27864c2..0000000
--- a/media/ndk/tests/AImageReaderWindowHandleTest.cpp
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * Copyright 2018 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 <gtest/gtest.h>
-#include <media/NdkImageReader.h>
-#include <media/NdkImage.h>
-#include <mediautils/AImageReaderUtils.h>
-#include <gui/IGraphicBufferProducer.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-#include <NdkImagePriv.h>
-#include <NdkImageReaderPriv.h>
-#include <vndk/hardware_buffer.h>
-#include <memory>
-
-namespace android {
-
-using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
- IGraphicBufferProducer;
-using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
-using aimg::AImageReader_getHGBPFromHandle;
-
-typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
-typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
-
-static constexpr uint64_t kImageBufferUsage =
- AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
-static constexpr int kImageWidth = 640;
-static constexpr int kImageHeight = 480;
-static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
-static constexpr int kMaxImages = 1;
-
-static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
-static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
-static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
-static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
-static constexpr int kQueueBufferInputScalingMode = 0;
-static constexpr int kQueueBufferInputTransform = 0;
-static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
-
-static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
-
-class AImageReaderWindowHandleTest : public ::testing::Test {
- public:
- void SetUp() override {
- AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
- kImageBufferUsage , kMaxImages, &imageReader_);
- media_status_t ret = AMEDIA_ERROR_UNKNOWN;
- ASSERT_NE(imageReader_, nullptr);
- ret = AImageReader_setImageListener(imageReader_,
- &imageReaderAvailableCb_);
- ASSERT_EQ(ret, AMEDIA_OK);
- ret = AImageReader_setBufferRemovedListener(imageReader_,
- &imageReaderDetachedCb_);
- ASSERT_EQ(ret, AMEDIA_OK);
- }
- void TearDown() override {
- if (imageReader_) {
- AImageReader_delete(imageReader_);
- }
- }
-
- void HandleImageAvailable() {
- AImage *outImage = nullptr;
- media_status_t ret = AMEDIA_OK;
- auto imageDeleter = [](AImage *img) { AImage_delete(img); };
- std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
-
- // Test that the image can be acquired.
- ret = AImageReader_acquireNextImage(imageReader_, &outImage);
- ASSERT_EQ(ret, AMEDIA_OK);
- img.reset(outImage);
- ASSERT_NE(img, nullptr);
-
- // Test that we can get a handle to the image's hardware buffer and a
- // native handle to it.
- AHardwareBuffer *hardwareBuffer = nullptr;
- ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
- ASSERT_EQ(ret, AMEDIA_OK);
- ASSERT_NE(hardwareBuffer, nullptr);
- const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
- ASSERT_NE(nh, nullptr);
- std::unique_lock<std::mutex> lock(imageAvailableMutex_);
- imageAvailable_ = true;
- imageCondVar_.notify_one();
- }
-
- static void onImageAvailable(void *context, AImageReader *reader) {
- (void)reader;
- AImageReaderWindowHandleTest *thisContext =
- reinterpret_cast<AImageReaderWindowHandleTest *>(context);
- thisContext->HandleImageAvailable();
- }
-
- static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
- }
-
- AImageReader *imageReader_ = nullptr;
- AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
- AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
- std::mutex imageAvailableMutex_;
- std::condition_variable imageCondVar_;
- bool imageAvailable_ = false;
-};
-
-static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
- const size_t PIXEL_SIZE = 4;
- for (int x = 0; x < w; x++) {
- for (int y = 0; y < h; y++) {
- off_t offset = (y * stride + x) * PIXEL_SIZE;
- for (int c = 0; c < 4; c++) {
- int parityX = (x / (1 << (c+2))) & 1;
- int parityY = (y / (1 << (c+2))) & 1;
- buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
- }
- }
- }
-}
-
-TEST_F(AImageReaderWindowHandleTest, CreateWindowNativeHandle) {
- // Check that we can create a native_handle_t corresponding to the
- // AImageReader.
- native_handle_t *nh = nullptr;
- AImageReader_getWindowNativeHandle(imageReader_, &nh);
- ASSERT_NE(nh, nullptr);
-
- // Check that there are only ints in the handle.
- ASSERT_EQ(nh->numFds, 0);
- ASSERT_NE(nh->numInts, 0);
-
- // Check that the HGBP can be retrieved from the handle.
- sp<HGraphicBufferProducer> hgbp = AImageReader_getHGBPFromHandle(nh);
- ASSERT_NE(hgbp, nullptr);
- sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
- int dequeuedSlot = -1;
- sp<Fence> dequeuedFence;
- IGraphicBufferProducer::QueueBufferOutput output;
- ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
-
- // Test that we can dequeue a buffer.
- ASSERT_EQ(OK,
- ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
- (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
- kImageWidth, kImageHeight,
- kImageFormat, kImageBufferUsage,
- nullptr, nullptr)));
- EXPECT_LE(0, dequeuedSlot);
- EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
-
- sp<GraphicBuffer> dequeuedBuffer;
- igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
- uint8_t* img = nullptr;
- ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
-
- // Write in some dummy image data.
- fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
- dequeuedBuffer->getStride());
- ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
- QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
- kQueueBufferInputIsAutoTimeStamp,
- kQueueBufferInputDataspace,
- kQueueBufferInputRect,
- kQueueBufferInputScalingMode,
- kQueueBufferInputTransform,
- kQueueBufferInputFence);
- QueueBufferOutput queueBufferOutput;
- ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
- &queueBufferOutput));
- // wait until the onImageAvailable callback is called, or timeout completes.
- std::unique_lock<std::mutex> lock(imageAvailableMutex_);
- imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
- [this]{ return this->imageAvailable_;});
- EXPECT_TRUE(imageAvailable_) << "Timed out waiting for image data to be handled!\n";
-}
-
-class AImageReaderPrivateFormatTest : public ::testing::Test {
- public:
- void SetUp() override {
- auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
- kMaxImages, &imgReader);
- EXPECT_TRUE(status == AMEDIA_OK);
- }
-
- void TearDown() override {
- if (imgReader) {
- AImageReader_delete(imgReader);
- }
- }
- AImageReader *imgReader = nullptr;
-};
-
-TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
- EXPECT_TRUE(imgReader != nullptr);
-}
-
-
-} // namespace android
diff --git a/media/ndk/tests/AImageReaderWindowTest.cpp b/media/ndk/tests/AImageReaderWindowTest.cpp
new file mode 100644
index 0000000..650b990
--- /dev/null
+++ b/media/ndk/tests/AImageReaderWindowTest.cpp
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2018 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 <android/hidl/token/1.0/ITokenManager.h>
+#include <android/hidl/manager/1.2/IServiceManager.h>
+#include <gtest/gtest.h>
+#include <hidl/ServiceManagement.h>
+#include <media/NdkImageReader.h>
+#include <media/NdkImage.h>
+#include <mediautils/AImageReaderUtils.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/Surface.h>
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <NdkImagePriv.h>
+#include <NdkImageReaderPriv.h>
+#include <vndk/hardware_buffer.h>
+#include <memory>
+
+namespace android {
+
+using HGraphicBufferProducer = hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer;
+using hardware::graphics::bufferqueue::V1_0::utils::H2BGraphicBufferProducer;
+using hidl::manager::V1_2::IServiceManager;
+using hidl::token::V1_0::ITokenManager;
+using aimg::AImageReader_getHGBPFromHandle;
+
+typedef IGraphicBufferProducer::QueueBufferInput QueueBufferInput;
+typedef IGraphicBufferProducer::QueueBufferOutput QueueBufferOutput;
+
+static constexpr uint64_t kImageBufferUsage =
+ AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+static constexpr int kImageWidth = 640;
+static constexpr int kImageHeight = 480;
+static constexpr int kImageFormat = AIMAGE_FORMAT_RGBA_8888;
+static constexpr int kMaxImages = 1;
+
+static constexpr int64_t kQueueBufferInputTimeStamp = 1384888611;
+static constexpr bool kQueueBufferInputIsAutoTimeStamp = false;
+static constexpr android_dataspace kQueueBufferInputDataspace = HAL_DATASPACE_UNKNOWN;
+static const Rect kQueueBufferInputRect = Rect(kImageWidth, kImageHeight);
+static constexpr int kQueueBufferInputScalingMode = 0;
+static constexpr int kQueueBufferInputTransform = 0;
+static const sp<Fence> kQueueBufferInputFence = Fence::NO_FENCE;
+
+static constexpr int kOnImageAvailableWaitUs = 100 * 1000;
+
+class AImageReaderWindowTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ AImageReader_newWithUsage(kImageWidth, kImageHeight, kImageFormat,
+ kImageBufferUsage , kMaxImages, &imageReader_);
+ media_status_t ret = AMEDIA_ERROR_UNKNOWN;
+ ASSERT_NE(imageReader_, nullptr);
+ ret = AImageReader_setImageListener(imageReader_,
+ &imageReaderAvailableCb_);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ ret = AImageReader_setBufferRemovedListener(imageReader_,
+ &imageReaderDetachedCb_);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ }
+ void TearDown() override {
+ if (imageReader_) {
+ AImageReader_delete(imageReader_);
+ }
+ }
+
+ void HandleImageAvailable() {
+ AImage *outImage = nullptr;
+ media_status_t ret = AMEDIA_OK;
+ auto imageDeleter = [](AImage *img) { AImage_delete(img); };
+ std::unique_ptr<AImage, decltype(imageDeleter)> img(nullptr, imageDeleter);
+
+ // Test that the image can be acquired.
+ ret = AImageReader_acquireNextImage(imageReader_, &outImage);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ img.reset(outImage);
+ ASSERT_NE(img, nullptr);
+
+ // Test that we can get a handle to the image's hardware buffer and a
+ // native handle to it.
+ AHardwareBuffer *hardwareBuffer = nullptr;
+ ret = AImage_getHardwareBuffer(img.get(), &hardwareBuffer);
+ ASSERT_EQ(ret, AMEDIA_OK);
+ ASSERT_NE(hardwareBuffer, nullptr);
+ const native_handle_t *nh = AHardwareBuffer_getNativeHandle(hardwareBuffer);
+ ASSERT_NE(nh, nullptr);
+ std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+ imageAvailable_ = true;
+ imageCondVar_.notify_one();
+ }
+
+ static void onImageAvailable(void *context, AImageReader *reader) {
+ (void)reader;
+ AImageReaderWindowTest *thisContext =
+ reinterpret_cast<AImageReaderWindowTest *>(context);
+ thisContext->HandleImageAvailable();
+ }
+
+ static void onBufferRemoved(void *, AImageReader *, AHardwareBuffer *) {
+ }
+
+ static void fillRGBA8Buffer(uint8_t* buf, int w, int h, int stride) {
+ const size_t PIXEL_SIZE = 4;
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ off_t offset = (y * stride + x) * PIXEL_SIZE;
+ for (int c = 0; c < 4; c++) {
+ int parityX = (x / (1 << (c+2))) & 1;
+ int parityY = (y / (1 << (c+2))) & 1;
+ buf[offset + c] = (parityX ^ parityY) ? 231 : 35;
+ }
+ }
+ }
+ }
+
+ void validateIGBP(sp<IGraphicBufferProducer>& igbp) {
+ int dequeuedSlot = -1;
+ sp<Fence> dequeuedFence;
+ IGraphicBufferProducer::QueueBufferOutput output;
+ ASSERT_EQ(OK, igbp->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
+
+ // Test that we can dequeue a buffer.
+ ASSERT_EQ(OK,
+ ~IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION &
+ (igbp->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+ kImageWidth, kImageHeight,
+ kImageFormat, kImageBufferUsage,
+ nullptr, nullptr)));
+ EXPECT_LE(0, dequeuedSlot);
+ EXPECT_GT(BufferQueue::NUM_BUFFER_SLOTS, dequeuedSlot);
+
+ sp<GraphicBuffer> dequeuedBuffer;
+ igbp->requestBuffer(dequeuedSlot, &dequeuedBuffer);
+ uint8_t* img = nullptr;
+ ASSERT_EQ(NO_ERROR, dequeuedBuffer->lock(kImageBufferUsage, (void**)(&img)));
+
+ // Write in some placeholder image data.
+ fillRGBA8Buffer(img, dequeuedBuffer->getWidth(), dequeuedBuffer->getHeight(),
+ dequeuedBuffer->getStride());
+ ASSERT_EQ(NO_ERROR, dequeuedBuffer->unlock());
+ QueueBufferInput queueBufferInput(kQueueBufferInputTimeStamp,
+ kQueueBufferInputIsAutoTimeStamp,
+ kQueueBufferInputDataspace,
+ kQueueBufferInputRect,
+ kQueueBufferInputScalingMode,
+ kQueueBufferInputTransform,
+ kQueueBufferInputFence);
+ QueueBufferOutput queueBufferOutput;
+ ASSERT_EQ(OK, igbp->queueBuffer(dequeuedSlot, queueBufferInput,
+ &queueBufferOutput));
+ // wait until the onImageAvailable callback is called, or timeout completes.
+ std::unique_lock<std::mutex> lock(imageAvailableMutex_);
+ imageCondVar_.wait_for(lock, std::chrono::microseconds(kOnImageAvailableWaitUs),
+ [this]{ return this->imageAvailable_;});
+ EXPECT_TRUE(imageAvailable_) << "Timed out waiting for image data to be handled!\n";
+ }
+
+ AImageReader *imageReader_ = nullptr;
+ AImageReader_ImageListener imageReaderAvailableCb_{this, onImageAvailable};
+ AImageReader_BufferRemovedListener imageReaderDetachedCb_{this, onBufferRemoved};
+ std::mutex imageAvailableMutex_;
+ std::condition_variable imageCondVar_;
+ bool imageAvailable_ = false;
+};
+
+
+TEST_F(AImageReaderWindowTest, CreateWindowNativeHandle) {
+ // Check that we can create a native_handle_t corresponding to the
+ // AImageReader.
+ native_handle_t *nh = nullptr;
+ media_status_t status = AImageReader_getWindowNativeHandle(imageReader_, &nh);
+
+ // On newer devices without the HIDL TokenManager service this API is
+ // deprecated and will return an error.
+ if (IServiceManager::Transport::EMPTY ==
+ hardware::defaultServiceManager1_2()->getTransport(ITokenManager::descriptor, "default")) {
+ EXPECT_EQ(status, AMEDIA_ERROR_UNKNOWN);
+ return;
+ }
+ ASSERT_NE(nh, nullptr);
+
+ // Check that there are only ints in the handle.
+ ASSERT_EQ(nh->numFds, 0);
+ ASSERT_NE(nh->numInts, 0);
+
+ // Check that the HGBP can be retrieved from the handle.
+ sp<HGraphicBufferProducer> hgbp = AImageReader_getHGBPFromHandle(nh);
+ ASSERT_NE(hgbp, nullptr);
+ sp<IGraphicBufferProducer> igbp = new H2BGraphicBufferProducer(hgbp);
+
+ validateIGBP(igbp);
+}
+
+TEST_F(AImageReaderWindowTest, CreateWindow) {
+ ANativeWindow* window = nullptr;
+ media_status_t status = AImageReader_getWindow(imageReader_, &window);
+
+ ASSERT_NE(window, nullptr);
+
+ sp<IGraphicBufferProducer> igbp = Surface::getIGraphicBufferProducer(window);
+
+ validateIGBP(igbp);
+}
+
+class AImageReaderPrivateFormatTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ auto status = AImageReader_new(kImageWidth, kImageHeight, AIMAGE_FORMAT_RAW_DEPTH,
+ kMaxImages, &imgReader);
+ EXPECT_TRUE(status == AMEDIA_OK);
+ }
+
+ void TearDown() override {
+ if (imgReader) {
+ AImageReader_delete(imgReader);
+ }
+ }
+ AImageReader *imgReader = nullptr;
+};
+
+TEST_F(AImageReaderPrivateFormatTest, CreateTest) {
+ EXPECT_TRUE(imgReader != nullptr);
+}
+
+
+} // namespace android
diff --git a/media/utils/MethodStatistics.cpp b/media/utils/MethodStatistics.cpp
index 086757b..80f0fc4 100644
--- a/media/utils/MethodStatistics.cpp
+++ b/media/utils/MethodStatistics.cpp
@@ -20,6 +20,8 @@
// Repository for MethodStatistics Objects
+// It's important to have the HAL class name defined with suffix "Hidl/Aidl" because
+// TimerThread::isRequestFromHal use this string to match binder call to/from hal.
std::shared_ptr<std::vector<std::string>>
getStatisticsClassesForModule(std::string_view moduleName) {
static const std::map<std::string, std::shared_ptr<std::vector<std::string>>,
@@ -34,6 +36,15 @@
"StreamOutHalHidl",
})
},
+ {
+ METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL,
+ std::shared_ptr<std::vector<std::string>>(
+ new std::vector<std::string>{
+ "DeviceHalAidl",
+ "EffectHalAidl",
+ "StreamHalAidl",
+ })
+ },
};
auto it = m.find(moduleName);
if (it == m.end()) return {};
@@ -61,6 +72,9 @@
addClassesToMap(
getStatisticsClassesForModule(METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL),
m);
+ addClassesToMap(
+ getStatisticsClassesForModule(METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL),
+ m);
return m;
}();
diff --git a/media/utils/TimerThread.cpp b/media/utils/TimerThread.cpp
index ad27af3..1c94691 100644
--- a/media/utils/TimerThread.cpp
+++ b/media/utils/TimerThread.cpp
@@ -129,11 +129,16 @@
//
/* static */
bool TimerThread::isRequestFromHal(const std::shared_ptr<const Request>& request) {
- const size_t hidlPos = request->tag.asStringView().find("Hidl");
- if (hidlPos == std::string::npos) return false;
- // should be a separator afterwards Hidl which indicates the string was in the class.
- const size_t separatorPos = request->tag.asStringView().find("::", hidlPos);
- return separatorPos != std::string::npos;
+ for (const auto& s : {"Hidl", "Aidl"}) {
+ const auto& tagSV = request->tag.asStringView();
+ const size_t halStrPos = tagSV.find(s);
+ // should be a separator afterwards Hidl/Aidl which indicates the string was in the class.
+ if (halStrPos != std::string::npos && tagSV.find("::", halStrPos) != std::string::npos) {
+ return true;
+ }
+ }
+
+ return false;
}
struct TimerThread::SnapshotAnalysis TimerThread::getSnapshotAnalysis(size_t retiredCount) const {
diff --git a/media/utils/include/mediautils/MethodStatistics.h b/media/utils/include/mediautils/MethodStatistics.h
index c8b36d8..2543dfa 100644
--- a/media/utils/include/mediautils/MethodStatistics.h
+++ b/media/utils/include/mediautils/MethodStatistics.h
@@ -124,6 +124,7 @@
// Managed Statistics support.
// Supported Modules
#define METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL "AudioHidl"
+#define METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL "AudioAidl"
// Returns a vector of class names for the module, or a nullptr if module not found.
std::shared_ptr<std::vector<std::string>>
diff --git a/media/utils/include/mediautils/StaticStringView.h b/media/utils/include/mediautils/StaticStringView.h
index 14be240..e9a5deb 100644
--- a/media/utils/include/mediautils/StaticStringView.h
+++ b/media/utils/include/mediautils/StaticStringView.h
@@ -21,15 +21,15 @@
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_OPERATOR")
#undef EXPLICIT_CONVERSION_GENERATE_OPERATOR
-#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
- friend constexpr bool operator op(T lhs, T rhs) { \
- return operator op(static_cast<U>(lhs), static_cast<U>(rhs)); \
- } \
- friend constexpr bool operator op(T lhs, U rhs) { \
- return operator op(static_cast<U>(lhs), rhs); \
- } \
- friend constexpr bool operator op(U lhs, T rhs) { \
- return operator op(lhs, static_cast<U>(rhs)); \
+#define EXPLICIT_CONVERSION_GENERATE_OPERATOR(T, U, op) \
+ friend constexpr bool operator op(T lhs, T rhs) { \
+ return static_cast<U>(lhs) op static_cast<U>(rhs); \
+ } \
+ friend constexpr bool operator op(T lhs, U rhs) { \
+ return static_cast<U>(lhs) op rhs; \
+ } \
+ friend constexpr bool operator op(U lhs, T rhs) { \
+ return lhs op static_cast<U>(rhs); \
}
#pragma push_macro("EXPLICIT_CONVERSION_GENERATE_COMPARISON_OPERATORS")
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index afd28e5..129541f 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -145,6 +145,7 @@
"audioflinger-aidl-cpp",
"audioclient-types-aidl-cpp",
"av-types-aidl-cpp",
+ "com.android.media.audio-aconfig-cc",
"effect-aidl-cpp",
"libaudioclient_aidl_conversion",
"libactivitymanager_aidl",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index b87b373..aafe3cd 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -31,6 +31,7 @@
#include <afutils/Permission.h>
#include <afutils/PropertyUtils.h>
#include <afutils/TypedLogger.h>
+#include <android-base/errors.h>
#include <android-base/stringprintf.h>
#include <android/media/IAudioPolicyService.h>
#include <audiomanager/IAudioManager.h>
@@ -38,6 +39,7 @@
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <cutils/properties.h>
+#include <com_android_media_audioserver.h>
#include <media/AidlConversion.h>
#include <media/AudioParameter.h>
#include <media/AudioValidator.h>
@@ -210,6 +212,20 @@
return methodStatistics;
}
+namespace base {
+template <typename T>
+struct OkOrFail<std::optional<T>> {
+ using opt_t = std::optional<T>;
+ OkOrFail() = delete;
+ OkOrFail(const opt_t&) = delete;
+
+ static bool IsOk(const opt_t& opt) { return opt.has_value(); }
+ static T Unwrap(opt_t&& opt) { return std::move(opt.value()); }
+ static std::string ErrorMessage(const opt_t&) { return "Empty optional"; }
+ static void Fail(opt_t&&) {}
+};
+}
+
class DevicesFactoryHalCallbackImpl : public DevicesFactoryHalCallback {
public:
void onNewDevicesAvailable() override {
@@ -270,9 +286,6 @@
BatteryNotifier::getInstance().noteResetAudio();
mMediaLogNotifier->run("MediaLogNotifier");
- std::vector<pid_t> halPids;
- mDevicesFactoryHal->getHalPids(&halPids);
- mediautils::TimeCheck::setAudioHalPids(halPids);
// Notify that we have started (also called when audioserver service restarts)
mediametrics::LogItem(mMetricsId)
@@ -859,12 +872,15 @@
dprintf(fd, "\nIEffect binder call profile:\n");
write(fd, timeCheckStats.c_str(), timeCheckStats.size());
- // Automatically fetch HIDL statistics.
- std::shared_ptr<std::vector<std::string>> hidlClassNames =
- mediautils::getStatisticsClassesForModule(
- METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL);
- if (hidlClassNames) {
- for (const auto& className : *hidlClassNames) {
+ // Automatically fetch HIDL or AIDL statistics.
+ const std::string_view halType = (mDevicesFactoryHal->getHalVersion().getType() ==
+ AudioHalVersionInfo::Type::HIDL)
+ ? METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL
+ : METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL;
+ const std::shared_ptr<std::vector<std::string>> halClassNames =
+ mediautils::getStatisticsClassesForModule(halType);
+ if (halClassNames) {
+ for (const auto& className : *halClassNames) {
auto stats = mediautils::getStatisticsForClass(className);
if (stats) {
timeCheckStats = stats->dump();
@@ -3206,41 +3222,19 @@
return 0;
}
- audio_config_t halconfig = *config;
- sp<DeviceHalInterface> inHwHal = inHwDev->hwDevice();
- sp<StreamInHalInterface> inStream;
- status_t status = inHwHal->openInputStream(
- *input, devices, &halconfig, flags, address, source,
- outputDevice, outputDeviceAddress, &inStream);
- ALOGV("openInput_l() openInputStream returned input %p, devices %#x, SamplingRate %d"
- ", Format %#x, Channels %#x, flags %#x, status %d addr %s",
- inStream.get(),
+ AudioStreamIn *inputStream = nullptr;
+ status_t status = inHwDev->openInputStream(
+ &inputStream,
+ *input,
devices,
- halconfig.sample_rate,
- halconfig.format,
- halconfig.channel_mask,
flags,
- status, address);
+ config,
+ address,
+ source,
+ outputDevice,
+ outputDeviceAddress.c_str());
- // If the input could not be opened with the requested parameters and we can handle the
- // conversion internally, try to open again with the proposed parameters.
- if (status == BAD_VALUE &&
- audio_is_linear_pcm(config->format) &&
- audio_is_linear_pcm(halconfig.format) &&
- (halconfig.sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) &&
- (audio_channel_count_from_in_mask(halconfig.channel_mask) <= FCC_LIMIT) &&
- (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_LIMIT)) {
- // FIXME describe the change proposed by HAL (save old values so we can log them here)
- ALOGV("openInput_l() reopening with proposed sampling rate and channel mask");
- inStream.clear();
- status = inHwHal->openInputStream(
- *input, devices, &halconfig, flags, address, source,
- outputDevice, outputDeviceAddress, &inStream);
- // FIXME log this new status; HAL should not propose any further changes
- }
-
- if (status == NO_ERROR && inStream != 0) {
- AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
+ if (status == NO_ERROR) {
if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0) {
const sp<IAfMmapCaptureThread> thread =
IAfMmapCaptureThread::create(this, *input, inHwDev, inputStream, mSystemReady);
@@ -3597,11 +3591,20 @@
void AudioFlinger::dumpToThreadLog_l(const sp<IAfThreadBase> &thread)
{
constexpr int THREAD_DUMP_TIMEOUT_MS = 2;
- audio_utils::FdToStringOldImpl fdToString("- ", THREAD_DUMP_TIMEOUT_MS);
- const int fd = fdToString.borrowFdUnsafe();
- if (fd >= 0) {
- thread->dump(fd, {} /* args */);
- mThreadLog.logs(-1 /* time */, fdToString.closeAndGetString());
+ constexpr auto PREFIX = "- ";
+ if (com::android::media::audioserver::fdtostring_timeout_fix()) {
+ using ::android::audio_utils::FdToString;
+
+ auto writer = OR_RETURN(FdToString::createWriter(PREFIX));
+ thread->dump(writer.borrowFdUnsafe(), {} /* args */);
+ mThreadLog.logs(-1 /* time */, FdToString::closeWriterAndGetString(std::move(writer)));
+ } else {
+ audio_utils::FdToStringOldImpl fdToString("- ", THREAD_DUMP_TIMEOUT_MS);
+ const int fd = fdToString.borrowFdUnsafe();
+ if (fd >= 0) {
+ thread->dump(fd, {} /* args */);
+ mThreadLog.logs(-1 /* time */, fdToString.closeAndGetString());
+ }
}
}
@@ -4141,7 +4144,7 @@
}
// Only audio policy service can create a spatializer effect
- if ((memcmp(&descOut.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0) &&
+ if (IAfEffectModule::isSpatializer(&descOut.type) &&
(callingUid != AID_AUDIOSERVER || currentPid != getpid())) {
ALOGW("%s: attempt to create a spatializer effect from uid/pid %d/%d",
__func__, callingUid, currentPid);
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 73a89e5..3147433 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -1528,6 +1528,15 @@
return IAfEffectModule::isHapticGenerator(&mDescriptor.type);
}
+/*static*/
+bool IAfEffectModule::isSpatializer(const effect_uuid_t *type) {
+ return memcmp(type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0;
+}
+
+bool EffectModule::isSpatializer() const {
+ return IAfEffectModule::isSpatializer(&mDescriptor.type);
+}
+
status_t EffectModule::setHapticIntensity(int id, os::HapticScale intensity)
{
if (mStatus != NO_ERROR) {
@@ -1600,6 +1609,35 @@
return NO_ERROR;
}
+status_t EffectModule::sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) {
+ if (mStatus != NO_ERROR) {
+ return mStatus;
+ }
+ // TODO b/307368176: send all metadata to effects if requested by the implementation.
+ // For now only send channel mask to Spatializer.
+ if (!isSpatializer()) {
+ return INVALID_OPERATION;
+ }
+
+ std::vector<uint8_t> request(
+ sizeof(effect_param_t) + sizeof(int32_t) + metadata.size() * sizeof(uint32_t));
+ effect_param_t *param = (effect_param_t*) request.data();
+ param->psize = sizeof(int32_t);
+ param->vsize = metadata.size() * sizeof(uint32_t);
+ *(int32_t*)param->data = SPATIALIZER_PARAM_INPUT_CHANNEL_MASK;
+ uint32_t* channelMasks = reinterpret_cast<uint32_t*>(param->data + sizeof(int32_t));
+ for (auto m : metadata) {
+ *channelMasks++ = m.channel_mask;
+ }
+ std::vector<uint8_t> response;
+ status_t status = command(EFFECT_CMD_SET_PARAM, request, sizeof(int32_t), &response);
+ if (status == NO_ERROR) {
+ LOG_ALWAYS_FATAL_IF(response.size() != sizeof(status_t));
+ status = *reinterpret_cast<const status_t*>(response.data());
+ }
+ return status;
+}
+
static std::string dumpInOutBuffer(bool isInput, const sp<EffectBufferHalInterface> &buffer) {
std::stringstream ss;
@@ -2387,7 +2425,7 @@
// already present
// Spatializer or Downmixer effects are inserted in first position because
// they adapt the channel count for all other effects in the chain
- if ((memcmp(&desc.type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0)
+ if (IAfEffectModule::isSpatializer(&desc.type)
|| (memcmp(&desc.type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0)) {
return 0;
}
@@ -2983,6 +3021,20 @@
return true;
}
+// sendMetadata_l() must be called with thread->mutex() held
+void EffectChain::sendMetadata_l(const std::vector<playback_track_metadata_v7_t>& allMetadata,
+ const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata) {
+ audio_utils::lock_guard _l(mutex());
+ for (const auto& effect : mEffects) {
+ if (spatializedMetadata.has_value()
+ && IAfEffectModule::isSpatializer(&effect->desc().type)) {
+ effect->sendMetadata(spatializedMetadata.value());
+ } else {
+ effect->sendMetadata(allMetadata);
+ }
+ }
+}
+
// EffectCallbackInterface implementation
status_t EffectChain::EffectCallback::createEffectHal(
const effect_uuid_t *pEffectUuid, int32_t sessionId, int32_t deviceId,
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 9208c88..8583d47 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -224,9 +224,11 @@
sp<IAfEffectModule> asEffectModule() final { return this; }
bool isHapticGenerator() const final;
+ bool isSpatializer() const final;
status_t setHapticIntensity(int id, os::HapticScale intensity) final;
status_t setVibratorInfo(const media::AudioVibratorInfo& vibratorInfo) final;
+ status_t sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) final;
status_t getConfigs(audio_config_base_t* inputCfg,
audio_config_base_t* outputCfg,
@@ -513,6 +515,10 @@
return mEffects[index];
}
+ void sendMetadata_l(const std::vector<playback_track_metadata_v7_t>& allMetadata,
+ const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata)
+ final REQUIRES(audio_utils::ThreadBase_Mutex);
+
void setThread(const sp<IAfThreadBase>& thread) final;
private:
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index 8c5bc4b..56076a3 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -175,8 +175,12 @@
static bool isHapticGenerator(const effect_uuid_t* type);
virtual bool isHapticGenerator() const = 0;
+ static bool isSpatializer(const effect_uuid_t* type);
+ virtual bool isSpatializer() const = 0;
+
virtual status_t setHapticIntensity(int id, os::HapticScale intensity) = 0;
virtual status_t setVibratorInfo(const media::AudioVibratorInfo& vibratorInfo) = 0;
+ virtual status_t sendMetadata(const std::vector<playback_track_metadata_v7_t>& metadata) = 0;
private:
virtual void process() = 0;
@@ -309,6 +313,10 @@
virtual size_t numberOfEffects() const = 0;
virtual sp<IAfEffectModule> getEffectModule(size_t index) const = 0;
+ // sendMetadata_l() must be called with thread->mLock held
+ virtual void sendMetadata_l(const std::vector<playback_track_metadata_v7_t>& allMetadata,
+ const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata);
+
virtual void dump(int fd, const Vector<String16>& args) const = 0;
};
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 7084be9..46a67e8 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -386,6 +386,12 @@
const effect_uuid_t* type, bool suspend, audio_session_t sessionId)
REQUIRES(mutex()) = 0;
+ // Wait while the Thread is busy. This is done to ensure that
+ // the Thread is not busy releasing the Tracks, during which the Thread mutex
+ // may be temporarily unlocked. Some Track methods will use this method to
+ // avoid races.
+ virtual void waitWhileThreadBusy_l(audio_utils::unique_lock& ul)
+ REQUIRES(mutex()) = 0;
// Dynamic cast to derived interface
virtual sp<IAfDirectOutputThread> asIAfDirectOutputThread() { return nullptr; }
virtual sp<IAfDuplicatingThread> asIAfDuplicatingThread() { return nullptr; }
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 4a1948c..b4cb805 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -23,6 +23,7 @@
#include <audio_utils/mutex.h>
#include <audio_utils/LinearMap.h>
#include <binder/AppOpsManager.h>
+#include <utils/RWLock.h>
namespace android {
@@ -352,6 +353,7 @@
// Must hold thread lock to access tee patches
template <class F>
void forEachTeePatchTrack_l(F f) {
+ RWLock::AutoRLock readLock(mTeePatchesRWLock);
for (auto& tp : mTeePatches) { f(tp.patchTrack); }
};
@@ -387,6 +389,7 @@
audio_output_flags_t mFlags;
TeePatches mTeePatches;
std::optional<TeePatches> mTeePatchesToUpdate;
+ RWLock mTeePatchesRWLock;
const float mSpeed;
const bool mIsSpatialized;
const bool mIsBitPerfect;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 54880f8..244a262 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -47,6 +47,7 @@
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/PersistableBundle.h>
+#include <com_android_media_audio.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
#include <fastpath/AutoPark.h>
@@ -185,7 +186,7 @@
// Minimum amount of time between checking to see if the timestamp is advancing
// for underrun detection. If we check too frequently, we may not detect a
// timestamp update and will falsely detect underrun.
-static const nsecs_t kMinimumTimeBetweenTimestampChecksNs = 150 /* ms */ * 1000;
+static constexpr nsecs_t kMinimumTimeBetweenTimestampChecksNs = 150 /* ms */ * 1'000'000;
// The universal constant for ubiquitous 20ms value. The value of 20ms seems to provide a good
// balance between power consumption and latency, and allows threads to be scheduled reliably
@@ -1483,7 +1484,7 @@
return BAD_VALUE;
}
- if (memcmp(&desc->type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0
+ if (IAfEffectModule::isSpatializer(&desc->type)
&& mType != SPATIALIZER) {
ALOGW("%s: attempt to create a spatializer effect on a thread of type %d",
__func__, mType);
@@ -1571,7 +1572,7 @@
return BAD_VALUE;
} else if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
// only post processing , downmixer or spatializer effects on output stage session
- if (memcmp(&desc->type, FX_IID_SPATIALIZER, sizeof(effect_uuid_t)) == 0
+ if (IAfEffectModule::isSpatializer(&desc->type)
|| memcmp(&desc->type, EFFECT_UIID_DOWNMIX, sizeof(effect_uuid_t)) == 0) {
break;
}
@@ -2849,6 +2850,8 @@
// effectively get the latency it requested.
if (track->isExternalTrack()) {
IAfTrackBase::track_state state = track->state();
+ // Because the track is not on the ActiveTracks,
+ // at this point, only the TrackHandle will be adding the track.
mutex().unlock();
status = AudioSystem::startOutput(track->portId());
mutex().lock();
@@ -2929,7 +2932,12 @@
track->setResetDone(false);
track->resetPresentationComplete();
+
+ // Do not release the ThreadBase mutex after the track is added to mActiveTracks unless
+ // all key changes are complete. It is possible that the threadLoop will begin
+ // processing the added track immediately after the ThreadBase mutex is released.
mActiveTracks.add(track);
+
if (chain != 0) {
ALOGV("addTrack_l() starting track on chain %p for session %d", chain.get(),
track->sessionId());
@@ -3311,10 +3319,44 @@
return {}; // nothing to do
}
StreamOutHalInterface::SourceMetadata metadata;
- auto backInserter = std::back_inserter(metadata.tracks);
- for (const sp<IAfTrack>& track : mActiveTracks) {
- // No track is invalid as this is called after prepareTrack_l in the same critical section
- track->copyMetadataTo(backInserter);
+ if (com_android_media_audio_stereo_spatialization()) {
+ std::map<audio_session_t, std::vector<playback_track_metadata_v7_t> >allSessionsMetadata;
+ for (const sp<IAfTrack>& track : mActiveTracks) {
+ std::vector<playback_track_metadata_v7_t>& sessionMetadata =
+ allSessionsMetadata[track->sessionId()];
+ auto backInserter = std::back_inserter(sessionMetadata);
+ // No track is invalid as this is called after prepareTrack_l in the same
+ // critical section
+ track->copyMetadataTo(backInserter);
+ }
+ std::vector<playback_track_metadata_v7_t> spatializedTracksMetaData;
+ for (const auto& [session, sessionTrackMetadata] : allSessionsMetadata) {
+ metadata.tracks.insert(metadata.tracks.end(),
+ sessionTrackMetadata.begin(), sessionTrackMetadata.end());
+ if (auto chain = getEffectChain_l(session) ; chain != nullptr) {
+ chain->sendMetadata_l(sessionTrackMetadata, {});
+ }
+ if ((hasAudioSession_l(session) & IAfThreadBase::SPATIALIZED_SESSION) != 0) {
+ spatializedTracksMetaData.insert(spatializedTracksMetaData.end(),
+ sessionTrackMetadata.begin(), sessionTrackMetadata.end());
+ }
+ }
+ if (auto chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_MIX); chain != nullptr) {
+ chain->sendMetadata_l(metadata.tracks, {});
+ }
+ if (auto chain = getEffectChain_l(AUDIO_SESSION_OUTPUT_STAGE); chain != nullptr) {
+ chain->sendMetadata_l(metadata.tracks, spatializedTracksMetaData);
+ }
+ if (auto chain = getEffectChain_l(AUDIO_SESSION_DEVICE); chain != nullptr) {
+ chain->sendMetadata_l(metadata.tracks, {});
+ }
+ } else {
+ auto backInserter = std::back_inserter(metadata.tracks);
+ for (const sp<IAfTrack>& track : mActiveTracks) {
+ // No track is invalid as this is called after prepareTrack_l in the same
+ // critical section
+ track->copyMetadataTo(backInserter);
+ }
}
sendMetadataToBackend_l(metadata);
MetadataUpdate change;
@@ -4704,8 +4746,12 @@
void PlaybackThread::removeTracks_l(const Vector<sp<IAfTrack>>& tracksToRemove)
NO_THREAD_SAFETY_ANALYSIS // release and re-acquire mutex()
{
+ if (tracksToRemove.empty()) return;
+
+ // Block all incoming TrackHandle requests until we are finished with the release.
+ setThreadBusy_l(true);
+
for (const auto& track : tracksToRemove) {
- mActiveTracks.remove(track);
ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
sp<IAfEffectChain> chain = getEffectChain_l(track->sessionId());
if (chain != 0) {
@@ -4713,17 +4759,16 @@
__func__, track->id(), chain.get(), track->sessionId());
chain->decActiveTrackCnt();
}
+
// If an external client track, inform APM we're no longer active, and remove if needed.
- // We do this under lock so that the state is consistent if the Track is destroyed.
+ // Since the track is active, we do it here instead of TrackBase::destroy().
if (track->isExternalTrack()) {
+ mutex().unlock();
AudioSystem::stopOutput(track->portId());
if (track->isTerminated()) {
AudioSystem::releaseOutput(track->portId());
}
- }
- if (track->isTerminated()) {
- // remove from our tracks vector
- removeTrack_l(track);
+ mutex().lock();
}
if (mHapticChannelCount > 0 &&
((track->channelMask() & AUDIO_CHANNEL_HAPTIC_ALL) != AUDIO_CHANNEL_NONE
@@ -4740,7 +4785,24 @@
chain->setHapticIntensity_l(track->id(), os::HapticScale::MUTE);
}
}
+
+ // Under lock, the track is removed from the active tracks list.
+ //
+ // Once the track is no longer active, the TrackHandle may directly
+ // modify it as the threadLoop() is no longer responsible for its maintenance.
+ // Do not modify the track from threadLoop after the mutex is unlocked
+ // if it is not active.
+ mActiveTracks.remove(track);
+
+ if (track->isTerminated()) {
+ // remove from our tracks vector
+ removeTrack_l(track);
+ }
}
+
+ // Allow incoming TrackHandle requests. We still hold the mutex,
+ // so pending TrackHandle requests will occur after we unlock it.
+ setThreadBusy_l(false);
}
status_t PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp)
@@ -7608,6 +7670,23 @@
}
}
+void DuplicatingThread::threadLoop_exit()
+{
+ // Prevent calling the OutputTrack dtor in the DuplicatingThread dtor
+ // where other mutexes (i.e. AudioPolicyService_Mutex) may be held.
+ // Do so here in the threadLoop_exit().
+
+ SortedVector <sp<IAfOutputTrack>> localTracks;
+ {
+ audio_utils::lock_guard l(mutex());
+ localTracks = std::move(mOutputTracks);
+ mOutputTracks.clear();
+ }
+ localTracks.clear();
+ outputTracks.clear();
+ PlaybackThread::threadLoop_exit();
+}
+
void DuplicatingThread::dumpInternals_l(int fd, const Vector<String16>& args)
{
MixerThread::dumpInternals_l(fd, args);
@@ -7881,6 +7960,15 @@
}
}
+void SpatializerThread::threadLoop_exit()
+{
+ // The Spatializer EffectHandle must be released on the PlaybackThread
+ // threadLoop() to prevent lock inversion in the SpatializerThread dtor.
+ mFinalDownMixer.clear();
+
+ PlaybackThread::threadLoop_exit();
+}
+
// ----------------------------------------------------------------------------
// Record
// ----------------------------------------------------------------------------
@@ -9553,10 +9641,24 @@
void RecordThread::readInputParameters_l()
{
- status_t result = mInput->stream->getAudioProperties(&mSampleRate, &mChannelMask, &mHALFormat);
- LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving audio properties from HAL: %d", result);
- mFormat = mHALFormat;
+ const audio_config_base_t audioConfig = mInput->getAudioProperties();
+ mSampleRate = audioConfig.sample_rate;
+ mChannelMask = audioConfig.channel_mask;
+ if (!audio_is_input_channel(mChannelMask)) {
+ LOG_ALWAYS_FATAL("Channel mask %#x not valid for input", mChannelMask);
+ }
+
mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
+
+ // Get actual HAL format.
+ status_t result = mInput->stream->getAudioProperties(nullptr, nullptr, &mHALFormat);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Error when retrieving input stream format: %d", result);
+ // Get format from the shim, which will be different than the HAL format
+ // if recording compressed audio from IEC61937 wrapped sources.
+ mFormat = audioConfig.format;
+ if (!audio_is_valid_format(mFormat)) {
+ LOG_ALWAYS_FATAL("Format %#x not valid for input", mFormat);
+ }
if (audio_is_linear_pcm(mFormat)) {
LOG_ALWAYS_FATAL_IF(mChannelCount > FCC_LIMIT, "HAL channel count %d > %d",
mChannelCount, FCC_LIMIT);
@@ -9564,8 +9666,7 @@
// Can have more that FCC_LIMIT channels in encoded streams.
ALOGI("HAL format %#x is not linear pcm", mFormat);
}
- result = mInput->stream->getFrameSize(&mFrameSize);
- LOG_ALWAYS_FATAL_IF(result != OK, "Error retrieving frame size from HAL: %d", result);
+ mFrameSize = mInput->getFrameSize();
LOG_ALWAYS_FATAL_IF(mFrameSize <= 0, "Error frame size was %zu but must be greater than zero",
mFrameSize);
result = mInput->stream->getBufferSize(&mBufferSize);
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a5afdd8..8491e43 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -599,6 +599,35 @@
// check if some effects must be suspended when an effect chain is added
void checkSuspendOnAddEffectChain_l(const sp<IAfEffectChain>& chain) REQUIRES(mutex());
+ /**
+ * waitWhileThreadBusy_l() serves as a mutex gate, which does not allow
+ * progress beyond the method while the PlaybackThread is busy (see setThreadBusy_l()).
+ * During the wait, the ThreadBase_Mutex is temporarily unlocked.
+ *
+ * This implementation uses a condition variable. Alternative methods to gate
+ * the thread may use a second mutex (i.e. entry based on scoped_lock(mutex, gating_mutex)),
+ * but those have less flexibility and more lock order issues.
+ *
+ * Current usage by Track::destroy(), Track::start(), Track::stop(), Track::pause(),
+ * and Track::flush() block this way, and the primary caller is through TrackHandle
+ * with no other mutexes held.
+ *
+ * Special tracks like PatchTrack and OutputTrack may also hold the another thread's
+ * ThreadBase_Mutex during this time. No other mutex is held.
+ */
+
+ void waitWhileThreadBusy_l(audio_utils::unique_lock& ul) final REQUIRES(mutex()) {
+ // the wait returns immediately if the predicate is satisfied.
+ mThreadBusyCv.wait(ul, [&]{ return mThreadBusy == false;});
+ }
+
+ void setThreadBusy_l(bool busy) REQUIRES(mutex()) {
+ if (busy == mThreadBusy) return;
+ mThreadBusy = busy;
+ if (busy == true) return; // no need to wake threads if we become busy.
+ mThreadBusyCv.notify_all();
+ }
+
// sends the metadata of the active tracks to the HAL
struct MetadataUpdate {
std::vector<playback_track_metadata_v7_t> playbackMetadataUpdate;
@@ -641,6 +670,13 @@
ThreadMetrics mThreadMetrics;
const bool mIsOut;
+ // mThreadBusy is checked under the ThreadBase_Mutex to ensure that
+ // TrackHandle operations do not proceed while the ThreadBase is busy
+ // with the track. mThreadBusy is only true if the track is active.
+ //
+ bool mThreadBusy = false; // GUARDED_BY(ThreadBase_Mutex) but read in lambda.
+ audio_utils::condition_variable mThreadBusyCv;
+
// updated by PlaybackThread::readOutputParameters_l() or
// RecordThread::readInputParameters_l()
uint32_t mSampleRate;
@@ -839,7 +875,7 @@
SimpleLog mLocalLog; // locked internally
-private:
+ private:
void dumpBase_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
void dumpEffectChains_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
};
@@ -1849,6 +1885,7 @@
void threadLoop_sleepTime() final REQUIRES(ThreadBase_ThreadLoop);
ssize_t threadLoop_write() final REQUIRES(ThreadBase_ThreadLoop);
void threadLoop_standby() final REQUIRES(ThreadBase_ThreadLoop);
+ void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
void cacheParameters_l() final REQUIRES(mutex(), ThreadBase_ThreadLoop);
private:
@@ -1900,6 +1937,8 @@
REQUIRES(ThreadBase_ThreadLoop) EXCLUDES_ThreadBase_Mutex;
void setHalLatencyMode_l() final REQUIRES(mutex());
+ void threadLoop_exit() final REQUIRES(ThreadBase_ThreadLoop);
+
private:
// Do not request a specific mode by default
audio_latency_mode_t mRequestedLatencyMode = AUDIO_LATENCY_MODE_FREE;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index fe582eb..4e82173 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -890,12 +890,17 @@
bool wasActive = false;
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
- audio_utils::lock_guard _l(thread->mutex());
+ audio_utils::unique_lock ul(thread->mutex());
+ thread->waitWhileThreadBusy_l(ul);
+
auto* const playbackThread = thread->asIAfPlaybackThread().get();
wasActive = playbackThread->destroyTrack_l(this);
forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
}
if (isExternalTrack() && !wasActive) {
+ // If the track is not active, the TrackHandle is responsible for
+ // releasing the port id, not the ThreadBase::threadLoop().
+ // At this point, there is no concurrency issue as the track is going away.
AudioSystem::releaseOutput(mPortId);
}
}
@@ -1079,7 +1084,13 @@
// Additionally PatchProxyBufferProvider::obtainBuffer (called by PathTrack::getNextBuffer)
// does not allow 0 frame size request contrary to getNextBuffer
}
- for (auto& teePatch : mTeePatches) {
+ TeePatches teePatches;
+ if (mTeePatchesRWLock.tryReadLock() == NO_ERROR) {
+ // Cache a copy of tee patches in case it is updated while using.
+ teePatches = mTeePatches;
+ mTeePatchesRWLock.unlock();
+ }
+ for (auto& teePatch : teePatches) {
IAfPatchRecord* patchRecord = teePatch.patchRecord.get();
const size_t framesWritten = patchRecord->writeFrames(
sourceBuffer.i8, frameCount, mFrameSize);
@@ -1092,7 +1103,7 @@
using namespace std::chrono_literals;
// Average is ~20us per track, this should virtually never be logged (Logging takes >200us)
ALOGD_IF(spent > 500us, "%s: took %lldus to intercept %zu tracks", __func__,
- spent.count(), mTeePatches.size());
+ spent.count(), teePatches.size());
}
// ExtendedAudioBufferProvider interface
@@ -1181,7 +1192,9 @@
return PERMISSION_DENIED;
}
}
- audio_utils::lock_guard _lth(thread->mutex());
+ audio_utils::unique_lock ul(thread->mutex());
+ thread->waitWhileThreadBusy_l(ul);
+
track_state state = mState;
// here the track could be either new, or restarted
// in both cases "unstop" the track
@@ -1306,7 +1319,9 @@
ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
- audio_utils::lock_guard _l(thread->mutex());
+ audio_utils::unique_lock ul(thread->mutex());
+ thread->waitWhileThreadBusy_l(ul);
+
track_state state = mState;
if (state == RESUMING || state == ACTIVE || state == PAUSING || state == PAUSED) {
// If the track is not active (PAUSED and buffers full), flush buffers
@@ -1341,7 +1356,9 @@
ALOGV("%s(%d): calling pid %d", __func__, mId, IPCThreadState::self()->getCallingPid());
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
- audio_utils::lock_guard _l(thread->mutex());
+ audio_utils::unique_lock ul(thread->mutex());
+ thread->waitWhileThreadBusy_l(ul);
+
auto* const playbackThread = thread->asIAfPlaybackThread().get();
switch (mState) {
case STOPPING_1:
@@ -1378,7 +1395,9 @@
ALOGV("%s(%d)", __func__, mId);
const sp<IAfThreadBase> thread = mThread.promote();
if (thread != 0) {
- audio_utils::lock_guard _l(thread->mutex());
+ audio_utils::unique_lock ul(thread->mutex());
+ thread->waitWhileThreadBusy_l(ul);
+
auto* const playbackThread = thread->asIAfPlaybackThread().get();
// Flush the ring buffer now if the track is not active in the PlaybackThread.
@@ -1616,7 +1635,10 @@
void Track::updateTeePatches_l() {
if (mTeePatchesToUpdate.has_value()) {
forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->destroy(); });
- mTeePatches = mTeePatchesToUpdate.value();
+ {
+ RWLock::AutoWLock writeLock(mTeePatchesRWLock);
+ mTeePatches = std::move(mTeePatchesToUpdate.value());
+ }
if (mState == TrackBase::ACTIVE || mState == TrackBase::RESUMING ||
mState == TrackBase::STOPPING_1) {
forEachTeePatchTrack_l([](const auto& patchTrack) { patchTrack->start(); });
diff --git a/services/audioflinger/afutils/Vibrator.cpp b/services/audioflinger/afutils/Vibrator.cpp
index 25fcc6a..ab15a09 100644
--- a/services/audioflinger/afutils/Vibrator.cpp
+++ b/services/audioflinger/afutils/Vibrator.cpp
@@ -44,6 +44,10 @@
}
os::HapticScale onExternalVibrationStart(const sp<os::ExternalVibration>& externalVibration) {
+ if (externalVibration->getAudioAttributes().flags & AUDIO_FLAG_MUTE_HAPTIC) {
+ ALOGD("%s, mute haptic according to audio attributes flag", __func__);
+ return os::HapticScale::MUTE;
+ }
const sp<os::IExternalVibratorService> evs = getExternalVibratorService();
if (evs != nullptr) {
int32_t ret;
diff --git a/services/audioflinger/datapath/Android.bp b/services/audioflinger/datapath/Android.bp
index ee98aef..4235f14 100644
--- a/services/audioflinger/datapath/Android.bp
+++ b/services/audioflinger/datapath/Android.bp
@@ -43,11 +43,14 @@
srcs: [
"AudioHwDevice.cpp",
+ "AudioStreamIn.cpp",
"AudioStreamOut.cpp",
+ "SpdifStreamIn.cpp",
"SpdifStreamOut.cpp",
],
header_libs: [
+ "libaudioclient_headers",
"libaudiohal_headers",
"liberror_headers",
],
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 67e9991..95e9ecc 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -1,19 +1,19 @@
/*
-**
-** Copyright 2007, 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.
-*/
+ *
+ * Copyright 2007, 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 "AudioHwDevice"
//#define LOG_NDEBUG 0
@@ -21,10 +21,13 @@
#include <system/audio.h>
#include <utils/Log.h>
+#include <audio_utils/spdif/SPDIFDecoder.h>
#include <audio_utils/spdif/SPDIFEncoder.h>
+#include <media/AudioResamplerPublic.h>
#include "AudioHwDevice.h"
#include "AudioStreamOut.h"
+#include "SpdifStreamIn.h"
#include "SpdifStreamOut.h"
namespace android {
@@ -47,12 +50,8 @@
auto outputStream = new AudioStreamOut(this, flags);
// Try to open the HAL first using the current format.
- ALOGV("openOutputStream(), try "
- " sampleRate %d, Format %#x, "
- "channelMask %#x",
- config->sample_rate,
- config->format,
- config->channel_mask);
+ ALOGV("openOutputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
+ config->format, config->channel_mask);
status_t status = outputStream->open(handle, deviceType, config, address);
if (status != NO_ERROR) {
@@ -62,13 +61,8 @@
// FIXME Look at any modification to the config.
// The HAL might modify the config to suggest a wrapped format.
// Log this so we can see what the HALs are doing.
- ALOGI("openOutputStream(), HAL returned"
- " sampleRate %d, Format %#x, "
- "channelMask %#x, status %d",
- config->sample_rate,
- config->format,
- config->channel_mask,
- status);
+ ALOGI("openOutputStream(), HAL returned sampleRate %d, format %#x, channelMask %#x,"
+ " status %d", config->sample_rate, config->format, config->channel_mask, status);
// If the data is encoded then try again using wrapped PCM.
const bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
@@ -96,6 +90,79 @@
return status;
}
+status_t AudioHwDevice::openInputStream(
+ AudioStreamIn **ppStreamIn,
+ audio_io_handle_t handle,
+ audio_devices_t deviceType,
+ audio_input_flags_t flags,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char *outputDeviceAddress) {
+
+ struct audio_config originalConfig = *config;
+ auto inputStream = new AudioStreamIn(this, flags);
+
+ // Try to open the HAL first using the current format.
+ ALOGV("openInputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
+ config->format, config->channel_mask);
+ status_t status = inputStream->open(handle, deviceType, config, address, source, outputDevice,
+ outputDeviceAddress);
+
+ // If the input could not be opened with the requested parameters and we can handle the
+ // conversion internally, try to open again with the proposed parameters.
+ if (status == BAD_VALUE &&
+ audio_is_linear_pcm(originalConfig.format) &&
+ audio_is_linear_pcm(config->format) &&
+ (config->sample_rate <= AUDIO_RESAMPLER_DOWN_RATIO_MAX * config->sample_rate) &&
+ (audio_channel_count_from_in_mask(config->channel_mask) <= FCC_LIMIT) &&
+ (audio_channel_count_from_in_mask(originalConfig.channel_mask) <= FCC_LIMIT)) {
+ // FIXME describe the change proposed by HAL (save old values so we can log them here)
+ ALOGV("openInputStream() reopening with proposed sampling rate and channel mask");
+ status = inputStream->open(handle, deviceType, config, address, source,
+ outputDevice, outputDeviceAddress);
+ // FIXME log this new status; HAL should not propose any further changes
+ if (status != NO_ERROR) {
+ delete inputStream;
+ inputStream = nullptr;
+ }
+ } else if (status != NO_ERROR) {
+ delete inputStream;
+ inputStream = nullptr;
+
+ // FIXME Look at any modification to the config.
+ // The HAL might modify the config to suggest a wrapped format.
+ // Log this so we can see what the HALs are doing.
+ ALOGI("openInputStream(), HAL returned sampleRate %d, format %#x, channelMask %#x,"
+ " status %d", config->sample_rate, config->format, config->channel_mask, status);
+
+ // If the data is encoded then try again using wrapped PCM.
+ const bool unwrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
+ && ((flags & AUDIO_INPUT_FLAG_DIRECT) != 0);
+
+ if (unwrapperNeeded) {
+ if (SPDIFDecoder::isFormatSupported(originalConfig.format)) {
+ inputStream = new SpdifStreamIn(this, flags, originalConfig.format);
+ status = inputStream->open(handle, deviceType, &originalConfig, address, source,
+ outputDevice, outputDeviceAddress);
+ if (status != NO_ERROR) {
+ ALOGE("ERROR - openInputStream(), SPDIF open returned %d",
+ status);
+ delete inputStream;
+ inputStream = nullptr;
+ }
+ } else {
+ ALOGE("ERROR - openInputStream(), SPDIFDecoder does not support format 0x%08x",
+ originalConfig.format);
+ }
+ }
+ }
+
+ *ppStreamIn = inputStream;
+ return status;
+}
+
bool AudioHwDevice::supportsAudioPatches() const {
bool result;
return mHwDevice->supportsAudioPatches(&result) == OK ? result : false;
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index cfb6fbd..80c1473 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -1,22 +1,21 @@
/*
-**
-** Copyright 2007, 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.
-*/
+ *
+ * Copyright 2007, 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_AUDIO_HW_DEVICE_H
-#define ANDROID_AUDIO_HW_DEVICE_H
+#pragma once
#include <stdint.h>
#include <stdlib.h>
@@ -30,6 +29,7 @@
namespace android {
+class AudioStreamIn;
class AudioStreamOut;
class AudioHwDevice {
@@ -89,6 +89,17 @@
struct audio_config *config,
const char *address);
+ status_t openInputStream(
+ AudioStreamIn **ppStreamIn,
+ audio_io_handle_t handle,
+ audio_devices_t deviceType,
+ audio_input_flags_t flags,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char *outputDeviceAddress);
+
[[nodiscard]] bool supportsAudioPatches() const;
[[nodiscard]] status_t getAudioPort(struct audio_port_v7 *port) const;
@@ -112,5 +123,3 @@
};
} // namespace android
-
-#endif // ANDROID_AUDIO_HW_DEVICE_H
diff --git a/services/audioflinger/datapath/AudioStreamIn.cpp b/services/audioflinger/datapath/AudioStreamIn.cpp
new file mode 100644
index 0000000..24f3bb9
--- /dev/null
+++ b/services/audioflinger/datapath/AudioStreamIn.cpp
@@ -0,0 +1,137 @@
+/*
+ *
+ * Copyright 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 "AudioFlinger"
+//#define LOG_NDEBUG 0
+#include "AudioStreamIn.h"
+
+#include <media/audiohal/DeviceHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include "AudioHwDevice.h"
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+AudioStreamIn::AudioStreamIn(AudioHwDevice *dev, audio_input_flags_t flags)
+ : audioHwDev(dev)
+ , flags(flags)
+{
+}
+
+// This must be defined here together with the HAL includes above and
+// not solely in the header.
+AudioStreamIn::~AudioStreamIn() = default;
+
+sp<DeviceHalInterface> AudioStreamIn::hwDev() const
+{
+ return audioHwDev->hwDevice();
+}
+
+status_t AudioStreamIn::getCapturePosition(int64_t* frames, int64_t* time)
+{
+ if (stream == nullptr) {
+ return NO_INIT;
+ }
+
+ int64_t halPosition = 0;
+ const status_t status = stream->getCapturePosition(&halPosition, time);
+ if (status != NO_ERROR) {
+ return status;
+ }
+
+ // Adjust for standby using HAL rate frames.
+ // Only apply this correction if the HAL is getting PCM frames.
+ if (mHalFormatHasProportionalFrames) {
+ const uint64_t adjustedPosition = (halPosition <= mFramesReadAtStandby) ?
+ 0 : (halPosition - mFramesReadAtStandby);
+ // Scale from HAL sample rate to application rate.
+ *frames = adjustedPosition / mRateMultiplier;
+ } else {
+ // For compressed formats.
+ *frames = halPosition;
+ }
+
+ return status;
+}
+
+status_t AudioStreamIn::open(
+ audio_io_handle_t handle,
+ audio_devices_t deviceType,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char *outputDeviceAddress)
+{
+ sp<StreamInHalInterface> inStream;
+
+ int status = hwDev()->openInputStream(
+ handle,
+ deviceType,
+ config,
+ flags,
+ address,
+ source,
+ outputDevice,
+ outputDeviceAddress,
+ &inStream);
+ ALOGV("AudioStreamIn::open(), HAL returned stream %p, sampleRate %d, format %#x,"
+ " channelMask %#x, status %d", inStream.get(), config->sample_rate, config->format,
+ config->channel_mask, status);
+
+ if (status == NO_ERROR) {
+ stream = inStream;
+ mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
+ status = stream->getFrameSize(&mHalFrameSize);
+ LOG_ALWAYS_FATAL_IF(status != OK, "Error retrieving frame size from HAL: %d", status);
+ LOG_ALWAYS_FATAL_IF(mHalFrameSize == 0, "Error frame size was %zu but must be greater than"
+ " zero", mHalFrameSize);
+ }
+
+ return status;
+}
+
+audio_config_base_t AudioStreamIn::getAudioProperties() const
+{
+ audio_config_base_t result = AUDIO_CONFIG_BASE_INITIALIZER;
+ if (stream->getAudioProperties(&result) != OK) {
+ result.sample_rate = 0;
+ result.channel_mask = AUDIO_CHANNEL_INVALID;
+ result.format = AUDIO_FORMAT_INVALID;
+ }
+ return result;
+}
+
+status_t AudioStreamIn::standby()
+{
+ mFramesReadAtStandby = mFramesRead;
+ return stream->standby();
+}
+
+status_t AudioStreamIn::read(void* buffer, size_t bytes, size_t* read)
+{
+ const status_t result = stream->read(buffer, bytes, read);
+ if (result == OK && *read > 0 && mHalFrameSize > 0) {
+ mFramesRead += *read / mHalFrameSize;
+ }
+ return result;
+}
+
+} // namespace android
diff --git a/services/audioflinger/datapath/AudioStreamIn.h b/services/audioflinger/datapath/AudioStreamIn.h
index 604a4e4..6d1c6a7 100644
--- a/services/audioflinger/datapath/AudioStreamIn.h
+++ b/services/audioflinger/datapath/AudioStreamIn.h
@@ -31,30 +31,57 @@
virtual status_t standby() = 0;
};
-// AudioStreamIn is immutable, so its fields are const.
-// The methods must not be const to match StreamHalInterface signature.
-
-struct AudioStreamIn : public Source {
+/**
+ * Managed access to a HAL input stream.
+ */
+class AudioStreamIn : public Source {
+public:
const AudioHwDevice* const audioHwDev;
- const sp<StreamInHalInterface> stream;
+ sp<StreamInHalInterface> stream;
const audio_input_flags_t flags;
- AudioStreamIn(
- const AudioHwDevice* dev, const sp<StreamInHalInterface>& in,
- audio_input_flags_t flags)
- : audioHwDev(dev), stream(in), flags(flags) {}
+ [[nodiscard]] sp<DeviceHalInterface> hwDev() const;
- status_t read(void* buffer, size_t bytes, size_t* read) final {
- return stream->read(buffer, bytes, read);
- }
+ AudioStreamIn(AudioHwDevice *dev, audio_input_flags_t flags);
- status_t getCapturePosition(int64_t* frames, int64_t* time) final {
- return stream->getCapturePosition(frames, time);
- }
+ virtual status_t open(
+ audio_io_handle_t handle,
+ audio_devices_t deviceType,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char *outputDeviceAddress);
- status_t standby() final { return stream->standby(); }
+ ~AudioStreamIn() override;
- sp<DeviceHalInterface> hwDev() const { return audioHwDev->hwDevice(); }
+ status_t getCapturePosition(int64_t* frames, int64_t* time) override;
+
+ status_t read(void* buffer, size_t bytes, size_t* read) override;
+
+ /**
+ * @return frame size from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] virtual size_t getFrameSize() const { return mHalFrameSize; }
+
+ /**
+ * @return audio stream configuration: channel mask, format, sample rate:
+ * - channel mask from the perspective of the application and the AudioFlinger,
+ * The HAL is in stereo mode when playing multi-channel compressed audio over HDMI;
+ * - format from the perspective of the application and the AudioFlinger;
+ * - sample rate from the perspective of the application and the AudioFlinger,
+ * The HAL may be running at a higher sample rate if, for example, playing wrapped EAC3.
+ */
+ [[nodiscard]] virtual audio_config_base_t getAudioProperties() const;
+
+ status_t standby() override;
+
+protected:
+ uint64_t mFramesRead = 0;
+ int64_t mFramesReadAtStandby = 0;
+ int mRateMultiplier = 1;
+ bool mHalFormatHasProportionalFrames = false;
+ size_t mHalFrameSize = 0;
};
} // namespace android
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index 6fa82e5..1830d15 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -1,30 +1,31 @@
/*
-**
-** Copyright 2015, 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.
-*/
+ *
+ * Copyright 2015, 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 "AudioFlinger"
//#define LOG_NDEBUG 0
+#include "AudioStreamOut.h"
+
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
#include <system/audio.h>
#include <utils/Log.h>
#include "AudioHwDevice.h"
-#include "AudioStreamOut.h"
namespace android {
@@ -132,14 +133,9 @@
config,
address,
&outStream);
- ALOGV("AudioStreamOut::open(), HAL returned "
- " stream %p, sampleRate %d, Format %#x, "
- "channelMask %#x, status %d",
- outStream.get(),
- config->sample_rate,
- config->format,
- config->channel_mask,
- status);
+ ALOGV("AudioStreamOut::open(), HAL returned stream %p, sampleRate %d, format %#x,"
+ " channelMask %#x, status %d", outStream.get(), config->sample_rate, config->format,
+ config->channel_mask, status);
// Some HALs may not recognize AUDIO_FORMAT_IEC61937. But if we declare
// it as PCM then it will probably work.
@@ -162,7 +158,7 @@
mHalFormatHasProportionalFrames = audio_has_proportional_frames(config->format);
status = stream->getFrameSize(&mHalFrameSize);
LOG_ALWAYS_FATAL_IF(status != OK, "Error retrieving frame size from HAL: %d", status);
- LOG_ALWAYS_FATAL_IF(mHalFrameSize <= 0, "Error frame size was %zu but must be greater than"
+ LOG_ALWAYS_FATAL_IF(mHalFrameSize == 0, "Error frame size was %zu but must be greater than"
" zero", mHalFrameSize);
}
diff --git a/services/audioflinger/datapath/AudioStreamOut.h b/services/audioflinger/datapath/AudioStreamOut.h
index ce00f8c..ea41bba 100644
--- a/services/audioflinger/datapath/AudioStreamOut.h
+++ b/services/audioflinger/datapath/AudioStreamOut.h
@@ -1,27 +1,28 @@
/*
-**
-** Copyright 2015, 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.
-*/
+ *
+ * Copyright 2015, 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_AUDIO_STREAM_OUT_H
-#define ANDROID_AUDIO_STREAM_OUT_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
#include <system/audio.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
namespace android {
@@ -34,9 +35,6 @@
*/
class AudioStreamOut {
public:
-// AudioStreamOut is immutable, so its fields are const.
-// For emphasis, we could also make all pointers to them be "const *",
-// but that would clutter the code unnecessarily.
AudioHwDevice * const audioHwDev;
sp<StreamOutHalInterface> stream;
const audio_output_flags_t flags;
@@ -101,15 +99,13 @@
virtual void presentationComplete() { mExpectRetrograde = true; }
protected:
- uint64_t mFramesWritten = 0; // reset by flush
- uint64_t mFramesWrittenAtStandby = 0;
- uint64_t mRenderPosition = 0; // reset by flush, standby, or presentation complete
- int mRateMultiplier = 1;
- bool mHalFormatHasProportionalFrames = false;
- size_t mHalFrameSize = 0;
- bool mExpectRetrograde = false; // see presentationComplete
+ uint64_t mFramesWritten = 0; // reset by flush
+ uint64_t mFramesWrittenAtStandby = 0;
+ uint64_t mRenderPosition = 0; // reset by flush, standby, or presentation complete
+ int mRateMultiplier = 1;
+ bool mHalFormatHasProportionalFrames = false;
+ size_t mHalFrameSize = 0;
+ bool mExpectRetrograde = false; // see presentationComplete
};
} // namespace android
-
-#endif // ANDROID_AUDIO_STREAM_OUT_H
diff --git a/services/audioflinger/datapath/SpdifStreamIn.cpp b/services/audioflinger/datapath/SpdifStreamIn.cpp
new file mode 100644
index 0000000..98ce712
--- /dev/null
+++ b/services/audioflinger/datapath/SpdifStreamIn.cpp
@@ -0,0 +1,128 @@
+/*
+ *
+ * Copyright 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 "AudioFlinger"
+//#define LOG_NDEBUG 0
+#include "Configuration.h"
+#include <system/audio.h>
+#include <utils/Log.h>
+
+#include <audio_utils/spdif/SPDIFDecoder.h>
+
+#include "AudioHwDevice.h"
+#include "SpdifStreamIn.h"
+
+namespace android {
+
+/**
+ * If the HAL is generating IEC61937 data and AudioFlinger expects elementary stream then we need to
+ * extract the data using an SPDIF decoder.
+ */
+SpdifStreamIn::SpdifStreamIn(AudioHwDevice *dev,
+ audio_input_flags_t flags,
+ audio_format_t format)
+ : AudioStreamIn(dev, flags)
+ , mSpdifDecoder(this, format)
+{
+}
+
+status_t SpdifStreamIn::open(
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char* outputDeviceAddress)
+{
+ struct audio_config customConfig = *config;
+
+ mApplicationConfig.format = config->format;
+ mApplicationConfig.sample_rate = config->sample_rate;
+ mApplicationConfig.channel_mask = config->channel_mask;
+
+ mRateMultiplier = spdif_rate_multiplier(config->format);
+ if (mRateMultiplier <= 0) {
+ ALOGE("ERROR SpdifStreamIn::open() unrecognized format 0x%08X\n", config->format);
+ return BAD_VALUE;
+ }
+ customConfig.sample_rate = config->sample_rate * mRateMultiplier;
+ customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ customConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
+
+ // Always print this because otherwise it could be very confusing if the
+ // HAL and AudioFlinger are using different formats.
+ // Print before open() because HAL may modify customConfig.
+ ALOGI("SpdifStreamIn::open() AudioFlinger requested sampleRate %d, format %#x, channelMask %#x",
+ config->sample_rate, config->format, config->channel_mask);
+ ALOGI("SpdifStreamIn::open() HAL configured for sampleRate %d, format %#x, channelMask %#x",
+ customConfig.sample_rate, customConfig.format, customConfig.channel_mask);
+
+ const status_t status = AudioStreamIn::open(
+ handle,
+ devices,
+ &customConfig,
+ address,
+ source,
+ outputDevice,
+ outputDeviceAddress);
+
+ ALOGI("SpdifStreamIn::open() status = %d", status);
+
+#ifdef TEE_SINK
+ if (status == OK) {
+ // Don't use PCM 16-bit format to avoid WAV encoding IEC61937 data.
+ mTee.set(customConfig.sample_rate,
+ audio_channel_count_from_in_mask(customConfig.channel_mask),
+ AUDIO_FORMAT_IEC61937, NBAIO_Tee::TEE_FLAG_INPUT_THREAD);
+ mTee.setId(std::string("_") + std::to_string(handle) + "_C");
+ }
+#endif
+
+ return status;
+}
+
+int SpdifStreamIn::standby()
+{
+ mSpdifDecoder.reset();
+ return AudioStreamIn::standby();
+}
+
+status_t SpdifStreamIn::readDataBurst(void* buffer, size_t bytes, size_t* read)
+{
+ status_t status = AudioStreamIn::read(buffer, bytes, read);
+
+#ifdef TEE_SINK
+ if (*read > 0) {
+ mTee.write(reinterpret_cast<const char *>(buffer), *read / AudioStreamIn::getFrameSize());
+ }
+#endif
+ return status;
+}
+
+status_t SpdifStreamIn::read(void* buffer, size_t numBytes, size_t* read)
+{
+ // Read from SPDIF extractor. It will call back to readDataBurst().
+ const auto bytesRead = mSpdifDecoder.read(buffer, numBytes);
+ if (bytesRead >= 0) {
+ *read = bytesRead;
+ return OK;
+ }
+ return NOT_ENOUGH_DATA;
+}
+
+} // namespace android
diff --git a/services/audioflinger/datapath/SpdifStreamIn.h b/services/audioflinger/datapath/SpdifStreamIn.h
new file mode 100644
index 0000000..78832ee
--- /dev/null
+++ b/services/audioflinger/datapath/SpdifStreamIn.h
@@ -0,0 +1,134 @@
+/*
+ *
+ * Copyright 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 <stdint.h>
+#include <sys/types.h>
+
+#include <system/audio.h>
+
+#include "AudioStreamIn.h"
+
+#include <audio_utils/spdif/SPDIFDecoder.h>
+#include <afutils/NBAIO_Tee.h>
+
+namespace android {
+
+/**
+ * Stream that is a PCM data burst in the HAL but looks like an encoded stream
+ * to the AudioFlinger. Wraps encoded data in an SPDIF wrapper per IEC61973-3.
+ */
+class SpdifStreamIn : public AudioStreamIn {
+public:
+
+ SpdifStreamIn(AudioHwDevice *dev, audio_input_flags_t flags,
+ audio_format_t format);
+
+ status_t open(
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ const char *address,
+ audio_source_t source,
+ audio_devices_t outputDevice,
+ const char* outputDeviceAddress) override;
+
+ /**
+ * Read audio buffer from driver. If at least one frame was read successfully prior to the error,
+ * it is suggested that the driver return that successful (short) byte count
+ * and then return an error in the subsequent call.
+ *
+ * If set_callback() has previously been called to enable non-blocking mode
+ * the write() is not allowed to block. It must write only the number of
+ * bytes that currently fit in the driver/hardware buffer and then return
+ * this byte count. If this is less than the requested write size the
+ * callback function must be called when more space is available in the
+ * driver/hardware buffer.
+ */
+ status_t read(void* buffer, size_t bytes, size_t* read) override;
+
+ /**
+ * @return frame size from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] size_t getFrameSize() const override { return sizeof(int8_t); }
+
+ /**
+ * @return audio_config_base_t from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] audio_config_base_t getAudioProperties() const override {
+ return mApplicationConfig;
+ }
+
+ /**
+ * @return format from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] virtual audio_format_t getFormat() const { return mApplicationConfig.format; }
+
+ /**
+ * The HAL may be running at a higher sample rate if, for example, reading wrapped EAC3.
+ * @return sample rate from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] virtual uint32_t getSampleRate() const { return mApplicationConfig.sample_rate; }
+
+ /**
+ * The HAL is in stereo mode when reading multi-channel compressed audio.
+ * @return channel mask from the perspective of the application and the AudioFlinger.
+ */
+ [[nodiscard]] virtual audio_channel_mask_t getChannelMask() const {
+ return mApplicationConfig.channel_mask;
+ }
+
+ status_t standby() override;
+
+private:
+
+ class MySPDIFDecoder : public SPDIFDecoder
+ {
+ public:
+ MySPDIFDecoder(SpdifStreamIn *spdifStreamIn, audio_format_t format)
+ : SPDIFDecoder(format)
+ , mSpdifStreamIn(spdifStreamIn)
+ {
+ }
+
+ ssize_t readInput(void* buffer, size_t bytes) override
+ {
+ size_t bytesRead = 0;
+ const auto result = mSpdifStreamIn->readDataBurst(buffer, bytes, &bytesRead);
+ if (result < 0) {
+ return result;
+ }
+ return bytesRead;
+ }
+
+ protected:
+ SpdifStreamIn * const mSpdifStreamIn;
+ };
+
+ MySPDIFDecoder mSpdifDecoder;
+ audio_config_base_t mApplicationConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+
+ status_t readDataBurst(void* data, size_t bytes, size_t* read);
+
+#ifdef TEE_SINK
+ NBAIO_Tee mTee;
+#endif
+
+};
+
+} // namespace android
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index 0c6a5a1..65a4eec 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -1,19 +1,19 @@
/*
-**
-** Copyright 2015, 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.
-*/
+ *
+ * Copyright 2015, 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 "AudioFlinger"
//#define LOG_NDEBUG 0
@@ -42,10 +42,10 @@
}
status_t SpdifStreamOut::open(
- audio_io_handle_t handle,
- audio_devices_t devices,
- struct audio_config *config,
- const char *address)
+ audio_io_handle_t handle,
+ audio_devices_t devices,
+ struct audio_config *config,
+ const char *address)
{
struct audio_config customConfig = *config;
@@ -53,22 +53,10 @@
mApplicationConfig.sample_rate = config->sample_rate;
mApplicationConfig.channel_mask = config->channel_mask;
- // Some data bursts run at a higher sample rate.
- // TODO Move this into the audio_utils as a static method.
- switch(config->format) {
- case AUDIO_FORMAT_E_AC3:
- case AUDIO_FORMAT_E_AC3_JOC:
- mRateMultiplier = 4;
- break;
- case AUDIO_FORMAT_AC3:
- case AUDIO_FORMAT_DTS:
- case AUDIO_FORMAT_DTS_HD:
- mRateMultiplier = 1;
- break;
- default:
- ALOGE("ERROR SpdifStreamOut::open() unrecognized format 0x%08X\n",
- config->format);
- return BAD_VALUE;
+ mRateMultiplier = spdif_rate_multiplier(config->format);
+ if (mRateMultiplier <= 0) {
+ ALOGE("ERROR SpdifStreamOut::open() unrecognized format 0x%08X\n", config->format);
+ return BAD_VALUE;
}
customConfig.sample_rate = config->sample_rate * mRateMultiplier;
@@ -78,16 +66,10 @@
// Always print this because otherwise it could be very confusing if the
// HAL and AudioFlinger are using different formats.
// Print before open() because HAL may modify customConfig.
- ALOGI("SpdifStreamOut::open() AudioFlinger requested"
- " sampleRate %d, format %#x, channelMask %#x",
- config->sample_rate,
- config->format,
- config->channel_mask);
- ALOGI("SpdifStreamOut::open() HAL configured for"
- " sampleRate %d, format %#x, channelMask %#x",
- customConfig.sample_rate,
- customConfig.format,
- customConfig.channel_mask);
+ ALOGI("SpdifStreamOut::open() AudioFlinger requested sampleRate %d, format %#x,"
+ " channelMask %#x", config->sample_rate, config->format, config->channel_mask);
+ ALOGI("SpdifStreamOut::open() HAL configured for sampleRate %d, format %#x, channelMask %#x",
+ customConfig.sample_rate, customConfig.format, customConfig.channel_mask);
const status_t status = AudioStreamOut::open(
handle,
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index 56d57f6..c6d27ba 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -1,22 +1,21 @@
/*
-**
-** Copyright 2015, 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.
-*/
+ *
+ * Copyright 2015, 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_SPDIF_STREAM_OUT_H
-#define ANDROID_SPDIF_STREAM_OUT_H
+#pragma once
#include <stdint.h>
#include <sys/types.h>
@@ -40,8 +39,6 @@
SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags,
audio_format_t format);
- ~SpdifStreamOut() override = default;
-
status_t open(
audio_io_handle_t handle,
audio_devices_t devices,
@@ -116,10 +113,10 @@
SpdifStreamOut * const mSpdifStreamOut;
};
- MySPDIFEncoder mSpdifEncoder;
- audio_config_base_t mApplicationConfig = AUDIO_CONFIG_BASE_INITIALIZER;
+ MySPDIFEncoder mSpdifEncoder;
+ audio_config_base_t mApplicationConfig = AUDIO_CONFIG_BASE_INITIALIZER;
- ssize_t writeDataBurst(const void* data, size_t bytes);
+ ssize_t writeDataBurst(const void* data, size_t bytes);
#ifdef TEE_SINK
NBAIO_Tee mTee;
@@ -128,5 +125,3 @@
};
} // namespace android
-
-#endif // ANDROID_SPDIF_STREAM_OUT_H
diff --git a/services/audioflinger/datapath/ThreadMetrics.h b/services/audioflinger/datapath/ThreadMetrics.h
index c643a57..4eb8aa0 100644
--- a/services/audioflinger/datapath/ThreadMetrics.h
+++ b/services/audioflinger/datapath/ThreadMetrics.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_AUDIO_THREADMETRICS_H
-#define ANDROID_AUDIO_THREADMETRICS_H
+#pragma once
#include <media/MediaMetricsItem.h>
@@ -210,5 +209,3 @@
};
} // namespace android
-
-#endif // ANDROID_AUDIO_THREADMETRICS_H
diff --git a/services/audioflinger/datapath/TrackMetrics.h b/services/audioflinger/datapath/TrackMetrics.h
index 2b44acb..ad5d3db 100644
--- a/services/audioflinger/datapath/TrackMetrics.h
+++ b/services/audioflinger/datapath/TrackMetrics.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_AUDIO_TRACKMETRICS_H
-#define ANDROID_AUDIO_TRACKMETRICS_H
+#pragma once
#include <binder/IActivityManager.h>
#include <binder/IPCThreadState.h>
@@ -306,5 +305,3 @@
};
} // namespace android
-
-#endif // ANDROID_AUDIO_TRACKMETRICS_H
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 197cff9..47f7228 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -21,10 +21,12 @@
#include "SoundDoseManager.h"
#include "android/media/SoundDoseRecord.h"
+#include <algorithm>
#include <android-base/stringprintf.h>
-#include <media/AidlConversionCppNdk.h>
#include <cinttypes>
#include <ctime>
+#include <functional>
+#include <media/AidlConversionCppNdk.h>
#include <utils/Log.h>
namespace android {
@@ -46,6 +48,8 @@
return now_ts.tv_sec;
}
+constexpr float kDefaultRs2LowerBound = 80.f; // dBA
+
} // namespace
sp<audio_utils::MelProcessor> SoundDoseManager::getOrCreateProcessorForDevice(
@@ -53,7 +57,7 @@
size_t channelCount, audio_format_t format) {
const std::lock_guard _l(mLock);
- if (mHalSoundDose.size() > 0 && mEnabledCsd) {
+ if (!mUseFrameworkMel && mHalSoundDose.size() > 0 && mEnabledCsd) {
ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
return nullptr;
}
@@ -143,7 +147,7 @@
ALOGV("%s", __func__);
const std::lock_guard _l(mLock);
- if (mHalSoundDose.size() > 0) {
+ if (!mUseFrameworkMel && mHalSoundDose.size() > 0) {
bool success = true;
for (auto& halSoundDose : mHalSoundDose) {
// using the HAL sound dose interface
@@ -187,6 +191,21 @@
}
}
+float SoundDoseManager::getAttenuationForDeviceId(audio_port_handle_t id) const {
+ float attenuation = 0.f;
+
+ const std::lock_guard _l(mLock);
+ const auto deviceTypeIt = mActiveDeviceTypes.find(id);
+ if (deviceTypeIt != mActiveDeviceTypes.end()) {
+ auto attenuationIt = mMelAttenuationDB.find(deviceTypeIt->second);
+ if (attenuationIt != mMelAttenuationDB.end()) {
+ attenuation = attenuationIt->second;
+ }
+ }
+
+ return attenuation;
+}
+
audio_port_handle_t SoundDoseManager::getIdForAudioDevice(const AudioDevice& audioDevice) const {
if (isComputeCsdForcedOnAllDevices()) {
// If CSD is forced on all devices return random port id. Used only in testing.
@@ -212,6 +231,13 @@
ALOGI("%s: could not find port id for device %s", __func__, adt.toString().c_str());
return AUDIO_PORT_HANDLE_NONE;
}
+ const auto btDeviceIt = mBluetoothDevicesWithCsd.find(std::make_pair(address, type));
+ if (btDeviceIt != mBluetoothDevicesWithCsd.end()) {
+ if (!btDeviceIt->second) {
+ ALOGI("%s: bt device %s does not support sound dose", __func__, adt.toString().c_str());
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ }
return deviceIt->second;
}
@@ -260,7 +286,11 @@
in_audioDevice.address.toString().c_str());
return ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
}
- soundDoseManager->onMomentaryExposure(in_currentDbA, id);
+
+ float attenuation = soundDoseManager->getAttenuationForDeviceId(id);
+ ALOGV("%s: attenuating received momentary exposure with %f dB", __func__, attenuation);
+ // TODO: remove attenuation when enforcing HAL MELs to always be attenuated
+ soundDoseManager->onMomentaryExposure(in_currentDbA - attenuation, id);
return ndk::ScopedAStatus::ok();
}
@@ -289,9 +319,10 @@
in_audioDevice.address.toString().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);
+ soundDoseManager->onNewMelValues(in_melRecord.melValues, 0, in_melRecord.melValues.size(),
+ id, /*attenuated=*/false);
return ndk::ScopedAStatus::ok();
}
@@ -549,9 +580,6 @@
}
void SoundDoseManager::setUseFrameworkMel(bool useFrameworkMel) {
- // invalidate any HAL sound dose interface used
- resetHalSoundDoseInterfaces();
-
const std::lock_guard _l(mLock);
mUseFrameworkMel = useFrameworkMel;
}
@@ -582,7 +610,7 @@
bool SoundDoseManager::useHalSoundDose() const {
const std::lock_guard _l(mLock);
- return mHalSoundDose.size() > 0;
+ return !mUseFrameworkMel && mHalSoundDose.size() > 0;
}
void SoundDoseManager::resetSoundDose() {
@@ -604,26 +632,68 @@
}
void SoundDoseManager::onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
- audio_port_handle_t deviceId) const {
+ audio_port_handle_t deviceId, bool attenuated) const {
ALOGV("%s", __func__);
-
sp<media::ISoundDoseCallback> soundDoseCallback;
std::vector<audio_utils::CsdRecord> records;
float currentCsd;
+
+ // TODO: delete this case when enforcing HAL MELs to always be attenuated
+ float attenuation = attenuated ? 0.0f : getAttenuationForDeviceId(deviceId);
+
{
const std::lock_guard _l(mLock);
if (!mEnabledCsd) {
return;
}
-
const int64_t timestampSec = getMonotonicSecond();
- // only for internal callbacks
- records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
- deviceId, std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
- timestampSec - length));
+ if (attenuated) {
+ records = mMelAggregator->aggregateAndAddNewMelRecord(audio_utils::MelRecord(
+ deviceId,
+ std::vector<float>(mels.begin() + offset, mels.begin() + offset + length),
+ timestampSec - length));
+ } else {
+ ALOGV("%s: attenuating received values with %f dB", __func__, attenuation);
+
+ // Extracting all intervals that contain values >= RS2 low limit (80dBA) after the
+ // attenuation is applied
+ size_t start = offset;
+ size_t stop = offset;
+ for (; stop < mels.size() && stop < offset + length; ++stop) {
+ if (mels[stop] - attenuation < kDefaultRs2LowerBound) {
+ if (start < stop) {
+ std::vector<float> attMel(stop-start, -attenuation);
+ // attMel[i] = mels[i] + attenuation, i in [start, stop)
+ std::transform(mels.begin() + start, mels.begin() + stop, attMel.begin(),
+ attMel.begin(), std::plus<float>());
+ std::vector<audio_utils::CsdRecord> newRec =
+ mMelAggregator->aggregateAndAddNewMelRecord(
+ audio_utils::MelRecord(deviceId,
+ attMel,
+ timestampSec - length + start -
+ offset));
+ std::copy(newRec.begin(), newRec.end(), std::back_inserter(records));
+ }
+ start = stop+1;
+ }
+ }
+ if (start < stop) {
+ std::vector<float> attMel(stop-start, -attenuation);
+ // attMel[i] = mels[i] + attenuation, i in [start, stop)
+ std::transform(mels.begin() + start, mels.begin() + stop, attMel.begin(),
+ attMel.begin(), std::plus<float>());
+ std::vector<audio_utils::CsdRecord> newRec =
+ mMelAggregator->aggregateAndAddNewMelRecord(
+ audio_utils::MelRecord(deviceId,
+ attMel,
+ timestampSec - length + start -
+ offset));
+ std::copy(newRec.begin(), newRec.end(), std::back_inserter(records));
+ }
+ }
currentCsd = mMelAggregator->getCsd();
}
@@ -658,6 +728,10 @@
if (!mEnabledCsd) {
return;
}
+
+ if (currentMel < mRs2UpperBound) {
+ return;
+ }
}
auto soundDoseCallback = getSoundDoseCallback();
diff --git a/services/audioflinger/sounddose/SoundDoseManager.h b/services/audioflinger/sounddose/SoundDoseManager.h
index 347eabe..0c49a80 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.h
+++ b/services/audioflinger/sounddose/SoundDoseManager.h
@@ -53,6 +53,13 @@
mMelAggregator(sp<audio_utils::MelAggregator>::make(kCsdWindowSeconds)),
mRs2UpperBound(kDefaultRs2UpperBound) {};
+ // Used only for testing
+ SoundDoseManager(const sp<IMelReporterCallback>& melReporterCallback,
+ const sp<audio_utils::MelAggregator>& melAggregator)
+ : mMelReporterCallback(melReporterCallback),
+ mMelAggregator(melAggregator),
+ mRs2UpperBound(kDefaultRs2UpperBound) {};
+
/**
* \brief Creates or gets the MelProcessor assigned to the streamHandle
*
@@ -144,7 +151,7 @@
// ------ Override audio_utils::MelProcessor::MelCallback ------
void onNewMelValues(const std::vector<float>& mels, size_t offset, size_t length,
- audio_port_handle_t deviceId) const override;
+ audio_port_handle_t deviceId, bool attenuated) const override;
void onMomentaryExposure(float currentMel, audio_port_handle_t deviceId) const override;
@@ -205,6 +212,8 @@
sp<media::ISoundDoseCallback> getSoundDoseCallback() const;
+ float getAttenuationForDeviceId(audio_port_handle_t id) const;
+
void updateAttenuation(float attenuationDB, audio_devices_t deviceType);
void setCsdEnabled(bool enabled);
void setUseFrameworkMel(bool useFrameworkMel);
diff --git a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
index 294080b..1151647 100644
--- a/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
+++ b/services/audioflinger/sounddose/tests/sounddosemanager_tests.cpp
@@ -20,6 +20,7 @@
#include <SoundDoseManager.h>
#include <aidl/android/hardware/audio/core/sounddose/BnSoundDose.h>
+#include <audio_utils/MelAggregator.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <media/AidlConversionCppNdk.h>
@@ -45,6 +46,14 @@
MOCK_METHOD(void, stopMelComputationForDeviceId, (audio_port_handle_t), (override));
};
+class MelAggregatorMock : public audio_utils::MelAggregator {
+public:
+ MelAggregatorMock() : MelAggregator(100) {}
+
+ MOCK_METHOD(std::vector<audio_utils::CsdRecord>, aggregateAndAddNewMelRecord,
+ (const audio_utils::MelRecord&), (override));
+};
+
constexpr char kPrimaryModule[] = "primary";
constexpr char kSecondaryModule[] = "secondary";
@@ -52,7 +61,8 @@
protected:
void SetUp() override {
mMelReporterCallback = sp<MelReporterCallback>::make();
- mSoundDoseManager = sp<SoundDoseManager>::make(mMelReporterCallback);
+ mMelAggregator = sp<MelAggregatorMock>::make();
+ mSoundDoseManager = sp<SoundDoseManager>::make(mMelReporterCallback, mMelAggregator);
mHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
mSecondaryHalSoundDose = ndk::SharedRefBase::make<HalSoundDoseMock>();
@@ -69,6 +79,7 @@
}
sp<MelReporterCallback> mMelReporterCallback;
+ sp<MelAggregatorMock> mMelAggregator;
sp<SoundDoseManager> mSoundDoseManager;
std::shared_ptr<HalSoundDoseMock> mHalSoundDose;
std::shared_ptr<HalSoundDoseMock> mSecondaryHalSoundDose;
@@ -110,12 +121,33 @@
EXPECT_NE(processor1, processor2);
}
-TEST_F(SoundDoseManagerTest, NewMelValuesCacheNewRecord) {
- std::vector<float>mels{1, 1};
+TEST_F(SoundDoseManagerTest, NewMelValuesAttenuatedAggregateMels) {
+ std::vector<float>mels{1.f, 1.f};
- mSoundDoseManager->onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1);
+ EXPECT_CALL(*mMelAggregator.get(), aggregateAndAddNewMelRecord)
+ .Times(1)
+ .WillOnce([&] (const audio_utils::MelRecord& record) {
+ EXPECT_THAT(record.mels, ::testing::ElementsAreArray(mels));
+ return std::vector<audio_utils::CsdRecord>();
+ });
- EXPECT_EQ(mSoundDoseManager->getCachedMelRecordsSize(), size_t{1});
+ mSoundDoseManager->onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1,
+ /*attenuated=*/true);
+}
+
+TEST_F(SoundDoseManagerTest, NewMelValuesUnattenuatedAreSplit) {
+ std::vector<float>mels{79.f, 80.f, 79.f, 80.f, 79.f, 79.f, 80.f};
+
+ EXPECT_CALL(*mMelAggregator.get(), aggregateAndAddNewMelRecord)
+ .Times(3)
+ .WillRepeatedly([&] (const audio_utils::MelRecord& record) {
+ EXPECT_EQ(record.mels.size(), size_t {1});
+ EXPECT_EQ(record.mels[0], 80.f);
+ return std::vector<audio_utils::CsdRecord>();
+ });
+
+ mSoundDoseManager->onNewMelValues(mels, 0, mels.size(), /*deviceId=*/1,
+ /*attenuated=*/false);
}
TEST_F(SoundDoseManagerTest, InvalidHalInterfaceIsNotSet) {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index b164159..9ececea 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -285,7 +285,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid) = 0;
+ uid_t uid,
+ bool internal = false) = 0;
virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 13b70e5..7c70877 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -364,7 +364,7 @@
void dump(String8 *dst, int spaces, const char* extraInfo = nullptr) const override;
virtual DeviceVector devices() const;
- void setDevices(const DeviceVector &devices) { mDevices = devices; }
+ void setDevices(const DeviceVector &devices);
bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc);
virtual DeviceVector supportedDevices() const;
virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index b560bc4..f066c09 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -61,7 +61,7 @@
status_t updateMix(const AudioMix& mix, const std::vector<AudioMixMatchCriterion>& newCriteria);
- void closeOutput(sp<SwAudioOutputDescriptor> &desc);
+ void closeOutput(sp<SwAudioOutputDescriptor> &desc, const SwAudioOutputCollection& allOutputs);
/**
* Tries to find the best matching audio policy mix
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 7119b85..fe90a1e 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -222,7 +222,8 @@
const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice,
audio_stream_type_t stream, product_strategy_t strategy,
- VolumeSource volumeSource);
+ VolumeSource volumeSource,
+ bool isInternal);
~SourceClientDescriptor() override = default;
@@ -248,6 +249,7 @@
void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput, bool closeOutput = false);
wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
+ bool isInternal() const override { return mIsInternal; }
using ClientDescriptor::dump;
void dump(String8 *dst, int spaces) const override;
@@ -268,34 +270,17 @@
* behavior of AudioDeviceCallback.
*/
bool mCloseOutput = false;
-};
-
-/**
- * @brief The InternalSourceClientDescriptor class
- * Specialized Client Descriptor for either a raw patch created from @see createAudioPatch API
- * or for internal audio patches managed by APM (e.g. phone call patches).
- * Whatever the bridge created (software or hardware), we need a client to track the activity
- * and manage volumes.
- * The Audio Patch requested sink is expressed as a preferred device which allows to route
- * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
- * requester to prevent rerouting SwOutput involved in raw patches.
- */
-class InternalSourceClientDescriptor: public SourceClientDescriptor
-{
-public:
- InternalSourceClientDescriptor(
- audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
- const struct audio_port_config &config, const sp<DeviceDescriptor>& srcDevice,
- const sp<DeviceDescriptor>& sinkDevice,
- product_strategy_t strategy, VolumeSource volumeSource) :
- SourceClientDescriptor(
- portId, uid, attributes, config, srcDevice, AUDIO_STREAM_PATCH, strategy,
- volumeSource)
- {
- setPreferredDeviceId(sinkDevice->getId());
- }
- bool isInternal() const override { return true; }
- ~InternalSourceClientDescriptor() override = default;
+ /**
+ * True for specialized Client Descriptor for either a raw patch created from
+ * @see createAudioPatch API or for internal audio patches managed by APM
+ * (e.g. phone call patches).
+ * Whatever the bridge created (software or hardware), we need a client to track the activity
+ * and manage volumes.
+ * The Audio Patch requested sink is expressed as a preferred device which allows to route
+ * the SwOutput. Then APM will performs checks on the UID (against UID of Audioserver) of the
+ * requester to prevent rerouting SwOutput involved in raw patches.
+ */
+ bool mIsInternal = false;
};
class SourceClientCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 6c130fd..c502fc2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -93,6 +93,8 @@
void setEncapsulationInfoFromHal(AudioPolicyClientInterface *clientInterface);
+ void setPreferredConfig(const audio_config_base_t * preferredConfig);
+
void dump(String8 *dst, int spaces, bool verbose = true) const;
private:
@@ -107,6 +109,7 @@
audio_format_t mCurrentEncodedFormat;
bool mIsDynamic = false;
std::string mDeclaredAddress; // Original device address
+ std::optional<audio_config_base_t> mPreferredConfig;
};
class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index cf20260..d206637 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -89,10 +89,12 @@
status_t addProfile(const sp<IOProfile> &profile);
status_t addOutputProfile(const std::string& name, const audio_config_t *config,
- audio_devices_t device, const String8& address);
+ audio_devices_t device, const String8& address,
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE);
status_t removeOutputProfile(const std::string& name);
status_t addInputProfile(const std::string& name, const audio_config_t *config,
- audio_devices_t device, const String8& address);
+ audio_devices_t device, const String8& address,
+ audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE);
status_t removeInputProfile(const std::string& name);
audio_module_handle_t getHandle() const { return mHandle; }
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index d027564..6537a00 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -778,6 +778,19 @@
}
}
+void SwAudioOutputDescriptor::setDevices(const android::DeviceVector &devices) {
+ if ((mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) == AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ for (auto device : mDevices) {
+ device->setPreferredConfig(nullptr);
+ }
+ auto config = getConfig();
+ for (auto device : devices) {
+ device->setPreferredConfig(&config);
+ }
+ }
+ mDevices = devices;
+}
+
// HwAudioOutputDescriptor implementation
HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface)
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 7ee75c7..dc0f466 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -272,12 +272,33 @@
return BAD_VALUE;
}
-void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc)
+void AudioPolicyMixCollection::closeOutput(sp<SwAudioOutputDescriptor> &desc,
+ const SwAudioOutputCollection& allOutputs)
{
for (size_t i = 0; i < size(); i++) {
sp<AudioPolicyMix> policyMix = itemAt(i);
- if (policyMix->getOutput() == desc) {
- policyMix->clearOutput();
+ if (policyMix->getOutput() != desc) {
+ continue;
+ }
+ policyMix->clearOutput();
+ if (policyMix->mRouteFlags != MIX_ROUTE_FLAG_RENDER) {
+ continue;
+ }
+ auto device = desc->supportedDevices().getDevice(
+ policyMix->mDeviceType, policyMix->mDeviceAddress, AUDIO_FORMAT_DEFAULT);
+ if (device == nullptr) {
+ // This must not happen
+ ALOGE("%s, the rerouted device is not found", __func__);
+ continue;
+ }
+ // Restore the policy mix mix output to the first opened output supporting a route to
+ // the mix device. This is because the current mix output can be changed to a direct output.
+ for (size_t j = 0; j < allOutputs.size(); ++j) {
+ if (allOutputs[i] != desc && !allOutputs[i]->isDuplicated() &&
+ allOutputs[i]->supportedDevices().contains(device)) {
+ policyMix->setOutput(allOutputs[i]);
+ break;
+ }
}
}
}
@@ -335,13 +356,6 @@
"audio policy mix.", __func__);
return INVALID_OPERATION;
}
- if (mixDevice != nullptr) {
- // TODO(b/301619865): Only disallow the device that doesn't support MMAP.
- ALOGD("%s: Rejecting MMAP_NOIRQ request matched to dynamic audio policy "
- "mix pointing to device %s which the mmap support is unknown at this moment",
- __func__, mixDevice->toString(false).c_str());
- return INVALID_OPERATION;
- }
}
if (mixDevice != nullptr && mixDevice->equals(requestedDevice)) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 8b6866e..2aee501 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -96,12 +96,12 @@
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
audio_attributes_t attributes, const struct audio_port_config &config,
const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream,
- product_strategy_t strategy, VolumeSource volumeSource) :
+ product_strategy_t strategy, VolumeSource volumeSource, bool isInternal) :
TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
{config.sample_rate, config.channel_mask, config.format}, AUDIO_PORT_HANDLE_NONE,
stream, strategy, volumeSource, AUDIO_OUTPUT_FLAG_NONE, false,
{} /* Sources do not support secondary outputs*/, nullptr),
- mSrcDevice(srcDevice)
+ mSrcDevice(srcDevice), mIsInternal(isInternal)
{
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index fe25693..9f7b8fc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -132,6 +132,20 @@
{
DeviceDescriptorBase::toAudioPortConfig(dstConfig, srcConfig);
dstConfig->ext.device.hw_module = getModuleHandle();
+ if (mPreferredConfig.has_value()) {
+ if (mPreferredConfig->format != AUDIO_FORMAT_DEFAULT) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_FORMAT;
+ dstConfig->format = mPreferredConfig->format;
+ }
+ if (mPreferredConfig->sample_rate != 0) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_SAMPLE_RATE;
+ dstConfig->sample_rate = mPreferredConfig->sample_rate;
+ }
+ if (mPreferredConfig->channel_mask != AUDIO_CHANNEL_NONE) {
+ dstConfig->config_mask |= AUDIO_PORT_CONFIG_CHANNEL_MASK;
+ dstConfig->channel_mask = mPreferredConfig->channel_mask;
+ }
+ }
}
void DeviceDescriptor::toAudioPort(struct audio_port *port) const
@@ -183,6 +197,14 @@
}
}
+void DeviceDescriptor::setPreferredConfig(const audio_config_base_t* preferredConfig) {
+ if (preferredConfig == nullptr) {
+ mPreferredConfig.reset();
+ } else {
+ mPreferredConfig = *preferredConfig;
+ }
+}
+
void DeviceDescriptor::dump(String8 *dst, int spaces, bool verbose) const
{
String8 extraInfo;
@@ -193,6 +215,13 @@
std::string descBaseDumpStr;
DeviceDescriptorBase::dump(&descBaseDumpStr, spaces, extraInfo.c_str(), verbose);
dst->append(descBaseDumpStr.c_str());
+
+ if (mPreferredConfig.has_value()) {
+ dst->append(base::StringPrintf(
+ "%*sPreferred Config: format=%#x, channelMask=%#x, sampleRate=%u\n",
+ spaces, "", mPreferredConfig.value().format, mPreferredConfig.value().channel_mask,
+ mPreferredConfig.value().sample_rate).c_str());
+ }
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index cb45f54..6696b45 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -59,12 +59,13 @@
}
status_t HwModule::addOutputProfile(const std::string& name, const audio_config_t *config,
- audio_devices_t device, const String8& address)
+ audio_devices_t device, const String8& address,
+ audio_output_flags_t flags)
{
sp<IOProfile> profile = new OutputProfile(name);
-
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
+ profile->setFlags(flags);
sp<DeviceDescriptor> devDesc =
new DeviceDescriptor(device, getTagForDevice(device), address.c_str());
@@ -128,11 +129,13 @@
}
status_t HwModule::addInputProfile(const std::string& name, const audio_config_t *config,
- audio_devices_t device, const String8& address)
+ audio_devices_t device, const String8& address,
+ audio_input_flags_t flags)
{
sp<IOProfile> profile = new InputProfile(name);
profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
config->sample_rate));
+ profile->setFlags(flags);
sp<DeviceDescriptor> devDesc =
new DeviceDescriptor(device, getTagForDevice(device), address.c_str());
diff --git a/services/audiopolicy/managerdefault/Android.bp b/services/audiopolicy/managerdefault/Android.bp
index a1785da..6a37b4e 100644
--- a/services/audiopolicy/managerdefault/Android.bp
+++ b/services/audiopolicy/managerdefault/Android.bp
@@ -22,6 +22,7 @@
export_include_dirs: ["."],
shared_libs: [
+ "com.android.media.audio-aconfig-cc",
"libaudiofoundation",
"libaudiopolicycomponents",
"libcutils",
@@ -42,6 +43,8 @@
"framework-permission-aidl-cpp",
"libaudioclient_aidl_conversion",
"audioclient-types-aidl-cpp",
+ // Flag support
+ "com.android.media.audioserver-aconfig-cc"
],
header_libs: [
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 69d3b5d..6160f77 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -18,7 +18,7 @@
#define LOG_TAG "APM_AudioPolicyManager"
// Need to keep the log statements even in production builds
-// to enable VERBOSE logging dynamically.
+// to enable VERBOSE logging dynamicstartAudioSourceally.
// You can enable VERBOSE logging as follows:
// adb shell setprop log.tag.APM_AudioPolicyManager V
#define LOG_NDEBUG 0
@@ -41,6 +41,8 @@
#include <Serializer.h>
#include <android/media/audio/common/AudioPort.h>
+#include <com_android_media_audio.h>
+#include <com_android_media_audioserver.h>
#include <cutils/bitops.h>
#include <cutils/properties.h>
#include <media/AudioParameter.h>
@@ -780,7 +782,11 @@
.ext.device.type = AUDIO_DEVICE_IN_TELEPHONY_RX, .ext.device.address = ""
};
const auto aa = mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL);
- mCallRxSourceClient = startAudioSourceInternal(&source, &aa, 0/*uid*/);
+
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ status_t status = startAudioSource(&source, &aa, &portId, 0 /*uid*/, true /*internal*/);
+ ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
+ mCallRxSourceClient = mAudioSources.valueFor(portId);
ALOGE_IF(mCallRxSourceClient == nullptr,
"%s failed to start Telephony Rx AudioSource", __func__);
}
@@ -813,9 +819,11 @@
struct audio_port_config source = {};
srcDevice->toAudioPortConfig(&source);
- mCallTxSourceClient = new InternalSourceClientDescriptor(
- callTxSourceClientPortId, mUidCached, aa, source, srcDevice, sinkDevice,
- mCommunnicationStrategy, toVolumeSource(aa));
+ mCallTxSourceClient = new SourceClientDescriptor(
+ callTxSourceClientPortId, mUidCached, aa, source, srcDevice, AUDIO_STREAM_PATCH,
+ mCommunnicationStrategy, toVolumeSource(aa), true);
+ mCallTxSourceClient->setPreferredDeviceId(sinkDevice->getId());
+
audio_patch_handle_t patchHandle = AUDIO_PATCH_HANDLE_NONE;
status_t status = connectAudioSourceToSink(
mCallTxSourceClient, sinkDevice, patchBuilder.patch(), patchHandle, mUidCached,
@@ -1217,13 +1225,14 @@
return BAD_VALUE;
}
if (usePrimaryOutputFromPolicyMixes) {
- sp<DeviceDescriptor> deviceDesc =
+ sp<DeviceDescriptor> policyMixDevice =
mAvailableOutputDevices.getDevice(primaryMix->mDeviceType,
primaryMix->mDeviceAddress,
AUDIO_FORMAT_DEFAULT);
sp<SwAudioOutputDescriptor> policyDesc = primaryMix->getOutput();
bool tryDirectForFlags = policyDesc == nullptr ||
- (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT);
+ (policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) ||
+ (*flags & (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ));
// if a direct output can be opened to deliver the track's multi-channel content to the
// output rather than being downmixed by the primary output, then use this direct
// output by by-passing the primary mix if possible, otherwise fall-through to primary
@@ -1231,23 +1240,29 @@
bool tryDirectForChannelMask = policyDesc != nullptr
&& (audio_channel_count_from_out_mask(policyDesc->getConfig().channel_mask) <
audio_channel_count_from_out_mask(config->channel_mask));
- if (deviceDesc != nullptr && (tryDirectForFlags || tryDirectForChannelMask)) {
+ if (policyMixDevice != nullptr && (tryDirectForFlags || tryDirectForChannelMask)) {
audio_io_handle_t newOutput;
status = openDirectOutput(
*stream, session, config,
(audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_DIRECT),
- DeviceVector(deviceDesc), &newOutput);
+ DeviceVector(policyMixDevice), &newOutput);
if (status == NO_ERROR) {
policyDesc = mOutputs.valueFor(newOutput);
primaryMix->setOutput(policyDesc);
} else if (tryDirectForFlags) {
+ ALOGW("%s, failed open direct, status: %d", __func__, status);
policyDesc = nullptr;
} // otherwise use primary if available.
}
if (policyDesc != nullptr) {
policyDesc->mPolicyMix = primaryMix;
*output = policyDesc->mIoHandle;
- *selectedDeviceId = deviceDesc != 0 ? deviceDesc->getId() : AUDIO_PORT_HANDLE_NONE;
+ *selectedDeviceId = policyMixDevice != nullptr ? policyMixDevice->getId()
+ : AUDIO_PORT_HANDLE_NONE;
+ if ((policyDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != AUDIO_OUTPUT_FLAG_DIRECT) {
+ // Remove direct flag as it is not on a direct output.
+ *flags = (audio_output_flags_t) (*flags & ~AUDIO_OUTPUT_FLAG_DIRECT);
+ }
ALOGV("getOutputForAttr() returns output %d", *output);
if (resultAttr->usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
@@ -1256,6 +1271,13 @@
*outputType = API_OUTPUT_LEGACY;
}
return NO_ERROR;
+ } else {
+ if (policyMixDevice != nullptr) {
+ ALOGE("%s, try to use primary mix but no output found", __func__);
+ return INVALID_OPERATION;
+ }
+ // Fallback to default engine selection as the selected primary mix device is not
+ // available.
}
}
// Virtual sources must always be dynamicaly or explicitly routed
@@ -1494,11 +1516,30 @@
}
if (!profile->canOpenNewIo()) {
+ if (!com::android::media::audioserver::direct_track_reprioritization()) {
+ return NAME_NOT_FOUND;
+ } else if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) != 0) {
+ // MMAP gracefully handles lack of an exclusive track resource by mixing
+ // above the audio framework. For AAudio to know that the limit is reached,
+ // return an error.
+ return NAME_NOT_FOUND;
+ } else {
+ // Close outputs on this profile, if available, to free resources for this request
+ for (int i = 0; i < mOutputs.size() && !profile->canOpenNewIo(); i++) {
+ const auto desc = mOutputs.valueAt(i);
+ if (desc->mProfile == profile) {
+ closeOutput(desc->mIoHandle);
+ }
+ }
+ }
+ }
+
+ // Unable to close streams to find free resources for this request
+ if (!profile->canOpenNewIo()) {
return NAME_NOT_FOUND;
}
- sp<SwAudioOutputDescriptor> outputDesc =
- new SwAudioOutputDescriptor(profile, mpClientInterface);
+ auto outputDesc = sp<SwAudioOutputDescriptor>::make(profile, mpClientInterface);
// An MSD patch may be using the only output stream that can service this request. Release
// all MSD patches to prioritize this request over any active output on MSD.
@@ -1593,7 +1634,8 @@
*isSpatialized = false;
if (mSpatializerOutput != nullptr
- && canBeSpatializedInt(attr, config, devices.toTypeAddrVector())) {
+ && canBeSpatializedInt(attr, config, devices.toTypeAddrVector())
+ && prefMixerConfigInfo == nullptr) {
*isSpatialized = true;
return mSpatializerOutput->mIoHandle;
}
@@ -3246,7 +3288,8 @@
ALOGD("%s: no group matching with %s", __FUNCTION__, toString(attributes).c_str());
return BAD_VALUE;
}
- ALOGV("%s: group %d matching with %s", __FUNCTION__, group, toString(attributes).c_str());
+ ALOGV("%s: group %d matching with %s index %d",
+ __FUNCTION__, group, toString(attributes).c_str(), index);
status_t status = NO_ERROR;
IVolumeCurves &curves = getVolumeCurves(attributes);
VolumeSource vs = toVolumeSource(group);
@@ -3363,6 +3406,21 @@
status = volStatus;
}
}
+
+ // update voice volume if the an active call route exists
+ if (mCallRxSourceClient != nullptr && mCallRxSourceClient->isConnected()
+ && (curSrcDevices.find(
+ Volume::getDeviceForVolume({mCallRxSourceClient->sinkDevice()->type()}))
+ != curSrcDevices.end())) {
+ bool isVoiceVolSrc;
+ bool isBtScoVolSrc;
+ if (isVolumeConsistentForCalls(vs, {mCallRxSourceClient->sinkDevice()->type()},
+ isVoiceVolSrc, isBtScoVolSrc, __func__)
+ && (isVoiceVolSrc || isBtScoVolSrc)) {
+ setVoiceVolume(index, curves, isVoiceVolSrc, 0);
+ }
+ }
+
mpClientInterface->onAudioVolumeGroupChanged(group, 0 /*flags*/);
return status;
}
@@ -3659,9 +3717,13 @@
outputConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
inputConfig.channel_mask = AUDIO_CHANNEL_IN_STEREO;
rSubmixModule->addOutputProfile(address.c_str(), &outputConfig,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address);
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, address,
+ audio_is_linear_pcm(outputConfig.format)
+ ? AUDIO_OUTPUT_FLAG_NONE : AUDIO_OUTPUT_FLAG_DIRECT);
rSubmixModule->addInputProfile(address.c_str(), &inputConfig,
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, address);
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX, address,
+ audio_is_linear_pcm(inputConfig.format)
+ ? AUDIO_INPUT_FLAG_NONE : AUDIO_INPUT_FLAG_DIRECT);
if ((res = setDeviceConnectionStateInt(deviceTypeToMakeAvailable,
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
@@ -4430,8 +4492,8 @@
if (!mAvailableOutputDevices.containsAtLeastOne(curProfile->getSupportedDevices())) {
continue;
}
- if ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
- != AUDIO_OUTPUT_FLAG_NONE) {
+ if (offloadPossible && ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
+ != AUDIO_OUTPUT_FLAG_NONE)) {
if ((directMode & AUDIO_DIRECT_OFFLOAD_GAPLESS_SUPPORTED)
!= AUDIO_DIRECT_NOT_SUPPORTED) {
// Already reports offload gapless supported. No need to report offload support.
@@ -4818,9 +4880,11 @@
audio_attributes_t attributes = attributes_initializer(AUDIO_USAGE_MEDIA);
const struct audio_port_config *source = &patch->sources[0];
sp<SourceClientDescriptor> sourceDesc =
- new InternalSourceClientDescriptor(
- portId, uid, attributes, *source, srcDevice, sinkDevice,
- mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes));
+ new SourceClientDescriptor(
+ portId, uid, attributes, *source, srcDevice, AUDIO_STREAM_PATCH,
+ mEngine->getProductStrategyForAttributes(attributes), toVolumeSource(attributes),
+ true);
+ sourceDesc->setPreferredDeviceId(sinkDevice->getId());
status_t status =
connectAudioSourceToSink(sourceDesc, sinkDevice, patch, *handle, uid, 0 /* delayMs */);
@@ -5487,7 +5551,7 @@
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid)
+ uid_t uid, bool internal)
{
ALOGV("%s", __FUNCTION__);
*portId = AUDIO_PORT_HANDLE_NONE;
@@ -5520,7 +5584,7 @@
new SourceClientDescriptor(*portId, uid, *attributes, *source, srcDevice,
mEngine->getStreamTypeForAttributes(*attributes),
mEngine->getProductStrategyForAttributes(*attributes),
- toVolumeSource(*attributes));
+ toVolumeSource(*attributes), internal);
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
@@ -5529,18 +5593,6 @@
return status;
}
-sp<SourceClientDescriptor> AudioPolicyManager::startAudioSourceInternal(
- const struct audio_port_config *source, const audio_attributes_t *attributes, uid_t uid)
-{
- ALOGV("%s", __FUNCTION__);
- audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
-
- status_t status = startAudioSource(source, attributes, &portId, uid);
- ALOGE_IF(status != OK, "%s: failed to start audio source (%d)", __func__, status);
- return mAudioSources.valueFor(portId);
-}
-
-
status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
@@ -5952,7 +6004,11 @@
// some positional channel masks and PCM format
if (config != nullptr && *config != AUDIO_CONFIG_INITIALIZER) {
- if (!audio_is_channel_mask_spatialized(config->channel_mask)) {
+ const bool channel_mask_spatialized =
+ com_android_media_audio_stereo_spatialization()
+ ? audio_channel_mask_contains_stereo(config->channel_mask)
+ : audio_is_channel_mask_spatialized(config->channel_mask);
+ if (!channel_mask_spatialized) {
return false;
}
if (!audio_is_linear_pcm(config->format)) {
@@ -6689,7 +6745,7 @@
return;
}
const bool closingOutputWasActive = closingOutput->isActive();
- mPolicyMixes.closeOutput(closingOutput);
+ mPolicyMixes.closeOutput(closingOutput, mOutputs);
// look for duplicated outputs connected to the output being removed.
for (size_t i = 0; i < mOutputs.size(); i++) {
@@ -6733,6 +6789,12 @@
closingOutput->stop();
}
closingOutput->close();
+ if ((closingOutput->getFlags().output & AUDIO_OUTPUT_FLAG_BIT_PERFECT)
+ == AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ for (const auto device : closingOutput->devices()) {
+ device->setPreferredConfig(nullptr);
+ }
+ }
removeOutput(output);
mPreviousOutputs = mOutputs;
@@ -7853,26 +7915,16 @@
outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
return NO_ERROR;
}
- VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
- VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
- bool isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
- bool isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
- bool isScoRequested = isScoRequestedForComm();
- bool isHAUsed = isHearingAidUsedForComm();
-
- // do not change in call volume if bluetooth is connected and vice versa
- // if sco and call follow same curves, bypass forceUseForComm
- if ((callVolSrc != btScoVolSrc) &&
- ((isVoiceVolSrc && isScoRequested) ||
- (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
- !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
- ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__,
- volumeSource, isScoRequested ? " " : " not ");
+ bool isVoiceVolSrc;
+ bool isBtScoVolSrc;
+ if (!isVolumeConsistentForCalls(
+ volumeSource, deviceTypes, isVoiceVolSrc, isBtScoVolSrc, __func__)) {
// Do not return an error here as AudioService will always set both voice call
- // and bluetooth SCO volumes due to stream aliasing.
+ // and Bluetooth SCO volumes due to stream aliasing.
return NO_ERROR;
}
+
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
index = curves.getVolumeIndex(deviceTypes);
@@ -7897,21 +7949,51 @@
deviceTypes, delayMs, force, isVoiceVolSrc);
if (outputDesc == mPrimaryOutput && (isVoiceVolSrc || isBtScoVolSrc)) {
- float voiceVolume;
- // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed by the headset
- if (isVoiceVolSrc) {
- voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
- } else {
- voiceVolume = index == 0 ? 0.0 : 1.0;
- }
- if (voiceVolume != mLastVoiceVolume) {
- mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
- mLastVoiceVolume = voiceVolume;
- }
+ setVoiceVolume(index, curves, isVoiceVolSrc, delayMs);
}
return NO_ERROR;
}
+void AudioPolicyManager::setVoiceVolume(
+ int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs) {
+ float voiceVolume;
+ // Force voice volume to max or mute for Bluetooth SCO as other attenuations are managed
+ // by the headset
+ if (isVoiceVolSrc) {
+ voiceVolume = (float)index/(float)curves.getVolumeIndexMax();
+ } else {
+ voiceVolume = index == 0 ? 0.0 : 1.0;
+ }
+ if (voiceVolume != mLastVoiceVolume) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+}
+
+bool AudioPolicyManager::isVolumeConsistentForCalls(VolumeSource volumeSource,
+ const DeviceTypeSet& deviceTypes,
+ bool& isVoiceVolSrc,
+ bool& isBtScoVolSrc,
+ const char* caller) {
+ const VolumeSource callVolSrc = toVolumeSource(AUDIO_STREAM_VOICE_CALL, false);
+ const VolumeSource btScoVolSrc = toVolumeSource(AUDIO_STREAM_BLUETOOTH_SCO, false);
+ const bool isScoRequested = isScoRequestedForComm();
+ const bool isHAUsed = isHearingAidUsedForComm();
+
+ isVoiceVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (callVolSrc == volumeSource);
+ isBtScoVolSrc = (volumeSource != VOLUME_SOURCE_NONE) && (btScoVolSrc == volumeSource);
+
+ if ((callVolSrc != btScoVolSrc) &&
+ ((isVoiceVolSrc && isScoRequested) ||
+ (isBtScoVolSrc && !(isScoRequested || isHAUsed))) &&
+ !isSingleDeviceType(deviceTypes, AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
+ ALOGV("%s cannot set volume group %d volume when is%srequested for comm", caller,
+ volumeSource, isScoRequested ? " " : " not ");
+ return false;
+ }
+ return true;
+}
+
void AudioPolicyManager::applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
const DeviceTypeSet& deviceTypes,
int delayMs,
@@ -8347,6 +8429,12 @@
ALOGE("%s failed to open output %d", __func__, status);
return nullptr;
}
+ if ((flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) == AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ auto portConfig = desc->getConfig();
+ for (const auto& device : devices) {
+ device->setPreferredConfig(&portConfig);
+ }
+ }
// Here is where the out_set_parameters() for card & device gets called
sp<DeviceDescriptor> device = devices.getDeviceForOpening();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index a1c8f62..ea60c2b 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -339,7 +339,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
audio_port_handle_t *portId,
- uid_t uid);
+ uid_t uid,
+ bool internal = false);
virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
@@ -580,6 +581,20 @@
DeviceTypeSet deviceTypes,
int delayMs = 0, bool force = false);
+ void setVoiceVolume(int index, IVolumeCurves &curves, bool isVoiceVolSrc, int delayMs);
+
+ // returns true if the supplied set of volume source and devices are consistent with
+ // call volume rules:
+ // if Bluetooth SCO and voice call use different volume curves:
+ // - do not apply voice call volume if Bluetooth SCO is used for call
+ // - do not apply Bluetooth SCO volume if SCO or Hearing Aid is not used for call.
+ // Also updates the booleans isVoiceVolSrc and isBtScoVolSrc according to the
+ // volume source supplied.
+ bool isVolumeConsistentForCalls(VolumeSource volumeSource,
+ const DeviceTypeSet& deviceTypes,
+ bool& isVoiceVolSrc,
+ bool& isBtScoVolSrc,
+ const char* caller);
// apply all stream volumes to the specified output and device
void applyStreamVolumes(const sp<AudioOutputDescriptor>& outputDesc,
const DeviceTypeSet& deviceTypes,
@@ -1041,9 +1056,6 @@
bool isMsdPatch(const audio_patch_handle_t &handle) const;
private:
- sp<SourceClientDescriptor> startAudioSourceInternal(
- const struct audio_port_config *source, const audio_attributes_t *attributes,
- uid_t uid);
void onNewAudioModulesAvailableInt(DeviceVector *newDevices);
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 7584632..6de71a3 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -164,6 +164,8 @@
status_t status = af->openInput(request, &response);
if (status == OK) {
*input = VALUE_OR_RETURN_STATUS(aidl2legacy_int32_t_audio_module_handle_t(response.input));
+ *config = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioConfig_audio_config_t(response.config, true /*isInput*/));
}
return status;
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 85b7ad9..71edd57 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -42,15 +42,19 @@
// ----------------------------------------------------------------------------
AudioPolicyEffects::AudioPolicyEffects(const sp<EffectsFactoryHalInterface>& effectsFactoryHal) {
+ // Note: clang thread-safety permits the ctor to call guarded _l methods without
+ // acquiring the associated mutex capability as standard practice is to assume
+ // single threaded construction and destruction.
+
// load xml config with effectsFactoryHal
- status_t loadResult = loadAudioEffectConfig(effectsFactoryHal);
+ status_t loadResult = loadAudioEffectConfig_ll(effectsFactoryHal);
if (loadResult < 0) {
ALOGW("Failed to query effect configuration, fallback to load .conf");
// load automatic audio effect modules
if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
- loadAudioEffectConfigLegacy(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+ loadAudioEffectConfigLegacy_l(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
} else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
- loadAudioEffectConfigLegacy(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ loadAudioEffectConfigLegacy_l(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
}
} else if (loadResult > 0) {
ALOGE("Effect config is partially invalid, skipped %d elements", loadResult);
@@ -62,35 +66,6 @@
std::launch::async, &AudioPolicyEffects::initDefaultDeviceEffects, this);
}
-AudioPolicyEffects::~AudioPolicyEffects()
-{
- size_t i = 0;
- // release audio input processing resources
- for (i = 0; i < mInputSources.size(); i++) {
- delete mInputSources.valueAt(i);
- }
- mInputSources.clear();
-
- for (i = 0; i < mInputSessions.size(); i++) {
- mInputSessions.valueAt(i)->mEffects.clear();
- delete mInputSessions.valueAt(i);
- }
- mInputSessions.clear();
-
- // release audio output processing resources
- for (i = 0; i < mOutputStreams.size(); i++) {
- delete mOutputStreams.valueAt(i);
- }
- mOutputStreams.clear();
-
- for (i = 0; i < mOutputSessions.size(); i++) {
- mOutputSessions.valueAt(i)->mEffects.clear();
- delete mOutputSessions.valueAt(i);
- }
- mOutputSessions.clear();
-}
-
-
status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input,
audio_source_t inputSource,
audio_session_t audioSession)
@@ -101,48 +76,43 @@
audio_source_t aliasSource = (inputSource == AUDIO_SOURCE_HOTWORD) ?
AUDIO_SOURCE_VOICE_RECOGNITION : inputSource;
- Mutex::Autolock _l(mLock);
- ssize_t index = mInputSources.indexOfKey(aliasSource);
- if (index < 0) {
+ audio_utils::lock_guard _l(mMutex);
+ auto sourceIt = mInputSources.find(aliasSource);
+ if (sourceIt == mInputSources.end()) {
ALOGV("addInputEffects(): no processing needs to be attached to this source");
return status;
}
- ssize_t idx = mInputSessions.indexOfKey(audioSession);
- EffectVector *sessionDesc;
- if (idx < 0) {
- sessionDesc = new EffectVector(audioSession);
- mInputSessions.add(audioSession, sessionDesc);
- } else {
- // EffectVector is existing and we just need to increase ref count
- sessionDesc = mInputSessions.valueAt(idx);
+ std::shared_ptr<EffectVector>& sessionDesc = mInputSessions[audioSession];
+ if (sessionDesc == nullptr) {
+ sessionDesc = std::make_shared<EffectVector>(audioSession);
}
sessionDesc->mRefCount++;
ALOGV("addInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
if (sessionDesc->mRefCount == 1) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
- Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
- for (size_t i = 0; i < effects.size(); i++) {
- EffectDesc *effect = effects[i];
+ const std::shared_ptr<EffectDescVector>& effects = sourceIt->second;
+ for (const std::shared_ptr<EffectDesc>& effect : *effects) {
AttributionSourceState attributionSource;
attributionSource.packageName = "android";
attributionSource.token = sp<BBinder>::make();
- sp<AudioEffect> fx = new AudioEffect(attributionSource);
+ auto fx = sp<AudioEffect>::make(attributionSource);
fx->set(nullptr /*type */, &effect->mUuid, -1 /* priority */, nullptr /* callback */,
audioSession, input);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGW("addInputEffects(): failed to create Fx %s on source %d",
- effect->mName, (int32_t)aliasSource);
+ effect->mName.c_str(), (int32_t)aliasSource);
// fx goes out of scope and strong ref on AudioEffect is released
continue;
}
for (size_t j = 0; j < effect->mParams.size(); j++) {
- fx->setParameter(effect->mParams[j]);
+ // const_cast here due to API.
+ fx->setParameter(const_cast<effect_param_t*>(effect->mParams[j].get()));
}
ALOGV("addInputEffects(): added Fx %s on source: %d",
- effect->mName, (int32_t)aliasSource);
- sessionDesc->mEffects.add(fx);
+ effect->mName.c_str(), (int32_t)aliasSource);
+ sessionDesc->mEffects.push_back(std::move(fx));
}
sessionDesc->setProcessorEnabled(true);
IPCThreadState::self()->restoreCallingIdentity(token);
@@ -156,18 +126,17 @@
{
status_t status = NO_ERROR;
- Mutex::Autolock _l(mLock);
- ssize_t index = mInputSessions.indexOfKey(audioSession);
- if (index < 0) {
+ audio_utils::lock_guard _l(mMutex);
+ auto it = mInputSessions.find(audioSession);
+ if (it == mInputSessions.end()) {
return status;
}
- EffectVector *sessionDesc = mInputSessions.valueAt(index);
+ std::shared_ptr<EffectVector> sessionDesc = it->second;
sessionDesc->mRefCount--;
ALOGV("releaseInputEffects(): input: %d, refCount: %d", input, sessionDesc->mRefCount);
if (sessionDesc->mRefCount == 0) {
sessionDesc->setProcessorEnabled(false);
- delete sessionDesc;
- mInputSessions.removeItemsAt(index);
+ mInputSessions.erase(it);
ALOGV("releaseInputEffects(): all effects released");
}
return status;
@@ -179,24 +148,16 @@
{
status_t status = NO_ERROR;
- Mutex::Autolock _l(mLock);
- size_t index;
- for (index = 0; index < mInputSessions.size(); index++) {
- if (mInputSessions.valueAt(index)->mSessionId == audioSession) {
- break;
- }
- }
- if (index == mInputSessions.size()) {
+ audio_utils::lock_guard _l(mMutex);
+ auto it = mInputSessions.find(audioSession);
+ if (it == mInputSessions.end()) {
*count = 0;
return BAD_VALUE;
}
- Vector< sp<AudioEffect> > effects = mInputSessions.valueAt(index)->mEffects;
-
- for (size_t i = 0; i < effects.size(); i++) {
- effect_descriptor_t desc = effects[i]->descriptor();
- if (i < *count) {
- descriptors[i] = desc;
- }
+ const std::vector<sp<AudioEffect>>& effects = it->second->mEffects;
+ const size_t copysize = std::min(effects.size(), (size_t)*count);
+ for (size_t i = 0; i < copysize; i++) {
+ descriptors[i] = effects[i]->descriptor();
}
if (effects.size() > *count) {
status = NO_MEMORY;
@@ -212,24 +173,16 @@
{
status_t status = NO_ERROR;
- Mutex::Autolock _l(mLock);
- size_t index;
- for (index = 0; index < mOutputSessions.size(); index++) {
- if (mOutputSessions.valueAt(index)->mSessionId == audioSession) {
- break;
- }
- }
- if (index == mOutputSessions.size()) {
+ audio_utils::lock_guard _l(mMutex);
+ auto it = mOutputSessions.find(audioSession);
+ if (it == mOutputSessions.end()) {
*count = 0;
return BAD_VALUE;
}
- Vector< sp<AudioEffect> > effects = mOutputSessions.valueAt(index)->mEffects;
-
- for (size_t i = 0; i < effects.size(); i++) {
- effect_descriptor_t desc = effects[i]->descriptor();
- if (i < *count) {
- descriptors[i] = desc;
- }
+ const std::vector<sp<AudioEffect>>& effects = it->second->mEffects;
+ const size_t copysize = std::min(effects.size(), (size_t)*count);
+ for (size_t i = 0; i < copysize; i++) {
+ descriptors[i] = effects[i]->descriptor();
}
if (effects.size() > *count) {
status = NO_MEMORY;
@@ -245,27 +198,22 @@
{
status_t status = NO_ERROR;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// create audio processors according to stream
// FIXME: should we have specific post processing settings for internal streams?
// default to media for now.
if (stream >= AUDIO_STREAM_PUBLIC_CNT) {
stream = AUDIO_STREAM_MUSIC;
}
- ssize_t index = mOutputStreams.indexOfKey(stream);
- if (index < 0) {
+ auto it = mOutputStreams.find(stream);
+ if (it == mOutputStreams.end()) {
ALOGV("addOutputSessionEffects(): no output processing needed for this stream");
return NO_ERROR;
}
- ssize_t idx = mOutputSessions.indexOfKey(audioSession);
- EffectVector *procDesc;
- if (idx < 0) {
- procDesc = new EffectVector(audioSession);
- mOutputSessions.add(audioSession, procDesc);
- } else {
- // EffectVector is existing and we just need to increase ref count
- procDesc = mOutputSessions.valueAt(idx);
+ std::shared_ptr<EffectVector>& procDesc = mOutputSessions[audioSession];
+ if (procDesc == nullptr) {
+ procDesc = std::make_shared<EffectVector>(audioSession);
}
procDesc->mRefCount++;
@@ -274,25 +222,24 @@
if (procDesc->mRefCount == 1) {
// make sure effects are associated to audio server even if we are executing a binder call
int64_t token = IPCThreadState::self()->clearCallingIdentity();
- Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects;
- for (size_t i = 0; i < effects.size(); i++) {
- EffectDesc *effect = effects[i];
+ const std::shared_ptr<EffectDescVector>& effects = it->second;
+ for (const std::shared_ptr<EffectDesc>& effect : *effects) {
AttributionSourceState attributionSource;
attributionSource.packageName = "android";
attributionSource.token = sp<BBinder>::make();
- sp<AudioEffect> fx = new AudioEffect(attributionSource);
+ auto fx = sp<AudioEffect>::make(attributionSource);
fx->set(nullptr /* type */, &effect->mUuid, 0 /* priority */, nullptr /* callback */,
audioSession, output);
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGE("addOutputSessionEffects(): failed to create Fx %s on session %d",
- effect->mName, audioSession);
+ effect->mName.c_str(), audioSession);
// fx goes out of scope and strong ref on AudioEffect is released
continue;
}
ALOGV("addOutputSessionEffects(): added Fx %s on session: %d for stream: %d",
- effect->mName, audioSession, (int32_t)stream);
- procDesc->mEffects.add(fx);
+ effect->mName.c_str(), audioSession, (int32_t)stream);
+ procDesc->mEffects.push_back(std::move(fx));
}
procDesc->setProcessorEnabled(true);
@@ -305,30 +252,28 @@
audio_stream_type_t stream,
audio_session_t audioSession)
{
- status_t status = NO_ERROR;
(void) output; // argument not used for now
(void) stream; // argument not used for now
- Mutex::Autolock _l(mLock);
- ssize_t index = mOutputSessions.indexOfKey(audioSession);
- if (index < 0) {
+ audio_utils::lock_guard _l(mMutex);
+ auto it = mOutputSessions.find(audioSession);
+ if (it == mOutputSessions.end()) {
ALOGV("releaseOutputSessionEffects: no output processing was attached to this stream");
return NO_ERROR;
}
- EffectVector *procDesc = mOutputSessions.valueAt(index);
+ std::shared_ptr<EffectVector> procDesc = it->second;
procDesc->mRefCount--;
ALOGV("releaseOutputSessionEffects(): session: %d, refCount: %d",
audioSession, procDesc->mRefCount);
if (procDesc->mRefCount == 0) {
procDesc->setProcessorEnabled(false);
procDesc->mEffects.clear();
- delete procDesc;
- mOutputSessions.removeItemsAt(index);
+ mOutputSessions.erase(it);
ALOGV("releaseOutputSessionEffects(): output processing released from session: %d",
audioSession);
}
- return status;
+ return NO_ERROR;
}
status_t AudioPolicyEffects::addSourceDefaultEffect(const effect_uuid_t *type,
@@ -370,17 +315,12 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// Find the EffectDescVector for the given source type, or create a new one if necessary.
- ssize_t index = mInputSources.indexOfKey(source);
- EffectDescVector *desc = NULL;
- if (index < 0) {
- // No effects for this source type yet.
- desc = new EffectDescVector();
- mInputSources.add(source, desc);
- } else {
- desc = mInputSources.valueAt(index);
+ std::shared_ptr<EffectDescVector>& desc = mInputSources[source];
+ if (desc == nullptr) {
+ desc = std::make_shared<EffectDescVector>();
}
// Create a new effect and add it to the vector.
@@ -389,9 +329,9 @@
ALOGE("addSourceDefaultEffect(): failed to get new unique id.");
return res;
}
- EffectDesc *effect = new EffectDesc(
+ std::shared_ptr<EffectDesc> effect = std::make_shared<EffectDesc>(
descriptor.name, descriptor.type, opPackageName, descriptor.uuid, priority, *id);
- desc->mEffects.add(effect);
+ desc->push_back(std::move(effect));
// TODO(b/71813697): Support setting params as well.
// TODO(b/71814300): Retroactively attach to any existing sources of the given type.
@@ -435,17 +375,13 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// Find the EffectDescVector for the given stream type, or create a new one if necessary.
- ssize_t index = mOutputStreams.indexOfKey(stream);
- EffectDescVector *desc = NULL;
- if (index < 0) {
+ std::shared_ptr<EffectDescVector>& desc = mOutputStreams[stream];
+ if (desc == nullptr) {
// No effects for this stream type yet.
- desc = new EffectDescVector();
- mOutputStreams.add(stream, desc);
- } else {
- desc = mOutputStreams.valueAt(index);
+ desc = std::make_shared<EffectDescVector>();
}
// Create a new effect and add it to the vector.
@@ -454,9 +390,9 @@
ALOGE("addStreamDefaultEffect(): failed to get new unique id.");
return res;
}
- EffectDesc *effect = new EffectDesc(
+ std::shared_ptr<EffectDesc> effect = std::make_shared<EffectDesc>(
descriptor.name, descriptor.type, opPackageName, descriptor.uuid, priority, *id);
- desc->mEffects.add(effect);
+ desc->push_back(std::move(effect));
// TODO(b/71813697): Support setting params as well.
// TODO(b/71814300): Retroactively attach to any existing streams of the given type.
@@ -475,18 +411,16 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// Check each source type.
- size_t numSources = mInputSources.size();
- for (size_t i = 0; i < numSources; ++i) {
+ for (auto& [source, descVector] : mInputSources) {
// Check each effect for each source.
- EffectDescVector* descVector = mInputSources[i];
- for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+ for (auto desc = descVector->begin(); desc != descVector->end(); ++desc) {
if ((*desc)->mId == id) {
// Found it!
// TODO(b/71814300): Remove from any sources the effect was attached to.
- descVector->mEffects.erase(desc);
+ descVector->erase(desc);
// Handles are unique; there can only be one match, so return early.
return NO_ERROR;
}
@@ -506,18 +440,16 @@
return BAD_VALUE;
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// Check each stream type.
- size_t numStreams = mOutputStreams.size();
- for (size_t i = 0; i < numStreams; ++i) {
+ for (auto& [stream, descVector] : mOutputStreams) {
// Check each effect for each stream.
- EffectDescVector* descVector = mOutputStreams[i];
- for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+ for (auto desc = descVector->begin(); desc != descVector->end(); ++desc) {
if ((*desc)->mId == id) {
// Found it!
// TODO(b/71814300): Remove from any streams the effect was attached to.
- descVector->mEffects.erase(desc);
+ descVector->erase(desc);
// Handles are unique; there can only be one match, so return early.
return NO_ERROR;
}
@@ -530,8 +462,8 @@
void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
{
- for (size_t i = 0; i < mEffects.size(); i++) {
- mEffects.itemAt(i)->setEnabled(enabled);
+ for (const auto& effect : mEffects) {
+ effect->setEnabled(enabled);
}
}
@@ -540,7 +472,8 @@
// Audio processing configuration
// ----------------------------------------------------------------------------
-/*static*/ const char * const AudioPolicyEffects::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
+// we keep to const char* instead of std::string_view as comparison is believed faster.
+constexpr const char* kInputSourceNames[AUDIO_SOURCE_CNT - 1] = {
MIC_SRC_TAG,
VOICE_UL_SRC_TAG,
VOICE_DL_SRC_TAG,
@@ -567,7 +500,8 @@
return (audio_source_t)i;
}
-const char *AudioPolicyEffects::kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1] = {
+// +1 as enum starts from -1
+constexpr const char* kStreamNames[AUDIO_STREAM_PUBLIC_CNT + 1] = {
AUDIO_STREAM_DEFAULT_TAG,
AUDIO_STREAM_VOICE_CALL_TAG,
AUDIO_STREAM_SYSTEM_TAG,
@@ -584,6 +518,7 @@
// returns the audio_stream_t enum corresponding to the output stream name or
// AUDIO_STREAM_PUBLIC_CNT is no match found
+/* static */
audio_stream_type_t AudioPolicyEffects::streamNameToEnum(const char *name)
{
int i;
@@ -600,6 +535,7 @@
// Audio Effect Config parser
// ----------------------------------------------------------------------------
+/* static */
size_t AudioPolicyEffects::growParamSize(char **param,
size_t size,
size_t *curSize,
@@ -623,7 +559,7 @@
return pos;
}
-
+/* static */
size_t AudioPolicyEffects::readParamValue(cnode *node,
char **param,
size_t *curSize,
@@ -692,7 +628,8 @@
return len;
}
-effect_param_t *AudioPolicyEffects::loadEffectParameter(cnode *root)
+/* static */
+std::shared_ptr<const effect_param_t> AudioPolicyEffects::loadEffectParameter(cnode* root)
{
cnode *param;
cnode *value;
@@ -722,7 +659,7 @@
*ptr = atoi(param->value);
fx_param->psize = sizeof(int);
fx_param->vsize = sizeof(int);
- return fx_param;
+ return {fx_param, free};
}
}
if (param == NULL || value == NULL) {
@@ -760,42 +697,43 @@
value = value->next;
}
- return fx_param;
+ return {fx_param, free};
error:
free(fx_param);
return NULL;
}
-void AudioPolicyEffects::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
+/* static */
+void AudioPolicyEffects::loadEffectParameters(
+ cnode* root, std::vector<std::shared_ptr<const effect_param_t>>& params)
{
cnode *node = root->first_child;
while (node) {
ALOGV("loadEffectParameters() loading param %s", node->name);
- effect_param_t *param = loadEffectParameter(node);
- if (param != NULL) {
- params.add(param);
+ const auto param = loadEffectParameter(node);
+ if (param != nullptr) {
+ params.push_back(param);
}
node = node->next;
}
}
-
-AudioPolicyEffects::EffectDescVector *AudioPolicyEffects::loadEffectConfig(
- cnode *root,
- const Vector <EffectDesc *>& effects)
+/* static */
+std::shared_ptr<AudioPolicyEffects::EffectDescVector> AudioPolicyEffects::loadEffectConfig(
+ cnode* root, const EffectDescVector& effects)
{
cnode *node = root->first_child;
if (node == NULL) {
ALOGW("loadInputSource() empty element %s", root->name);
return NULL;
}
- EffectDescVector *desc = new EffectDescVector();
+ auto desc = std::make_shared<EffectDescVector>();
while (node) {
size_t i;
for (i = 0; i < effects.size(); i++) {
- if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
+ if (effects[i]->mName == node->name) {
ALOGV("loadEffectConfig() found effect %s in list", node->name);
break;
}
@@ -805,23 +743,22 @@
node = node->next;
continue;
}
- EffectDesc *effect = new EffectDesc(*effects[i]); // deep copy
+ auto effect = std::make_shared<EffectDesc>(*effects[i]); // deep copy
loadEffectParameters(node, effect->mParams);
ALOGV("loadEffectConfig() adding effect %s uuid %08x",
- effect->mName, effect->mUuid.timeLow);
- desc->mEffects.add(effect);
+ effect->mName.c_str(), effect->mUuid.timeLow);
+ desc->push_back(std::move(effect));
node = node->next;
}
- if (desc->mEffects.size() == 0) {
+ if (desc->empty()) {
ALOGW("loadEffectConfig() no valid effects found in config %s", root->name);
- delete desc;
- return NULL;
+ return nullptr;
}
return desc;
}
-status_t AudioPolicyEffects::loadInputEffectConfigurations(cnode *root,
- const Vector <EffectDesc *>& effects)
+status_t AudioPolicyEffects::loadInputEffectConfigurations_l(cnode* root,
+ const EffectDescVector& effects)
{
cnode *node = config_find(root, PREPROCESSING_TAG);
if (node == NULL) {
@@ -831,24 +768,24 @@
while (node) {
audio_source_t source = inputSourceNameToEnum(node->name);
if (source == AUDIO_SOURCE_CNT) {
- ALOGW("loadInputSources() invalid input source %s", node->name);
+ ALOGW("%s() invalid input source %s", __func__, node->name);
node = node->next;
continue;
}
- ALOGV("loadInputSources() loading input source %s", node->name);
- EffectDescVector *desc = loadEffectConfig(node, effects);
+ ALOGV("%s() loading input source %s", __func__, node->name);
+ auto desc = loadEffectConfig(node, effects);
if (desc == NULL) {
node = node->next;
continue;
}
- mInputSources.add(source, desc);
+ mInputSources[source] = std::move(desc);
node = node->next;
}
return NO_ERROR;
}
-status_t AudioPolicyEffects::loadStreamEffectConfigurations(cnode *root,
- const Vector <EffectDesc *>& effects)
+status_t AudioPolicyEffects::loadStreamEffectConfigurations_l(cnode* root,
+ const EffectDescVector& effects)
{
cnode *node = config_find(root, OUTPUT_SESSION_PROCESSING_TAG);
if (node == NULL) {
@@ -858,23 +795,24 @@
while (node) {
audio_stream_type_t stream = streamNameToEnum(node->name);
if (stream == AUDIO_STREAM_PUBLIC_CNT) {
- ALOGW("loadStreamEffectConfigurations() invalid output stream %s", node->name);
+ ALOGW("%s() invalid output stream %s", __func__, node->name);
node = node->next;
continue;
}
- ALOGV("loadStreamEffectConfigurations() loading output stream %s", node->name);
- EffectDescVector *desc = loadEffectConfig(node, effects);
+ ALOGV("%s() loading output stream %s", __func__, node->name);
+ std::shared_ptr<EffectDescVector> desc = loadEffectConfig(node, effects);
if (desc == NULL) {
node = node->next;
continue;
}
- mOutputStreams.add(stream, desc);
+ mOutputStreams[stream] = std::move(desc);
node = node->next;
}
return NO_ERROR;
}
-AudioPolicyEffects::EffectDesc *AudioPolicyEffects::loadEffect(cnode *root)
+/* static */
+std::shared_ptr<AudioPolicyEffects::EffectDesc> AudioPolicyEffects::loadEffect(cnode* root)
{
cnode *node = config_find(root, UUID_TAG);
if (node == NULL) {
@@ -885,30 +823,33 @@
ALOGW("loadEffect() invalid uuid %s", node->value);
return NULL;
}
- return new EffectDesc(root->name, uuid);
+ return std::make_shared<EffectDesc>(root->name, uuid);
}
-status_t AudioPolicyEffects::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
+/* static */
+android::AudioPolicyEffects::EffectDescVector AudioPolicyEffects::loadEffects(cnode *root)
{
+ EffectDescVector effects;
cnode *node = config_find(root, EFFECTS_TAG);
if (node == NULL) {
- return -ENOENT;
+ ALOGW("%s() Cannot find %s configuration", __func__, EFFECTS_TAG);
+ return effects;
}
node = node->first_child;
while (node) {
ALOGV("loadEffects() loading effect %s", node->name);
- EffectDesc *effect = loadEffect(node);
+ auto effect = loadEffect(node);
if (effect == NULL) {
node = node->next;
continue;
}
- effects.add(effect);
+ effects.push_back(std::move(effect));
node = node->next;
}
- return NO_ERROR;
+ return effects;
}
-status_t AudioPolicyEffects::loadAudioEffectConfig(
+status_t AudioPolicyEffects::loadAudioEffectConfig_ll(
const sp<EffectsFactoryHalInterface>& effectsFactoryHal) {
if (!effectsFactoryHal) {
ALOGE("%s Null EffectsFactoryHalInterface", __func__);
@@ -924,11 +865,12 @@
auto loadProcessingChain = [](auto& processingChain, auto& streams) {
for (auto& stream : processingChain) {
- auto effectDescs = std::make_unique<EffectDescVector>();
+ auto effectDescs = std::make_shared<EffectDescVector>();
for (auto& effect : stream.effects) {
- effectDescs->mEffects.add(new EffectDesc{effect->name.c_str(), effect->uuid});
+ effectDescs->push_back(
+ std::make_shared<EffectDesc>(effect->name, effect->uuid));
}
- streams.add(stream.type, effectDescs.release());
+ streams[stream.type] = std::move(effectDescs);
}
};
@@ -936,26 +878,26 @@
for (auto& deviceProcess : processingChain) {
auto effectDescs = std::make_unique<EffectDescVector>();
for (auto& effect : deviceProcess.effects) {
- effectDescs->mEffects.add(new EffectDesc{effect->name.c_str(), effect->uuid});
+ effectDescs->push_back(
+ std::make_shared<EffectDesc>(effect->name, effect->uuid));
}
- auto deviceEffects = std::make_unique<DeviceEffects>(
+ auto devEffects = std::make_unique<DeviceEffects>(
std::move(effectDescs), deviceProcess.type, deviceProcess.address);
- devicesEffects.emplace(deviceProcess.address, std::move(deviceEffects));
+ devicesEffects.emplace(deviceProcess.address, std::move(devEffects));
}
};
+ // access to mInputSources and mOutputStreams requires mMutex;
loadProcessingChain(processings->preprocess, mInputSources);
loadProcessingChain(processings->postprocess, mOutputStreams);
- {
- Mutex::Autolock _l(mLock);
- loadDeviceProcessingChain(processings->deviceprocess, mDeviceEffects);
- }
+ // access to mDeviceEffects requires mDeviceEffectsMutex
+ loadDeviceProcessingChain(processings->deviceprocess, mDeviceEffects);
return skippedElements;
}
-status_t AudioPolicyEffects::loadAudioEffectConfigLegacy(const char *path)
+status_t AudioPolicyEffects::loadAudioEffectConfigLegacy_l(const char *path)
{
cnode *root;
char *data;
@@ -967,15 +909,11 @@
root = config_node("", "");
config_load(root, data);
- Vector <EffectDesc *> effects;
- loadEffects(root, effects);
- loadInputEffectConfigurations(root, effects);
- loadStreamEffectConfigurations(root, effects);
+ const EffectDescVector effects = loadEffects(root);
- for (size_t i = 0; i < effects.size(); i++) {
- delete effects[i];
- }
-
+ // requires mMutex
+ loadInputEffectConfigurations_l(root, effects);
+ loadStreamEffectConfigurations_l(root, effects);
config_free(root);
free(root);
free(data);
@@ -985,14 +923,14 @@
void AudioPolicyEffects::initDefaultDeviceEffects()
{
- Mutex::Autolock _l(mLock);
+ std::lock_guard _l(mDeviceEffectsMutex);
for (const auto& deviceEffectsIter : mDeviceEffects) {
const auto& deviceEffects = deviceEffectsIter.second;
- for (const auto& effectDesc : deviceEffects->mEffectDescriptors->mEffects) {
+ for (const auto& effectDesc : *deviceEffects->mEffectDescriptors) {
AttributionSourceState attributionSource;
attributionSource.packageName = "android";
attributionSource.token = sp<BBinder>::make();
- sp<AudioEffect> fx = new AudioEffect(attributionSource);
+ sp<AudioEffect> fx = sp<AudioEffect>::make(attributionSource);
fx->set(EFFECT_UUID_NULL, &effectDesc->mUuid, 0 /* priority */, nullptr /* callback */,
AUDIO_SESSION_DEVICE, AUDIO_IO_HANDLE_NONE,
AudioDeviceTypeAddr{deviceEffects->getDeviceType(),
@@ -1000,16 +938,16 @@
status_t status = fx->initCheck();
if (status != NO_ERROR && status != ALREADY_EXISTS) {
ALOGE("%s(): failed to create Fx %s on port type=%d address=%s", __func__,
- effectDesc->mName, deviceEffects->getDeviceType(),
+ effectDesc->mName.c_str(), deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress().c_str());
// fx goes out of scope and strong ref on AudioEffect is released
continue;
}
fx->setEnabled(true);
ALOGV("%s(): create Fx %s added on port type=%d address=%s", __func__,
- effectDesc->mName, deviceEffects->getDeviceType(),
+ effectDesc->mName.c_str(), deviceEffects->getDeviceType(),
deviceEffects->getDeviceAddress().c_str());
- deviceEffects->mEffects.push_back(fx);
+ deviceEffects->mEffects.push_back(std::move(fx));
}
}
}
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index e17df48..a9628c2 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_AUDIOPOLICYEFFECTS_H
-#define ANDROID_AUDIOPOLICYEFFECTS_H
+#pragma once
#include <stdlib.h>
#include <stdio.h>
@@ -23,6 +22,7 @@
#include <future>
#include <android-base/thread_annotations.h>
+#include <audio_utils/mutex.h>
#include <cutils/misc.h>
#include <media/AudioEffect.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
@@ -56,44 +56,43 @@
// First it will look whether vendor specific file exists,
// otherwise it will parse the system default file.
explicit AudioPolicyEffects(const sp<EffectsFactoryHalInterface>& effectsFactoryHal);
- virtual ~AudioPolicyEffects();
// NOTE: methods on AudioPolicyEffects should never be called with the AudioPolicyService
- // main mutex (mLock) held as they will indirectly call back into AudioPolicyService when
+ // main mutex (mMutex) held as they will indirectly call back into AudioPolicyService when
// managing audio effects.
// Return a list of effect descriptors for default input effects
// associated with audioSession
status_t queryDefaultInputEffects(audio_session_t audioSession,
effect_descriptor_t *descriptors,
- uint32_t *count);
+ uint32_t* count) EXCLUDES_AudioPolicyEffects_Mutex;
// Add all input effects associated with this input
// Effects are attached depending on the audio_source_t
status_t addInputEffects(audio_io_handle_t input,
audio_source_t inputSource,
- audio_session_t audioSession);
+ audio_session_t audioSession) EXCLUDES_AudioPolicyEffects_Mutex;
// Add all input effects associated to this input
status_t releaseInputEffects(audio_io_handle_t input,
- audio_session_t audioSession);
+ audio_session_t audioSession) EXCLUDES_AudioPolicyEffects_Mutex;
// Return a list of effect descriptors for default output effects
// associated with audioSession
status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
effect_descriptor_t *descriptors,
- uint32_t *count);
+ uint32_t* count) EXCLUDES_AudioPolicyEffects_Mutex;
// Add all output effects associated to this output
// Effects are attached depending on the audio_stream_type_t
status_t addOutputSessionEffects(audio_io_handle_t output,
audio_stream_type_t stream,
- audio_session_t audioSession);
+ audio_session_t audioSession) EXCLUDES_AudioPolicyEffects_Mutex;
// release all output effects associated with this output stream and audiosession
status_t releaseOutputSessionEffects(audio_io_handle_t output,
audio_stream_type_t stream,
- audio_session_t audioSession);
+ audio_session_t audioSession) EXCLUDES_AudioPolicyEffects_Mutex;
// Add the effect to the list of default effects for sources of type |source|.
status_t addSourceDefaultEffect(const effect_uuid_t *type,
@@ -101,7 +100,7 @@
const effect_uuid_t *uuid,
int32_t priority,
audio_source_t source,
- audio_unique_id_t* id);
+ audio_unique_id_t* id) EXCLUDES_AudioPolicyEffects_Mutex;
// Add the effect to the list of default effects for streams of a given usage.
status_t addStreamDefaultEffect(const effect_uuid_t *type,
@@ -109,36 +108,39 @@
const effect_uuid_t *uuid,
int32_t priority,
audio_usage_t usage,
- audio_unique_id_t* id);
+ audio_unique_id_t* id) EXCLUDES_AudioPolicyEffects_Mutex;
// Remove the default source effect from wherever it's attached.
- status_t removeSourceDefaultEffect(audio_unique_id_t id);
+ status_t removeSourceDefaultEffect(audio_unique_id_t id) EXCLUDES_AudioPolicyEffects_Mutex;
// Remove the default stream effect from wherever it's attached.
- status_t removeStreamDefaultEffect(audio_unique_id_t id);
+ status_t removeStreamDefaultEffect(audio_unique_id_t id) EXCLUDES_AudioPolicyEffects_Mutex;
+ // Called by AudioPolicyService::onFirstRef() to load device effects
+ // on a separate worker thread.
+ // TODO(b/319515492) move this initialization after AudioPolicyService::onFirstRef().
void setDefaultDeviceEffects();
private:
- void initDefaultDeviceEffects();
// class to store the description of an effects and its parameters
// as defined in audio_effects.conf
class EffectDesc {
public:
- EffectDesc(const char *name,
+ EffectDesc(std::string_view name,
const effect_uuid_t& typeUuid,
const String16& opPackageName,
const effect_uuid_t& uuid,
uint32_t priority,
audio_unique_id_t id) :
- mName(strdup(name)),
+ mName(name),
mTypeUuid(typeUuid),
mOpPackageName(opPackageName),
mUuid(uuid),
mPriority(priority),
mId(id) { }
- EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ // Modern EffectDesc usage:
+ EffectDesc(std::string_view name, const effect_uuid_t& uuid) :
EffectDesc(name,
*EFFECT_UUID_NULL,
String16(""),
@@ -146,67 +148,36 @@
0,
AUDIO_UNIQUE_ID_ALLOCATE) { }
EffectDesc(const EffectDesc& orig) :
- mName(strdup(orig.mName)),
+ mName(orig.mName),
mTypeUuid(orig.mTypeUuid),
mOpPackageName(orig.mOpPackageName),
mUuid(orig.mUuid),
mPriority(orig.mPriority),
- mId(orig.mId) {
- // deep copy mParams
- for (size_t k = 0; k < orig.mParams.size(); k++) {
- effect_param_t *origParam = orig.mParams[k];
- // psize and vsize are rounded up to an int boundary for allocation
- size_t origSize = sizeof(effect_param_t) +
- ((origParam->psize + 3) & ~3) +
- ((origParam->vsize + 3) & ~3);
- effect_param_t *dupParam = (effect_param_t *) malloc(origSize);
- memcpy(dupParam, origParam, origSize);
- // This works because the param buffer allocation is also done by
- // multiples of 4 bytes originally. In theory we should memcpy only
- // the actual param size, that is without rounding vsize.
- mParams.add(dupParam);
- }
- }
- /*virtual*/ ~EffectDesc() {
- free(mName);
- for (size_t k = 0; k < mParams.size(); k++) {
- free(mParams[k]);
- }
- }
- char *mName;
- effect_uuid_t mTypeUuid;
- String16 mOpPackageName;
- effect_uuid_t mUuid;
- int32_t mPriority;
- audio_unique_id_t mId;
- Vector <effect_param_t *> mParams;
+ mId(orig.mId),
+ mParams(orig.mParams) { }
+
+ const std::string mName;
+ const effect_uuid_t mTypeUuid;
+ const String16 mOpPackageName;
+ const effect_uuid_t mUuid;
+ const int32_t mPriority;
+ const audio_unique_id_t mId;
+ std::vector<std::shared_ptr<const effect_param_t>> mParams;
};
- // class to store voctor of EffectDesc
- class EffectDescVector {
- public:
- EffectDescVector() {}
- /*virtual*/ ~EffectDescVector() {
- for (size_t j = 0; j < mEffects.size(); j++) {
- delete mEffects[j];
- }
- }
- Vector <EffectDesc *> mEffects;
- };
+ using EffectDescVector = std::vector<std::shared_ptr<EffectDesc>>;
- // class to store voctor of AudioEffects
class EffectVector {
public:
- explicit EffectVector(audio_session_t session) : mSessionId(session), mRefCount(0) {}
- /*virtual*/ ~EffectVector() {}
+ explicit EffectVector(audio_session_t session) : mSessionId(session) {}
// Enable or disable all effects in effect vector
void setProcessorEnabled(bool enabled);
const audio_session_t mSessionId;
- // AudioPolicyManager keeps mLock, no need for lock on reference count here
- int mRefCount;
- Vector< sp<AudioEffect> >mEffects;
+ // AudioPolicyManager keeps mMutex, no need for lock on reference count here
+ int mRefCount = 0;
+ std::vector<sp<AudioEffect>> mEffects;
};
/**
@@ -215,12 +186,11 @@
class DeviceEffects {
public:
DeviceEffects(std::unique_ptr<EffectDescVector> effectDescriptors,
- audio_devices_t device, const std::string& address) :
+ audio_devices_t device, std::string_view address) :
mEffectDescriptors(std::move(effectDescriptors)),
mDeviceType(device), mDeviceAddress(address) {}
- /*virtual*/ ~DeviceEffects() = default;
- std::vector< sp<AudioEffect> > mEffects;
+ std::vector<sp<AudioEffect>> mEffects;
audio_devices_t getDeviceType() const { return mDeviceType; }
std::string getDeviceAddress() const { return mDeviceAddress; }
const std::unique_ptr<EffectDescVector> mEffectDescriptors;
@@ -231,65 +201,98 @@
};
- static const char * const kInputSourceNames[AUDIO_SOURCE_CNT -1];
+ // Called on an async thread because it creates AudioEffects
+ // which register with AudioFlinger and AudioPolicy.
+ // We must therefore exclude the EffectHandle_Mutex.
+ void initDefaultDeviceEffects() EXCLUDES(mDeviceEffectsMutex) EXCLUDES_EffectHandle_Mutex;
+
+ status_t loadAudioEffectConfig_ll(const sp<EffectsFactoryHalInterface>& effectsFactoryHal)
+ REQUIRES(mMutex, mDeviceEffectsMutex);
+
+ // Legacy: Begin methods below.
+ // Parse audio_effects.conf - called from constructor.
+ status_t loadAudioEffectConfigLegacy_l(const char* path) REQUIRES(mMutex);
+
+ // Legacy: Load all automatic effect configurations
+ status_t loadInputEffectConfigurations_l(cnode* root,
+ const EffectDescVector& effects) REQUIRES(mMutex);
+ status_t loadStreamEffectConfigurations_l(cnode* root,
+ const EffectDescVector& effects) REQUIRES(mMutex);
+
+ // Legacy: static methods below.
+
static audio_source_t inputSourceNameToEnum(const char *name);
- static const char *kStreamNames[AUDIO_STREAM_PUBLIC_CNT+1]; //+1 required as streams start from -1
- audio_stream_type_t streamNameToEnum(const char *name);
-
- // Parse audio_effects.conf
- status_t loadAudioEffectConfigLegacy(const char *path);
- status_t loadAudioEffectConfig(const sp<EffectsFactoryHalInterface>& effectsFactoryHal);
+ static audio_stream_type_t streamNameToEnum(const char* name);
// Load all effects descriptors in configuration file
- status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects);
- EffectDesc *loadEffect(cnode *root);
-
- // Load all automatic effect configurations
- status_t loadInputEffectConfigurations(cnode *root, const Vector <EffectDesc *>& effects);
- status_t loadStreamEffectConfigurations(cnode *root, const Vector <EffectDesc *>& effects);
- EffectDescVector *loadEffectConfig(cnode *root, const Vector <EffectDesc *>& effects);
+ static EffectDescVector loadEffects(cnode* root);
+ static std::shared_ptr<AudioPolicyEffects::EffectDesc> loadEffect(cnode* root);
+ static std::shared_ptr<EffectDescVector> loadEffectConfig(cnode* root,
+ const EffectDescVector& effects);
// Load all automatic effect parameters
- void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params);
- effect_param_t *loadEffectParameter(cnode *root);
- size_t readParamValue(cnode *node,
+ static void loadEffectParameters(
+ cnode* root, std::vector<std::shared_ptr<const effect_param_t>>& params);
+
+ // loadEffectParameter returns a shared_ptr instead of a unique_ptr as there may
+ // be multiple references to the same effect parameter.
+ static std::shared_ptr<const effect_param_t> loadEffectParameter(cnode* root);
+ static size_t readParamValue(cnode* node,
char **param,
size_t *curSize,
size_t *totSize);
- size_t growParamSize(char **param,
+ static size_t growParamSize(char** param,
size_t size,
size_t *curSize,
size_t *totSize);
+ // Legacy: End methods above.
+
+ // Note: The association of Effects to audio source, session, or stream
+ // is done through std::map instead of std::unordered_map. This gives
+ // better reproducibility of issues, since map is ordered and more predictable
+ // in enumeration.
+
// protects access to mInputSources, mInputSessions, mOutputStreams, mOutputSessions
- // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // never hold AudioPolicyService::mMutex when calling AudioPolicyEffects methods as
// those can call back into AudioPolicyService methods and try to acquire the mutex
- Mutex mLock;
+ mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kAudioPolicyEffects_Mutex};
// Automatic input effects are configured per audio_source_t
- KeyedVector< audio_source_t, EffectDescVector* > mInputSources;
- // Automatic input effects are unique for audio_io_handle_t
- KeyedVector< audio_session_t, EffectVector* > mInputSessions;
+ std::map<audio_source_t, std::shared_ptr<EffectDescVector>> mInputSources
+ GUARDED_BY(mMutex);
+ // Automatic input effects are unique for an audio_session_t.
+ std::map<audio_session_t, std::shared_ptr<EffectVector>> mInputSessions
+ GUARDED_BY(mMutex);
// Automatic output effects are organized per audio_stream_type_t
- KeyedVector< audio_stream_type_t, EffectDescVector* > mOutputStreams;
- // Automatic output effects are unique for audiosession ID
- KeyedVector< audio_session_t, EffectVector* > mOutputSessions;
+ std::map<audio_stream_type_t, std::shared_ptr<EffectDescVector>> mOutputStreams
+ GUARDED_BY(mMutex);
+ // Automatic output effects are unique for an audio_session_t.
+ std::map<audio_session_t, std::shared_ptr<EffectVector>> mOutputSessions
+ GUARDED_BY(mMutex);
/**
* @brief mDeviceEffects map of device effects indexed by the device address
*/
- std::map<std::string, std::unique_ptr<DeviceEffects>> mDeviceEffects GUARDED_BY(mLock);
+
+ // mDeviceEffects is never accessed through AudioPolicyEffects methods.
+ // We keep a separate mutex here to catch future methods attempting to access this variable.
+ std::mutex mDeviceEffectsMutex;
+ std::map<std::string, std::unique_ptr<DeviceEffects>> mDeviceEffects
+ GUARDED_BY(mDeviceEffectsMutex);
/**
* Device Effect initialization must be asynchronous: the audio_policy service parses and init
* effect on first reference. AudioFlinger will handle effect creation and register these
* effect on audio_policy service.
- * We must store the reference of the furture garantee real asynchronous operation.
+ *
+ * The future is associated with the std::async launched thread - no need to lock as
+ * it is only set once on init. Due to the async nature, it is conceivable that
+ * some device effects are not available immediately after AudioPolicyService::onFirstRef()
+ * while the effects are being created.
*/
std::future<void> mDefaultDeviceEffectFuture;
};
} // namespace android
-
-#endif // ANDROID_AUDIOPOLICYEFFECTS_H
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 509b673..6e1ecec 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -114,7 +114,7 @@
void AudioPolicyService::doOnNewAudioModulesAvailable()
{
if (mAudioPolicyManager == NULL) return;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
mAudioPolicyManager->onNewAudioModulesAvailable();
}
@@ -140,7 +140,7 @@
}
ALOGV("setDeviceConnectionState()");
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
status_t status = mAudioPolicyManager->setDeviceConnectionState(
state, port, encodedFormat);
@@ -162,7 +162,7 @@
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
return Status::ok();
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(
@@ -190,7 +190,7 @@
}
ALOGV("handleDeviceConfigChange()");
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
status_t status = mAudioPolicyManager->handleDeviceConfigChange(
device, address.c_str(), deviceNameAidl.c_str(), encodedFormat);
@@ -221,7 +221,7 @@
// acquire lock before calling setMode() so that setMode() + setPhoneState() are an atomic
// operation from policy manager standpoint (no other operation (e.g track start or stop)
// can be interleaved).
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// TODO: check if it is more appropriate to do it in platform specific policy manager
// Audio HAL mode conversion for call redirect modes
@@ -242,7 +242,7 @@
}
Status AudioPolicyService::getPhoneState(AudioMode* _aidl_return) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_mode_t_AudioMode(mPhoneState));
return Status::ok();
}
@@ -270,7 +270,7 @@
return binderStatusFromStatusT(BAD_VALUE);
}
ALOGV("setForceUse()");
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
mAudioPolicyManager->setForceUse(usage, config);
onCheckSpatializer_l();
@@ -312,7 +312,7 @@
return binderStatusFromStatusT(NO_INIT);
}
ALOGV("getOutput()");
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_io_handle_t_int32_t(mAudioPolicyManager->getOutput(stream)));
@@ -352,7 +352,7 @@
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attr, attributionSource)));
ALOGV("%s()", __func__);
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (!mPackageManager.allowPlaybackCapture(VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_uid_t(attributionSource.uid)))) {
@@ -458,7 +458,7 @@
sp<AudioPolicyEffects>& effects,
const char *context)
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
if (index < 0) {
ALOGE("%s AudioTrack client not found for portId %d", context, portId);
@@ -489,7 +489,7 @@
ALOGW("Failed to add effects on session %d", client->session);
}
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
status_t status = mAudioPolicyManager->startOutput(portId);
if (status == NO_ERROR) {
@@ -531,7 +531,7 @@
ALOGW("Failed to release effects on session %d", client->session);
}
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
status_t status = mAudioPolicyManager->stopOutput(portId);
if (status == NO_ERROR) {
@@ -567,7 +567,7 @@
audioPolicyEffects->releaseOutputSessionEffects(
client->io, client->stream, client->session);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (client != nullptr && client->active) {
onUpdateActiveSpatializerTracks_l();
}
@@ -691,7 +691,7 @@
status_t status;
AudioPolicyInterface::input_type_t inputType;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
{
AutoCallerClear acc;
// the audio_in_acoustics_t parameter is ignored by get_input()
@@ -794,7 +794,7 @@
}
sp<AudioRecordClient> client;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
ssize_t index = mAudioRecordClients.indexOfKey(portId);
if (index < 0) {
@@ -817,7 +817,7 @@
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
ALOGW_IF(client->silenced, "startInput on silenced input for port %d, uid %d. Unsilencing.",
portIdAidl,
@@ -937,7 +937,7 @@
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
ssize_t index = mAudioRecordClients.indexOfKey(portId);
if (index < 0) {
@@ -967,7 +967,7 @@
sp<AudioPolicyEffects>audioPolicyEffects;
sp<AudioRecordClient> client;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
audioPolicyEffects = mAudioPolicyEffects;
ssize_t index = mAudioRecordClients.indexOfKey(portId);
if (index < 0) {
@@ -995,7 +995,7 @@
}
}
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
mAudioPolicyManager->releaseInput(portId);
}
@@ -1019,7 +1019,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return binderStatusFromStatusT(BAD_VALUE);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
mAudioPolicyManager->initStreamVolume(stream, indexMin, indexMax);
return binderStatusFromStatusT(NO_ERROR);
@@ -1043,7 +1043,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return binderStatusFromStatusT(BAD_VALUE);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->setStreamVolumeIndex(stream,
index,
@@ -1065,7 +1065,7 @@
if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
return binderStatusFromStatusT(BAD_VALUE);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getStreamVolumeIndex(stream, &index, device)));
@@ -1090,7 +1090,7 @@
if (!settingsAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(
mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, device));
@@ -1110,7 +1110,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getVolumeIndexForAttributes(attributes, index, device)));
@@ -1129,7 +1129,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getMinVolumeIndexForAttributes(attributes, index)));
@@ -1148,7 +1148,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getMaxVolumeIndexForAttributes(attributes, index)));
@@ -1190,7 +1190,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getDevicesForAttributes(aa, &devices, forVolume)));
@@ -1210,7 +1210,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_io_handle_t_int32_t(mAudioPolicyManager->getOutputForEffect(&desc)));
@@ -1235,7 +1235,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(
mAudioPolicyManager->registerEffect(&desc, io, strategy, session, id));
@@ -1247,7 +1247,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->unregisterEffect(id));
}
@@ -1258,7 +1258,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->setEffectEnabled(id, enabled));
}
@@ -1277,7 +1277,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->moveEffectsToIo(ids, io));
}
@@ -1295,7 +1295,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isStreamActive(stream, inPastMs);
return Status::ok();
@@ -1315,7 +1315,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isStreamActiveRemotely(stream, inPastMs);
return Status::ok();
@@ -1327,7 +1327,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isSourceActive(source);
return Status::ok();
@@ -1339,7 +1339,7 @@
return NO_INIT;
}
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
audioPolicyEffects = mAudioPolicyEffects;
}
if (audioPolicyEffects == 0) {
@@ -1463,7 +1463,7 @@
convertRange(systemUsagesAidl.begin(), systemUsagesAidl.begin() + size,
std::back_inserter(systemUsages), aidl2legacy_AudioUsage_audio_usage_t)));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1483,7 +1483,7 @@
audio_flags_mask_t capturePolicy = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_flags_mask_t_mask(capturePolicyAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
ALOGV("%s() mAudioPolicyManager == NULL", __func__);
return binderStatusFromStatusT(NO_INIT);
@@ -1500,7 +1500,7 @@
ALOGV("mAudioPolicyManager == NULL");
return binderStatusFromStatusT(AUDIO_OFFLOAD_NOT_SUPPORTED);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_offload_mode_t_AudioOffloadMode(
mAudioPolicyManager->getOffloadSupport(info)));
@@ -1525,7 +1525,7 @@
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(validateUsage(attributes)));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
*_aidl_return = mAudioPolicyManager->isDirectOutputSupported(config, attributes);
return Status::ok();
}
@@ -1561,7 +1561,7 @@
std::unique_ptr<audio_port_v7[]> ports(new audio_port_v7[num_ports]);
unsigned int generation;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1589,7 +1589,7 @@
Status AudioPolicyService::listDeclaredDevicePorts(media::AudioPortRole role,
std::vector<media::AudioPortFw>* _aidl_return) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1601,7 +1601,7 @@
Status AudioPolicyService::getAudioPort(int portId,
media::AudioPortFw* _aidl_return) {
audio_port_v7 port{ .id = portId };
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1628,7 +1628,7 @@
aidl2legacy_int32_t_audio_port_handle_t(handleAidl));
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(AudioValidator::validateAudioPatch(patch)));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1647,7 +1647,7 @@
{
audio_patch_handle_t handle = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_patch_handle_t(handleAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1672,7 +1672,7 @@
std::unique_ptr<audio_patch[]> patches(new audio_patch[num_patches]);
unsigned int generation;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1710,7 +1710,7 @@
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(AudioValidator::validateAudioPortConfig(config)));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1728,7 +1728,7 @@
audio_devices_t device;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1750,7 +1750,7 @@
{
audio_session_t session = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_session_t(sessionAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1769,7 +1769,7 @@
convertRange(mixesAidl.begin(), mixesAidl.begin() + size, std::back_inserter(mixes),
aidl2legacy_AudioMix)));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// loopback|render only need a MediaProjection (checked in caller AudioService.java)
bool needModifyAudioRouting = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
@@ -1812,7 +1812,7 @@
Status AudioPolicyService::updatePolicyMixes(
const ::std::vector<::android::media::AudioMixUpdate>& updates) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
for (const auto& update : updates) {
AudioMix mix = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_AudioMix(update.audioMix));
std::vector<AudioMixMatchCriterion> newCriteria =
@@ -1834,7 +1834,7 @@
convertContainer<AudioDeviceTypeAddrVector>(devicesAidl,
aidl2legacy_AudioDeviceTypeAddress));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1848,7 +1848,7 @@
Status AudioPolicyService::removeUidDeviceAffinities(int32_t uidAidl) {
uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1867,7 +1867,7 @@
convertContainer<AudioDeviceTypeAddrVector>(devicesAidl,
aidl2legacy_AudioDeviceTypeAddress));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1881,7 +1881,7 @@
Status AudioPolicyService::removeUserIdDeviceAffinities(int32_t userIdAidl) {
int userId = VALUE_OR_RETURN_BINDER_STATUS(convertReinterpret<int>(userIdAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if(!modifyAudioRoutingAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
@@ -1905,7 +1905,7 @@
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
AudioValidator::validateAudioAttributes(attributes, "68953950")));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1926,7 +1926,7 @@
audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
@@ -1942,7 +1942,7 @@
if (!settingsAllowed()) {
return binderStatusFromStatusT(PERMISSION_DENIED);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->setMasterMono(mono));
}
@@ -1952,7 +1952,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->getMasterMono(_aidl_return));
}
@@ -1970,7 +1970,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->getStreamVolumeDB(stream, index, device);
return Status::ok();
@@ -1991,7 +1991,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getSurroundFormats(&numSurroundFormats, surroundFormats.get(),
@@ -2022,7 +2022,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getReportedSurroundFormats(
@@ -2044,7 +2044,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
audio_devices_t device = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioDeviceDescription_audio_devices_t(deviceAidl));
@@ -2064,7 +2064,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(
mAudioPolicyManager->setSurroundFormatEnabled(audioFormat, enabled));
@@ -2087,7 +2087,7 @@
std::vector<uid_t> uids;
RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(uidsAidl, uids));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mUidPolicy->setAssistantUids(uids);
return Status::ok();
}
@@ -2097,7 +2097,7 @@
std::vector<uid_t> activeUids;
RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(activeUidsAidl, activeUids));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mUidPolicy->setActiveAssistantUids(activeUids);
return Status::ok();
}
@@ -2107,7 +2107,7 @@
std::vector<uid_t> uids;
RETURN_IF_BINDER_ERROR(convertInt32VectorToUidVectorWithLimit(uidsAidl, uids));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mUidPolicy->setA11yUids(uids);
return Status::ok();
}
@@ -2115,7 +2115,7 @@
Status AudioPolicyService::setCurrentImeUid(int32_t uidAidl)
{
uid_t uid = VALUE_OR_RETURN_BINDER_STATUS(aidl2legacy_int32_t_uid_t(uidAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mUidPolicy->setCurrentImeUid(uid);
return Status::ok();
}
@@ -2125,7 +2125,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isHapticPlaybackSupported();
return Status::ok();
@@ -2136,7 +2136,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isUltrasoundSupported();
return Status::ok();
@@ -2147,7 +2147,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isHotwordStreamSupported(lookbackAudio);
return Status::ok();
@@ -2160,7 +2160,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(mAudioPolicyManager->listAudioProductStrategies(strategies)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2180,7 +2180,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getProductStrategyFromAudioAttributes(
aa, productStrategy, fallbackOnDefault)));
@@ -2195,7 +2195,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(mAudioPolicyManager->listAudioVolumeGroups(groups)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2214,7 +2214,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(
mAudioPolicyManager->getVolumeGroupFromAudioAttributes(
@@ -2225,7 +2225,7 @@
Status AudioPolicyService::setRttEnabled(bool enabled)
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mUidPolicy->setRttEnabled(enabled);
return Status::ok();
}
@@ -2235,7 +2235,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
*_aidl_return = mAudioPolicyManager->isCallScreenModeSupported();
return Status::ok();
@@ -2256,7 +2256,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
status_t status = mAudioPolicyManager->setDevicesRoleForStrategy(strategy, role, devices);
if (status == NO_ERROR) {
onCheckSpatializer_l();
@@ -2279,7 +2279,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
status_t status = mAudioPolicyManager->removeDevicesRoleForStrategy(strategy, role, devices);
if (status == NO_ERROR) {
onCheckSpatializer_l();
@@ -2296,7 +2296,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
status_t status = mAudioPolicyManager->clearDevicesRoleForStrategy(strategy, role);
if (status == NO_ERROR) {
onCheckSpatializer_l();
@@ -2317,7 +2317,7 @@
if (mAudioPolicyManager == NULL) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getDevicesForRoleAndStrategy(strategy, role, devices)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2347,7 +2347,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->setDevicesRoleForCapturePreset(audioSource, role, devices));
}
@@ -2367,7 +2367,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->addDevicesRoleForCapturePreset(audioSource, role, devices));
}
@@ -2387,7 +2387,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->removeDevicesRoleForCapturePreset(audioSource, role, devices));
}
@@ -2402,7 +2402,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->clearDevicesRoleForCapturePreset(audioSource, role));
}
@@ -2420,7 +2420,7 @@
if (mAudioPolicyManager == nullptr) {
return binderStatusFromStatusT(NO_INIT);
}
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getDevicesForRoleAndCapturePreset(audioSource, role, devices)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2467,7 +2467,7 @@
convertContainer<AudioDeviceTypeAddrVector>(devicesAidl,
aidl2legacy_AudioDeviceTypeAddress));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
*_aidl_return = mAudioPolicyManager->canBeSpatialized(&attr, &config, devices);
return Status::ok();
}
@@ -2486,7 +2486,7 @@
aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
audio_config_t config = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioConfig_audio_config_t(configAidl, false /*isInput*/));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
*_aidl_return = static_cast<media::AudioDirectMode>(
VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_direct_mode_t_int32_t_mask(
mAudioPolicyManager->getDirectPlaybackSupport(&attr, &config))));
@@ -2503,7 +2503,7 @@
aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
AudioProfileVector audioProfiles;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
mAudioPolicyManager->getDirectProfilesForAttributes(&attr, audioProfiles)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
@@ -2523,7 +2523,7 @@
aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
std::vector<audio_mixer_attributes_t> mixerAttrs;
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(mAudioPolicyManager->getSupportedMixerAttributes(
portId, mixerAttrs)));
@@ -2551,7 +2551,7 @@
audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->setPreferredMixerAttributes(&attr, portId, uid, &mixerAttr));
}
@@ -2569,7 +2569,7 @@
audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
audio_mixer_attributes_t mixerAttr = AUDIO_MIXER_ATTRIBUTES_INITIALIZER;
RETURN_IF_BINDER_ERROR(
binderStatusFromStatusT(mAudioPolicyManager->getPreferredMixerAttributes(
@@ -2593,7 +2593,7 @@
audio_port_handle_t portId = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_int32_t_audio_port_handle_t(portIdAidl));
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
return binderStatusFromStatusT(
mAudioPolicyManager->clearPreferredMixerAttributes(&attr, portId, uid));
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 7241597..57e2718 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -265,7 +265,7 @@
.set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
.record(); });
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
// start audio commands thread
mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this);
@@ -280,11 +280,11 @@
// load audio processing modules
const sp<EffectsFactoryHalInterface> effectsFactoryHal = EffectsFactoryHalInterface::create();
- sp<AudioPolicyEffects> audioPolicyEffects = new AudioPolicyEffects(effectsFactoryHal);
- sp<UidPolicy> uidPolicy = new UidPolicy(this);
- sp<SensorPrivacyPolicy> sensorPrivacyPolicy = new SensorPrivacyPolicy(this);
+ auto audioPolicyEffects = sp<AudioPolicyEffects>::make(effectsFactoryHal);
+ auto uidPolicy = sp<UidPolicy>::make(this);
+ auto sensorPrivacyPolicy = sp<SensorPrivacyPolicy>::make(this);
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mAudioPolicyEffects = audioPolicyEffects;
mUidPolicy = uidPolicy;
mSensorPrivacyPolicy = sensorPrivacyPolicy;
@@ -294,12 +294,16 @@
// Create spatializer if supported
if (mAudioPolicyManager != nullptr) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
const audio_attributes_t attr = attributes_initializer(AUDIO_USAGE_MEDIA);
AudioDeviceTypeAddrVector devices;
bool hasSpatializer = mAudioPolicyManager->canBeSpatialized(&attr, nullptr, devices);
if (hasSpatializer) {
+ // Unlock as Spatializer::create() will use the callback and acquire the
+ // AudioPolicyService_Mutex.
+ mMutex.unlock();
mSpatializer = Spatializer::create(this, effectsFactoryHal);
+ mMutex.lock();
}
if (mSpatializer == nullptr) {
// No spatializer created, signal the reason: NO_INIT a failure, OK means intended.
@@ -352,7 +356,7 @@
ALOGW("%s got NULL client", __FUNCTION__);
return Status::ok();
}
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
uid_t uid = IPCThreadState::self()->getCallingUid();
pid_t pid = IPCThreadState::self()->getCallingPid();
@@ -375,7 +379,7 @@
Status AudioPolicyService::setAudioPortCallbacksEnabled(bool enabled)
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
uid_t uid = IPCThreadState::self()->getCallingUid();
pid_t pid = IPCThreadState::self()->getCallingPid();
@@ -390,7 +394,7 @@
Status AudioPolicyService::setAudioVolumeGroupCallbacksEnabled(bool enabled)
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
uid_t uid = IPCThreadState::self()->getCallingUid();
pid_t pid = IPCThreadState::self()->getCallingPid();
@@ -408,7 +412,7 @@
{
bool hasSameUid = false;
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
int64_t token = ((int64_t)uid<<32) | pid;
mNotificationClients.removeItem(token);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
@@ -419,7 +423,7 @@
}
}
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
if (mAudioPolicyManager && !hasSameUid) {
// called from binder death notification: no need to clear caller identity
mAudioPolicyManager->releaseResourcesForUid(uid);
@@ -434,7 +438,7 @@
void AudioPolicyService::doOnAudioPortListUpdate()
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onAudioPortListUpdate();
}
@@ -447,7 +451,7 @@
void AudioPolicyService::doOnAudioPatchListUpdate()
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onAudioPatchListUpdate();
}
@@ -460,7 +464,7 @@
void AudioPolicyService::doOnAudioVolumeGroupChanged(volume_group_t group, int flags)
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onAudioVolumeGroupChanged(group, flags);
}
@@ -475,7 +479,7 @@
void AudioPolicyService::doOnDynamicPolicyMixStateUpdate(const String8& regId, int32_t state)
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onDynamicPolicyMixStateUpdate(regId, state);
}
@@ -505,7 +509,7 @@
audio_patch_handle_t patchHandle,
audio_source_t source)
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, clientInfo,
clientConfig, clientEffects, deviceConfig, effects, patchHandle, source);
@@ -519,7 +523,7 @@
void AudioPolicyService::doOnRoutingUpdated()
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onRoutingUpdated();
}
@@ -532,7 +536,7 @@
void AudioPolicyService::doOnVolumeRangeInitRequest()
{
- Mutex::Autolock _l(mNotificationClientsLock);
+ audio_utils::lock_guard _l(mNotificationClientsMutex);
for (size_t i = 0; i < mNotificationClients.size(); i++) {
mNotificationClients.valueAt(i)->onVolumeRangeInitRequest();
}
@@ -540,7 +544,7 @@
void AudioPolicyService::onCheckSpatializer()
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
onCheckSpatializer_l();
}
@@ -564,7 +568,7 @@
const audio_attributes_t attr = attributes_initializer(AUDIO_USAGE_MEDIA);
audio_config_base_t config = mSpatializer->getAudioInConfig();
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
status_t status =
mAudioPolicyManager->getSpatializerOutput(&config, &attr, &newOutput);
ALOGV("%s currentOutput %d newOutput %d channel_mask %#x",
@@ -573,13 +577,13 @@
return;
}
size_t numActiveTracks = countActiveClientsOnOutput_l(newOutput);
- mLock.unlock();
+ mMutex.unlock();
// It is OK to call detachOutput() is none is already attached.
mSpatializer->detachOutput();
if (status == NO_ERROR && newOutput != AUDIO_IO_HANDLE_NONE) {
status = mSpatializer->attachOutput(newOutput, numActiveTracks);
}
- mLock.lock();
+ mMutex.lock();
if (status != NO_ERROR) {
mAudioPolicyManager->releaseSpatializerOutput(newOutput);
}
@@ -588,7 +592,7 @@
audio_io_handle_t output = mSpatializer->detachOutput();
if (output != AUDIO_IO_HANDLE_NONE) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mAudioPolicyManager->releaseSpatializerOutput(output);
}
}
@@ -623,7 +627,7 @@
audio_io_handle_t output = mSpatializer->getOutput();
size_t activeClients;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
activeClients = countActiveClientsOnOutput_l(output);
}
mSpatializer->updateActiveTracks(activeClients);
@@ -779,12 +783,8 @@
IPCThreadState::self()->getCallingPid());
}
-static bool dumpTryLock(Mutex& mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
-{
- return mutex.timedLock(kDumpLockTimeoutNs) == NO_ERROR;
-}
-
-static void dumpReleaseLock(Mutex& mutex, bool locked) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
+static void dumpReleaseLock(audio_utils::mutex& mutex, bool locked)
+ RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
{
if (locked) mutex.unlock();
}
@@ -821,7 +821,7 @@
void AudioPolicyService::updateUidStates()
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
updateUidStates_l();
}
@@ -1023,7 +1023,7 @@
bool isTopOrLatestAssistant = latestActiveAssistant == nullptr ? false :
current->attributionSource.uid == latestActiveAssistant->attributionSource.uid;
- auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mLock) {
+ auto canCaptureIfInCallOrCommunication = [&](const auto &recordClient) REQUIRES(mMutex) {
uid_t recordUid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(
recordClient->attributionSource.uid));
bool canCaptureCall = recordClient->canCaptureOutput;
@@ -1201,11 +1201,12 @@
}
status_t AudioPolicyService::dump(int fd, const Vector<String16>& args __unused)
+NO_THREAD_SAFETY_ANALYSIS // update for trylock.
{
if (!dumpAllowed()) {
dumpPermissionDenial(fd);
} else {
- const bool locked = dumpTryLock(mLock);
+ const bool locked = mMutex.try_lock(kDumpLockTimeoutNs);
if (!locked) {
String8 result(kDeadlockedString);
write(fd, result.c_str(), result.size());
@@ -1234,7 +1235,7 @@
mPackageManager.dump(fd);
- dumpReleaseLock(mLock, locked);
+ dumpReleaseLock(mMutex, locked);
if (mSpatializer != nullptr) {
std::string dumpString = mSpatializer->toString(1 /* level */);
@@ -1479,7 +1480,7 @@
sp<UidPolicy> uidPolicy;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
uidPolicy = mUidPolicy;
}
if (uidPolicy) {
@@ -1508,7 +1509,7 @@
sp<UidPolicy> uidPolicy;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
uidPolicy = mUidPolicy;
}
if (uidPolicy) {
@@ -1537,7 +1538,7 @@
sp<UidPolicy> uidPolicy;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
uidPolicy = mUidPolicy;
}
if (uidPolicy) {
@@ -1575,7 +1576,7 @@
ActivityManager::PROCESS_STATE_UNKNOWN,
String16("audioserver"));
if (!res) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mObserverRegistered = true;
} else {
ALOGE("UidPolicy::registerSelf linkToDeath failed: %d", res);
@@ -1587,12 +1588,12 @@
void AudioPolicyService::UidPolicy::unregisterSelf() {
mAm.unlinkToDeath(this);
mAm.unregisterUidObserver(this);
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mObserverRegistered = false;
}
void AudioPolicyService::UidPolicy::binderDied(__unused const wp<IBinder> &who) {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mCachedUids.clear();
mObserverRegistered = false;
}
@@ -1600,7 +1601,7 @@
void AudioPolicyService::UidPolicy::checkRegistered() {
bool needToReregister = false;
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
needToReregister = !mObserverRegistered;
}
if (needToReregister) {
@@ -1613,7 +1614,7 @@
if (isServiceUid(uid)) return true;
checkRegistered();
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
auto overrideIter = mOverrideUids.find(uid);
if (overrideIter != mOverrideUids.end()) {
return overrideIter->second.first;
@@ -1628,7 +1629,7 @@
ActivityManager am;
bool active = am.isUidActive(uid, String16("audioserver"));
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mCachedUids.insert(std::pair<uid_t,
std::pair<bool, int>>(uid, std::pair<bool, int>(active,
ActivityManager::PROCESS_STATE_UNKNOWN)));
@@ -1642,7 +1643,7 @@
}
checkRegistered();
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
auto overrideIter = mOverrideUids.find(uid);
if (overrideIter != mOverrideUids.end()) {
if (overrideIter->second.first) {
@@ -1677,7 +1678,7 @@
state = am.getUidProcessState(uid, String16("audioserver"));
}
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
mCachedUids.insert(std::pair<uid_t,
std::pair<bool, int>>(uid, std::pair<bool, int>(active, state)));
}
@@ -1732,7 +1733,7 @@
bool wasActive = isUidActive(uid);
int previousState = getUidState(uid);
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
updateUidLocked(uids, uid, active, state, insert);
}
if (wasActive != isUidActive(uid) || state != previousState) {
@@ -1767,7 +1768,7 @@
}
bool AudioPolicyService::UidPolicy::isA11yOnTop() {
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
for (const auto &uid : mCachedUids) {
if (!isA11yUid(uid.first)) {
continue;
@@ -1898,7 +1899,7 @@
{
nsecs_t waitTime = -1;
- mLock.lock();
+ audio_utils::unique_lock ul(mMutex);
while (!exitPending())
{
sp<AudioPolicyService> svc;
@@ -1919,27 +1920,27 @@
VolumeData *data = (VolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set volume stream %d, \
volume %f, output %d", data->mStream, data->mVolume, data->mIO);
- mLock.unlock();
+ ul.unlock();
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
data->mIO);
- mLock.lock();
+ ul.lock();
}break;
case SET_PARAMETERS: {
ParametersData *data = (ParametersData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
data->mKeyValuePairs.c_str(), data->mIO);
- mLock.unlock();
+ ul.unlock();
command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
- mLock.lock();
+ ul.lock();
}break;
case SET_VOICE_VOLUME: {
VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set voice volume volume %f",
data->mVolume);
- mLock.unlock();
+ ul.unlock();
command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
- mLock.lock();
+ ul.lock();
}break;
case STOP_OUTPUT: {
StopOutputData *data = (StopOutputData *)command->mParam.get();
@@ -1949,9 +1950,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doStopOutput(data->mPortId);
- mLock.lock();
+ ul.lock();
}break;
case RELEASE_OUTPUT: {
ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
@@ -1961,9 +1962,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doReleaseOutput(data->mPortId);
- mLock.lock();
+ ul.lock();
}break;
case CREATE_AUDIO_PATCH: {
CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get();
@@ -1972,9 +1973,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
- mLock.unlock();
+ ul.unlock();
command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
- mLock.lock();
+ ul.lock();
}
} break;
case RELEASE_AUDIO_PATCH: {
@@ -1984,9 +1985,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
- mLock.unlock();
+ ul.unlock();
command->mStatus = af->releaseAudioPatch(data->mHandle);
- mLock.lock();
+ ul.lock();
}
} break;
case UPDATE_AUDIOPORT_LIST: {
@@ -1995,9 +1996,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnAudioPortListUpdate();
- mLock.lock();
+ ul.lock();
}break;
case UPDATE_AUDIOPATCH_LIST: {
ALOGV("AudioCommandThread() processing update audio patch list");
@@ -2005,9 +2006,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnAudioPatchListUpdate();
- mLock.lock();
+ ul.lock();
}break;
case CHANGED_AUDIOVOLUMEGROUP: {
AudioVolumeGroupData *data =
@@ -2017,9 +2018,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnAudioVolumeGroupChanged(data->mGroup, data->mFlags);
- mLock.lock();
+ ul.lock();
}break;
case SET_AUDIOPORT_CONFIG: {
SetAudioPortConfigData *data = (SetAudioPortConfigData *)command->mParam.get();
@@ -2028,9 +2029,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
- mLock.unlock();
+ ul.unlock();
command->mStatus = af->setAudioPortConfig(&data->mConfig);
- mLock.lock();
+ ul.lock();
}
} break;
case DYN_POLICY_MIX_STATE_UPDATE: {
@@ -2042,9 +2043,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
- mLock.lock();
+ ul.lock();
} break;
case RECORDING_CONFIGURATION_UPDATE: {
RecordingConfigurationUpdateData *data =
@@ -2054,21 +2055,21 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnRecordingConfigurationUpdate(data->mEvent, &data->mClientInfo,
&data->mClientConfig, data->mClientEffects,
&data->mDeviceConfig, data->mEffects,
data->mPatchHandle, data->mSource);
- mLock.lock();
+ ul.lock();
} break;
case SET_EFFECT_SUSPENDED: {
SetEffectSuspendedData *data = (SetEffectSuspendedData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set effect suspended");
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af != 0) {
- mLock.unlock();
+ ul.unlock();
af->setEffectSuspended(data->mEffectId, data->mSessionId, data->mSuspended);
- mLock.lock();
+ ul.lock();
}
} break;
case AUDIO_MODULES_UPDATE: {
@@ -2077,9 +2078,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnNewAudioModulesAvailable();
- mLock.lock();
+ ul.lock();
} break;
case ROUTING_UPDATED: {
ALOGV("AudioCommandThread() processing routing update");
@@ -2087,9 +2088,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnRoutingUpdated();
- mLock.lock();
+ ul.lock();
} break;
case UPDATE_UID_STATES: {
@@ -2098,9 +2099,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->updateUidStates();
- mLock.lock();
+ ul.lock();
} break;
case CHECK_SPATIALIZER_OUTPUT: {
@@ -2109,9 +2110,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnCheckSpatializer();
- mLock.lock();
+ ul.lock();
} break;
case UPDATE_ACTIVE_SPATIALIZER_TRACKS: {
@@ -2120,9 +2121,9 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnUpdateActiveSpatializerTracks();
- mLock.lock();
+ ul.lock();
} break;
case VOL_RANGE_INIT_REQUEST: {
@@ -2131,28 +2132,28 @@
if (svc == 0) {
break;
}
- mLock.unlock();
+ ul.unlock();
svc->doOnVolumeRangeInitRequest();
- mLock.lock();
+ ul.lock();
} break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
{
- Mutex::Autolock _l(command->mLock);
+ audio_utils::lock_guard _l(command->mMutex);
if (command->mWaitStatus) {
command->mWaitStatus = false;
- command->mCond.signal();
+ command->mCond.notify_one();
}
}
waitTime = -1;
- // release mLock before releasing strong reference on the service as
+ // release ul before releasing strong reference on the service as
// AudioPolicyService destructor calls AudioCommandThread::exit() which
- // acquires mLock.
- mLock.unlock();
+ // acquires ul.
+ ul.unlock();
svc.clear();
- mLock.lock();
+ ul.lock();
} else {
waitTime = mAudioCommands[0]->mTime - curTime;
break;
@@ -2170,9 +2171,10 @@
if (!exitPending()) {
ALOGV("AudioCommandThread() going to sleep");
if (waitTime == -1) {
- mWaitWorkCV.wait(mLock);
+ mWaitWorkCV.wait(ul);
} else {
- mWaitWorkCV.waitRelative(mLock, waitTime);
+ // discard return value.
+ mWaitWorkCV.wait_for(ul, std::chrono::nanoseconds(waitTime));
}
}
}
@@ -2180,17 +2182,17 @@
if (!mAudioCommands.isEmpty()) {
release_wake_lock(mName.c_str());
}
- mLock.unlock();
return false;
}
status_t AudioPolicyService::AudioCommandThread::dump(int fd)
+NO_THREAD_SAFETY_ANALYSIS // trylock
{
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
- const bool locked = dumpTryLock(mLock);
+ const bool locked = mMutex.try_lock(kDumpLockTimeoutNs);
if (!locked) {
String8 result2(kCmdDeadlockedString);
write(fd, result2.c_str(), result2.size());
@@ -2213,7 +2215,7 @@
write(fd, result.c_str(), result.size());
- dumpReleaseLock(mLock, locked);
+ dumpReleaseLock(mMutex, locked);
return NO_ERROR;
}
@@ -2471,14 +2473,15 @@
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
- Mutex::Autolock _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
insertCommand_l(command, delayMs);
- mWaitWorkCV.signal();
+ mWaitWorkCV.notify_one();
}
- Mutex::Autolock _l(command->mLock);
+ audio_utils::unique_lock ul(command->mMutex);
while (command->mWaitStatus) {
nsecs_t timeOutNs = kAudioCommandTimeoutNs + milliseconds(delayMs);
- if (command->mCond.waitRelative(command->mLock, timeOutNs) != NO_ERROR) {
+ if (command->mCond.wait_for(
+ ul, std::chrono::nanoseconds(timeOutNs)) == std::cv_status::timeout) {
command->mStatus = TIMED_OUT;
command->mWaitStatus = false;
}
@@ -2486,7 +2489,7 @@
return command->mStatus;
}
-// insertCommand_l() must be called with mLock held
+// insertCommand_l() must be called with mMutex held
void AudioPolicyService::AudioCommandThread::insertCommand_l(sp<AudioCommand>& command, int delayMs)
{
ssize_t i; // not size_t because i will count down to -1
@@ -2674,9 +2677,9 @@
{
ALOGV("AudioCommandThread::exit");
{
- AutoMutex _l(mLock);
+ audio_utils::lock_guard _l(mMutex);
requestExit();
- mWaitWorkCV.signal();
+ mWaitWorkCV.notify_one();
}
// Note that we can call it from the thread loop if all other references have been released
// but it will safely return WOULD_BLOCK in this case
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index aaf0b1b..9a8a056 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -20,6 +20,7 @@
#include <android/media/BnAudioPolicyService.h>
#include <android/media/GetSpatializerResponse.h>
#include <android-base/thread_annotations.h>
+#include <audio_utils/mutex.h>
#include <cutils/misc.h>
#include <cutils/config_utils.h>
#include <cutils/compiler.h>
@@ -387,10 +388,10 @@
* by audio policy manager and attach/detach the spatializer effect accordingly.
*/
void onCheckSpatializer() override;
- void onCheckSpatializer_l() REQUIRES(mLock);
+ void onCheckSpatializer_l() REQUIRES(mMutex);
void doOnCheckSpatializer();
- void onUpdateActiveSpatializerTracks_l() REQUIRES(mLock);
+ void onUpdateActiveSpatializerTracks_l() REQUIRES(mMutex);
void doOnUpdateActiveSpatializerTracks();
@@ -402,14 +403,14 @@
AudioPolicyService() ANDROID_API;
virtual ~AudioPolicyService();
- status_t dumpInternals(int fd) REQUIRES(mLock);
+ status_t dumpInternals(int fd) REQUIRES(mMutex);
// Handles binder shell commands
virtual status_t shellCommand(int in, int out, int err, Vector<String16>& args);
// Sets whether the given UID records only silence
- virtual void setAppState_l(sp<AudioRecordClient> client, app_state_t state) REQUIRES(mLock);
+ virtual void setAppState_l(sp<AudioRecordClient> client, app_state_t state) REQUIRES(mMutex);
// Overrides the UID state as if it is idle
status_t handleSetUidState(Vector<String16>& args, int err);
@@ -435,9 +436,9 @@
const AttributionSourceState& attributionSource);
void updateUidStates();
- void updateUidStates_l() REQUIRES(mLock);
+ void updateUidStates_l() REQUIRES(mMutex);
- void silenceAllRecordings_l() REQUIRES(mLock);
+ void silenceAllRecordings_l() REQUIRES(mMutex);
static bool isVirtualSource(audio_source_t source);
@@ -510,11 +511,11 @@
void checkRegistered();
wp<AudioPolicyService> mService;
- Mutex mLock;
+ audio_utils::mutex mMutex{audio_utils::MutexOrder::kUidPolicy_Mutex};
ActivityManager mAm;
bool mObserverRegistered = false;
- std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids GUARDED_BY(mLock);
- std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids GUARDED_BY(mLock);
+ std::unordered_map<uid_t, std::pair<bool, int>> mOverrideUids GUARDED_BY(mMutex);
+ std::unordered_map<uid_t, std::pair<bool, int>> mCachedUids GUARDED_BY(mMutex);
std::vector<uid_t> mAssistantUids;
std::vector<uid_t> mActiveAssistantUids;
std::vector<uid_t> mA11yUids;
@@ -641,8 +642,8 @@
int mCommand; // SET_VOLUME, SET_PARAMETERS...
nsecs_t mTime; // time stamp
- Mutex mLock; // mutex associated to mCond
- Condition mCond; // condition for status return
+ audio_utils::mutex mMutex{audio_utils::MutexOrder::kAudioCommand_Mutex};
+ audio_utils::condition_variable mCond; // condition for status return
status_t mStatus; // command status
bool mWaitStatus; // true if caller is waiting for status
sp<AudioCommandData> mParam; // command specific parameter data
@@ -730,8 +731,8 @@
bool mSuspended;
};
- Mutex mLock;
- Condition mWaitWorkCV;
+ mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kCommandThread_Mutex};
+ audio_utils::condition_variable mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
sp<AudioCommand> mLastCommand; // last processed command (used by dump)
String8 mName; // string used by wake lock fo delayed commands
@@ -996,12 +997,12 @@
* @return the number of active tracks.
*/
size_t countActiveClientsOnOutput_l(
- audio_io_handle_t output, bool spatializedOnly = true) REQUIRES(mLock);
+ audio_io_handle_t output, bool spatializedOnly = true) REQUIRES(mMutex);
- mutable Mutex mLock; // prevents concurrent access to AudioPolicy manager functions changing
- // device connection state or routing
- // Note: lock acquisition order is always mLock > mEffectsLock:
- // mLock protects AudioPolicyManager methods that can call into audio flinger
+ mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kAudioPolicyService_Mutex};
+ // prevents concurrent access to AudioPolicy manager functions changing
+ // device connection state or routing.
+ // mMutex protects AudioPolicyManager methods that can call into audio flinger
// and possibly back in to audio policy service and acquire mEffectsLock.
sp<AudioCommandThread> mAudioCommandThread; // audio commands thread
sp<AudioCommandThread> mOutputCommandThread; // process stop and release output
@@ -1009,29 +1010,30 @@
AudioPolicyClient *mAudioPolicyClient;
std::vector<audio_usage_t> mSupportedSystemUsages;
- Mutex mNotificationClientsLock;
+ mutable audio_utils::mutex mNotificationClientsMutex{
+ audio_utils::MutexOrder::kAudioPolicyService_NotificationClientsMutex};
DefaultKeyedVector<int64_t, sp<NotificationClient>> mNotificationClients
- GUARDED_BY(mNotificationClientsLock);
+ GUARDED_BY(mNotificationClientsMutex);
// Manage all effects configured in audio_effects.conf
- // never hold AudioPolicyService::mLock when calling AudioPolicyEffects methods as
+ // never hold AudioPolicyService::mMutex when calling AudioPolicyEffects methods as
// those can call back into AudioPolicyService methods and try to acquire the mutex
- sp<AudioPolicyEffects> mAudioPolicyEffects GUARDED_BY(mLock);
- audio_mode_t mPhoneState GUARDED_BY(mLock);
- uid_t mPhoneStateOwnerUid GUARDED_BY(mLock);
+ sp<AudioPolicyEffects> mAudioPolicyEffects GUARDED_BY(mMutex);
+ audio_mode_t mPhoneState GUARDED_BY(mMutex);
+ uid_t mPhoneStateOwnerUid GUARDED_BY(mMutex);
- sp<UidPolicy> mUidPolicy GUARDED_BY(mLock);
- sp<SensorPrivacyPolicy> mSensorPrivacyPolicy GUARDED_BY(mLock);
+ sp<UidPolicy> mUidPolicy GUARDED_BY(mMutex);
+ sp<SensorPrivacyPolicy> mSensorPrivacyPolicy GUARDED_BY(mMutex);
DefaultKeyedVector<audio_port_handle_t, sp<AudioRecordClient>> mAudioRecordClients
- GUARDED_BY(mLock);
+ GUARDED_BY(mMutex);
DefaultKeyedVector<audio_port_handle_t, sp<AudioPlaybackClient>> mAudioPlaybackClients
- GUARDED_BY(mLock);
+ GUARDED_BY(mMutex);
MediaPackageManager mPackageManager; // To check allowPlaybackCapture
CaptureStateNotifier mCaptureStateNotifier;
- // created in onFirstRef() and never cleared: does not need to be guarded by mLock
+ // created in onFirstRef() and never cleared: does not need to be guarded by mMutex
sp<Spatializer> mSpatializer;
void *mLibraryHandle = nullptr;
diff --git a/services/audiopolicy/service/Spatializer.cpp b/services/audiopolicy/service/Spatializer.cpp
index 90418a5..ca3e0e0 100644
--- a/services/audiopolicy/service/Spatializer.cpp
+++ b/services/audiopolicy/service/Spatializer.cpp
@@ -229,7 +229,7 @@
return;
}
auto latencyModesStrs = android::sysprop::BluetoothProperties::dsa_transport_preference();
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
// First load preferred low latency modes ordered from the property
for (auto str : latencyModesStrs) {
if (!str.has_value()) continue;
@@ -394,7 +394,11 @@
return status;
}
for (const auto channelMask : channelMasks) {
- if (!audio_is_channel_mask_spatialized(channelMask)) {
+ const bool channel_mask_spatialized =
+ com_android_media_audio_stereo_spatialization()
+ ? audio_channel_mask_contains_stereo(channelMask)
+ : audio_is_channel_mask_spatialized(channelMask);
+ if (!channel_mask_spatialized) {
ALOGW("%s: ignoring channelMask:%#x", __func__, channelMask);
continue;
}
@@ -461,7 +465,7 @@
/** Gets the channel mask, sampling rate and format set for the spatializer input. */
audio_config_base_t Spatializer::getAudioInConfig() const {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
audio_config_base_t config = AUDIO_CONFIG_BASE_INITIALIZER;
// For now use highest supported channel count
config.channel_mask = getMaxChannelMask(mChannelMasks, FCC_LIMIT);
@@ -470,7 +474,7 @@
status_t Spatializer::registerCallback(
const sp<media::INativeSpatializerCallback>& callback) {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (callback == nullptr) {
return BAD_VALUE;
}
@@ -498,7 +502,7 @@
// IBinder::DeathRecipient
void Spatializer::binderDied(__unused const wp<IBinder> &who) {
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
mLevel = Spatialization::Level::NONE;
mSpatializerCallback.clear();
}
@@ -527,7 +531,7 @@
sp<media::INativeSpatializerCallback> callback;
bool levelChanged = false;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
levelChanged = mLevel != level;
mLevel = level;
callback = mSpatializerCallback;
@@ -551,7 +555,7 @@
if (level == nullptr) {
return binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
*level = mLevel;
ALOGV("%s level %d", __func__, (int)*level);
return Status::ok();
@@ -562,14 +566,14 @@
if (supports == nullptr) {
return binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
*supports = mSupportsHeadTracking;
return Status::ok();
}
Status Spatializer::getSupportedHeadTrackingModes(
std::vector<HeadTracking::Mode>* modes) {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
ALOGV("%s", __func__);
if (modes == nullptr) {
return binderStatusFromStatusT(BAD_VALUE);
@@ -585,7 +589,7 @@
return binderStatusFromStatusT(INVALID_OPERATION);
}
mLocalLog.log("%s with %s", __func__, ToString(mode).c_str());
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
switch (mode) {
case HeadTracking::Mode::OTHER:
return binderStatusFromStatusT(BAD_VALUE);
@@ -610,7 +614,7 @@
if (mode == nullptr) {
return binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
*mode = mActualHeadTrackingMode;
ALOGV("%s mode %d", __func__, (int)*mode);
return Status::ok();
@@ -620,7 +624,7 @@
if (!mSupportsHeadTracking) {
return binderStatusFromStatusT(INVALID_OPERATION);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mPoseController != nullptr) {
mPoseController->recenter();
}
@@ -637,7 +641,7 @@
ALOGW("Invalid screenToStage vector.");
return binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mPoseController != nullptr) {
mLocalLog.log("%s with screenToStage %s", __func__,
media::VectorRecorder::toString<float>(screenToStage).c_str());
@@ -650,7 +654,7 @@
ALOGV("%s", __func__);
bool levelChanged = false;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mSpatializerCallback == nullptr) {
return binderStatusFromStatusT(INVALID_OPERATION);
}
@@ -674,7 +678,7 @@
if (!mSupportsHeadTracking) {
return binderStatusFromStatusT(INVALID_OPERATION);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mHeadSensor != sensorHandle) {
mLocalLog.log("%s with 0x%08x", __func__, sensorHandle);
mHeadSensor = sensorHandle;
@@ -689,7 +693,7 @@
if (!mSupportsHeadTracking) {
return binderStatusFromStatusT(INVALID_OPERATION);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mScreenSensor != sensorHandle) {
mLocalLog.log("%s with 0x%08x", __func__, sensorHandle);
mScreenSensor = sensorHandle;
@@ -708,7 +712,7 @@
// It is possible due to numerical inaccuracies to exceed the boundaries of 0 to 2 * M_PI.
ALOGI_IF(angle != physicalToLogicalAngle,
"%s: clamping %f to %f", __func__, physicalToLogicalAngle, angle);
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
mDisplayOrientation = angle;
if (mPoseController != nullptr) {
// This turns on the rate-limiter.
@@ -728,7 +732,7 @@
// It is possible due to numerical inaccuracies to exceed the boundaries of 0 to 2 * M_PI.
ALOGI_IF(angle != hingeAngle,
"%s: clamping %f to %f", __func__, hingeAngle, angle);
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
mHingeAngle = angle;
if (mEngine != nullptr) {
setEffectParameter_l(SPATIALIZER_PARAM_HINGE_ANGLE, std::vector<float>{angle});
@@ -739,7 +743,7 @@
Status Spatializer::setFoldState(bool folded) {
ALOGV("%s foldState %d", __func__, (int)folded);
mLocalLog.log("%s with %d", __func__, (int)folded);
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
mFoldedState = folded;
if (mEngine != nullptr) {
// we don't suppress multiple calls with the same folded state - that's
@@ -761,7 +765,7 @@
Status Spatializer::registerHeadTrackingCallback(
const sp<media::ISpatializerHeadTrackingCallback>& callback) {
ALOGV("%s callback %p", __func__, callback.get());
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (!mSupportsHeadTracking) {
return binderStatusFromStatusT(INVALID_OPERATION);
}
@@ -771,7 +775,7 @@
Status Spatializer::setParameter(int key, const std::vector<unsigned char>& value) {
ALOGV("%s key %d", __func__, key);
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
status_t status = INVALID_OPERATION;
if (mEngine != nullptr) {
status = setEffectParameter_l(key, value);
@@ -785,7 +789,7 @@
if (value == nullptr) {
return binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
status_t status = INVALID_OPERATION;
if (mEngine != nullptr) {
ALOGV("%s key %d mEngine %p", __func__, key, mEngine.get());
@@ -799,7 +803,7 @@
if (output == nullptr) {
binderStatusFromStatusT(BAD_VALUE);
}
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
*output = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_io_handle_t_int32_t(mOutput));
ALOGV("%s got output %d", __func__, *output);
return Status::ok();
@@ -837,7 +841,7 @@
ALOGV("%s", __func__);
sp<media::ISpatializerHeadTrackingCallback> callback;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
callback = mHeadTrackingCallback;
if (mEngine != nullptr) {
setEffectParameter_l(SPATIALIZER_PARAM_HEAD_TO_STAGE, headToStage);
@@ -865,7 +869,7 @@
sp<media::ISpatializerHeadTrackingCallback> callback;
HeadTracking::Mode spatializerMode;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (!mSupportsHeadTracking) {
spatializerMode = HeadTracking::Mode::DISABLED;
} else {
@@ -932,7 +936,7 @@
sp<media::INativeSpatializerCallback> callback;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
ALOGV("%s output %d mOutput %d", __func__, (int)output, (int)mOutput);
mLocalLog.log("%s with output %d tracks %zu (mOutput %d)", __func__, (int)output,
numActiveTracks, (int)mOutput);
@@ -998,7 +1002,7 @@
sp<media::INativeSpatializerCallback> callback;
{
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
mLocalLog.log("%s with output %d tracks %zu", __func__, (int)mOutput, mNumActiveTracks);
ALOGV("%s mOutput %d", __func__, (int)mOutput);
if (mOutput == AUDIO_IO_HANDLE_NONE) {
@@ -1032,7 +1036,7 @@
void Spatializer::onSupportedLatencyModesChangedMsg(
audio_io_handle_t output, std::vector<audio_latency_mode_t>&& modes) {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
ALOGV("%s output %d mOutput %d num modes %zu",
__func__, (int)output, (int)mOutput, modes.size());
if (output == mOutput) {
@@ -1043,7 +1047,7 @@
}
void Spatializer::updateActiveTracks(size_t numActiveTracks) {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mNumActiveTracks != numActiveTracks) {
mLocalLog.log("%s from %zu to %zu", __func__, mNumActiveTracks, numActiveTracks);
mNumActiveTracks = numActiveTracks;
@@ -1174,7 +1178,7 @@
void Spatializer::calculateHeadPose() {
ALOGV("%s", __func__);
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
if (mPoseController != nullptr) {
mPoseController->calculateAsync();
}
@@ -1193,7 +1197,7 @@
bool needUnlock = false;
prefixSpace += ' ';
- if (!mLock.try_lock()) {
+ if (!mMutex.try_lock()) {
// dumpsys even try_lock failed, information dump can be useful although may not accurate
ss.append(prefixSpace).append("try_lock failed, dumpsys below maybe INACCURATE!\n");
} else {
@@ -1239,6 +1243,10 @@
base::StringAppendF(&ss, "%sDisplayOrientation: %f\n", prefixSpace.c_str(),
mDisplayOrientation);
+ // 4. Show flag or property state.
+ base::StringAppendF(&ss, "%sStereo Spatialization: %s\n", prefixSpace.c_str(),
+ com_android_media_audio_stereo_spatialization() ? "true" : "false");
+
ss.append(prefixSpace + "CommandLog:\n");
ss += mLocalLog.dumpToString((prefixSpace + " ").c_str(), mMaxLocalLogLine);
@@ -1258,7 +1266,7 @@
}
if (needUnlock) {
- mLock.unlock();
+ mMutex.unlock();
}
return ss;
}
diff --git a/services/audiopolicy/service/Spatializer.h b/services/audiopolicy/service/Spatializer.h
index 123517e..24788dc 100644
--- a/services/audiopolicy/service/Spatializer.h
+++ b/services/audiopolicy/service/Spatializer.h
@@ -23,6 +23,7 @@
#include <android/media/audio/common/AudioLatencyMode.h>
#include <android/media/audio/common/HeadTracking.h>
#include <android/media/audio/common/Spatialization.h>
+#include <audio_utils/mutex.h>
#include <audio_utils/SimpleLog.h>
#include <math.h>
#include <media/AudioEffect.h>
@@ -148,7 +149,7 @@
/** Level getter for use by local classes. */
media::audio::common::Spatialization::Level getLevel() const {
- std::lock_guard lock(mLock);
+ audio_utils::lock_guard lock(mMutex);
return mLevel;
}
@@ -161,7 +162,7 @@
*/
audio_io_handle_t detachOutput();
/** Returns the output stream the spatializer is attached to. */
- audio_io_handle_t getOutput() const { std::lock_guard lock(mLock); return mOutput; }
+ audio_io_handle_t getOutput() const { audio_utils::lock_guard lock(mMutex); return mOutput; }
void updateActiveTracks(size_t numActiveTracks);
@@ -261,7 +262,7 @@
* according to values vector size.
*/
template<typename T>
- status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mLock) {
+ status_t setEffectParameter_l(uint32_t type, const std::vector<T>& values) REQUIRES(mMutex) {
static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values.size()];
@@ -286,7 +287,7 @@
* The variant is for compound parameters with two values of different base types
*/
template<typename P1, typename P2>
- status_t setEffectParameter_l(uint32_t type, const P1 val1, const P2 val2) REQUIRES(mLock) {
+ status_t setEffectParameter_l(uint32_t type, const P1 val1, const P2 val2) REQUIRES(mMutex) {
static_assert(sizeof(P1) <= sizeof(uint32_t), "The size of P1 must less than 32 bits");
static_assert(sizeof(P2) <= sizeof(uint32_t), "The size of P2 must less than 32 bits");
@@ -314,7 +315,7 @@
* by specifying values vector size.
*/
template<typename T>
- status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mLock) {
+ status_t getEffectParameter_l(uint32_t type, std::vector<T> *values) REQUIRES(mMutex) {
static_assert(sizeof(T) <= sizeof(uint32_t), "The size of T must less than 32 bits");
uint32_t cmd[sizeof(effect_param_t) / sizeof(uint32_t) + 1 + values->size()];
@@ -345,7 +346,7 @@
* The variant is for compound parameters with two values of different base types
*/
template<typename P1, typename P2>
- status_t getEffectParameter_l(uint32_t type, P1 *val1, P2 *val2) REQUIRES(mLock) {
+ status_t getEffectParameter_l(uint32_t type, P1 *val1, P2 *val2) REQUIRES(mMutex) {
static_assert(sizeof(P1) <= sizeof(uint32_t), "The size of P1 must less than 32 bits");
static_assert(sizeof(P2) <= sizeof(uint32_t), "The size of P2 must less than 32 bits");
@@ -375,25 +376,25 @@
* spatializer state and playback activity and configures the pose controller
* accordingly.
*/
- void checkSensorsState_l() REQUIRES(mLock);
+ void checkSensorsState_l() REQUIRES(mMutex);
/**
* Checks if the head pose controller should be created or destroyed according
* to desired head tracking mode.
*/
- void checkPoseController_l() REQUIRES(mLock);
+ void checkPoseController_l() REQUIRES(mMutex);
/**
* Checks if the spatializer effect should be enabled based on
* playback activity and requested level.
*/
- void checkEngineState_l() REQUIRES(mLock);
+ void checkEngineState_l() REQUIRES(mMutex);
/**
* Reset head tracking mode and recenter pose in engine: Called when the head tracking
* is disabled.
*/
- void resetEngineHeadPose_l() REQUIRES(mLock);
+ void resetEngineHeadPose_l() REQUIRES(mMutex);
/** Read bluetooth.core.le.dsa_transport_preference property and populate the ordered list of
* preferred low latency modes in mOrderedLowLatencyModes.
@@ -406,7 +407,7 @@
* Note: Because MODE_FREE is not in mOrderedLowLatencyModes, it will always be at
* the end of the list.
*/
- void sortSupportedLatencyModes_l() REQUIRES(mLock);
+ void sortSupportedLatencyModes_l() REQUIRES(mMutex);
/**
* Called after enabling head tracking in the spatializer engine to indicate which
@@ -415,14 +416,14 @@
* When the connection mode is direct to the sensor, the sensor ID is also communicated
* to the spatializer engine.
*/
- void setEngineHeadtrackingConnectionMode_l() REQUIRES(mLock);
+ void setEngineHeadtrackingConnectionMode_l() REQUIRES(mMutex);
/**
* Select the desired head tracking connection mode for the spatializer engine among the list
* stored in mSupportedHeadtrackingConnectionModes at init time.
* Also returns the desired low latency mode according to selected connection mode.
*/
- audio_latency_mode_t selectHeadtrackingConnectionMode_l() REQUIRES(mLock);
+ audio_latency_mode_t selectHeadtrackingConnectionMode_l() REQUIRES(mMutex);
/** Effect engine descriptor */
const effect_descriptor_t mEngineDescriptor;
@@ -435,48 +436,48 @@
const std::string mMetricsId = kDefaultMetricsId;
/** Mutex protecting internal state */
- mutable std::mutex mLock;
+ mutable audio_utils::mutex mMutex{audio_utils::MutexOrder::kSpatializer_Mutex};
/** Client AudioEffect for the engine */
- sp<AudioEffect> mEngine GUARDED_BY(mLock);
+ sp<AudioEffect> mEngine GUARDED_BY(mMutex);
/** Output stream the spatializer mixer thread is attached to */
- audio_io_handle_t mOutput GUARDED_BY(mLock) = AUDIO_IO_HANDLE_NONE;
+ audio_io_handle_t mOutput GUARDED_BY(mMutex) = AUDIO_IO_HANDLE_NONE;
/** Callback interface to the client (AudioService) controlling this`Spatializer */
- sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mLock);
+ sp<media::INativeSpatializerCallback> mSpatializerCallback GUARDED_BY(mMutex);
/** Callback interface for head tracking */
- sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mLock);
+ sp<media::ISpatializerHeadTrackingCallback> mHeadTrackingCallback GUARDED_BY(mMutex);
/** Requested spatialization level */
- media::audio::common::Spatialization::Level mLevel GUARDED_BY(mLock) =
+ media::audio::common::Spatialization::Level mLevel GUARDED_BY(mMutex) =
media::audio::common::Spatialization::Level::NONE;
/** Control logic for head-tracking, etc. */
- std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mLock);
+ std::shared_ptr<SpatializerPoseController> mPoseController GUARDED_BY(mMutex);
/** Last requested head tracking mode */
- media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mLock)
+ media::HeadTrackingMode mDesiredHeadTrackingMode GUARDED_BY(mMutex)
= media::HeadTrackingMode::STATIC;
/** Last-reported actual head-tracking mode. */
- media::audio::common::HeadTracking::Mode mActualHeadTrackingMode GUARDED_BY(mLock)
+ media::audio::common::HeadTracking::Mode mActualHeadTrackingMode GUARDED_BY(mMutex)
= media::audio::common::HeadTracking::Mode::DISABLED;
/** Selected Head pose sensor */
- int32_t mHeadSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
+ int32_t mHeadSensor GUARDED_BY(mMutex) = SpatializerPoseController::INVALID_SENSOR;
/** Selected Screen pose sensor */
- int32_t mScreenSensor GUARDED_BY(mLock) = SpatializerPoseController::INVALID_SENSOR;
+ int32_t mScreenSensor GUARDED_BY(mMutex) = SpatializerPoseController::INVALID_SENSOR;
/** Last display orientation received */
- float mDisplayOrientation GUARDED_BY(mLock) = 0.f; // aligned to natural up orientation.
+ float mDisplayOrientation GUARDED_BY(mMutex) = 0.f; // aligned to natural up orientation.
/** Last folded state */
- bool mFoldedState GUARDED_BY(mLock) = false; // foldable: true means folded.
+ bool mFoldedState GUARDED_BY(mMutex) = false; // foldable: true means folded.
/** Last hinge angle */
- float mHingeAngle GUARDED_BY(mLock) = 0.f; // foldable: 0.f is closed, M_PI flat open.
+ float mHingeAngle GUARDED_BY(mMutex) = 0.f; // foldable: 0.f is closed, M_PI flat open.
std::vector<media::audio::common::Spatialization::Level> mLevels;
std::vector<media::audio::common::HeadTracking::Mode> mHeadTrackingModes;
@@ -497,8 +498,8 @@
sp<ALooper> mLooper;
sp<EngineCallbackHandler> mHandler;
- size_t mNumActiveTracks GUARDED_BY(mLock) = 0;
- std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mLock);
+ size_t mNumActiveTracks GUARDED_BY(mMutex) = 0;
+ std::vector<audio_latency_mode_t> mSupportedLatencyModes GUARDED_BY(mMutex);
/** preference order for low latency modes according to persist.bluetooth.hid.transport */
std::vector<audio_latency_mode_t> mOrderedLowLatencyModes;
/** string to latency mode map used to parse bluetooth.core.le.dsa_transport_preference */
@@ -514,10 +515,10 @@
* Dump to local log with max/average pose angle every mPoseRecordThreshold.
*/
// Record one log line per second (up to mMaxLocalLogLine) to capture most recent sensor data.
- media::VectorRecorder mPoseRecorder GUARDED_BY(mLock) {
+ media::VectorRecorder mPoseRecorder GUARDED_BY(mMutex) {
6 /* vectorSize */, std::chrono::seconds(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */};
// Record one log line per minute (up to mMaxLocalLogLine) to capture durable sensor data.
- media::VectorRecorder mPoseDurableRecorder GUARDED_BY(mLock) {
+ media::VectorRecorder mPoseDurableRecorder GUARDED_BY(mMutex) {
6 /* vectorSize */, std::chrono::minutes(1), mMaxLocalLogLine, { 3 } /* delimiterIdx */};
}; // Spatializer
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 8dbf471..74d3474 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -211,7 +211,7 @@
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
- const uint32_t k48000SamplingRate = 48000;
+ constexpr static const uint32_t k48000SamplingRate = 48000;
};
void AudioPolicyManagerTest::SetUp() {
@@ -1274,13 +1274,30 @@
std::string mixAddress, const audio_config_t& audioConfig,
const std::vector<AudioMixMatchCriterion>& matchCriteria);
void clearPolicyMix();
+ void addPolicyMixAndStartInputForLoopback(
+ int mixType, int mixFlag, audio_devices_t deviceType, std::string mixAddress,
+ const audio_config_t& audioConfig,
+ const std::vector<AudioMixMatchCriterion>& matchCriteria,
+ audio_session_t session=AUDIO_SESSION_NONE,
+ audio_config_base_t config=DEFAULT_INPUT_CONFIG,
+ audio_input_flags_t inputFlags=AUDIO_INPUT_FLAG_NONE);
Vector<AudioMix> mAudioMixes;
const std::string mMixAddress = "remote_submix_media";
+
+ audio_port_handle_t mLoopbackInputPortId = AUDIO_PORT_HANDLE_NONE;
+ std::unique_ptr<RecordingActivityTracker> mTracker;
+ struct audio_port_v7 mInjectionPort;
+
+ constexpr static const audio_config_base_t DEFAULT_INPUT_CONFIG = {
+ .sample_rate = k48000SamplingRate,
+ .channel_mask = AUDIO_CHANNEL_IN_STEREO,
+ .format = AUDIO_FORMAT_PCM_16_BIT
+ };
};
void AudioPolicyManagerTestDynamicPolicy::TearDown() {
- mManager->unregisterPolicyMixes(mAudioMixes);
+ clearPolicyMix();
AudioPolicyManagerTestWithConfigurationFile::TearDown();
}
@@ -1302,11 +1319,45 @@
void AudioPolicyManagerTestDynamicPolicy::clearPolicyMix() {
if (mManager != nullptr) {
+ mManager->stopInput(mLoopbackInputPortId);
mManager->unregisterPolicyMixes(mAudioMixes);
}
mAudioMixes.clear();
}
+void AudioPolicyManagerTestDynamicPolicy::addPolicyMixAndStartInputForLoopback(
+ int mixType, int mixFlag, audio_devices_t deviceType, std::string mixAddress,
+ const audio_config_t& audioConfig,
+ const std::vector<AudioMixMatchCriterion>& matchCriteria, audio_session_t session,
+ audio_config_base_t config, audio_input_flags_t inputFlags) {
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(mixType, mixFlag, deviceType, mixAddress, audioConfig, matchCriteria));
+ if ((mixFlag & MIX_ROUTE_FLAG_LOOP_BACK) != MIX_ROUTE_FLAG_LOOP_BACK) {
+ return;
+ }
+
+ mTracker.reset(new RecordingActivityTracker());
+ struct audio_port_v7 extractionPort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
+ mixAddress, &extractionPort));
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
+ audio_attributes_t attr = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
+ std::string tags = "addr=" + mMixAddress;
+ audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
+ strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
+ ASSERT_NO_FATAL_FAILURE(
+ getInputForAttr(attr, &input, session, mTracker->getRiid(),
+ &selectedDeviceId, config.format, config.channel_mask,
+ config.sample_rate, inputFlags, &mLoopbackInputPortId));
+ ASSERT_EQ(NO_ERROR, mManager->startInput(mLoopbackInputPortId));
+ ASSERT_EQ(extractionPort.id, selectedDeviceId);
+
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ mMixAddress, &mInjectionPort));
+}
+
TEST_F(AudioPolicyManagerTestDynamicPolicy, InitSuccess) {
// SetUp must finish with no assertions
}
@@ -1684,11 +1735,6 @@
public testing::WithParamInterface<DPTestParam> {
protected:
void SetUp() override;
- void TearDown() override;
-
- std::unique_ptr<RecordingActivityTracker> mTracker;
- struct audio_port_v7 mInjectionPort;
- audio_port_handle_t mPortId = AUDIO_PORT_HANDLE_NONE;
};
void AudioPolicyManagerTestDPPlaybackReRouting::SetUp() {
@@ -1702,34 +1748,10 @@
audioConfig.sample_rate = k48000SamplingRate;
DPTestParam param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
- AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria);
- ASSERT_EQ(NO_ERROR, ret);
-
- struct audio_port_v7 extractionPort;
- ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SOURCE, AUDIO_DEVICE_IN_REMOTE_SUBMIX,
- mMixAddress, &extractionPort));
-
- audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
- audio_source_t source = AUDIO_SOURCE_REMOTE_SUBMIX;
- audio_attributes_t attr = {
- AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, source, AUDIO_FLAG_NONE, ""};
- std::string tags = "addr=" + mMixAddress;
- audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
- strncpy(attr.tags, tags.c_str(), AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1);
- getInputForAttr(attr, &input, param.session, mTracker->getRiid(),
- &selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- k48000SamplingRate, AUDIO_INPUT_FLAG_NONE, &mPortId);
- ASSERT_EQ(NO_ERROR, mManager->startInput(mPortId));
- ASSERT_EQ(extractionPort.id, selectedDeviceId);
-
- ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
- mMixAddress, &mInjectionPort));
-}
-
-void AudioPolicyManagerTestDPPlaybackReRouting::TearDown() {
- mManager->stopInput(mPortId);
- AudioPolicyManagerTestDynamicPolicy::TearDown();
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_LOOP_BACK,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX, mMixAddress, audioConfig, param.mixCriteria,
+ param.session));
}
TEST_P(AudioPolicyManagerTestDPPlaybackReRouting, PlaybackReRouting) {
@@ -1924,12 +1946,14 @@
// Add mix matching the test uid.
const int testUid = 12345;
const auto param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, param.mixRouteFlags, param.deviceType,
- param.deviceAddress, audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, param.mixRouteFlags,
+ param.deviceType, param.deviceAddress, audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid and mmap-ed stream should fail.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ // Getting output for matching uid and mmap-ed stream should fail.
+ audio_output_flags_t outputFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(INVALID_OPERATION,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
@@ -1942,11 +1966,12 @@
// Add mix matching the test uid.
const int testUid = 12345;
const auto param = GetParam();
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, param.mixRouteFlags, param.deviceType,
- param.deviceAddress, audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_NO_FATAL_FAILURE(
+ addPolicyMixAndStartInputForLoopback(MIX_TYPE_PLAYERS, param.mixRouteFlags,
+ param.deviceType,param.deviceAddress, audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid should succeed for non-mmaped stream.
+ // Getting output for matching uid should succeed for non-mmaped stream.
audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_NONE;
ASSERT_EQ(NO_ERROR,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
@@ -1957,23 +1982,57 @@
TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
MmapPlaybackStreamMatchingRenderDapMixSupportingMmapSucceeds) {
+ const std::string usbAddress = "card=1;device=0";
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ usbAddress.c_str(), "", AUDIO_FORMAT_DEFAULT));
+ audio_port_v7 usbDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_USB_DEVICE,
+ usbAddress, &usbDevicePort));
+
// Add render-only mix matching the test uid.
const int testUid = 12345;
// test_audio_policy_configuration.xml declares mmap-capable mix port
// for AUDIO_DEVICE_OUT_USB_DEVICE.
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
- AUDIO_DEVICE_OUT_USB_DEVICE, /*mixAddress=*/"",
- audioConfig, {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_USB_DEVICE, /*mixAddress=*/"",
+ audioConfig, {createUidCriterion(testUid)}));
- // Geting output for matching uid should succeed for mmaped stream, because matched mix
+ static const audio_output_flags_t mmapDirectFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
+ // Getting output for matching uid should succeed for mmaped stream, because matched mix
// redirects to mmap capable device.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ audio_output_flags_t outputFlags = mmapDirectFlags;
ASSERT_EQ(NO_ERROR,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
&mOutputType, &mIsSpatialized, &mIsBitPerfect));
+ ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
+ auto outputDesc = mManager->getOutputs().valueFor(mOutput);
+ ASSERT_NE(nullptr, outputDesc);
+ ASSERT_EQ(mmapDirectFlags, outputDesc->getFlags().output);
+
+ // After releasing the client, the output is closed. APM should reselect output for the policy
+ // mix.
+ mManager->releaseOutput(mPortId);
+ ASSERT_EQ(nullptr, mManager->getOutputs().valueFor(mOutput));
+ outputFlags = AUDIO_OUTPUT_FLAG_NONE;
+ mPortId = AUDIO_PORT_HANDLE_NONE;
+ ASSERT_EQ(NO_ERROR,
+ mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
+ createAttributionSourceState(testUid), &audioConfig,
+ &outputFlags, &mSelectedDeviceId, &mPortId, {},
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect));
+ ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
+ outputDesc = mManager->getOutputs().valueFor(mOutput);
+ ASSERT_NE(nullptr, outputDesc);
+ ASSERT_NE(mmapDirectFlags, outputDesc->getFlags().output);
+
+ ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
+ AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ usbAddress.c_str(), "", AUDIO_FORMAT_DEFAULT));
}
TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -1981,14 +2040,15 @@
// Add render-only mix matching the test uid.
const int testUid = 12345;
// Per test_audio_policy_configuration.xml AUDIO_DEVICE_OUT_SPEAKER doesn't support mmap.
- status_t ret = addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
- AUDIO_DEVICE_OUT_SPEAKER, /*mixAddress=*/"", audioConfig,
- {createUidCriterion(testUid)});
- ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR,
+ addPolicyMix(MIX_TYPE_PLAYERS, MIX_ROUTE_FLAG_RENDER,
+ AUDIO_DEVICE_OUT_SPEAKER, /*mixAddress=*/"", audioConfig,
+ {createUidCriterion(testUid)}));
- // Geting output for matching uid should fail for mmaped stream, because
+ // Getting output for matching uid should fail for mmaped stream, because
// matched mix redirects to device which doesn't support mmap.
- audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ audio_output_flags_t outputFlags =
+ (audio_output_flags_t) (AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);
ASSERT_EQ(INVALID_OPERATION,
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
@@ -2322,6 +2382,7 @@
static const std::string sCarBusNavigationOutput;
static const std::string sCarRearZoneOneOutput;
static const std::string sCarRearZoneTwoOutput;
+ static const std::string sCarBusMmapOutput;
};
const std::string AudioPolicyManagerCarTest::sCarConfig =
@@ -2335,6 +2396,8 @@
const std::string AudioPolicyManagerCarTest::sCarRearZoneTwoOutput = "bus200_audio_zone_2";
+const std::string AudioPolicyManagerCarTest::sCarBusMmapOutput = "bus8_mmap_out";
+
TEST_F(AudioPolicyManagerCarTest, InitSuccess) {
// SetUp must finish with no assertions.
}
@@ -2784,6 +2847,37 @@
ASSERT_EQ(navDevicePort.id, selectedDeviceId);
}
+TEST_F(AudioPolicyManagerCarTest, GetOutputForAttrForMMapWithPolicyMatched) {
+ 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, sCarBusMmapOutput, audioConfig, mediaMatchCriteria);
+ ASSERT_EQ(NO_ERROR, ret);
+ ASSERT_EQ(NO_ERROR, ret);
+ audio_port_v7 mmapDevicePort;
+ ASSERT_TRUE(findDevicePort(AUDIO_PORT_ROLE_SINK, AUDIO_DEVICE_OUT_BUS,
+ sCarBusMmapOutput, &mmapDevicePort));
+ 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_flags_t)(AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT),
+ &output, &portId, mediaAttribute);
+
+ ASSERT_EQ(mmapDevicePort.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 9e092c6..4efdf8a 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -56,7 +56,7 @@
</mixPort>
<mixPort name="hifi_output" role="source" flags="AUDIO_OUTPUT_FLAG_BIT_PERFECT"/>
<mixPort name="mmap_no_irq_out" role="source"
- flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
diff --git a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
index d131ed8..d40ebfc 100644
--- a/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_car_ap_atmos_offload_configuration.xml
@@ -30,6 +30,7 @@
<item>bus5_alarm_out</item>
<item>bus6_notification_out</item>
<item>bus7_system_sound_out</item>
+ <item>bus8_mmap_out</item>
<!-- names with _audio_zone_# are used for defined an emulator rear seat audio zone
where each number # is the zone id number -->
<item>bus100_audio_zone_1</item>
@@ -96,6 +97,11 @@
samplingRates="48000"
channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
</mixPort>
+ <mixPort name="mixport_bus8_mmap_out" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
<mixPort name="mixport_bus100_audio_zone_1" role="source">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
samplingRates="48000"
@@ -213,6 +219,16 @@
stepValueMB="100"/>
</gains>
</devicePort>
+ <devicePort tagName="bus8_mmap_out" role="sink" type="AUDIO_DEVICE_OUT_BUS"
+ address="bus8_mmap_out">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ <gains>
+ <gain name="" mode="AUDIO_GAIN_MODE_JOINT"
+ minValueMB="-3200" maxValueMB="600" defaultValueMB="0"
+ stepValueMB="100"/>
+ </gains>
+ </devicePort>
<devicePort tagName="bus100_audio_zone_1" role="sink" type="AUDIO_DEVICE_OUT_BUS"
address="bus100_audio_zone_1">
<profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
@@ -295,6 +311,8 @@
sources="mixport_bus6_notification_out"/>
<route type="mix" sink="bus7_system_sound_out"
sources="mixport_bus7_system_sound_out"/>
+ <route type="mix" sink="bus8_mmap_out"
+ sources="mixport_bus8_mmap_out"/>
<route type="mix" sink="bus100_audio_zone_1" sources="mixport_bus100_audio_zone_1"/>
<route type="mix" sink="bus200_audio_zone_2" sources="mixport_bus200_audio_zone_2"/>
<route type="mix" sink="primary input"
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 4883a09..575e0fb 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -101,7 +101,7 @@
"android.frameworks.cameraservice.device-V2-ndk",
"android.hardware.camera.common-V1-ndk",
"android.hardware.camera.device-V3-ndk",
- "android.hardware.camera.metadata-V2-ndk",
+ "android.hardware.camera.metadata-V3-ndk",
"android.hardware.camera.provider@2.4",
"android.hardware.camera.provider@2.5",
"android.hardware.camera.provider@2.6",
@@ -195,6 +195,7 @@
"utils/SessionStatsBuilder.cpp",
"utils/TagMonitor.cpp",
"utils/LatencyHistogram.cpp",
+ "utils/Utils.cpp",
],
header_libs: [
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index feb9c75..3f43af5 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -123,6 +123,10 @@
android_atomic_write(level, &gLogLevel);
}
+int32_t format_as(CameraService::StatusInternal s) {
+ return fmt::underlying(s);
+}
+
// ----------------------------------------------------------------------------
static const std::string sDumpPermission("android.permission.DUMP");
@@ -510,8 +514,8 @@
}
if (newStatus == StatusInternal::NOT_PRESENT) {
- logDeviceRemoved(cameraId, fmt::sprintf("Device status changed from %d to %d", oldStatus,
- newStatus));
+ logDeviceRemoved(cameraId, fmt::format("Device status changed from {} to {}",
+ oldStatus, newStatus));
// Set the device status to NOT_PRESENT, clients will no longer be able to connect
// to this device until the status changes
@@ -537,8 +541,8 @@
removeStates(cameraId);
} else {
if (oldStatus == StatusInternal::NOT_PRESENT) {
- logDeviceAdded(cameraId, fmt::sprintf("Device status changed from %d to %d", oldStatus,
- newStatus));
+ logDeviceAdded(cameraId, fmt::format("Device status changed from {} to {}",
+ oldStatus, newStatus));
}
updateStatus(newStatus, cameraId);
}
@@ -578,9 +582,9 @@
if (updated) {
std::string idCombo = id + " : " + physicalId;
if (newStatus == StatusInternal::PRESENT) {
- logDeviceAdded(idCombo, fmt::sprintf("Device status changed to %d", newStatus));
+ logDeviceAdded(idCombo, fmt::format("Device status changed to {}", newStatus));
} else {
- logDeviceRemoved(idCombo, fmt::sprintf("Device status changed to %d", newStatus));
+ logDeviceRemoved(idCombo, fmt::format("Device status changed to {}", newStatus));
}
// Avoid calling getSystemCameraKind() with mStatusListenerLock held (b/141756275)
SystemCameraKind deviceKind = SystemCameraKind::PUBLIC;
@@ -1092,6 +1096,39 @@
}
}
+Status CameraService::injectSessionParams(
+ const std::string& cameraId,
+ const CameraMetadata& sessionParams) {
+ if (!checkCallingPermission(toString16(sCameraInjectExternalCameraPermission))) {
+ const int pid = CameraThreadState::getCallingPid();
+ const int uid = CameraThreadState::getCallingUid();
+ ALOGE("%s: Permission Denial: can't inject session params pid=%d, uid=%d",
+ __FUNCTION__, pid, uid);
+ return STATUS_ERROR(ERROR_PERMISSION_DENIED,
+ "Permission Denial: no permission to inject session params");
+ }
+
+ std::unique_ptr<AutoConditionLock> serviceLockWrapper =
+ AutoConditionLock::waitAndAcquire(mServiceLockWrapper);
+
+ auto clientDescriptor = mActiveClientManager.get(cameraId);
+ if (clientDescriptor == nullptr) {
+ ALOGI("%s: No active client for camera id %s", __FUNCTION__, cameraId.c_str());
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+ "No active client for camera id %s", cameraId.c_str());
+ }
+
+ sp<BasicClient> clientSp = clientDescriptor->getValue();
+ status_t res = clientSp->injectSessionParams(sessionParams);
+
+ if (res != OK) {
+ return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
+ "Error injecting session params into camera \"%s\": %s (%d)",
+ cameraId.c_str(), strerror(-res), res);
+ }
+ return Status::ok();
+}
+
std::vector<std::string> CameraService::findOriginalIdsForRemappedCameraId(
const std::string& inputCameraId, int clientUid) {
std::string packageName = getPackageNameFromUid(clientUid);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index cabac17..1487013 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -232,7 +232,11 @@
const hardware::CameraExtensionSessionStats& stats, std::string* sessionKey /*out*/);
virtual binder::Status remapCameraIds(const hardware::CameraIdRemapping&
- cameraIdRemapping);
+ cameraIdRemapping);
+
+ virtual binder::Status injectSessionParams(
+ const std::string& cameraId,
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams);
virtual binder::Status createDefaultRequest(const std::string& cameraId, int templateId,
/*out*/
@@ -412,6 +416,10 @@
// Stop the injection camera and restore to internal camera session.
virtual status_t stopInjection() = 0;
+ // Inject session parameters into an existing session.
+ virtual status_t injectSessionParams(
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams) = 0;
+
protected:
BasicClient(const sp<CameraService>& cameraService,
const sp<IBinder>& remoteCallback,
@@ -685,6 +693,8 @@
UNKNOWN = static_cast<int32_t>(hardware::ICameraServiceListener::STATUS_UNKNOWN)
};
+ friend int32_t format_as(StatusInternal s);
+
/**
* Container class for the state of each logical camera device, including: ID, status, and
* dependencies on other devices. The mapping of camera ID -> state saved in mCameraStates
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
index 954cb8b..9e6a925 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
@@ -20,6 +20,7 @@
#include <aidl/AidlUtils.h>
#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
#include <android-base/properties.h>
+#include <utils/Utils.h>
namespace android::frameworks::cameraservice::device::implementation {
@@ -56,7 +57,7 @@
AidlCameraDeviceUser::AidlCameraDeviceUser(const sp<UICameraDeviceUser>& deviceRemote):
mDeviceRemote(deviceRemote) {
mInitSuccess = initDevice();
- mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+ mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
}
bool AidlCameraDeviceUser::initDevice() {
diff --git a/services/camera/libcameraservice/aidl/AidlCameraService.cpp b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
index 8cd7d1f..79dbfed 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraService.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraService.cpp
@@ -27,6 +27,7 @@
#include <android/binder_manager.h>
#include <binder/Status.h>
#include <hidl/HidlTransportSupport.h>
+#include <utils/Utils.h>
namespace android::frameworks::cameraservice::service::implementation {
@@ -79,7 +80,7 @@
AidlCameraService::AidlCameraService(::android::CameraService* cameraService):
mCameraService(cameraService) {
- mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+ mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
}
ScopedAStatus AidlCameraService::getCameraCharacteristics(const std::string& in_cameraId,
SCameraMetadata* _aidl_return) {
diff --git a/services/camera/libcameraservice/aidl/AidlUtils.cpp b/services/camera/libcameraservice/aidl/AidlUtils.cpp
index f5d68eb..f2d1414 100644
--- a/services/camera/libcameraservice/aidl/AidlUtils.cpp
+++ b/services/camera/libcameraservice/aidl/AidlUtils.cpp
@@ -310,8 +310,8 @@
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.
+ // VNDK version derived from ro.board.api_level is a version code-name that
+ // corresponds to the current SDK version.
return OK;
}
const auto &apiLevelToKeys =
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index b193be2..e403b97 100644
--- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -77,6 +77,7 @@
{34, {
ANDROID_CONTROL_AUTOFRAMING_AVAILABLE,
ANDROID_CONTROL_AVAILABLE_SETTINGS_OVERRIDES,
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
@@ -108,6 +109,7 @@
{34, {
ANDROID_CONTROL_AUTOFRAMING,
ANDROID_CONTROL_AUTOFRAMING_STATE,
+ ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
ANDROID_CONTROL_SETTINGS_OVERRIDE,
ANDROID_CONTROL_SETTINGS_OVERRIDING_FRAME_NUMBER,
ANDROID_EXTENSION_CURRENT_TYPE,
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 095d425..3488629 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -777,6 +777,60 @@
return res;
}
+binder::Status CameraDeviceClient::getSessionCharacteristics(
+ const SessionConfiguration& sessionConfiguration,
+ /*out*/
+ hardware::camera2::impl::CameraMetadataNative* sessionCharacteristics) {
+ ATRACE_CALL();
+ binder::Status res;
+ status_t ret = OK;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ auto operatingMode = sessionConfiguration.getOperatingMode();
+ res = SessionConfigurationUtils::checkOperatingMode(operatingMode, mDevice->info(),
+ mCameraIdStr);
+ if (!res.isOk()) {
+ return res;
+ }
+
+ camera3::metadataGetter getMetadata = [this](const std::string &id,
+ bool /*overrideForPerfClass*/) {
+ return mDevice->infoPhysical(id);};
+ ret = mProviderManager->getSessionCharacteristics(mCameraIdStr.c_str(),
+ sessionConfiguration, mOverrideForPerfClass, getMetadata,
+ sessionCharacteristics);
+
+ switch (ret) {
+ case OK:
+ // Expected, do nothing.
+ break;
+ case INVALID_OPERATION: {
+ std::string msg = fmt::sprintf(
+ "Camera %s: Session characteristics query not supported!",
+ mCameraIdStr.c_str());
+ ALOGD("%s: %s", __FUNCTION__, msg.c_str());
+ res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.c_str());
+ }
+
+ break;
+ default: {
+ std::string msg = fmt::sprintf( "Camera %s: Error: %s (%d)", mCameraIdStr.c_str(),
+ strerror(-ret), ret);
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ msg.c_str());
+ }
+ }
+
+ return res;
+}
+
binder::Status CameraDeviceClient::deleteStream(int streamId) {
ATRACE_CALL();
ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
@@ -1009,7 +1063,7 @@
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
"Camera %s: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
mCameraIdStr.c_str(), streamInfo.width, streamInfo.height, streamInfo.format,
- streamInfo.dataSpace, strerror(-err), err);
+ static_cast<int>(streamInfo.dataSpace), strerror(-err), err);
} else {
int i = 0;
for (auto& binder : binders) {
@@ -1106,7 +1160,8 @@
if (err != OK) {
res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
"Camera %s: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
- mCameraIdStr.c_str(), width, height, format, dataSpace, strerror(-err), err);
+ mCameraIdStr.c_str(), width, height, format, static_cast<int>(dataSpace),
+ strerror(-err), err);
} else {
// Can not add streamId to mStreamMap here, as the surface is deferred. Add it to
// a separate list to track. Once the deferred surface is set, this id will be
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index b2c9626..c2f7f56 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -109,6 +109,11 @@
/*out*/
bool* streamStatus) override;
+ virtual binder::Status getSessionCharacteristics(
+ const SessionConfiguration& sessionConfiguration,
+ /*out*/
+ hardware::camera2::impl::CameraMetadataNative* sessionCharacteristics) override;
+
// Returns -EBUSY if device is not idle or in error state
virtual binder::Status deleteStream(int streamId) override;
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index 4ed352d..dc9e0c1 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -383,5 +383,12 @@
return OK;
}
+status_t CameraOfflineSessionClient::injectSessionParams(
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams) {
+ ALOGV("%s: This client doesn't support the injecting session parameters camera.",
+ __FUNCTION__);
+ (void)sessionParams;
+ return OK;
+}
// ----------------------------------------------------------------------------
}; // namespace android
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
index 8aad4e9..804498f 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.h
@@ -120,6 +120,8 @@
status_t injectCamera(const std::string& injectedCamId,
sp<CameraProviderManager> manager) override;
status_t stopInjection() override;
+ status_t injectSessionParams(
+ const hardware::camera2::impl::CameraMetadataNative& sessionParams) override;
private:
mutable Mutex mBinderSerializationLock;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index c730b14..a126f61 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -509,6 +509,12 @@
return mDevice->stopInjection();
}
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::injectSessionParams(
+ const CameraMetadata& sessionParams) {
+ return mDevice->injectSessionParams(sessionParams);
+}
+
template class Camera2ClientBase<CameraService::Client>;
template class Camera2ClientBase<CameraDeviceClientBase>;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index bac4af8..2bb90d9 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
#include "common/CameraDeviceBase.h"
+#include "camera/CameraMetadata.h"
#include "camera/CaptureResult.h"
#include "utils/CameraServiceProxyWrapper.h"
#include "CameraServiceWatchdog.h"
@@ -136,6 +137,8 @@
sp<CameraProviderManager> manager) override;
status_t stopInjection() override;
+ status_t injectSessionParams(const CameraMetadata& sessionParams) override;
+
protected:
// The PID provided in the constructor call
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 983b2c1..cfc41c3 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -509,6 +509,10 @@
*/
virtual status_t stopInjection() = 0;
+ // Inject session parameters into an existing client.
+ virtual status_t injectSessionParams(
+ const CameraMetadata& sessionParams) = 0;
+
protected:
bool mImageDumpMask = 0;
std::vector<int64_t> mStreamUseCaseOverrides;
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index fbb5e1b..98c1a79 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -147,7 +147,7 @@
if (flags::lazy_aidl_wait_for_service()) {
binder = AServiceManager_waitForService(serviceName.c_str());
} else {
- binder = AServiceManager_getService(serviceName.c_str());
+ binder = AServiceManager_checkService(serviceName.c_str());
}
if (binder == nullptr) {
@@ -442,6 +442,23 @@
return OK;
}
+status_t CameraProviderManager::getSessionCharacteristics(const std::string& id,
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ metadataGetter getMetadata,
+ CameraMetadata* sessionCharacteristics /*out*/) const {
+ if (!flags::feature_combination_query()) {
+ return INVALID_OPERATION;
+ }
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ auto deviceInfo = findDeviceInfoLocked(id);
+ if (deviceInfo == nullptr) {
+ return NAME_NOT_FOUND;
+ }
+
+ return deviceInfo->getSessionCharacteristics(configuration,
+ overrideForPerfClass, getMetadata, sessionCharacteristics);
+}
+
status_t CameraProviderManager::getCameraIdIPCTransport(const std::string &id,
IPCTransport *providerTransport) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -1790,18 +1807,13 @@
auto& c = mCameraCharacteristics;
auto entry = c.find(ANDROID_SENSOR_READOUT_TIMESTAMP);
- if (entry.count != 0) {
- ALOGE("%s: CameraCharacteristics must not contain ANDROID_SENSOR_READOUT_TIMESTAMP!",
- __FUNCTION__);
+ if (entry.count == 0) {
+ uint8_t defaultReadoutTimestamp = readoutTimestampSupported ?
+ ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE :
+ ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED;
+ res = c.update(ANDROID_SENSOR_READOUT_TIMESTAMP, &defaultReadoutTimestamp, 1);
}
- uint8_t readoutTimestamp = ANDROID_SENSOR_READOUT_TIMESTAMP_NOT_SUPPORTED;
- if (readoutTimestampSupported) {
- readoutTimestamp = ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
- }
-
- res = c.update(ANDROID_SENSOR_READOUT_TIMESTAMP, &readoutTimestamp, 1);
-
return res;
}
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 6142a71..53a2102 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -317,6 +317,14 @@
bool *status /*out*/) const;
/**
+ * Get session characteristics for a particular session.
+ */
+ status_t getSessionCharacteristics(const std::string& id,
+ const SessionConfiguration &configuration,
+ bool overrideForPerfClass, camera3::metadataGetter getMetadata,
+ CameraMetadata* sessionCharacteristics /*out*/) const;
+
+ /**
* Return the highest supported device interface version for this ID
*/
status_t getHighestSupportedVersion(const std::string &id,
@@ -632,6 +640,15 @@
bool * /*status*/) {
return INVALID_OPERATION;
}
+
+ virtual status_t getSessionCharacteristics(
+ const SessionConfiguration &/*configuration*/,
+ bool /*overrideForPerfClass*/,
+ camera3::metadataGetter /*getMetadata*/,
+ CameraMetadata* /*sessionCharacteristics*/) {
+ return INVALID_OPERATION;
+ }
+
virtual status_t filterSmallJpegSizes() = 0;
virtual void notifyDeviceStateChange(int64_t /*newState*/) {}
virtual status_t createDefaultRequest(
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index a64c9d7..921ee43 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -275,54 +275,57 @@
if (mSavedInterface != nullptr) {
return mSavedInterface;
}
+
if (!kEnableLazyHal) {
ALOGE("Bad provider state! Should not be here on a non-lazy HAL!");
return nullptr;
}
auto interface = mActiveInterface.lock();
- if (interface == nullptr) {
- // Try to get service without starting
- interface =
- ICameraProvider::fromBinder(
- ndk::SpAIBinder(AServiceManager_checkService(mProviderName.c_str())));
- if (interface == nullptr) {
- ALOGV("Camera provider actually needs restart, calling getService(%s)",
- mProviderName.c_str());
- interface = mManager->mAidlServiceProxy->getAidlService(mProviderName.c_str());
-
- if (interface == nullptr) {
- ALOGD("%s: %s service not started", __FUNCTION__, mProviderName.c_str());
- return nullptr;
- }
-
- // Set all devices as ENUMERATING, provider should update status
- // to PRESENT after initializing.
- // This avoids failing getCameraDeviceInterface_V3_x before devices
- // are ready.
- for (auto& device : mDevices) {
- device->mIsDeviceAvailable = false;
- }
-
- interface->setCallback(mCallbacks);
- auto link = AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(),
- this);
- if (link != STATUS_OK) {
- ALOGW("%s: Unable to link to provider '%s' death notifications",
- __FUNCTION__, mProviderName.c_str());
- mManager->removeProvider(mProviderInstance);
- return nullptr;
- }
-
- // Send current device state
- interface->notifyDeviceStateChange(mDeviceState);
- }
- mActiveInterface = interface;
- } else {
- ALOGV("Camera provider (%s) already in use. Re-using instance.",
- mProviderName.c_str());
+ if (interface != nullptr) {
+ ALOGV("Camera provider (%s) already in use. Re-using instance.", mProviderName.c_str());
+ return interface;
}
+ // Try to get service without starting
+ interface = ICameraProvider::fromBinder(
+ ndk::SpAIBinder(AServiceManager_checkService(mProviderName.c_str())));
+ if (interface != nullptr) {
+ // Service is already running. Cache and return.
+ mActiveInterface = interface;
+ return interface;
+ }
+
+ ALOGV("Camera provider actually needs restart, calling getService(%s)", mProviderName.c_str());
+ interface = mManager->mAidlServiceProxy->getAidlService(mProviderName.c_str());
+ if (interface == nullptr) {
+ ALOGD("%s: %s service not started", __FUNCTION__, mProviderName.c_str());
+ return nullptr;
+ }
+
+ // Set all devices as ENUMERATING, provider should update status
+ // to PRESENT after initializing.
+ // This avoids failing getCameraDeviceInterface_V3_x before devices
+ // are ready.
+ for (auto& device : mDevices) {
+ device->mIsDeviceAvailable = false;
+ }
+
+ interface->setCallback(mCallbacks);
+ auto link = AIBinder_linkToDeath(interface->asBinder().get(), mDeathRecipient.get(),
+ this);
+ if (link != STATUS_OK) {
+ ALOGW("%s: Unable to link to provider '%s' death notifications",
+ __FUNCTION__, mProviderName.c_str());
+ mManager->removeProvider(mProviderInstance);
+ return nullptr;
+ }
+
+ // Send current device state
+ interface->notifyDeviceStateChange(mDeviceState);
+ // Cache interface to return early for future calls.
+ mActiveInterface = interface;
+
return interface;
}
@@ -900,6 +903,54 @@
return res;
}
+status_t AidlProviderInfo::AidlDeviceInfo3::getSessionCharacteristics(
+ const SessionConfiguration &configuration, bool overrideForPerfClass,
+ camera3::metadataGetter getMetadata, CameraMetadata *sessionCharacteristics) {
+ camera::device::StreamConfiguration streamConfiguration;
+ bool earlyExit = false;
+ auto res = SessionConfigurationUtils::convertToHALStreamCombination(configuration,
+ mId, mCameraCharacteristics, mCompositeJpegRDisabled, getMetadata,
+ mPhysicalIds, streamConfiguration, overrideForPerfClass, mProviderTagid,
+ /*checkSessionParams*/true, &earlyExit);
+
+ if (!res.isOk()) {
+ return UNKNOWN_ERROR;
+ }
+
+ if (earlyExit) {
+ return BAD_VALUE;
+ }
+
+ const std::shared_ptr<camera::device::ICameraDevice> interface =
+ startDeviceInterface();
+
+ if (interface == nullptr) {
+ return DEAD_OBJECT;
+ }
+
+ aidl::android::hardware::camera::device::CameraMetadata chars;
+ ::ndk::ScopedAStatus ret =
+ interface->getSessionCharacteristics(streamConfiguration, &chars);
+ std::vector<uint8_t> &metadata = chars.metadata;
+
+ camera_metadata_t *buffer = reinterpret_cast<camera_metadata_t*>(metadata.data());
+ size_t expectedSize = metadata.size();
+ int resV = validate_camera_metadata_structure(buffer, &expectedSize);
+ if (resV == OK || resV == CAMERA_METADATA_VALIDATION_SHIFTED) {
+ set_camera_metadata_vendor_id(buffer, mProviderTagid);
+ *sessionCharacteristics = buffer;
+ } else {
+ ALOGE("%s: Malformed camera metadata received from HAL", __FUNCTION__);
+ return BAD_VALUE;
+ }
+
+ if (!ret.isOk()) {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.getMessage());
+ return mapToStatusT(ret);
+ }
+ return OK;
+}
+
status_t AidlProviderInfo::convertToAidlHALStreamCombinationAndCameraIdsLocked(
const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
const std::set<std::string>& perfClassPrimaryCameraIds,
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
index cc5101a..0bfa7d4 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.h
@@ -134,6 +134,11 @@
camera3::camera_request_template_t templateId,
camera_metadata_t** metadata) override;
+ virtual status_t getSessionCharacteristics(
+ const SessionConfiguration &/*configuration*/,
+ bool overrideForPerfClass, camera3::metadataGetter /*getMetadata*/,
+ CameraMetadata *sessionCharacteristics /*sessionCharacteristics*/);
+
std::shared_ptr<aidl::android::hardware::camera::device::ICameraDevice>
startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index d2643c1..065f0c5 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -692,6 +692,14 @@
mHasFlashUnit = false;
}
+ if (flags::feature_combination_query()) {
+ res = addSessionConfigQueryVersionTag();
+ if (OK != res) {
+ ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ }
+ }
+
camera_metadata_entry entry =
mCameraCharacteristics.find(ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL);
if (entry.count == 1) {
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
index f53db7f..869bba0 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.h
@@ -107,6 +107,7 @@
const SessionConfiguration &/*configuration*/,
bool overrideForPerfClass, bool checkSessionParams,
bool *status/*status*/);
+
sp<hardware::camera::device::V3_2::ICameraDevice> startDeviceInterface();
};
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 0a5b0c4..c0a0544 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -69,6 +69,7 @@
#include "utils/SchedulingPolicyUtils.h"
#include "utils/SessionConfigurationUtils.h"
#include "utils/TraceHFR.h"
+#include "utils/Utils.h"
#include <algorithm>
#include <optional>
@@ -145,17 +146,6 @@
/** Register in-flight map to the status tracker */
mInFlightStatusId = mStatusTracker->addComponent("InflightRequests");
- if (mUseHalBufManager) {
- res = mRequestBufferSM.initialize(mStatusTracker);
- if (res != OK) {
- SET_ERR_L("Unable to start request buffer state machine: %s (%d)",
- strerror(-res), res);
- mInterface->close();
- mStatusTracker.clear();
- return res;
- }
- }
-
/** Create buffer manager */
mBufferManager = new Camera3BufferManager();
@@ -1622,7 +1612,9 @@
mStatusWaiters++;
bool signalPipelineDrain = false;
- if (!active && mUseHalBufManager) {
+ if (!active &&
+ (mUseHalBufManager ||
+ (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() != 0))) {
auto streamIds = mOutputStreams.getStreamIds();
if (mStatus == STATUS_ACTIVE) {
mRequestThread->signalPipelineDrain(streamIds);
@@ -2538,7 +2530,7 @@
}
config.streams = streams.editArray();
- config.use_hal_buf_manager = mUseHalBufManager;
+ config.hal_buffer_managed_streams = mHalBufManagedStreamIds;
// Do the HAL configuration; will potentially touch stream
// max_buffers, usage, and priv fields, as well as data_space and format
@@ -2562,13 +2554,17 @@
strerror(-res), res);
return res;
}
+ mUseHalBufManager = config.use_hal_buf_manager;
if (flags::session_hal_buf_manager()) {
- bool prevSessionHalBufManager = mUseHalBufManager;
- // It is possible that configureStreams() changed config.use_hal_buf_manager
- mUseHalBufManager = config.use_hal_buf_manager;
- if (prevSessionHalBufManager && !mUseHalBufManager) {
+ bool prevSessionHalBufManager = (mHalBufManagedStreamIds.size() != 0);
+ // It is possible that configureStreams() changed config.hal_buffer_managed_streams
+ mHalBufManagedStreamIds = config.hal_buffer_managed_streams;
+
+ bool thisSessionHalBufManager = mHalBufManagedStreamIds.size() != 0;
+
+ if (prevSessionHalBufManager && !thisSessionHalBufManager) {
mRequestBufferSM.deInit();
- } else if (!prevSessionHalBufManager && mUseHalBufManager) {
+ } else if (!prevSessionHalBufManager && thisSessionHalBufManager) {
res = mRequestBufferSM.initialize(mStatusTracker);
if (res != OK) {
SET_ERR_L("%s: Camera %s: RequestBuffer State machine couldn't be initialized!",
@@ -2576,7 +2572,7 @@
return res;
}
}
- mRequestThread->setHalBufferManager(mUseHalBufManager);
+ mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
}
// Finish all stream configuration immediately.
// TODO: Try to relax this later back to lazy completion, which should be
@@ -2904,7 +2900,8 @@
FlushInflightReqStates states {
mId, mInFlightLock, mInFlightMap, mUseHalBufManager,
- listener, *this, *mInterface, *this, mSessionStatsBuilder};
+ mHalBufManagedStreamIds, listener, *this, *mInterface, *this,
+ mSessionStatsBuilder};
camera3::flushInflightRequests(states);
}
@@ -2969,6 +2966,11 @@
return mBufferRecords.verifyBufferIds(streamId, bufIds);
}
+bool Camera3Device::HalInterface::isHalBufferManagedStream(int32_t streamId) const {
+ return (mUseHalBufManager || (flags::session_hal_buf_manager() &&
+ contains(mHalBufManagedStreamIds, streamId)));
+}
+
status_t Camera3Device::HalInterface::popInflightBuffer(
int32_t frameNumber, int32_t streamId,
/*out*/ buffer_handle_t **buffer) {
@@ -3061,7 +3063,7 @@
mOverrideToPortrait(overrideToPortrait),
mSupportSettingsOverride(supportSettingsOverride) {
mStatusId = statusTracker->addComponent("RequestThread");
- mVndkVersion = property_get_int32("ro.vndk.version", __ANDROID_API_FUTURE__);
+ mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
}
Camera3Device::RequestThread::~RequestThread() {}
@@ -3287,8 +3289,9 @@
mDoPauseSignal.signal();
}
-void Camera3Device::RequestThread::setHalBufferManager(bool enabled) {
- mUseHalBufManager = enabled;
+void Camera3Device::RequestThread::setHalBufferManagedStreams(
+ const std::set<int32_t> &halBufferManagedStreams) {
+ mHalBufManagedStreamIds = halBufferManagedStreams;
}
status_t Camera3Device::RequestThread::waitUntilRequestProcessed(
@@ -3590,12 +3593,16 @@
for (size_t i = 0; i < mNextRequests.size(); i++) {
auto& nextRequest = mNextRequests.editItemAt(i);
sp<CaptureRequest> captureRequest = nextRequest.captureRequest;
+ captureRequest->mTestPatternChanged = overrideTestPattern(captureRequest);
// Do not override rotate&crop for stream configurations that include
// SurfaceViews(HW_COMPOSER) output, unless mOverrideToPortrait is set.
// The display rotation there will be compensated by NATIVE_WINDOW_TRANSFORM_INVERSE_DISPLAY
captureRequest->mRotateAndCropChanged = (mComposerOutput && !mOverrideToPortrait) ? false :
overrideAutoRotateAndCrop(captureRequest);
captureRequest->mAutoframingChanged = overrideAutoframing(captureRequest);
+ if (flags::inject_session_params()) {
+ injectSessionParams(captureRequest, mInjectedSessionParams);
+ }
}
// 'mNextRequests' will at this point contain either a set of HFR batched requests
@@ -3619,7 +3626,10 @@
if (res == OK) {
sp<Camera3Device> parent = mParent.promote();
if (parent != nullptr) {
- mReconfigured |= parent->reconfigureCamera(mLatestSessionParams, mStatusId);
+ if (parent->reconfigureCamera(mLatestSessionParams, mStatusId)) {
+ mForceNewRequestAfterReconfigure = true;
+ mReconfigured = true;
+ }
}
if (mNextRequests[0].captureRequest->mInputStream != nullptr) {
@@ -3742,7 +3752,6 @@
bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
mPrevTriggers = triggerCount;
- bool testPatternChanged = overrideTestPattern(captureRequest);
bool settingsOverrideChanged = overrideSettingsOverride(captureRequest);
// If the request is the same as last, or we had triggers now or last time or
@@ -3751,12 +3760,20 @@
(mPrevRequest != captureRequest || triggersMixedIn ||
captureRequest->mRotateAndCropChanged ||
captureRequest->mAutoframingChanged ||
- testPatternChanged || settingsOverrideChanged) &&
+ captureRequest->mTestPatternChanged || settingsOverrideChanged ||
+ (flags::inject_session_params() && mForceNewRequestAfterReconfigure)) &&
// Request settings are all the same within one batch, so only treat the first
// request in a batch as new
!(batchedRequest && i > 0);
+
if (newRequest) {
std::set<std::string> cameraIdsWithZoom;
+
+ if (flags::inject_session_params() && mForceNewRequestAfterReconfigure) {
+ // This only needs to happen once.
+ mForceNewRequestAfterReconfigure = false;
+ }
+
/**
* HAL workaround:
* Insert a fake trigger ID if a trigger is set but no trigger ID is
@@ -3958,11 +3975,15 @@
nsecs_t waitDuration = kBaseGetBufferWait + parent->getExpectedInFlightDuration();
SurfaceMap uniqueSurfaceIdMap;
+ bool containsHalBufferManagedStream = false;
for (size_t j = 0; j < captureRequest->mOutputStreams.size(); j++) {
sp<Camera3OutputStreamInterface> outputStream =
captureRequest->mOutputStreams.editItemAt(j);
int streamId = outputStream->getId();
-
+ if (!containsHalBufferManagedStream) {
+ containsHalBufferManagedStream =
+ contains(mHalBufManagedStreamIds, streamId);
+ }
// Prepare video buffers for high speed recording on the first video request.
if (mPrepareVideoStream && outputStream->isVideoStream()) {
// Only try to prepare video stream on the first video request.
@@ -3994,7 +4015,7 @@
uniqueSurfaceIdMap.insert({streamId, std::move(uniqueSurfaceIds)});
}
- if (mUseHalBufManager) {
+ if (parent->isHalBufferManagedStream(streamId)) {
if (outputStream->isAbandoned()) {
ALOGV("%s: stream %d is abandoned, skipping request", __FUNCTION__, streamId);
return TIMED_OUT;
@@ -4085,6 +4106,9 @@
isZslCapture = true;
}
}
+ bool passSurfaceMap =
+ mUseHalBufManager ||
+ (flags::session_hal_buf_manager() && containsHalBufferManagedStream);
auto expectedDurationInfo = calculateExpectedDurationRange(settings);
res = parent->registerInFlight(halRequest->frame_number,
totalNumBuffers, captureRequest->mResultExtras,
@@ -4096,7 +4120,7 @@
requestedPhysicalCameras, isStillCapture, isZslCapture,
captureRequest->mRotateAndCropAuto, captureRequest->mAutoframingAuto,
mPrevCameraIdsWithZoom,
- (mUseHalBufManager) ? uniqueSurfaceIdMap :
+ passSurfaceMap ? uniqueSurfaceIdMap :
SurfaceMap{}, captureRequest->mRequestTimeNs);
ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
", burstId = %" PRId32 ".",
@@ -4199,7 +4223,8 @@
}
void Camera3Device::RequestThread::signalPipelineDrain(const std::vector<int>& streamIds) {
- if (!mUseHalBufManager) {
+ if (!mUseHalBufManager &&
+ (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() == 0)) {
ALOGE("%s called for camera device not supporting HAL buffer management", __FUNCTION__);
return;
}
@@ -4351,22 +4376,28 @@
captureRequest->mInputStream->returnInputBuffer(captureRequest->mInputBuffer);
}
- // No output buffer can be returned when using HAL buffer manager
- if (!mUseHalBufManager) {
- for (size_t i = 0; i < halRequest->num_output_buffers; i++) {
- //Buffers that failed processing could still have
- //valid acquire fence.
- int acquireFence = (*outputBuffers)[i].acquire_fence;
- if (0 <= acquireFence) {
- close(acquireFence);
- outputBuffers->editItemAt(i).acquire_fence = -1;
- }
- outputBuffers->editItemAt(i).status = CAMERA_BUFFER_STATUS_ERROR;
- captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i],
- /*timestamp*/0, /*readoutTimestamp*/0,
- /*timestampIncreasing*/true, std::vector<size_t> (),
- captureRequest->mResultExtras.frameNumber);
+ for (size_t i = 0; i < halRequest->num_output_buffers; i++) {
+ //Buffers that failed processing could still have
+ //valid acquire fence.
+ Camera3Stream *stream = Camera3Stream::cast((*outputBuffers)[i].stream);
+ int32_t streamId = stream->getId();
+ bool skipBufferForStream =
+ mUseHalBufManager || (flags::session_hal_buf_manager() &&
+ contains(mHalBufManagedStreamIds, streamId));
+ if (skipBufferForStream) {
+ // No output buffer can be returned when using HAL buffer manager for its stream
+ continue;
}
+ int acquireFence = (*outputBuffers)[i].acquire_fence;
+ if (0 <= acquireFence) {
+ close(acquireFence);
+ outputBuffers->editItemAt(i).acquire_fence = -1;
+ }
+ outputBuffers->editItemAt(i).status = CAMERA_BUFFER_STATUS_ERROR;
+ captureRequest->mOutputStreams.editItemAt(i)->returnBuffer((*outputBuffers)[i],
+ /*timestamp*/0, /*readoutTimestamp*/0,
+ /*timestampIncreasing*/true, std::vector<size_t> (),
+ captureRequest->mResultExtras.frameNumber);
}
if (sendRequestError) {
@@ -4904,6 +4935,45 @@
return false;
}
+void Camera3Device::RequestThread::injectSessionParams(
+ const sp<CaptureRequest> &request,
+ const CameraMetadata& injectedSessionParams) {
+ CameraMetadata &requestMetadata = request->mSettingsList.begin()->metadata;
+ uint32_t tag_section;
+ camera_metadata_ro_entry entry;
+ for (auto tag : mSessionParamKeys) {
+ tag_section = tag >> 16;
+ if (tag_section < VENDOR_SECTION) {
+ // Only allow injection of vendor tags.
+ continue;
+ }
+ entry = injectedSessionParams.find(tag);
+ if (entry.count > 0) {
+ requestMetadata.update(entry);
+ }
+ }
+}
+
+status_t Camera3Device::RequestThread::setInjectedSessionParams(
+ const CameraMetadata& injectedSessionParams) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mTriggerMutex);
+ mInjectedSessionParams = injectedSessionParams;
+ return OK;
+}
+
+status_t Camera3Device::injectSessionParams(const CameraMetadata& injectedSessionParams) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ if (mRequestThread == nullptr) {
+ return INVALID_OPERATION;
+ }
+
+ return mRequestThread->setInjectedSessionParams(injectedSessionParams);
+}
+
bool Camera3Device::RequestThread::overrideTestPattern(
const sp<CaptureRequest> &request) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index bde7e1b..498ef55 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -97,6 +97,10 @@
return mInterface->getTransportType();
}
+ bool isHalBufferManagedStream(int32_t streamId) const {
+ return mInterface->isHalBufferManagedStream(streamId);
+ };
+
/**
* CameraDeviceBase interface
*/
@@ -338,6 +342,11 @@
*/
status_t stopInjection();
+ /**
+ * Inject session params into the current client.
+ */
+ status_t injectSessionParams(const CameraMetadata& sessionParams);
+
protected:
status_t disconnectImpl();
static status_t removeFwkOnlyRegionKeys(CameraMetadata *request);
@@ -385,7 +394,6 @@
int mOperatingMode;
// Current session wide parameters
hardware::camera2::impl::CameraMetadataNative mSessionParams;
-
// Constant to use for no set operating mode
static const int NO_MODE = -1;
@@ -472,6 +480,9 @@
/////////////////////////////////////////////////////////////////////
+ //Check if a stream is hal buffer managed
+ bool isHalBufferManagedStream(int32_t streamId) const;
+
// Get a vector of (frameNumber, streamId) pair of currently inflight
// buffers
void getInflightBufferKeys(std::vector<std::pair<int32_t, int32_t>>* out);
@@ -543,7 +554,9 @@
uint32_t mNextStreamConfigCounter = 1;
+ // TODO: This can be removed after flags::session_hal_buf_manager is removed
bool mUseHalBufManager = false;
+ std::set<int32_t > mHalBufManagedStreamIds;
bool mIsReconfigurationQuerySupported;
const bool mSupportOfflineProcessing;
@@ -651,6 +664,8 @@
bool mAutoframingAuto;
// Indicates that the auto framing value within 'mSettingsList' was modified
bool mAutoframingChanged = false;
+ // Indicates that the camera test pattern setting is modified
+ bool mTestPatternChanged = false;
// Whether this capture request has its zoom ratio set to 1.0x before
// the framework overrides it for camera HAL consumption.
@@ -942,11 +957,11 @@
void setPaused(bool paused);
/**
- * Set Hal buffer manager behavior
- * @param enabled Whether HAL buffer manager is enabled for the current session.
+ * Set Hal buffer managed streams
+ * @param halBufferManagedStreams The streams for which hal buffer manager is enabled
*
*/
- void setHalBufferManager(bool enabled);
+ void setHalBufferManagedStreams(const std::set<int32_t> &halBufferManagedStreams);
/**
* Wait until thread processes the capture request with settings'
@@ -1005,6 +1020,12 @@
status_t setHalInterface(sp<HalInterface> newHalInterface);
+ status_t setInjectedSessionParams(const CameraMetadata& sessionParams);
+
+ void injectSessionParams(
+ const sp<CaptureRequest> &request,
+ const CameraMetadata& injectedSessionParams);
+
protected:
virtual bool threadLoop();
@@ -1185,10 +1206,13 @@
Vector<int32_t> mSessionParamKeys;
CameraMetadata mLatestSessionParams;
+ CameraMetadata mInjectedSessionParams;
+ bool mForceNewRequestAfterReconfigure;
std::map<int32_t, std::set<std::string>> mGroupIdPhysicalCameraMap;
bool mUseHalBufManager = false;
+ std::set<int32_t > mHalBufManagedStreamIds;
const bool mSupportCameraMute;
const bool mOverrideToPortrait;
const bool mSupportSettingsOverride;
@@ -1379,6 +1403,7 @@
// Whether HAL request buffers through requestStreamBuffers API
bool mUseHalBufManager = false;
+ std::set<int32_t > mHalBufManagedStreamIds;
bool mSessionHalBufManager = false;
// Lock to ensure requestStreamBuffers() callbacks are serialized
std::mutex mRequestBufferInterfaceLock;
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index c59138c..152687e 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -84,10 +84,10 @@
status_t res = getEndpointUsage(&consumerUsage);
if (res != OK) consumerUsage = 0;
- lines << fmt::sprintf(" State: %d\n", mState);
+ lines << fmt::sprintf(" State: %d\n", static_cast<int>(mState));
lines << fmt::sprintf(" Dims: %d x %d, format 0x%x, dataspace 0x%x\n",
camera_stream::width, camera_stream::height,
- camera_stream::format, camera_stream::data_space);
+ camera_stream::format, static_cast<int>(camera_stream::data_space));
lines << fmt::sprintf(" Max size: %zu\n", mMaxSize);
lines << fmt::sprintf(" Combined usage: 0x%" PRIx64 ", max HAL buffers: %d\n",
mUsage | consumerUsage, camera_stream::max_buffers);
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
index 172b62a..1025061 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.cpp
@@ -58,6 +58,7 @@
mTagMonitor(offlineStates.mTagMonitor),
mVendorTagId(offlineStates.mVendorTagId),
mUseHalBufManager(offlineStates.mUseHalBufManager),
+ mHalBufManagedStreamIds(offlineStates.mHalBufManagedStreamIds),
mNeedFixupMonochromeTags(offlineStates.mNeedFixupMonochromeTags),
mUsePartialResult(offlineStates.mUsePartialResult),
mNumPartialResults(offlineStates.mNumPartialResults),
@@ -136,7 +137,7 @@
FlushInflightReqStates states {
mId, mOfflineReqsLock, mOfflineReqs, mUseHalBufManager,
- listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
+ mHalBufManagedStreamIds, listener, *this, mBufferRecords, *this, mSessionStatsBuilder};
camera3::flushInflightRequests(states);
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index b5fd486..1ef3921 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -51,7 +51,8 @@
struct Camera3OfflineStates {
Camera3OfflineStates(
const TagMonitor& tagMonitor, const metadata_vendor_id_t vendorTagId,
- const bool useHalBufManager, const bool needFixupMonochromeTags,
+ const bool useHalBufManager, const std::set<int32_t> &halBufferManagedStreamIds,
+ const bool needFixupMonochromeTags,
const bool usePartialResult, const uint32_t numPartialResults,
const int64_t lastCompletedRegularFN, const int64_t lastCompletedReprocessFN,
const int64_t lastCompletedZslFN, const uint32_t nextResultFN,
@@ -64,7 +65,8 @@
const std::unordered_map<std::string, camera3::RotateAndCropMapper>&
rotateAndCropMappers) :
mTagMonitor(tagMonitor), mVendorTagId(vendorTagId),
- mUseHalBufManager(useHalBufManager), mNeedFixupMonochromeTags(needFixupMonochromeTags),
+ mUseHalBufManager(useHalBufManager), mHalBufManagedStreamIds(halBufferManagedStreamIds),
+ mNeedFixupMonochromeTags(needFixupMonochromeTags),
mUsePartialResult(usePartialResult), mNumPartialResults(numPartialResults),
mLastCompletedRegularFrameNumber(lastCompletedRegularFN),
mLastCompletedReprocessFrameNumber(lastCompletedReprocessFN),
@@ -85,6 +87,7 @@
const metadata_vendor_id_t mVendorTagId;
const bool mUseHalBufManager;
+ const std::set<int32_t > &mHalBufManagedStreamIds;
const bool mNeedFixupMonochromeTags;
const bool mUsePartialResult;
@@ -181,6 +184,7 @@
const metadata_vendor_id_t mVendorTagId;
const bool mUseHalBufManager;
+ const std::set<int32_t > &mHalBufManagedStreamIds;
const bool mNeedFixupMonochromeTags;
const bool mUsePartialResult;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 450f3dd..5d5c54c 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -45,13 +45,17 @@
#include <camera/CameraUtils.h>
#include <camera/StringUtils.h>
#include <camera_metadata_hidden.h>
+#include <com_android_internal_camera_flags.h>
#include "device3/Camera3OutputUtils.h"
+#include "utils/SessionConfigurationUtils.h"
#include "system/camera_metadata.h"
using namespace android::camera3;
+using namespace android::camera3::SessionConfigurationUtils;
using namespace android::hardware::camera;
+namespace flags = com::android::internal::camera::flags;
namespace android {
namespace camera3 {
@@ -534,7 +538,8 @@
request.pendingOutputBuffers.size() == 0);
returnOutputBuffers(
- states.useHalBufManager, states.listener,
+ states.useHalBufManager, states.halBufManagedStreamIds,
+ states.listener,
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), /*timestamp*/0, /*readoutTimestamp*/0,
/*requested*/true, request.requestTimeNs, states.sessionStatsBuilder,
@@ -794,7 +799,8 @@
result->num_output_buffers);
if (shutterTimestamp != 0) {
returnAndRemovePendingOutputBuffers(
- states.useHalBufManager, states.listener,
+ states.useHalBufManager, states.halBufManagedStreamIds,
+ states.listener,
request, states.sessionStatsBuilder);
}
@@ -845,6 +851,7 @@
void returnOutputBuffers(
bool useHalBufManager,
+ const std::set<int32_t> &halBufferManagedStreams,
sp<NotificationListener> listener,
const camera_stream_buffer_t *outputBuffers, size_t numBuffers,
nsecs_t timestamp, nsecs_t readoutTimestamp, bool requested,
@@ -871,7 +878,9 @@
}
if (outputBuffers[i].buffer == nullptr) {
- if (!useHalBufManager) {
+ if (!useHalBufManager &&
+ !(flags::session_hal_buf_manager() &&
+ contains(halBufferManagedStreams, streamId))) {
// With HAL buffer management API, HAL sometimes will have to return buffers that
// has not got a output buffer handle filled yet. This is though illegal if HAL
// buffer management API is not being used.
@@ -944,13 +953,14 @@
}
void returnAndRemovePendingOutputBuffers(bool useHalBufManager,
+ const std::set<int32_t> &halBufferManagedStreams,
sp<NotificationListener> listener, InFlightRequest& request,
SessionStatsBuilder& sessionStatsBuilder) {
bool timestampIncreasing =
!((request.zslCapture && request.stillCapture) || request.hasInputBuffer);
nsecs_t readoutTimestamp = request.resultExtras.hasReadoutTimestamp ?
request.resultExtras.readoutTimestamp : 0;
- returnOutputBuffers(useHalBufManager, listener,
+ returnOutputBuffers(useHalBufManager, halBufferManagedStreams, listener,
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(),
request.shutterTimestamp, readoutTimestamp,
@@ -1052,7 +1062,8 @@
r.rotateAndCropAuto, cameraIdsWithZoom, r.physicalMetadatas);
}
returnAndRemovePendingOutputBuffers(
- states.useHalBufManager, states.listener, r, states.sessionStatsBuilder);
+ states.useHalBufManager, states.halBufManagedStreamIds,
+ states.listener, r, states.sessionStatsBuilder);
removeInFlightRequestIfReadyLocked(states, idx);
}
@@ -1193,7 +1204,8 @@
for (size_t idx = 0; idx < states.inflightMap.size(); idx++) {
const InFlightRequest &request = states.inflightMap.valueAt(idx);
returnOutputBuffers(
- states.useHalBufManager, states.listener,
+ states.useHalBufManager, states.halBufManagedStreamIds,
+ states.listener,
request.pendingOutputBuffers.array(),
request.pendingOutputBuffers.size(), /*timestamp*/0, /*readoutTimestamp*/0,
/*requested*/true, request.requestTimeNs, states.sessionStatsBuilder,
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 134c037..d155fa2 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -48,6 +48,7 @@
// function also optionally calls notify(ERROR_BUFFER).
void returnOutputBuffers(
bool useHalBufManager,
+ const std::set<int32_t> &halBufferManagedStreams,
sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
const camera_stream_buffer_t *outputBuffers,
size_t numBuffers, nsecs_t timestamp,
@@ -65,6 +66,7 @@
// vector.
void returnAndRemovePendingOutputBuffers(
bool useHalBufManager,
+ const std::set<int32_t> &halBufferManagedStreams,
sp<NotificationListener> listener, // Only needed when outputSurfaces is not empty
InFlightRequest& request, SessionStatsBuilder& sessionStatsBuilder);
@@ -87,6 +89,7 @@
uint32_t& nextReprocResultFrameNum;
uint32_t& nextZslResultFrameNum; // end of outputLock scope
const bool useHalBufManager;
+ const std::set<int32_t > &halBufManagedStreamIds;
const bool usePartialResult;
const bool needFixupMonoChrome;
const uint32_t numPartialResults;
@@ -118,6 +121,7 @@
const std::string& cameraId;
std::mutex& reqBufferLock; // lock to serialize request buffer calls
const bool useHalBufManager;
+ const std::set<int32_t > &halBufManagedStreamIds;
StreamSet& outputStreams;
SessionStatsBuilder& sessionStatsBuilder;
SetErrorInterface& setErrIntf;
@@ -128,6 +132,7 @@
struct ReturnBufferStates {
const std::string& cameraId;
const bool useHalBufManager;
+ const std::set<int32_t > &halBufManagedStreamIds;
StreamSet& outputStreams;
SessionStatsBuilder& sessionStatsBuilder;
BufferRecordsInterface& bufferRecordsIntf;
@@ -138,6 +143,7 @@
std::mutex& inflightLock;
InFlightRequestMap& inflightMap; // end of inflightLock scope
const bool useHalBufManager;
+ const std::set<int32_t > &halBufManagedStreamIds;
sp<NotificationListener> listener;
InflightRequestUpdateInterface& inflightIntf;
BufferRecordsInterface& bufferRecordsIntf;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
index 3ac666b..2c30b15 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -32,13 +32,17 @@
#include <camera/CameraUtils.h>
#include <camera_metadata_hidden.h>
+#include <com_android_internal_camera_flags.h>
#include "device3/Camera3OutputUtils.h"
+#include "utils/SessionConfigurationUtils.h"
#include "system/camera_metadata.h"
using namespace android::camera3;
+using namespace android::camera3::SessionConfigurationUtils;
using namespace android::hardware::camera;
+namespace flags = com::android::internal::camera::flags;
namespace android {
namespace camera3 {
@@ -207,7 +211,9 @@
bool noBufferReturned = false;
buffer_handle_t *buffer = nullptr;
- if (states.useHalBufManager) {
+ if (states.useHalBufManager ||
+ (flags::session_hal_buf_manager() &&
+ contains(states.halBufManagedStreamIds, bSrc.streamId))) {
// This is suspicious most of the time but can be correct during flush where HAL
// has to return capture result before a buffer is requested
if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
@@ -294,13 +300,15 @@
template <class VecStreamBufferType>
void returnStreamBuffersT(ReturnBufferStates& states,
const VecStreamBufferType& buffers) {
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer managerment",
- __FUNCTION__, states.cameraId.c_str());
- return;
- }
for (const auto& buf : buffers) {
+ if (!states.useHalBufManager &&
+ !(flags::session_hal_buf_manager() &&
+ contains(states.halBufManagedStreamIds, buf.streamId))) {
+ ALOGE("%s: Camera %s does not support HAL buffer management for stream id %d",
+ __FUNCTION__, states.cameraId.c_str(), buf.streamId);
+ return;
+ }
if (buf.bufferId == BUFFER_ID_NO_BUFFER) {
ALOGE("%s: cannot return a buffer without bufferId", __FUNCTION__);
continue;
@@ -337,9 +345,10 @@
continue;
}
streamBuffer.stream = stream->asHalStream();
- returnOutputBuffers(states.useHalBufManager, /*listener*/nullptr,
- &streamBuffer, /*size*/1, /*timestamp*/ 0, /*readoutTimestamp*/0,
- /*requested*/false, /*requestTimeNs*/0, states.sessionStatsBuilder);
+ returnOutputBuffers(states.useHalBufManager, states.halBufManagedStreamIds,
+ /*listener*/nullptr, &streamBuffer, /*size*/1, /*timestamp*/ 0,
+ /*readoutTimestamp*/0, /*requested*/false, /*requestTimeNs*/0,
+ states.sessionStatsBuilder);
}
}
diff --git a/services/camera/libcameraservice/device3/InFlightRequest.h b/services/camera/libcameraservice/device3/InFlightRequest.h
index a7bd312..3626f20 100644
--- a/services/camera/libcameraservice/device3/InFlightRequest.h
+++ b/services/camera/libcameraservice/device3/InFlightRequest.h
@@ -35,6 +35,7 @@
uint32_t operation_mode;
bool input_is_multi_resolution;
bool use_hal_buf_manager = false;
+ std::set<int32_t> hal_buffer_managed_streams;
} camera_stream_configuration_t;
typedef struct camera_capture_request {
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 97475f0..13c500f 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -59,6 +59,7 @@
#include <com_android_internal_camera_flags.h>
#include "utils/CameraTraces.h"
+#include "utils/SessionConfigurationUtils.h"
#include "mediautils/SchedulingPolicyService.h"
#include "device3/Camera3OutputStream.h"
#include "device3/Camera3InputStream.h"
@@ -79,6 +80,7 @@
#include "AidlCamera3Device.h"
using namespace android::camera3;
+using namespace android::camera3::SessionConfigurationUtils;
using namespace aidl::android::hardware;
using aidl::android::hardware::camera::metadata::SensorPixelMode;
using aidl::android::hardware::camera::metadata::RequestAvailableDynamicRangeProfilesMap;
@@ -337,6 +339,16 @@
mBatchSizeLimitEnabled = (deviceVersion >= CAMERA_DEVICE_API_VERSION_1_2);
+ camera_metadata_entry readoutSupported = mDeviceInfo.find(ANDROID_SENSOR_READOUT_TIMESTAMP);
+ if (readoutSupported.count == 0) {
+ ALOGW("%s: Could not find value corresponding to ANDROID_SENSOR_READOUT_TIMESTAMP. "
+ "Assuming true.", __FUNCTION__);
+ mSensorReadoutTimestampSupported = true;
+ } else {
+ mSensorReadoutTimestampSupported =
+ readoutSupported.data.u8[0] == ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
+ }
+
return initializeCommonLocked();
}
@@ -400,7 +412,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
@@ -442,7 +454,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
@@ -450,7 +462,7 @@
mOverrideToPortrait, mActivePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
- camera3::notify(states, msg);
+ camera3::notify(states, msg, mSensorReadoutTimestampSupported);
}
return ::ndk::ScopedAStatus::ok();
@@ -531,7 +543,7 @@
}
// When not using HAL buf manager, only allow streams requested by app to be preserved
- if (!mUseHalBufManager) {
+ if (!isHalBufferManagedStream(id)) {
if (std::find(streamsToKeep.begin(), streamsToKeep.end(), id) == streamsToKeep.end()) {
SET_ERR("stream ID %d must not be switched to offline!", id);
return UNKNOWN_ERROR;
@@ -611,17 +623,18 @@
// TODO: check if we need to lock before copying states
// though technically no other thread should be talking to Camera3Device at this point
Camera3OfflineStates offlineStates(
- mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
- mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mNextResultFrameNumber, mNextReprocessResultFrameNumber,
- mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
- mZoomRatioMappers, mRotateAndCropMappers);
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mHalBufManagedStreamIds,
+ mNeedFixupMonochromeTags, mUsePartialResult, mNumPartialResults,
+ mLastCompletedRegularFrameNumber, mLastCompletedReprocessFrameNumber,
+ mLastCompletedZslFrameNumber, mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mNextShutterFrameNumber, mNextReprocessShutterFrameNumber,
+ mNextZslStillShutterFrameNumber, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers);
*session = new AidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
- std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
+ std::move(bufferRecords), offlineReqs, offlineStates,
+ offlineSession, mSensorReadoutTimestampSupported);
// Delete all streams that has been transferred to offline session
Mutex::Autolock l(mLock);
@@ -688,8 +701,8 @@
aidl::android::hardware::camera::device::BufferRequestStatus* status) {
RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams,
- mSessionStatsBuilder, *this, *(mInterface), *this};
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mHalBufManagedStreamIds,
+ mOutputStreams, mSessionStatsBuilder, *this, *(mInterface), *this};
camera3::requestStreamBuffers(states, bufReqs, outBuffers, status);
return ::ndk::ScopedAStatus::ok();
}
@@ -713,7 +726,7 @@
::ndk::ScopedAStatus AidlCamera3Device::returnStreamBuffers(
const std::vector<camera::device::StreamBuffer>& buffers) {
ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mId, mUseHalBufManager, mHalBufManagedStreamIds, mOutputStreams, mSessionStatsBuilder,
*(mInterface)};
camera3::returnStreamBuffers(states, buffers);
return ::ndk::ScopedAStatus::ok();
@@ -900,11 +913,18 @@
std::set<int> activeStreams;
camera::device::StreamConfiguration requestedConfiguration;
requestedConfiguration.streams.resize(config->num_streams);
+ config->use_hal_buf_manager = mUseHalBufManager;
for (size_t i = 0; i < config->num_streams; i++) {
camera::device::Stream &dst = requestedConfiguration.streams[i];
camera3::camera_stream_t *src = config->streams[i];
Camera3Stream* cam3stream = Camera3Stream::cast(src);
+ // For stream configurations with multi res streams, hal buffer manager has to be used.
+ if (!flags::session_hal_buf_manager() && cam3stream->getHalStreamGroupId() != -1 &&
+ src->stream_type != CAMERA_STREAM_INPUT) {
+ mUseHalBufManager = true;
+ config->use_hal_buf_manager = true;
+ }
cam3stream->setBufferFreedListener(this);
int streamId = cam3stream->getId();
StreamType streamType;
@@ -975,31 +995,38 @@
requestedConfiguration.multiResolutionInputImage = config->input_is_multi_resolution;
requestedConfiguration.logId = logId;
ndk::ScopedAStatus err = ndk::ScopedAStatus::ok();
+ int32_t interfaceVersion = 0;
camera::device::ConfigureStreamsRet configureStreamsRet;
- if (flags::session_hal_buf_manager()) {
- int32_t interfaceVersion = 0;
- err = mAidlSession->getInterfaceVersion(&interfaceVersion);
- if (!err.isOk()) {
- ALOGE("%s: Transaction error getting interface version: %s", __FUNCTION__,
- err.getMessage());
- return AidlProviderInfo::mapToStatusT(err);
- }
- if (interfaceVersion >= AIDL_DEVICE_SESSION_V3 && mSupportSessionHalBufManager) {
- err = mAidlSession->configureStreamsV2(requestedConfiguration, &configureStreamsRet);
- finalConfiguration = std::move(configureStreamsRet.halStreams);
- } else {
- err = mAidlSession->configureStreams(requestedConfiguration, &finalConfiguration);
- }
+ err = mAidlSession->getInterfaceVersion(&interfaceVersion);
+ if (!err.isOk()) {
+ ALOGE("%s: Transaction error getting interface version: %s", __FUNCTION__,
+ err.getMessage());
+ return AidlProviderInfo::mapToStatusT(err);
+ }
+ if (flags::session_hal_buf_manager() && interfaceVersion >= AIDL_DEVICE_SESSION_V3
+ && mSupportSessionHalBufManager) {
+ err = mAidlSession->configureStreamsV2(requestedConfiguration, &configureStreamsRet);
+ finalConfiguration = std::move(configureStreamsRet.halStreams);
} else {
err = mAidlSession->configureStreams(requestedConfiguration, &finalConfiguration);
}
+
if (!err.isOk()) {
ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
return AidlProviderInfo::mapToStatusT(err);
}
- if (flags::session_hal_buf_manager() && mSupportSessionHalBufManager) {
- mUseHalBufManager = configureStreamsRet.enableHalBufferManager;
- config->use_hal_buf_manager = configureStreamsRet.enableHalBufferManager;
+
+ if (flags::session_hal_buf_manager()) {
+ std::set<int32_t> halBufferManagedStreamIds;
+ for (const auto &halStream: finalConfiguration) {
+ if ((interfaceVersion >= AIDL_DEVICE_SESSION_V3 &&
+ mSupportSessionHalBufManager && halStream.enableHalBufferManager)
+ || mUseHalBufManager) {
+ halBufferManagedStreamIds.insert(halStream.id);
+ }
+ }
+ mHalBufManagedStreamIds = std::move(halBufferManagedStreamIds);
+ config->hal_buffer_managed_streams = mHalBufManagedStreamIds;
}
// And convert output stream configuration from AIDL
for (size_t i = 0; i < config->num_streams; i++) {
@@ -1070,9 +1097,9 @@
}
dstStream->setUsage(
mapProducerToFrameworkUsage(src.producerUsage));
-
if (flags::session_hal_buf_manager()) {
- dstStream->setHalBufferManager(mUseHalBufManager);
+ dstStream->setHalBufferManager(
+ contains(config->hal_buffer_managed_streams, streamId));
}
}
dst->max_buffers = src.maxBuffers;
@@ -1396,7 +1423,7 @@
handlesCreated->push_back(acquireFence);
}
dst.acquireFence = camera3::dupToAidlIfNotNull(acquireFence);
- } else if (mUseHalBufManager) {
+ } else if (isHalBufferManagedStream(streamId)) {
// HAL buffer management path
dst.bufferId = BUFFER_ID_NO_BUFFER;
dst.buffer = aidl::android::hardware::common::NativeHandle();
@@ -1410,7 +1437,7 @@
dst.releaseFence = aidl::android::hardware::common::NativeHandle();
// Output buffers are empty when using HAL buffer manager
- if (!mUseHalBufManager) {
+ if (!isHalBufferManagedStream(streamId)) {
mBufferRecords.pushInflightBuffer(
captureRequest->frameNumber, streamId, src->buffer);
inflightBuffers->push_back(std::make_pair(captureRequest->frameNumber, streamId));
@@ -1456,8 +1483,9 @@
bool supportCameraMute,
bool overrideToPortrait,
bool supportSettingsOverride) :
- RequestThread(parent, statusTracker, interface, sessionParamKeys, useHalBufManager,
- supportCameraMute, overrideToPortrait, supportSettingsOverride) {}
+ RequestThread(parent, statusTracker, interface, sessionParamKeys,
+ useHalBufManager, supportCameraMute, overrideToPortrait,
+ supportSettingsOverride) {}
status_t AidlCamera3Device::AidlRequestThread::switchToOffline(
const std::vector<int32_t>& streamsToKeep,
@@ -1690,7 +1718,8 @@
bool overrideToPortrait,
bool supportSettingsOverride) {
return new AidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
- useHalBufManager, supportCameraMute, overrideToPortrait, supportSettingsOverride);
+ useHalBufManager, supportCameraMute, overrideToPortrait,
+ supportSettingsOverride);
};
sp<Camera3Device::Camera3DeviceInjectionMethods>
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
index 90e2f97..f0a5f7e 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.h
@@ -289,6 +289,9 @@
// capture requests.
bool mBatchSizeLimitEnabled = false;
+ // Whether the HAL supports reporting sensor readout timestamp
+ bool mSensorReadoutTimestampSupported = true;
+
}; // class AidlCamera3Device
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
index 01c4e88..f8308df 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.cpp
@@ -122,7 +122,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
@@ -169,7 +169,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this,
@@ -177,7 +177,7 @@
/*overrideToPortrait*/false, activePhysicalId}, mResultMetadataQueue
};
for (const auto& msg : msgs) {
- camera3::notify(states, msg);
+ camera3::notify(states, msg, mSensorReadoutTimestampSupported);
}
return ::ndk::ScopedAStatus::ok();
}
@@ -208,7 +208,8 @@
}
RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager,
+ mHalBufManagedStreamIds, mOutputStreams, mSessionStatsBuilder,
*this, mBufferRecords, *this};
camera3::requestStreamBuffers(states, bufReqs, buffers, status);
return ::ndk::ScopedAStatus::ok();
@@ -241,7 +242,7 @@
}
ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mId, mUseHalBufManager, mHalBufManagedStreamIds, mOutputStreams, mSessionStatsBuilder,
mBufferRecords};
camera3::returnStreamBuffers(states, buffers);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
index 33b638c..f8fdeb9 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OfflineSession.h
@@ -105,19 +105,20 @@
};
// initialize by Camera3Device.
- explicit AidlCamera3OfflineSession(const std::string& id,
- const sp<camera3::Camera3Stream>& inputStream,
- const camera3::StreamSet& offlineStreamSet,
- camera3::BufferRecords&& bufferRecords,
+ explicit AidlCamera3OfflineSession(
+ const std::string& id, const sp<camera3::Camera3Stream>& inputStream,
+ const camera3::StreamSet& offlineStreamSet, camera3::BufferRecords&& bufferRecords,
const camera3::InFlightRequestMap& offlineReqs,
const Camera3OfflineStates& offlineStates,
std::shared_ptr<aidl::android::hardware::camera::device::ICameraOfflineSession>
- offlineSession) :
- Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
- offlineReqs, offlineStates),
- mSession(offlineSession) {
- mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
- };
+ offlineSession,
+ bool sensorReadoutTimestampSupported)
+ : Camera3OfflineSession(id, inputStream, offlineStreamSet, std::move(bufferRecords),
+ offlineReqs, offlineStates),
+ mSession(offlineSession),
+ mSensorReadoutTimestampSupported(sensorReadoutTimestampSupported) {
+ mCallbacks = ndk::SharedRefBase::make<AidlCameraDeviceCallbacks>(this);
+ };
/**
* End of CameraOfflineSessionBase interface
@@ -130,6 +131,8 @@
std::shared_ptr<AidlCameraDeviceCallbacks> mCallbacks;
+ bool mSensorReadoutTimestampSupported;
+
virtual void closeSessionLocked() override;
virtual void releaseSessionLocked() override;
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
index 74d4230..3fc070b 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.cpp
@@ -67,7 +67,8 @@
}
void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg) {
+ const aidl::android::hardware::camera::device::NotifyMsg& msg,
+ bool hasReadoutTimestamp) {
using ErrorCode = aidl::android::hardware::camera::device::ErrorCode;
using Tag = aidl::android::hardware::camera::device::NotifyMsg::Tag;
@@ -110,8 +111,9 @@
m.type = CAMERA_MSG_SHUTTER;
m.message.shutter.frame_number = msg.get<Tag::shutter>().frameNumber;
m.message.shutter.timestamp = msg.get<Tag::shutter>().timestamp;
- m.message.shutter.readout_timestamp_valid = true;
- m.message.shutter.readout_timestamp = msg.get<Tag::shutter>().readoutTimestamp;
+ m.message.shutter.readout_timestamp_valid = hasReadoutTimestamp;
+ m.message.shutter.readout_timestamp =
+ hasReadoutTimestamp ? msg.get<Tag::shutter>().readoutTimestamp : 0LL;
break;
}
notify(states, &m);
@@ -143,12 +145,6 @@
std::lock_guard<std::mutex> lock(states.reqBufferLock);
std::vector<StreamBufferRet> bufRets;
outBuffers->clear();
- if (!states.useHalBufManager) {
- ALOGE("%s: Camera %s does not support HAL buffer management",
- __FUNCTION__, states.cameraId.c_str());
- *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
- return;
- }
SortedVector<int32_t> streamIds;
ssize_t sz = streamIds.setCapacity(bufReqs.size());
@@ -174,6 +170,13 @@
*status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
return;
}
+ if (!states.useHalBufManager &&
+ !contains(states.halBufManagedStreamIds, bufReq.streamId)) {
+ ALOGE("%s: Camera %s does not support HAL buffer management for stream id %d",
+ __FUNCTION__, states.cameraId.c_str(), bufReq.streamId);
+ *status = BufferRequestStatus::FAILED_ILLEGAL_ARGUMENTS;
+ return;
+ }
streamIds.add(bufReq.streamId);
}
@@ -316,7 +319,7 @@
sb.acquire_fence = -1;
sb.status = CAMERA_BUFFER_STATUS_ERROR;
}
- returnOutputBuffers(states.useHalBufManager, nullptr,
+ returnOutputBuffers(states.useHalBufManager,states.halBufManagedStreamIds, nullptr,
streamBuffers.data(), numAllocatedBuffers, 0,
0, false,
0, states.sessionStatsBuilder);
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
index e795624..d3a8ede 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3OutputUtils.h
@@ -79,11 +79,8 @@
&physicalCameraMetadata);
void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg,
- bool hasReadoutTime, uint64_t readoutTime);
-
- void notify(CaptureOutputStates& states,
- const aidl::android::hardware::camera::device::NotifyMsg& msg);
+ const aidl::android::hardware::camera::device::NotifyMsg& msg,
+ bool hasReadoutTimestamp);
void requestStreamBuffers(RequestBufferStates& states,
const std::vector<aidl::android::hardware::camera::device::BufferRequest>& bufReqs,
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 4488067..f2e618f 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -47,6 +47,7 @@
#include <utils/Timers.h>
#include <cutils/properties.h>
#include <camera/StringUtils.h>
+#include <com_android_internal_camera_flags.h>
#include <android/hardware/camera/device/3.7/ICameraInjectionSession.h>
#include <android/hardware/camera2/ICameraDeviceUser.h>
@@ -66,6 +67,7 @@
using namespace android::hardware::camera;
using namespace android::hardware::camera::device::V3_2;
using android::hardware::camera::metadata::V3_6::CameraMetadataEnumAndroidSensorPixelMode;
+namespace flags = com::android::internal::camera::flags;
namespace android {
@@ -307,7 +309,8 @@
const hardware::hidl_vec<hardware::camera::device::V3_5::BufferRequest>& bufReqs,
requestStreamBuffers_cb _hidl_cb) {
RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager, mHalBufManagedStreamIds,
+ mOutputStreams, mSessionStatsBuilder,
*this, *mInterface, *this};
camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
return hardware::Void();
@@ -316,7 +319,8 @@
hardware::Return<void> HidlCamera3Device::returnStreamBuffers(
const hardware::hidl_vec<hardware::camera::device::V3_2::StreamBuffer>& buffers) {
ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, *mInterface};
+ mId, mUseHalBufManager, mHalBufManagedStreamIds, mOutputStreams,
+ mSessionStatsBuilder, *mInterface};
camera3::returnStreamBuffers(states, buffers);
return hardware::Void();
}
@@ -362,7 +366,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -425,7 +429,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -473,7 +477,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -641,14 +645,14 @@
// TODO: check if we need to lock before copying states
// though technically no other thread should be talking to Camera3Device at this point
Camera3OfflineStates offlineStates(
- mTagMonitor, mVendorTagId, mUseHalBufManager, mNeedFixupMonochromeTags,
- mUsePartialResult, mNumPartialResults, mLastCompletedRegularFrameNumber,
- mLastCompletedReprocessFrameNumber, mLastCompletedZslFrameNumber,
- mNextResultFrameNumber, mNextReprocessResultFrameNumber,
- mNextZslStillResultFrameNumber, mNextShutterFrameNumber,
- mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
- mDeviceInfo, mPhysicalDeviceInfoMap, mDistortionMappers,
- mZoomRatioMappers, mRotateAndCropMappers);
+ mTagMonitor, mVendorTagId, mUseHalBufManager, mHalBufManagedStreamIds,
+ mNeedFixupMonochromeTags, mUsePartialResult, mNumPartialResults,
+ mLastCompletedRegularFrameNumber, mLastCompletedReprocessFrameNumber,
+ mLastCompletedZslFrameNumber, mNextResultFrameNumber,
+ mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
+ mNextShutterFrameNumber, mNextReprocessShutterFrameNumber,
+ mNextZslStillShutterFrameNumber, mDeviceInfo, mPhysicalDeviceInfoMap,
+ mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers);
*session = new HidlCamera3OfflineSession(mId, inputStream, offlineStreamSet,
std::move(bufferRecords), offlineReqs, offlineStates, offlineSession);
@@ -716,7 +720,8 @@
bool overrideToPortrait,
bool supportSettingsOverride) {
return new HidlRequestThread(parent, statusTracker, interface, sessionParamKeys,
- useHalBufManager, supportCameraMute, overrideToPortrait, supportSettingsOverride);
+ useHalBufManager, supportCameraMute, overrideToPortrait,
+ supportSettingsOverride);
};
sp<Camera3Device::Camera3DeviceInjectionMethods>
@@ -909,6 +914,7 @@
requestedConfiguration3_2.streams.resize(config->num_streams);
requestedConfiguration3_4.streams.resize(config->num_streams);
requestedConfiguration3_7.streams.resize(config->num_streams);
+ mHalBufManagedStreamIds.clear();
for (size_t i = 0; i < config->num_streams; i++) {
device::V3_2::Stream &dst3_2 = requestedConfiguration3_2.streams[i];
device::V3_4::Stream &dst3_4 = requestedConfiguration3_4.streams[i];
@@ -922,6 +928,9 @@
switch (src->stream_type) {
case CAMERA_STREAM_OUTPUT:
streamType = StreamType::OUTPUT;
+ if (flags::session_hal_buf_manager() && mUseHalBufManager) {
+ mHalBufManagedStreamIds.insert(streamId);
+ }
break;
case CAMERA_STREAM_INPUT:
streamType = StreamType::INPUT;
@@ -931,6 +940,7 @@
__FUNCTION__, streamId, config->streams[i]->stream_type);
return BAD_VALUE;
}
+
dst3_2.id = streamId;
dst3_2.streamType = streamType;
dst3_2.width = src->width;
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
index e328ef6..aa4b762 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3OfflineSession.cpp
@@ -103,7 +103,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -145,7 +145,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -182,7 +182,7 @@
mNextReprocessShutterFrameNumber, mNextZslStillShutterFrameNumber,
mNextResultFrameNumber,
mNextReprocessResultFrameNumber, mNextZslStillResultFrameNumber,
- mUseHalBufManager, mUsePartialResult, mNeedFixupMonochromeTags,
+ mUseHalBufManager, mHalBufManagedStreamIds, mUsePartialResult, mNeedFixupMonochromeTags,
mNumPartialResults, mVendorTagId, mDeviceInfo, mPhysicalDeviceInfoMap,
mDistortionMappers, mZoomRatioMappers, mRotateAndCropMappers,
mTagMonitor, mInputStream, mOutputStreams, mSessionStatsBuilder, listener, *this, *this,
@@ -207,7 +207,8 @@
}
RequestBufferStates states {
- mId, mRequestBufferInterfaceLock, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder,
+ mId, mRequestBufferInterfaceLock, mUseHalBufManager,mHalBufManagedStreamIds,
+ mOutputStreams, mSessionStatsBuilder,
*this, mBufferRecords, *this};
camera3::requestStreamBuffers(states, bufReqs, _hidl_cb);
return hardware::Void();
@@ -224,7 +225,8 @@
}
ReturnBufferStates states {
- mId, mUseHalBufManager, mOutputStreams, mSessionStatsBuilder, mBufferRecords};
+ mId, mUseHalBufManager, mHalBufManagedStreamIds, mOutputStreams, mSessionStatsBuilder,
+ mBufferRecords};
camera3::returnStreamBuffers(states, buffers);
return hardware::Void();
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index 59fc1cd..d607d10 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -25,6 +25,7 @@
#include <hidl/Utils.h>
#include <android/hardware/camera/device/3.2/types.h>
#include <android-base/properties.h>
+#include <utils/Utils.h>
namespace android {
namespace frameworks {
@@ -58,7 +59,7 @@
const sp<hardware::camera2::ICameraDeviceUser> &deviceRemote)
: mDeviceRemote(deviceRemote) {
mInitSuccess = initDevice();
- mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
+ mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
}
bool HidlCameraDeviceUser::initDevice() {
diff --git a/services/camera/libcameraservice/hidl/HidlCameraService.cpp b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
index 94bf653..1a5a6b9 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraService.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraService.cpp
@@ -25,6 +25,8 @@
#include <hidl/HidlTransportSupport.h>
+#include <utils/Utils.h>
+
namespace android {
namespace frameworks {
namespace cameraservice {
@@ -56,8 +58,8 @@
}
HidlCameraService::HidlCameraService(android::CameraService *cs) : mAidlICameraService(cs) {
- mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
-};
+ mVndkVersion = getVNDKVersionFromProp(__ANDROID_API_FUTURE__);
+}
Return<void>
HidlCameraService::getCameraCharacteristics(const hidl_string& cameraId,
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 467707e..a53d26d 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -309,6 +309,12 @@
bool*) override {
return ndk::ScopedAStatus::ok();
}
+
+ ::ndk::ScopedAStatus getSessionCharacteristics(
+ const ::aidl::android::hardware::camera::device::StreamConfiguration&,
+ ::aidl::android::hardware::camera::device::CameraMetadata*) override {
+ return ndk::ScopedAStatus::ok();
+ }
};
/**
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 3be8e15..11ef9b7 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -623,7 +623,7 @@
if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
if (dataSpace != streamInfo.dataSpace) {
std::string msg = fmt::sprintf("Camera %s:Surface dataSpace doesn't match: %d vs %d",
- logicalCameraId.c_str(), dataSpace, streamInfo.dataSpace);
+ logicalCameraId.c_str(), static_cast<int>(dataSpace), static_cast<int>(streamInfo.dataSpace));
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
@@ -1133,7 +1133,7 @@
}
void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
- int vendorTagId, CameraMetadata& dst) {
+ metadata_vendor_id_t vendorTagId, CameraMetadata& dst) {
const CameraMetadata params(src);
camera_metadata_ro_entry_t availableSessionKeys = deviceInfo.find(
ANDROID_REQUEST_AVAILABLE_SESSION_KEYS);
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 29e3eca..0545cea 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -177,7 +177,11 @@
aidl::android::hardware::camera::device::RequestTemplate* tempId /*out*/);
void filterParameters(const CameraMetadata& src, const CameraMetadata& deviceInfo,
- int vendorTagId, CameraMetadata& dst);
+ metadata_vendor_id_t vendorTagId, CameraMetadata& dst);
+
+template <typename T> bool contains(std::set<T> container, T value) {
+ return container.find(value) != container.end();
+}
constexpr int32_t MAX_SURFACES_PER_STREAM = 4;
diff --git a/services/camera/libcameraservice/utils/Utils.cpp b/services/camera/libcameraservice/utils/Utils.cpp
new file mode 100644
index 0000000..c8f5e86
--- /dev/null
+++ b/services/camera/libcameraservice/utils/Utils.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2024 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 "Utils.h"
+#include <android-base/properties.h>
+#include <com_android_internal_camera_flags.h>
+
+
+namespace android {
+
+using namespace com::android::internal::camera::flags;
+
+constexpr const char *LEGACY_VNDK_VERSION_PROP = "ro.vndk.version";
+constexpr const char *BOARD_API_LEVEL_PROP = "ro.board.api_level";
+constexpr int MAX_VENDOR_API_LEVEL = 1000000;
+constexpr int FIRST_VNDK_VERSION = 202404;
+
+int getVNDKVersionFromProp(int defaultVersion) {
+ if (!com_android_internal_camera_flags_use_ro_board_api_level_for_vndk_version()) {
+ return base::GetIntProperty(LEGACY_VNDK_VERSION_PROP, defaultVersion);
+ }
+
+ int vndkVersion = base::GetIntProperty(BOARD_API_LEVEL_PROP, MAX_VENDOR_API_LEVEL);
+
+ if (vndkVersion == MAX_VENDOR_API_LEVEL) {
+ // Couldn't find property
+ return defaultVersion;
+ }
+
+ if (vndkVersion < __ANDROID_API_V__) {
+ // VNDK versions below V return the corresponding SDK version.
+ return vndkVersion;
+ }
+
+ // VNDK for Android V and above are of the format YYYYMM starting with 202404 and is bumped
+ // up once a year. So V would be 202404 and the next one would be 202504.
+ // This is the same assumption as that made in system/core/init/property_service.cpp.
+ vndkVersion = (vndkVersion - FIRST_VNDK_VERSION) / 100;
+ return __ANDROID_API_V__ + vndkVersion;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/utils/Utils.h b/services/camera/libcameraservice/utils/Utils.h
new file mode 100644
index 0000000..f8a107d
--- /dev/null
+++ b/services/camera/libcameraservice/utils/Utils.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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_UTILS_H
+#define ANDROID_SERVERS_CAMERA_UTILS_H
+
+namespace android {
+
+/**
+ * As of Android V, ro.board.api_level returns the year and month of release (ex. 202404)
+ * instead of release SDK version. This function maps year/month format back to release
+ * SDK version.
+ *
+ * Returns defaultVersion if the property is not found.
+ */
+int getVNDKVersionFromProp(int defaultVersion);
+
+} // namespace android
+
+#endif //ANDROID_SERVERS_CAMERA_UTILS_H
diff --git a/services/camera/virtualcamera/TEST_MAPPING b/services/camera/virtualcamera/TEST_MAPPING
index 66c5e52..25fca73 100644
--- a/services/camera/virtualcamera/TEST_MAPPING
+++ b/services/camera/virtualcamera/TEST_MAPPING
@@ -2,9 +2,7 @@
"presubmit" : [
{
"name": "virtual_camera_tests"
- }
- ],
- "postsubmit": [
+ },
{
"name": "CtsVirtualDevicesCameraTestCases",
"options": [
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.cc b/services/camera/virtualcamera/VirtualCameraDevice.cc
index ec72ee3..768dffb 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.cc
+++ b/services/camera/virtualcamera/VirtualCameraDevice.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -28,6 +28,7 @@
#include "VirtualCameraSession.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
@@ -44,7 +45,10 @@
using ::aidl::android::companion::virtualcamera::Format;
using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraResourceCost;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::CameraMetadata;
@@ -64,11 +68,15 @@
// Prefix of camera name - "device@1.1/virtual/{numerical_id}"
const char* kDevicePathPrefix = "device@1.1/virtual/";
-constexpr std::chrono::nanoseconds kMinFrameDuration30Fps = 1s / 30;
constexpr int32_t kMaxJpegSize = 3 * 1024 * 1024 /*3MiB*/;
constexpr MetadataBuilder::ControlRegion kDefaultEmptyControlRegion{};
+const std::array<int32_t, 3> kOutputFormats{
+ ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
+ ANDROID_SCALER_AVAILABLE_FORMATS_YCbCr_420_888,
+ ANDROID_SCALER_AVAILABLE_FORMATS_BLOB};
+
struct Resolution {
Resolution(const int w, const int h) : width(w), height(h) {
}
@@ -103,25 +111,36 @@
return Resolution(itMax->width, itMax->height);
}
-std::set<Resolution> getUniqueResolutions(
+// Returns a map of unique resolution to maximum maxFps for all streams with
+// that resolution.
+std::map<Resolution, int> getResolutionToMaxFpsMap(
const std::vector<SupportedStreamConfiguration>& configs) {
- std::set<Resolution> uniqueResolutions;
- std::transform(configs.begin(), configs.end(),
- std::inserter(uniqueResolutions, uniqueResolutions.begin()),
- [](const SupportedStreamConfiguration& config) {
- return Resolution(config.width, config.height);
- });
- return uniqueResolutions;
+ std::map<Resolution, int> resolutionToMaxFpsMap;
+
+ for (const SupportedStreamConfiguration& config : configs) {
+ Resolution resolution(config.width, config.height);
+ if (resolutionToMaxFpsMap.find(resolution) == resolutionToMaxFpsMap.end()) {
+ resolutionToMaxFpsMap[resolution] = config.maxFps;
+ } else {
+ int currentMaxFps = resolutionToMaxFpsMap[resolution];
+ resolutionToMaxFpsMap[resolution] = std::max(currentMaxFps, config.maxFps);
+ }
+ }
+
+ return resolutionToMaxFpsMap;
}
// TODO(b/301023410) - Populate camera characteristics according to camera configuration.
std::optional<CameraMetadata> initCameraCharacteristics(
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig) {
+ const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
+ const SensorOrientation sensorOrientation, const LensFacing lensFacing) {
if (!std::all_of(supportedInputConfig.begin(), supportedInputConfig.end(),
[](const SupportedStreamConfiguration& config) {
- return config.pixelFormat == Format::YUV_420_888;
+ return isFormatSupportedForInput(
+ config.width, config.height, config.pixelFormat,
+ config.maxFps);
})) {
- ALOGE("%s: input configuration contains unsupported pixel format", __func__);
+ ALOGE("%s: input configuration contains unsupported format", __func__);
return std::nullopt;
}
@@ -130,8 +149,9 @@
.setSupportedHardwareLevel(
ANDROID_INFO_SUPPORTED_HARDWARE_LEVEL_EXTERNAL)
.setFlashAvailable(false)
- .setLensFacing(ANDROID_LENS_FACING_EXTERNAL)
- .setSensorOrientation(0)
+ .setLensFacing(
+ static_cast<camera_metadata_enum_android_lens_facing>(lensFacing))
+ .setSensorOrientation(static_cast<int32_t>(sensorOrientation))
.setAvailableFaceDetectModes({ANDROID_STATISTICS_FACE_DETECT_MODE_OFF})
.setAvailableMaxDigitalZoom(1.0)
.setControlAvailableModes({ANDROID_CONTROL_MODE_AUTO})
@@ -165,45 +185,24 @@
// TODO(b/301023410) Add also all "standard" resolutions we can rescale the
// streams to (all standard resolutions with same aspect ratio).
- // Add IMPLEMENTATION_DEFINED format for all supported input resolutions.
- std::set<Resolution> uniqueResolutions =
- getUniqueResolutions(supportedInputConfig);
- std::transform(
- uniqueResolutions.begin(), uniqueResolutions.end(),
- std::back_inserter(outputConfigurations),
- [](const Resolution& resolution) {
- return MetadataBuilder::StreamConfiguration{
- .width = resolution.width,
- .height = resolution.height,
- .format = ANDROID_SCALER_AVAILABLE_FORMATS_IMPLEMENTATION_DEFINED,
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
+ std::map<Resolution, int> resolutionToMaxFpsMap =
+ getResolutionToMaxFpsMap(supportedInputConfig);
- // Add all supported configuration with explicit pixel format.
- std::transform(supportedInputConfig.begin(), supportedInputConfig.end(),
- std::back_inserter(outputConfigurations),
- [](const SupportedStreamConfiguration& config) {
- return MetadataBuilder::StreamConfiguration{
- .width = config.width,
- .height = config.height,
- .format = static_cast<int>(config.pixelFormat),
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
-
- // TODO(b/301023410) We currently don't support rescaling for still capture,
- // so only announce BLOB support for formats exactly matching the input.
- std::transform(uniqueResolutions.begin(), uniqueResolutions.end(),
- std::back_inserter(outputConfigurations),
- [](const Resolution& resolution) {
- return MetadataBuilder::StreamConfiguration{
- .width = resolution.width,
- .height = resolution.height,
- .format = ANDROID_SCALER_AVAILABLE_FORMATS_BLOB,
- .minFrameDuration = kMinFrameDuration30Fps,
- .minStallDuration = 0s};
- });
+ // Add configurations for all unique input resolutions and output formats.
+ for (int32_t format : kOutputFormats) {
+ std::transform(
+ resolutionToMaxFpsMap.begin(), resolutionToMaxFpsMap.end(),
+ std::back_inserter(outputConfigurations), [format](const auto& entry) {
+ Resolution resolution = entry.first;
+ int maxFps = entry.second;
+ return MetadataBuilder::StreamConfiguration{
+ .width = resolution.width,
+ .height = resolution.height,
+ .format = format,
+ .minFrameDuration = std::chrono::nanoseconds(1s) / maxFps,
+ .minStallDuration = 0s};
+ });
+ }
ALOGV("Adding %zu output configurations", outputConfigurations.size());
builder.setAvailableOutputStreamConfigurations(outputConfigurations);
@@ -220,14 +219,13 @@
} // namespace
VirtualCameraDevice::VirtualCameraDevice(
- const uint32_t cameraId,
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
- std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
+ const uint32_t cameraId, const VirtualCameraConfiguration& configuration)
: mCameraId(cameraId),
- mVirtualCameraClientCallback(virtualCameraClientCallback),
- mSupportedInputConfigurations(supportedInputConfig) {
- std::optional<CameraMetadata> metadata =
- initCameraCharacteristics(mSupportedInputConfigurations);
+ mVirtualCameraClientCallback(configuration.virtualCameraCallback),
+ mSupportedInputConfigurations(configuration.supportedStreamConfigs) {
+ std::optional<CameraMetadata> metadata = initCameraCharacteristics(
+ mSupportedInputConfigurations, configuration.sensorOrientation,
+ configuration.lensFacing);
if (metadata.has_value()) {
mCameraCharacteristics = *metadata;
} else {
@@ -285,6 +283,11 @@
bool VirtualCameraDevice::isStreamCombinationSupported(
const StreamConfiguration& streamConfiguration) const {
+ if (streamConfiguration.streams.empty()) {
+ ALOGE("%s: Querying empty configuration", __func__);
+ return false;
+ }
+
for (const Stream& stream : streamConfiguration.streams) {
ALOGV("%s: Configuration queried: %s", __func__, stream.toString().c_str());
@@ -322,7 +325,7 @@
ALOGV("%s", __func__);
*_aidl_return = ndk::SharedRefBase::make<VirtualCameraSession>(
- *this, in_callback, mVirtualCameraClientCallback);
+ sharedFromThis(), in_callback, mVirtualCameraClientCallback);
return ndk::ScopedAStatus::ok();
};
@@ -367,6 +370,13 @@
return std::string(kDevicePathPrefix) + std::to_string(mCameraId);
}
+std::shared_ptr<VirtualCameraDevice> VirtualCameraDevice::sharedFromThis() {
+ // SharedRefBase which BnCameraDevice inherits from breaks
+ // std::enable_shared_from_this. This is recommended replacement for
+ // shared_from_this() per documentation in binder_interface_utils.h.
+ return ref<VirtualCameraDevice>();
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/VirtualCameraDevice.h b/services/camera/virtualcamera/VirtualCameraDevice.h
index ee7a3a7..10d52af 100644
--- a/services/camera/virtualcamera/VirtualCameraDevice.h
+++ b/services/camera/virtualcamera/VirtualCameraDevice.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -22,6 +22,7 @@
#include "aidl/android/companion/virtualcamera/IVirtualCameraCallback.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/device/BnCameraDevice.h"
namespace android {
@@ -35,12 +36,8 @@
public:
explicit VirtualCameraDevice(
uint32_t cameraId,
- const std::vector<
- aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
- supportedInputConfig,
- std::shared_ptr<
- ::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
- virtualCameraClientCallback = nullptr);
+ const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+ configuration);
virtual ~VirtualCameraDevice() override = default;
@@ -98,6 +95,8 @@
uint32_t getCameraId() const { return mCameraId; }
private:
+ std::shared_ptr<VirtualCameraDevice> sharedFromThis();
+
const uint32_t mCameraId;
const std::shared_ptr<
::aidl::android::companion::virtualcamera::IVirtualCameraCallback>
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.cc b/services/camera/virtualcamera/VirtualCameraProvider.cc
index 25a43d6..e4a68f5 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.cc
+++ b/services/camera/virtualcamera/VirtualCameraProvider.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -33,8 +33,7 @@
namespace companion {
namespace virtualcamera {
-using ::aidl::android::companion::virtualcamera::IVirtualCameraCallback;
-using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::VendorTagSection;
@@ -155,10 +154,9 @@
}
std::shared_ptr<VirtualCameraDevice> VirtualCameraProvider::createCamera(
- const std::vector<SupportedStreamConfiguration>& supportedInputConfig,
- std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback) {
- auto camera = ndk::SharedRefBase::make<VirtualCameraDevice>(
- sNextId++, supportedInputConfig, virtualCameraClientCallback);
+ const VirtualCameraConfiguration& configuration) {
+ auto camera =
+ ndk::SharedRefBase::make<VirtualCameraDevice>(sNextId++, configuration);
std::shared_ptr<ICameraProviderCallback> callback;
{
const std::lock_guard<std::mutex> lock(mLock);
diff --git a/services/camera/virtualcamera/VirtualCameraProvider.h b/services/camera/virtualcamera/VirtualCameraProvider.h
index d41a005..11d3123 100644
--- a/services/camera/virtualcamera/VirtualCameraProvider.h
+++ b/services/camera/virtualcamera/VirtualCameraProvider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -74,14 +74,9 @@
// Create new virtual camera devices
// Returns nullptr if creation was not successful.
- //
- // TODO(b/301023410) - Add camera configuration.
std::shared_ptr<VirtualCameraDevice> createCamera(
- const std::vector<
- aidl::android::companion::virtualcamera::SupportedStreamConfiguration>&
- supportedInputConfig,
- std::shared_ptr<aidl::android::companion::virtualcamera::IVirtualCameraCallback>
- virtualCameraClientCallback = nullptr);
+ const aidl::android::companion::virtualcamera::VirtualCameraConfiguration&
+ configuration);
std::shared_ptr<VirtualCameraDevice> getCamera(const std::string& name);
@@ -105,4 +100,4 @@
} // namespace companion
} // namespace android
-#endif // ANDROID_SERVICES_VIRTUAL_CAMERA_VIRTUALCAMERAPROVIDER_H
+#endif // ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERAPROVIDER_H
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 8621160..25fe61b 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -19,6 +19,7 @@
#include <chrono>
#include <cstddef>
+#include <cstdint>
#include <future>
#include <memory>
#include <mutex>
@@ -38,6 +39,7 @@
#include "android-base/thread_annotations.h"
#include "android/binder_auto_utils.h"
#include "android/hardware_buffer.h"
+#include "ui/GraphicBuffer.h"
#include "util/EglFramebuffer.h"
#include "util/JpegUtil.h"
#include "util/MetadataBuilder.h"
@@ -109,6 +111,45 @@
return msg;
}
+std::shared_ptr<EglFrameBuffer> allocateTemporaryFramebuffer(
+ EGLDisplay eglDisplay, const uint width, const int height) {
+ const AHardwareBuffer_Desc desc{
+ .width = static_cast<uint32_t>(width),
+ .height = static_cast<uint32_t>(height),
+ .layers = 1,
+ .format = AHARDWAREBUFFER_FORMAT_Y8Cb8Cr8_420,
+ .usage = AHARDWAREBUFFER_USAGE_GPU_FRAMEBUFFER |
+ AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+ .rfu0 = 0,
+ .rfu1 = 0};
+
+ AHardwareBuffer* hwBufferPtr;
+ int status = AHardwareBuffer_allocate(&desc, &hwBufferPtr);
+ if (status != NO_ERROR) {
+ ALOGE(
+ "%s: Failed to allocate hardware buffer for temporary framebuffer: %d",
+ __func__, status);
+ return nullptr;
+ }
+
+ return std::make_shared<EglFrameBuffer>(
+ eglDisplay,
+ std::shared_ptr<AHardwareBuffer>(hwBufferPtr, AHardwareBuffer_release));
+}
+
+bool isYuvFormat(const PixelFormat pixelFormat) {
+ switch (static_cast<android_pixel_format_t>(pixelFormat)) {
+ case HAL_PIXEL_FORMAT_YCBCR_422_I:
+ case HAL_PIXEL_FORMAT_YCBCR_422_SP:
+ case HAL_PIXEL_FORMAT_Y16:
+ case HAL_PIXEL_FORMAT_YV12:
+ case HAL_PIXEL_FORMAT_YCBCR_420_888:
+ return true;
+ default:
+ return false;
+ }
+}
+
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -218,7 +259,10 @@
ALOGV("Render thread starting");
mEglDisplayContext = std::make_unique<EglDisplayContext>();
- mEglTextureProgram = std::make_unique<EglTextureProgram>();
+ mEglTextureYuvProgram =
+ std::make_unique<EglTextureProgram>(EglTextureProgram::TextureFormat::YUV);
+ mEglTextureRgbProgram = std::make_unique<EglTextureProgram>(
+ EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique<EglSurfaceTexture>(mInputSurfaceWidth,
mInputSurfaceHeight);
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
@@ -371,6 +415,22 @@
return cameraStatus(Status::INTERNAL_ERROR);
}
+ // Let's create YUV framebuffer and render the surface into this.
+ // This will take care about rescaling as well as potential format conversion.
+ std::shared_ptr<EglFrameBuffer> framebuffer = allocateTemporaryFramebuffer(
+ mEglDisplayContext->getEglDisplay(), stream->width, stream->height);
+ if (framebuffer == nullptr) {
+ ALOGE("Failed to allocate temporary framebuffer for JPEG compression");
+ return cameraStatus(Status::INTERNAL_ERROR);
+ }
+
+ // Render into temporary framebuffer.
+ ndk::ScopedAStatus status = renderIntoEglFramebuffer(*framebuffer);
+ if (!status.isOk()) {
+ ALOGE("Failed to render input texture into temporary framebuffer");
+ return status;
+ }
+
AHardwareBuffer_Planes planes_info;
int32_t rawFence = fence != nullptr ? fence->get() : -1;
@@ -382,10 +442,21 @@
return cameraStatus(Status::INTERNAL_ERROR);
}
- sp<GraphicBuffer> gBuffer = mEglSurfaceTexture->getCurrentBuffer();
+ std::shared_ptr<AHardwareBuffer> inHwBuffer = framebuffer->getHardwareBuffer();
+ GraphicBuffer* gBuffer = GraphicBuffer::fromAHardwareBuffer(inHwBuffer.get());
+
bool compressionSuccess = true;
if (gBuffer != nullptr) {
android_ycbcr ycbcr;
+ if (gBuffer->getPixelFormat() != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+ // This should never happen since we're allocating the temporary buffer
+ // with YUV420 layout above.
+ ALOGE("%s: Cannot compress non-YUV buffer (pixelFormat %d)", __func__,
+ gBuffer->getPixelFormat());
+ AHardwareBuffer_unlock(hwBuffer.get(), nullptr);
+ return cameraStatus(Status::INTERNAL_ERROR);
+ }
+
status_t status =
gBuffer->lockYCbCr(AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, &ycbcr);
ALOGV("Locked buffers");
@@ -434,31 +505,7 @@
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
- // Wait for fence to clear.
- if (fence != nullptr && fence->isValid()) {
- status_t ret = fence->wait(kAcquireFenceTimeout.count());
- if (ret != 0) {
- ALOGE(
- "Timeout while waiting for the acquire fence for buffer %d"
- " for streamId %d",
- bufferId, streamId);
- return cameraStatus(Status::INTERNAL_ERROR);
- }
- }
-
- mEglDisplayContext->makeCurrent();
- framebuffer->beforeDraw();
-
- if (mEglSurfaceTexture->getCurrentBuffer() == nullptr) {
- // If there's no current buffer, nothing was written to the surface and
- // texture is not initialized yet. Let's render the framebuffer black
- // instead of rendering the texture.
- glClearColor(0.0f, 0.5f, 0.5f, 0.0f);
- glClear(GL_COLOR_BUFFER_BIT);
- } else {
- mEglTextureProgram->draw(mEglSurfaceTexture->updateTexture());
- }
- framebuffer->afterDraw();
+ ndk::ScopedAStatus status = renderIntoEglFramebuffer(*framebuffer, fence);
const std::chrono::nanoseconds after =
std::chrono::duration_cast<std::chrono::nanoseconds>(
@@ -470,6 +517,47 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoEglFramebuffer(
+ EglFrameBuffer& framebuffer, sp<Fence> fence) {
+ ALOGV("%s", __func__);
+ // Wait for fence to clear.
+ if (fence != nullptr && fence->isValid()) {
+ status_t ret = fence->wait(kAcquireFenceTimeout.count());
+ if (ret != 0) {
+ ALOGE("Timeout while waiting for the acquire fence for buffer");
+ return cameraStatus(Status::INTERNAL_ERROR);
+ }
+ }
+
+ mEglDisplayContext->makeCurrent();
+ framebuffer.beforeDraw();
+
+ sp<GraphicBuffer> textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
+ if (textureBuffer == nullptr) {
+ // If there's no current buffer, nothing was written to the surface and
+ // texture is not initialized yet. Let's render the framebuffer black
+ // instead of rendering the texture.
+ glClearColor(0.0f, 0.5f, 0.5f, 0.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+ } else {
+ const bool renderSuccess =
+ isYuvFormat(static_cast<PixelFormat>(textureBuffer->getPixelFormat()))
+ ? mEglTextureYuvProgram->draw(
+ mEglSurfaceTexture->getTextureId(),
+ mEglSurfaceTexture->getTransformMatrix())
+ : mEglTextureRgbProgram->draw(
+ mEglSurfaceTexture->getTextureId(),
+ mEglSurfaceTexture->getTransformMatrix());
+ if (!renderSuccess) {
+ ALOGE("%s: Failed to render texture", __func__);
+ return cameraStatus(Status::INTERNAL_ERROR);
+ }
+ }
+ framebuffer.afterDraw();
+
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index a4374e6..b3aaed8 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -24,7 +24,9 @@
#include "VirtualCameraSessionContext.h"
#include "aidl/android/hardware/camera/device/ICameraDeviceCallback.h"
+#include "android/binder_auto_utils.h"
#include "util/EglDisplayContext.h"
+#include "util/EglFramebuffer.h"
#include "util/EglProgram.h"
#include "util/EglSurfaceTexture.h"
@@ -135,6 +137,13 @@
ndk::ScopedAStatus renderIntoImageStreamBuffer(int streamId, int bufferId,
sp<Fence> fence = nullptr);
+ // Render current image into provided EglFramebuffer.
+ // If fence is specified, this function will block until the fence is cleared
+ // before writing to the buffer.
+ // Always called on the render thread.
+ ndk::ScopedAStatus renderIntoEglFramebuffer(EglFrameBuffer& framebuffer,
+ sp<Fence> fence = nullptr);
+
// Camera callback
const std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
@@ -156,7 +165,8 @@
// EGL helpers - constructed and accessed only from rendering thread.
std::unique_ptr<EglDisplayContext> mEglDisplayContext;
- std::unique_ptr<EglTextureProgram> mEglTextureProgram;
+ std::unique_ptr<EglTextureProgram> mEglTextureYuvProgram;
+ std::unique_ptr<EglTextureProgram> mEglTextureRgbProgram;
std::unique_ptr<EglSurfaceTexture> mEglSurfaceTexture;
std::promise<sp<Surface>> mInputSurfacePromise;
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 370a5a8..1144997 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -41,6 +41,8 @@
namespace virtualcamera {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
@@ -48,6 +50,7 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 60;
constexpr char kEnableTestCameraCmd[] = "enable_test_camera";
constexpr char kDisableTestCameraCmd[] = "disable_test_camera";
constexpr char kShellCmdHelp[] = R"(
@@ -69,13 +72,29 @@
for (const SupportedStreamConfiguration& config :
configuration.supportedStreamConfigs) {
if (!isFormatSupportedForInput(config.width, config.height,
- config.pixelFormat)) {
+ config.pixelFormat, config.maxFps)) {
ALOGE("%s: Requested unsupported input format: %d x %d (%d)", __func__,
config.width, config.height, static_cast<int>(config.pixelFormat));
return ndk::ScopedAStatus::fromServiceSpecificError(
Status::EX_ILLEGAL_ARGUMENT);
}
}
+
+ if (configuration.sensorOrientation != SensorOrientation::ORIENTATION_0 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_90 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_180 &&
+ configuration.sensorOrientation != SensorOrientation::ORIENTATION_270) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ Status::EX_ILLEGAL_ARGUMENT);
+ }
+
+ if (configuration.lensFacing != LensFacing::FRONT &&
+ configuration.lensFacing != LensFacing::BACK &&
+ configuration.lensFacing != LensFacing::EXTERNAL) {
+ return ndk::ScopedAStatus::fromServiceSpecificError(
+ Status::EX_ILLEGAL_ARGUMENT);
+ }
+
return ndk::ScopedAStatus::ok();
}
@@ -121,10 +140,8 @@
return ndk::ScopedAStatus::ok();
}
- // TODO(b/301023410) Validate configuration and pass it to the camera.
std::shared_ptr<VirtualCameraDevice> camera =
- mVirtualCameraProvider->createCamera(configuration.supportedStreamConfigs,
- configuration.virtualCameraCallback);
+ mVirtualCameraProvider->createCamera(configuration);
if (camera == nullptr) {
ALOGE("Failed to create camera for binder token 0x%" PRIxPTR,
reinterpret_cast<uintptr_t>(token.get()));
@@ -241,8 +258,11 @@
bool ret;
VirtualCameraConfiguration configuration;
- configuration.supportedStreamConfigs.push_back(
- {.width = kVgaWidth, .height = kVgaHeight, Format::YUV_420_888});
+ configuration.supportedStreamConfigs.push_back({.width = kVgaWidth,
+ .height = kVgaHeight,
+ Format::YUV_420_888,
+ .maxFps = kMaxFps});
+ configuration.lensFacing = LensFacing::EXTERNAL;
registerCamera(mTestCameraToken, configuration, &ret);
if (ret) {
dprintf(out, "Successfully registered test camera %s",
diff --git a/services/camera/virtualcamera/VirtualCameraSession.cc b/services/camera/virtualcamera/VirtualCameraSession.cc
index 9e15871..03d63b8 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.cc
+++ b/services/camera/virtualcamera/VirtualCameraSession.cc
@@ -18,6 +18,7 @@
#define LOG_TAG "VirtualCameraSession"
#include "VirtualCameraSession.h"
+#include <algorithm>
#include <atomic>
#include <chrono>
#include <cstddef>
@@ -150,10 +151,17 @@
return halStream;
}
+Stream getHighestResolutionStream(const std::vector<Stream>& streams) {
+ return *(std::max_element(streams.begin(), streams.end(),
+ [](const Stream& a, const Stream& b) {
+ return a.width * a.height < b.width * b.height;
+ }));
+}
+
} // namespace
VirtualCameraSession::VirtualCameraSession(
- VirtualCameraDevice& cameraDevice,
+ std::shared_ptr<VirtualCameraDevice> cameraDevice,
std::shared_ptr<ICameraDeviceCallback> cameraDeviceCallback,
std::shared_ptr<IVirtualCameraCallback> virtualCameraClientCallback)
: mCameraDevice(cameraDevice),
@@ -201,6 +209,12 @@
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
+ std::shared_ptr<VirtualCameraDevice> virtualCamera = mCameraDevice.lock();
+ if (virtualCamera == nullptr) {
+ ALOGW("%s: configure called on already unregistered camera", __func__);
+ return cameraStatus(Status::CAMERA_DISCONNECTED);
+ }
+
mSessionContext.removeStreamsNotInStreamConfiguration(
in_requestedConfiguration);
@@ -213,7 +227,7 @@
int inputWidth;
int inputHeight;
- if (!mCameraDevice.isStreamCombinationSupported(in_requestedConfiguration)) {
+ if (!virtualCamera->isStreamCombinationSupported(in_requestedConfiguration)) {
ALOGE("%s: Requested stream configuration is not supported", __func__);
return cameraStatus(Status::ILLEGAL_ARGUMENT);
}
@@ -227,8 +241,9 @@
}
}
- inputWidth = streams[0].width;
- inputHeight = streams[0].height;
+ Stream maxResStream = getHighestResolutionStream(streams);
+ inputWidth = maxResStream.width;
+ inputHeight = maxResStream.height;
if (mRenderThread == nullptr) {
// If there's no client callback, start camera in test mode.
const bool testMode = mVirtualCameraClientCallback == nullptr;
diff --git a/services/camera/virtualcamera/VirtualCameraSession.h b/services/camera/virtualcamera/VirtualCameraSession.h
index 50962e5..82a7a34 100644
--- a/services/camera/virtualcamera/VirtualCameraSession.h
+++ b/services/camera/virtualcamera/VirtualCameraSession.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERASESSION_H
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERASESSION_H
+#include <atomic>
#include <memory>
#include <set>
@@ -46,7 +47,7 @@
// When virtualCameraClientCallback is null, the input surface will be filled
// with test pattern.
VirtualCameraSession(
- VirtualCameraDevice& mCameraDevice,
+ std::shared_ptr<VirtualCameraDevice> mCameraDevice,
std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
cameraDeviceCallback,
@@ -116,7 +117,7 @@
const ::aidl::android::hardware::camera::device::CaptureRequest& request)
EXCLUDES(mLock);
- VirtualCameraDevice& mCameraDevice;
+ std::weak_ptr<VirtualCameraDevice> mCameraDevice;
mutable std::mutex mLock;
diff --git a/services/camera/virtualcamera/aidl/Android.bp b/services/camera/virtualcamera/aidl/Android.bp
index 9105b09..a9c2195 100644
--- a/services/camera/virtualcamera/aidl/Android.bp
+++ b/services/camera/virtualcamera/aidl/Android.bp
@@ -8,9 +8,11 @@
unstable: true,
srcs: [
"android/companion/virtualcamera/Format.aidl",
+ "android/companion/virtualcamera/LensFacing.aidl",
"android/companion/virtualcamera/IVirtualCameraCallback.aidl",
"android/companion/virtualcamera/IVirtualCameraService.aidl",
"android/companion/virtualcamera/VirtualCameraConfiguration.aidl",
+ "android/companion/virtualcamera/SensorOrientation.aidl",
"android/companion/virtualcamera/SupportedStreamConfiguration.aidl",
],
local_include_dir: ".",
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/Format.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/Format.aidl
index d9b90a6..b155147 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/Format.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/Format.aidl
@@ -24,5 +24,6 @@
@Backing(type="int")
enum Format {
UNKNOWN = 0,
+ RGBA_8888 = 1,
YUV_420_888 = 0x23,
}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
index cbe03e9..f5a84f7 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/IVirtualCameraCallback.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -36,7 +36,8 @@
* @param height - height of the surface.
* @param pixelFormat - pixel format of the surface.
*/
- void onStreamConfigured(int streamId, in Surface surface, int width, int height, in Format pixelFormat);
+ void onStreamConfigured(int streamId, in Surface surface, int width, int height,
+ in Format pixelFormat);
/**
* Called when framework requests capture. This can be used by the client as a hint
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl
new file mode 100644
index 0000000..8568c91
--- /dev/null
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/LensFacing.aidl
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2024 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.companion.virtualcamera;
+
+/**
+ * Direction that the virtual camera faces relative to the device's screen.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum LensFacing {
+ FRONT = 0,
+ BACK = 1,
+ EXTERNAL = 2,
+}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl
new file mode 100644
index 0000000..ef91f00
--- /dev/null
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SensorOrientation.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.companion.virtualcamera;
+
+/**
+ * Sensor orientation of a virtual camera.
+ *
+ * @hide
+ */
+@Backing(type="int")
+enum SensorOrientation {
+ ORIENTATION_0 = 0,
+ ORIENTATION_90 = 90,
+ ORIENTATION_180 = 180,
+ ORIENTATION_270 = 270,
+}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
index 7070cbd..6f86cbe 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/SupportedStreamConfiguration.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.companion.virtualcamera;
import android.companion.virtualcamera.Format;
@@ -26,4 +27,5 @@
int width;
int height;
Format pixelFormat = Format.UNKNOWN;
+ int maxFps;
}
diff --git a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
index c1a2f22..887ad26 100644
--- a/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
+++ b/services/camera/virtualcamera/aidl/android/companion/virtualcamera/VirtualCameraConfiguration.aidl
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -13,9 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.companion.virtualcamera;
import android.companion.virtualcamera.IVirtualCameraCallback;
+import android.companion.virtualcamera.LensFacing;
+import android.companion.virtualcamera.SensorOrientation;
import android.companion.virtualcamera.SupportedStreamConfiguration;
/**
@@ -26,4 +29,6 @@
parcelable VirtualCameraConfiguration {
SupportedStreamConfiguration[] supportedStreamConfigs;
IVirtualCameraCallback virtualCameraCallback;
+ SensorOrientation sensorOrientation = SensorOrientation.ORIENTATION_0;
+ LensFacing lensFacing;
}
diff --git a/services/camera/virtualcamera/tests/EglUtilTest.cc b/services/camera/virtualcamera/tests/EglUtilTest.cc
index d0b7218..589e312 100644
--- a/services/camera/virtualcamera/tests/EglUtilTest.cc
+++ b/services/camera/virtualcamera/tests/EglUtilTest.cc
@@ -61,12 +61,24 @@
EXPECT_TRUE(eglTestPatternProgram.isInitialized());
}
-TEST_F(EglTest, EglTextureProgramSuccessfulInit) {
+TEST_F(EglTest, EglTextureProgramYuvSuccessfulInit) {
if (!isGlExtensionSupported(kGlExtYuvTarget)) {
GTEST_SKIP() << "Skipping test because of missing required GL extension " << kGlExtYuvTarget;
}
- EglTextureProgram eglTextureProgram;
+ EglTextureProgram eglTextureProgram(EglTextureProgram::TextureFormat::YUV);
+
+ // Verify the shaders compiled and linked successfully.
+ EXPECT_TRUE(eglTextureProgram.isInitialized());
+}
+
+TEST_F(EglTest, EglTextureProgramRgbaSuccessfulInit) {
+ if (!isGlExtensionSupported(kGlExtYuvTarget)) {
+ GTEST_SKIP() << "Skipping test because of missing required GL extension "
+ << kGlExtYuvTarget;
+ }
+
+ EglTextureProgram eglTextureProgram(EglTextureProgram::TextureFormat::RGBA);
// Verify the shaders compiled and linked successfully.
EXPECT_TRUE(eglTextureProgram.isInitialized());
diff --git a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
index 140ae65..027ecb7 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraDeviceTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -19,6 +19,7 @@
#include "VirtualCameraDevice.h"
#include "aidl/android/companion/virtualcamera/Format.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
#include "aidl/android/hardware/camera/device/CameraMetadata.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
#include "android/binder_interface_utils.h"
@@ -34,7 +35,10 @@
namespace {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::device::CameraMetadata;
using ::aidl::android::hardware::camera::device::Stream;
using ::aidl::android::hardware::camera::device::StreamConfiguration;
@@ -49,6 +53,7 @@
constexpr int kVgaHeight = 480;
constexpr int kHdWidth = 1280;
constexpr int kHdHeight = 720;
+constexpr int kMaxFps = 30;
struct AvailableStreamConfiguration {
const int width;
@@ -96,7 +101,7 @@
}
struct VirtualCameraConfigTestParam {
- std::vector<SupportedStreamConfiguration> inputConfig;
+ VirtualCameraConfiguration inputConfig;
std::vector<AvailableStreamConfiguration> expectedAvailableStreamConfigs;
};
@@ -106,8 +111,8 @@
TEST_P(VirtualCameraDeviceTest, cameraCharacteristicsForInputFormat) {
const VirtualCameraConfigTestParam& param = GetParam();
std::shared_ptr<VirtualCameraDevice> camera =
- ndk::SharedRefBase::make<VirtualCameraDevice>(
- kCameraId, param.inputConfig, /*virtualCameraClientCallback=*/nullptr);
+ ndk::SharedRefBase::make<VirtualCameraDevice>(kCameraId,
+ param.inputConfig);
CameraMetadata metadata;
ASSERT_TRUE(camera->getCameraCharacteristics(&metadata).isOk());
@@ -135,10 +140,16 @@
cameraCharacteristicsForInputFormat, VirtualCameraDeviceTest,
testing::Values(
VirtualCameraConfigTestParam{
- .inputConfig = {SupportedStreamConfiguration{
- .width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888}},
+ .inputConfig =
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT},
.expectedAvailableStreamConfigs =
{AvailableStreamConfiguration{
.width = kVgaWidth,
@@ -160,14 +171,22 @@
.streamConfiguration =
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT}}},
VirtualCameraConfigTestParam{
- .inputConfig = {SupportedStreamConfiguration{
- .width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888},
- SupportedStreamConfiguration{
- .width = kHdWidth,
- .height = kHdHeight,
- .pixelFormat = Format::YUV_420_888}},
+ .inputConfig =
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs =
+ {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{
+ .width = kHdWidth,
+ .height = kHdHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::BACK},
.expectedAvailableStreamConfigs = {
AvailableStreamConfiguration{
.width = kVgaWidth,
diff --git a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
index 615a77c..ab647a4 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraProviderTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -33,7 +33,10 @@
namespace {
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -49,6 +52,7 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 30;
constexpr char kVirtualCameraNameRegex[] =
"device@[0-9]+\\.[0-9]+/virtual/[0-9]+";
@@ -79,10 +83,15 @@
std::shared_ptr<VirtualCameraProvider> mCameraProvider;
std::shared_ptr<MockCameraProviderCallback> mMockCameraProviderCallback =
ndk::SharedRefBase::make<MockCameraProviderCallback>();
- std::vector<SupportedStreamConfiguration> mInputConfigs = {
- SupportedStreamConfiguration{.width = kVgaWidth,
- .height = kVgaHeight,
- .pixelFormat = Format::YUV_420_888}};
+ VirtualCameraConfiguration mInputConfig = VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT};
};
TEST_F(VirtualCameraProviderTest, SetNullCameraCallbackFails) {
@@ -109,7 +118,7 @@
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
EXPECT_THAT(camera, Not(IsNull()));
EXPECT_THAT(camera->getCameraName(), MatchesRegex(kVirtualCameraNameRegex));
@@ -127,7 +136,7 @@
.WillOnce(Return(ndk::ScopedAStatus::ok()));
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
// Created camera should be in the list of cameras.
@@ -139,7 +148,7 @@
TEST_F(VirtualCameraProviderTest, RemoveCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
EXPECT_CALL(*mMockCameraProviderCallback,
cameraDeviceStatusChange(Eq(camera->getCameraName()),
@@ -156,7 +165,7 @@
TEST_F(VirtualCameraProviderTest, RemoveNonExistingCamera) {
ASSERT_TRUE(mCameraProvider->setCallback(mMockCameraProviderCallback).isOk());
std::shared_ptr<VirtualCameraDevice> camera =
- mCameraProvider->createCamera(mInputConfigs);
+ mCameraProvider->createCamera(mInputConfig);
// Removing non-existing camera should fail.
const std::string cameraName = "DefinitelyNoTCamera";
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index f4d5042..d4d00a2 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -39,6 +39,8 @@
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
using ::aidl::android::hardware::camera::common::CameraDeviceStatus;
using ::aidl::android::hardware::camera::common::TorchModeStatus;
@@ -56,16 +58,25 @@
constexpr int kVgaWidth = 640;
constexpr int kVgaHeight = 480;
+constexpr int kMaxFps = 30;
+constexpr SensorOrientation kSensorOrientation =
+ SensorOrientation::ORIENTATION_0;
+constexpr LensFacing kLensFacing = LensFacing::FRONT;
constexpr char kCreateVirtualDevicePermissions[] =
"android.permission.CREATE_VIRTUAL_DEVICE";
const VirtualCameraConfiguration kEmptyVirtualCameraConfiguration;
VirtualCameraConfiguration createConfiguration(const int width, const int height,
- const Format format) {
+ const Format format,
+ const int maxFps) {
VirtualCameraConfiguration configuration;
- configuration.supportedStreamConfigs.push_back(
- {.width = width, .height = height, .pixelFormat = format});
+ configuration.supportedStreamConfigs.push_back({.width = width,
+ .height = height,
+ .pixelFormat = format,
+ .maxFps = maxFps});
+ configuration.sensorOrientation = kSensorOrientation;
+ configuration.lensFacing = kLensFacing;
return configuration;
}
@@ -150,10 +161,10 @@
int mDevNullFd;
VirtualCameraConfiguration mVgaYUV420OnlyConfiguration =
- createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888);
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, kMaxFps);
};
-TEST_F(VirtualCameraServiceTest, RegisterCameraSucceeds) {
+TEST_F(VirtualCameraServiceTest, RegisterCameraWithYuvInputSucceeds) {
sp<BBinder> token = sp<BBinder>::make();
ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
bool aidlRet;
@@ -167,6 +178,20 @@
EXPECT_THAT(getCameraIds(), SizeIs(1));
}
+TEST_F(VirtualCameraServiceTest, RegisterCameraWithRgbaInputSucceeds) {
+ sp<BBinder> token = sp<BBinder>::make();
+ ndk::SpAIBinder ndkToken(AIBinder_fromPlatformBinder(token));
+ bool aidlRet;
+
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::RGBA_8888, kMaxFps);
+
+ ASSERT_TRUE(mCameraService->registerCamera(ndkToken, config, &aidlRet).isOk());
+
+ EXPECT_TRUE(aidlRet);
+ EXPECT_THAT(getCameraIds(), SizeIs(1));
+}
+
TEST_F(VirtualCameraServiceTest, RegisterCameraTwiceSecondReturnsFalse) {
createCamera();
bool aidlRet;
@@ -194,7 +219,7 @@
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN);
+ createConfiguration(kVgaWidth, kVgaHeight, Format::UNKNOWN, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -205,7 +230,7 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighResFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(1000000, 1000000, Format::YUV_420_888);
+ createConfiguration(1000000, 1000000, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -216,7 +241,7 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithUnalignedResolutionFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(641, 481, Format::YUV_420_888);
+ createConfiguration(641, 481, Format::YUV_420_888, kMaxFps);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
@@ -227,7 +252,29 @@
TEST_F(VirtualCameraServiceTest, ConfigurationWithNegativeResolutionFails) {
bool aidlRet;
VirtualCameraConfiguration config =
- createConfiguration(-1, kVgaHeight, Format::YUV_420_888);
+ createConfiguration(-1, kVgaHeight, Format::YUV_420_888, kMaxFps);
+
+ ASSERT_FALSE(
+ mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ EXPECT_FALSE(aidlRet);
+ EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithTooLowMaxFpsFails) {
+ bool aidlRet;
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 0);
+
+ ASSERT_FALSE(
+ mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
+ EXPECT_FALSE(aidlRet);
+ EXPECT_THAT(getCameraIds(), IsEmpty());
+}
+
+TEST_F(VirtualCameraServiceTest, ConfigurationWithTooHighMaxFpsFails) {
+ bool aidlRet;
+ VirtualCameraConfiguration config =
+ createConfiguration(kVgaWidth, kVgaHeight, Format::YUV_420_888, 90);
ASSERT_FALSE(
mCameraService->registerCamera(mNdkOwnerToken, config, &aidlRet).isOk());
diff --git a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
index 9edfe77..446c679 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraSessionTest.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -20,8 +20,9 @@
#include "VirtualCameraDevice.h"
#include "VirtualCameraSession.h"
#include "aidl/android/companion/virtualcamera/BnVirtualCameraCallback.h"
-#include "aidl/android/companion/virtualcamera/IVirtualCameraCallback.h"
#include "aidl/android/companion/virtualcamera/SupportedStreamConfiguration.h"
+#include "aidl/android/companion/virtualcamera/VirtualCameraConfiguration.h"
+#include "aidl/android/hardware/camera/common/Status.h"
#include "aidl/android/hardware/camera/device/BnCameraDeviceCallback.h"
#include "aidl/android/hardware/camera/device/StreamConfiguration.h"
#include "aidl/android/hardware/graphics/common/PixelFormat.h"
@@ -36,14 +37,22 @@
namespace virtualcamera {
namespace {
-constexpr int kWidth = 640;
-constexpr int kHeight = 480;
+constexpr int kVgaWidth = 640;
+constexpr int kVgaHeight = 480;
+constexpr int kSvgaWidth = 800;
+constexpr int kSvgaHeight = 600;
+constexpr int kMaxFps = 30;
constexpr int kStreamId = 0;
+constexpr int kSecondStreamId = 1;
constexpr int kCameraId = 42;
using ::aidl::android::companion::virtualcamera::BnVirtualCameraCallback;
using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::companion::virtualcamera::LensFacing;
+using ::aidl::android::companion::virtualcamera::SensorOrientation;
using ::aidl::android::companion::virtualcamera::SupportedStreamConfiguration;
+using ::aidl::android::companion::virtualcamera::VirtualCameraConfiguration;
+using ::aidl::android::hardware::camera::common::Status;
using ::aidl::android::hardware::camera::device::BnCameraDeviceCallback;
using ::aidl::android::hardware::camera::device::BufferRequest;
using ::aidl::android::hardware::camera::device::BufferRequestStatus;
@@ -104,13 +113,22 @@
ndk::SharedRefBase::make<MockVirtualCameraCallback>();
mVirtualCameraDevice = ndk::SharedRefBase::make<VirtualCameraDevice>(
kCameraId,
- std::vector<SupportedStreamConfiguration>{
- SupportedStreamConfiguration{.width = kWidth,
- .height = kHeight,
- .pixelFormat = Format::YUV_420_888}},
- mMockVirtualCameraClientCallback);
+ VirtualCameraConfiguration{
+ .supportedStreamConfigs = {SupportedStreamConfiguration{
+ .width = kVgaWidth,
+ .height = kVgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps},
+ SupportedStreamConfiguration{
+ .width = kSvgaWidth,
+ .height = kSvgaHeight,
+ .pixelFormat = Format::YUV_420_888,
+ .maxFps = kMaxFps}},
+ .virtualCameraCallback = nullptr,
+ .sensorOrientation = SensorOrientation::ORIENTATION_0,
+ .lensFacing = LensFacing::FRONT});
mVirtualCameraSession = ndk::SharedRefBase::make<VirtualCameraSession>(
- *mVirtualCameraDevice, mMockCameraDeviceCallback,
+ mVirtualCameraDevice, mMockCameraDeviceCallback,
mMockVirtualCameraClientCallback);
// Explicitly defining default actions below to prevent gmock from
@@ -145,18 +163,22 @@
PixelFormat format = PixelFormat::YCBCR_420_888;
StreamConfiguration streamConfiguration;
streamConfiguration.streams = {
- createStream(kStreamId, kWidth, kHeight, format)};
+ createStream(kStreamId, kVgaWidth, kVgaHeight, format),
+ createStream(kSecondStreamId, kSvgaWidth, kSvgaHeight, format)};
std::vector<HalStream> halStreams;
- EXPECT_CALL(
- *mMockVirtualCameraClientCallback,
- onStreamConfigured(kStreamId, _, kWidth, kHeight, Format::YUV_420_888));
+
+ // Expect highest resolution to be picked for the client input.
+ EXPECT_CALL(*mMockVirtualCameraClientCallback,
+ onStreamConfigured(kStreamId, _, kSvgaWidth, kSvgaHeight,
+ Format::YUV_420_888));
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
EXPECT_THAT(halStreams, SizeIs(streamConfiguration.streams.size()));
- EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0));
+ EXPECT_THAT(mVirtualCameraSession->getStreamIds(),
+ ElementsAre(kStreamId, kSecondStreamId));
}
TEST_F(VirtualCameraSessionTest, SecondConfigureDropsUnreferencedStreams) {
@@ -164,18 +186,18 @@
StreamConfiguration streamConfiguration;
std::vector<HalStream> halStreams;
- streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
- createStream(1, kWidth, kHeight, format),
- createStream(2, kWidth, kHeight, format)};
+ streamConfiguration.streams = {createStream(0, kVgaWidth, kVgaHeight, format),
+ createStream(1, kVgaWidth, kVgaHeight, format),
+ createStream(2, kVgaWidth, kVgaHeight, format)};
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
EXPECT_THAT(mVirtualCameraSession->getStreamIds(), ElementsAre(0, 1, 2));
- streamConfiguration.streams = {createStream(0, kWidth, kHeight, format),
- createStream(2, kWidth, kHeight, format),
- createStream(3, kWidth, kHeight, format)};
+ streamConfiguration.streams = {createStream(0, kVgaWidth, kVgaHeight, format),
+ createStream(2, kVgaWidth, kVgaHeight, format),
+ createStream(3, kVgaWidth, kVgaHeight, format)};
ASSERT_TRUE(
mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
.isOk());
@@ -200,8 +222,8 @@
TEST_F(VirtualCameraSessionTest, onProcessCaptureRequestTriggersClientCallback) {
StreamConfiguration streamConfiguration;
- streamConfiguration.streams = {
- createStream(kStreamId, kWidth, kHeight, PixelFormat::YCBCR_420_888)};
+ streamConfiguration.streams = {createStream(kStreamId, kVgaWidth, kVgaHeight,
+ PixelFormat::YCBCR_420_888)};
std::vector<CaptureRequest> requests(1);
requests[0].frameNumber = 42;
requests[0].settings = *(
@@ -223,6 +245,33 @@
EXPECT_THAT(aidlReturn, Eq(requests.size()));
}
+TEST_F(VirtualCameraSessionTest, configureAfterCameraRelease) {
+ StreamConfiguration streamConfiguration;
+ streamConfiguration.streams = {createStream(kStreamId, kVgaWidth, kVgaHeight,
+ PixelFormat::YCBCR_420_888)};
+ std::vector<HalStream> halStreams;
+
+ // Release virtual camera.
+ mVirtualCameraDevice.reset();
+
+ // Expect configuration attempt returns CAMERA_DISCONNECTED service specific code.
+ EXPECT_THAT(
+ mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .getServiceSpecificError(),
+ Eq(static_cast<int32_t>(Status::CAMERA_DISCONNECTED)));
+}
+
+TEST_F(VirtualCameraSessionTest, ConfigureWithEmptyStreams) {
+ StreamConfiguration streamConfiguration;
+ std::vector<HalStream> halStreams;
+
+ // Expect configuration attempt returns CAMERA_DISCONNECTED service specific code.
+ EXPECT_THAT(
+ mVirtualCameraSession->configureStreams(streamConfiguration, &halStreams)
+ .getServiceSpecificError(),
+ Eq(static_cast<int32_t>(Status::ILLEGAL_ARGUMENT)));
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/util/EglFramebuffer.cc b/services/camera/virtualcamera/util/EglFramebuffer.cc
index acf0122..57b94d3 100644
--- a/services/camera/virtualcamera/util/EglFramebuffer.cc
+++ b/services/camera/virtualcamera/util/EglFramebuffer.cc
@@ -112,6 +112,10 @@
return mHeight;
}
+std::shared_ptr<AHardwareBuffer> EglFrameBuffer::getHardwareBuffer() {
+ return mHardwareBuffer;
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/EglFramebuffer.h b/services/camera/virtualcamera/util/EglFramebuffer.h
index 35f85e2..b39df6d 100644
--- a/services/camera/virtualcamera/util/EglFramebuffer.h
+++ b/services/camera/virtualcamera/util/EglFramebuffer.h
@@ -50,6 +50,9 @@
// Return height of framebuffer (in pixels).
int getHeight() const;
+ // Return underlying hardware buffer.
+ std::shared_ptr<AHardwareBuffer> getHardwareBuffer();
+
private:
// Keeping shared_ptr to hardware buffer instance here prevents it from being
// freed while tied to EGL framebufer / EGL texture.
diff --git a/services/camera/virtualcamera/util/EglProgram.cc b/services/camera/virtualcamera/util/EglProgram.cc
index c468d39..7554a67 100644
--- a/services/camera/virtualcamera/util/EglProgram.cc
+++ b/services/camera/virtualcamera/util/EglProgram.cc
@@ -68,30 +68,45 @@
})";
constexpr char kExternalTextureVertexShader[] = R"(#version 300 es
+ uniform mat4 aTextureTransformMatrix; // Transform matrix given by surface texture.
in vec4 aPosition;
in vec2 aTextureCoord;
out vec2 vTextureCoord;
void main() {
gl_Position = aPosition;
- vTextureCoord = aTextureCoord;
+ vTextureCoord = (aTextureTransformMatrix * vec4(aTextureCoord, 0.0, 1.0)).xy;
})";
-constexpr char kExternalTextureFragmentShader[] = R"(#version 300 es
+constexpr char kExternalYuvTextureFragmentShader[] = R"(#version 300 es
#extension GL_OES_EGL_image_external_essl3 : require
#extension GL_EXT_YUV_target : require
precision mediump float;
in vec2 vTextureCoord;
- out vec4 fragColor;
+ layout (yuv) out vec4 fragColor;
uniform __samplerExternal2DY2YEXT uTexture;
void main() {
fragColor = texture(uTexture, vTextureCoord);
})";
+constexpr char kExternalRgbaTextureFragmentShader[] = R"(#version 300 es
+ #extension GL_OES_EGL_image_external : require
+ #extension GL_EXT_YUV_target : require
+ precision mediump float;
+ in vec2 vTextureCoord;
+ layout (yuv) out vec4 fragColor;
+ uniform samplerExternalOES uTexture;
+ void main() {
+ vec4 rgbaColor = texture(uTexture, vTextureCoord);
+ fragColor = vec4(rgb_2_yuv(rgbaColor.xyz, itu_601_full_range), 0.0);
+ })";
+
constexpr int kCoordsPerVertex = 3;
-constexpr std::array<float, 12> kSquareCoords{-1.f, 1.0f, 0.0f, // top left
- -1.f, -1.f, 0.0f, // bottom left
- 1.0f, -1.f, 0.0f, // bottom right
- 1.0f, 1.0f, 0.0f}; // top right
+
+constexpr std::array<float, 12> kSquareCoords{
+ -1.f, -1.0f, 0.0f, // top left
+ -1.f, 1.f, 0.0f, // bottom left
+ 1.0f, 1.f, 0.0f, // bottom right
+ 1.0f, -1.0f, 0.0f}; // top right
constexpr std::array<float, 8> kTextureCoords{0.0f, 1.0f, // top left
0.0f, 0.0f, // bottom left
@@ -237,7 +252,7 @@
return true;
}
-EglTextureProgram::EglTextureProgram() {
+EglTextureProgram::EglTextureProgram(const TextureFormat textureFormat) {
if (!isGlExtensionSupported(kGlExtYuvTarget)) {
ALOGE(
"Cannot initialize external texture program due to missing "
@@ -245,37 +260,58 @@
return;
}
- if (initialize(kExternalTextureVertexShader, kExternalTextureFragmentShader)) {
+ const char* fragmentShaderSrc = textureFormat == TextureFormat::YUV
+ ? kExternalYuvTextureFragmentShader
+ : kExternalRgbaTextureFragmentShader;
+ if (initialize(kExternalTextureVertexShader, fragmentShaderSrc)) {
ALOGV("Successfully initialized EGL shaders for external texture program.");
} else {
ALOGE("External texture EGL shader program initialization failed.");
}
+
+ // Lookup and cache handles to uniforms & attributes.
+ mPositionHandle = glGetAttribLocation(mProgram, "aPosition");
+ mTextureCoordHandle = glGetAttribLocation(mProgram, "aTextureCoord");
+ mTransformMatrixHandle =
+ glGetUniformLocation(mProgram, "aTextureTransformMatrix");
+ mTextureHandle = glGetUniformLocation(mProgram, "uTexture");
+
+ // Pass vertex array to the shader.
+ glEnableVertexAttribArray(mPositionHandle);
+ glVertexAttribPointer(mPositionHandle, kCoordsPerVertex, GL_FLOAT, false,
+ kSquareCoords.size(), kSquareCoords.data());
+
+ // Pass texture coordinates corresponding to vertex array to the shader.
+ glEnableVertexAttribArray(mTextureCoordHandle);
+ glVertexAttribPointer(mTextureCoordHandle, 2, GL_FLOAT, false,
+ kTextureCoords.size(), kTextureCoords.data());
}
-bool EglTextureProgram::draw(GLuint textureId) {
+EglTextureProgram::~EglTextureProgram() {
+ if (mPositionHandle != -1) {
+ glDisableVertexAttribArray(mPositionHandle);
+ }
+ if (mTextureCoordHandle != -1) {
+ glDisableVertexAttribArray(mTextureCoordHandle);
+ }
+}
+
+bool EglTextureProgram::draw(GLuint textureId,
+ const std::array<float, 16>& transformMatrix) {
// Load compiled shader.
glUseProgram(mProgram);
if (checkEglError("glUseProgram")) {
return false;
}
- // Pass vertex array to the shader.
- int positionHandle = glGetAttribLocation(mProgram, "aPosition");
- glEnableVertexAttribArray(positionHandle);
- glVertexAttribPointer(positionHandle, kCoordsPerVertex, GL_FLOAT, false,
- kSquareCoords.size(), kSquareCoords.data());
-
- // Pass texture coordinates corresponding to vertex array to the shader.
- int textureCoordHandle = glGetAttribLocation(mProgram, "aTextureCoord");
- glEnableVertexAttribArray(textureCoordHandle);
- glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, false,
- kTextureCoords.size(), kTextureCoords.data());
+ // Pass transformation matrix for the texture coordinates.
+ glUniformMatrix4fv(mTransformMatrixHandle, 1, /*transpose=*/GL_FALSE,
+ transformMatrix.data());
// Configure texture for the shader.
- int textureHandle = glGetUniformLocation(mProgram, "uTexture");
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
- glUniform1i(textureHandle, 0);
+ glUniform1i(mTextureHandle, 0);
// Draw triangle strip forming a square filling the viewport.
glDrawElements(GL_TRIANGLES, kDrawOrder.size(), GL_UNSIGNED_BYTE,
diff --git a/services/camera/virtualcamera/util/EglProgram.h b/services/camera/virtualcamera/util/EglProgram.h
index 8e394e7..c695cbb 100644
--- a/services/camera/virtualcamera/util/EglProgram.h
+++ b/services/camera/virtualcamera/util/EglProgram.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_COMPANION_VIRTUALCAMERA_EGLPROGRAM_H
#define ANDROID_COMPANION_VIRTUALCAMERA_EGLPROGRAM_H
+#include <array>
+
#include "GLES/gl.h"
namespace android {
@@ -55,9 +57,26 @@
// TODO(b/301023410) Add support for translation / cropping.
class EglTextureProgram : public EglProgram {
public:
- EglTextureProgram();
+ enum class TextureFormat { RGBA, YUV };
- bool draw(GLuint textureId);
+ EglTextureProgram(TextureFormat textureFormat = TextureFormat::YUV);
+ virtual ~EglTextureProgram();
+
+ // Draw texture over whole viewport, applying transformMatrix to texture
+ // coordinates.
+ //
+ // Transform matrix is 4x4 matrix represented in column-major order and is
+ // applied to texture coordinates in (s,t,0,1), s,t from <0,1> range prior to
+ // sampling:
+ //
+ // textureCoord = transformMatrix * vec4(s,t,0,1).xy
+ bool draw(GLuint textureId, const std::array<float, 16>& transformMatrix);
+
+ private:
+ int mPositionHandle = -1;
+ int mTextureCoordHandle = -1;
+ int mTransformMatrixHandle = -1;
+ int mTextureHandle = -1;
};
} // namespace virtualcamera
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 5b479c0..9f26e19 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -68,6 +68,16 @@
return mTextureId;
}
+GLuint EglSurfaceTexture::getTextureId() const {
+ return mTextureId;
+}
+
+std::array<float, 16> EglSurfaceTexture::getTransformMatrix() {
+ std::array<float, 16> matrix;
+ mGlConsumer->getTransformMatrix(matrix.data());
+ return matrix;
+}
+
uint32_t EglSurfaceTexture::getWidth() const {
return mWidth;
}
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index 14dc7d6..faad7c4 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -57,6 +57,17 @@
// Returns EGL texture id of the texture.
GLuint updateTexture();
+ // Returns EGL texture id of the underlying texture.
+ GLuint getTextureId() const;
+
+ // Returns 4x4 transformation matrix in column-major order,
+ // which should be applied to EGL texture coordinates
+ // before sampling from the texture backed by android native buffer,
+ // so the corresponding region of the underlying buffer is sampled.
+ //
+ // See SurfaceTexture.getTransformMatrix for more details.
+ std::array<float, 16> getTransformMatrix();
+
private:
sp<IGraphicBufferProducer> mBufferProducer;
sp<IGraphicBufferConsumer> mBufferConsumer;
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.cc b/services/camera/virtualcamera/util/MetadataBuilder.cc
index 92a48b9..70e22be 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.cc
+++ b/services/camera/virtualcamera/util/MetadataBuilder.cc
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -221,8 +221,7 @@
metadataStreamConfigs;
mEntryMap[ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS] =
metadataMinFrameDurations;
- mEntryMap[ANDROID_SCALER_AVAILABLE_STALL_DURATIONS] =
- metadataMinFrameDurations;
+ mEntryMap[ANDROID_SCALER_AVAILABLE_STALL_DURATIONS] = metadataStallDurations;
return *this;
}
diff --git a/services/camera/virtualcamera/util/MetadataBuilder.h b/services/camera/virtualcamera/util/MetadataBuilder.h
index d992d31..46f4c43 100644
--- a/services/camera/virtualcamera/util/MetadataBuilder.h
+++ b/services/camera/virtualcamera/util/MetadataBuilder.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright 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.
@@ -44,7 +44,7 @@
int32_t format = 0;
// Minimal frame duration - corresponds to maximal FPS for given format.
// See ANDROID_SCALER_AVAILABLE_MIN_FRAME_DURATIONS in CameraMetadataTag.aidl.
- std::chrono::nanoseconds minFrameDuration{std::chrono::seconds(1) / 30};
+ std::chrono::nanoseconds minFrameDuration{0};
// Minimal stall duration.
// See ANDROID_SCALER_AVAILABLE_STALL_DURATIONS in CameraMetadataTag.aidl.
std::chrono::nanoseconds minStallDuration{0};
diff --git a/services/camera/virtualcamera/util/Util.cc b/services/camera/virtualcamera/util/Util.cc
index 11dc3a6..2d0545d 100644
--- a/services/camera/virtualcamera/util/Util.cc
+++ b/services/camera/virtualcamera/util/Util.cc
@@ -18,20 +18,27 @@
#include <unistd.h>
+#include <algorithm>
+#include <array>
+
#include "jpeglib.h"
namespace android {
namespace companion {
namespace virtualcamera {
+using ::aidl::android::companion::virtualcamera::Format;
+using ::aidl::android::hardware::common::NativeHandle;
+
// Lower bound for maximal supported texture size is at least 2048x2048
// but on most platforms will be more.
// TODO(b/301023410) - Query actual max texture size.
constexpr int kMaxTextureSize = 2048;
constexpr int kLibJpegDctSize = DCTSIZE;
+constexpr int kMaxFpsUpperLimit = 60;
-using ::aidl::android::companion::virtualcamera::Format;
-using ::aidl::android::hardware::common::NativeHandle;
+constexpr std::array<Format, 2> kSupportedFormats{Format::YUV_420_888,
+ Format::RGBA_8888};
sp<Fence> importFence(const NativeHandle& aidlHandle) {
if (aidlHandle.fds.size() != 1) {
@@ -41,11 +48,15 @@
return sp<Fence>::make(::dup(aidlHandle.fds[0].get()));
}
+bool isPixelFormatSupportedForInput(const Format format) {
+ return std::find(kSupportedFormats.begin(), kSupportedFormats.end(),
+ format) != kSupportedFormats.end();
+}
+
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(const int width, const int height,
- const Format format) {
- if (format != Format::YUV_420_888) {
- // For now only YUV_420_888 is supported for input.
+ const Format format, const int maxFps) {
+ if (!isPixelFormatSupportedForInput(format)) {
return false;
}
@@ -61,6 +72,10 @@
return false;
}
+ if (maxFps <= 0 || maxFps > kMaxFpsUpperLimit) {
+ return false;
+ }
+
return true;
}
diff --git a/services/camera/virtualcamera/util/Util.h b/services/camera/virtualcamera/util/Util.h
index b778321..e0a31c0 100644
--- a/services/camera/virtualcamera/util/Util.h
+++ b/services/camera/virtualcamera/util/Util.h
@@ -43,10 +43,14 @@
sp<Fence> importFence(
const ::aidl::android::hardware::common::NativeHandle& handle);
+// Returns true if specified pixel format is supported for virtual camera input.
+bool isPixelFormatSupportedForInput(
+ ::aidl::android::companion::virtualcamera::Format format);
+
// Returns true if specified format is supported for virtual camera input.
bool isFormatSupportedForInput(
int width, int height,
- ::aidl::android::companion::virtualcamera::Format format);
+ ::aidl::android::companion::virtualcamera::Format format, int maxFps);
} // namespace virtualcamera
} // namespace companion
diff --git a/services/mediacodec/Android.bp b/services/mediacodec/Android.bp
index a2f17c2..506b3bc 100644
--- a/services/mediacodec/Android.bp
+++ b/services/mediacodec/Android.bp
@@ -95,31 +95,6 @@
"android.hidl.memory@1.0",
],
- runtime_libs: [
- "libstagefright_soft_aacdec",
- "libstagefright_soft_aacenc",
- "libstagefright_soft_amrdec",
- "libstagefright_soft_amrnbenc",
- "libstagefright_soft_amrwbenc",
- "libstagefright_soft_avcdec",
- "libstagefright_soft_avcenc",
- "libstagefright_soft_flacdec",
- "libstagefright_soft_flacenc",
- "libstagefright_soft_g711dec",
- "libstagefright_soft_gsmdec",
- "libstagefright_soft_hevcdec",
- "libstagefright_soft_mp3dec",
- "libstagefright_soft_mpeg2dec",
- "libstagefright_soft_mpeg4dec",
- "libstagefright_soft_mpeg4enc",
- "libstagefright_soft_opusdec",
- "libstagefright_soft_rawdec",
- "libstagefright_soft_vorbisdec",
- "libstagefright_soft_vpxdec",
- "libstagefright_soft_vpxenc",
- "libstagefright_softomx_plugin",
- ],
-
// OMX interfaces force this to stay in 32-bit mode;
compile_multilib: "32",
diff --git a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
index a55c3eb..0c6aafd 100644
--- a/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
+++ b/services/mediacodec/seccomp_policy/mediaswcodec-riscv64.policy
@@ -52,6 +52,9 @@
getdents64: 1
ppoll: 1
+clock_gettime: 1
+pipe2: 1
+
# Required by AddressSanitizer
gettid: 1
sched_yield: 1
diff --git a/services/mediametrics/AudioPowerUsage.cpp b/services/mediametrics/AudioPowerUsage.cpp
index 630a436..7dc445b 100644
--- a/services/mediametrics/AudioPowerUsage.cpp
+++ b/services/mediametrics/AudioPowerUsage.cpp
@@ -549,7 +549,7 @@
int slot = 1;
std::stringstream ss;
- ss << "AudioPowerUsage:\n";
+ ss << "AudioPowerUsage interval " << mIntervalHours << " hours:\n";
for (const auto &item : mItems) {
if (slot >= limit - 1) {
ss << "-- AudioPowerUsage may be truncated!\n";
diff --git a/services/mediametrics/include/mediametricsservice/TimedAction.h b/services/mediametrics/include/mediametricsservice/TimedAction.h
index c7ef585..8b53ded 100644
--- a/services/mediametrics/include/mediametricsservice/TimedAction.h
+++ b/services/mediametrics/include/mediametricsservice/TimedAction.h
@@ -25,6 +25,12 @@
namespace android::mediametrics {
class TimedAction {
+ // Use system_clock instead of steady_clock to include suspend time.
+ using TimerClock = class std::chrono::system_clock;
+
+ // Define granularity of wakeup to prevent delayed events if
+ // device is suspended.
+ static constexpr auto kWakeupInterval = std::chrono::minutes(3);
public:
TimedAction() : mThread{[this](){threadLoop();}} {}
@@ -35,7 +41,7 @@
// TODO: return a handle for cancelling the action?
template <typename T> // T is in units of std::chrono::duration.
void postIn(const T& time, std::function<void()> f) {
- postAt(std::chrono::steady_clock::now() + time, f);
+ postAt(TimerClock::now() + time, f);
}
template <typename T> // T is in units of std::chrono::time_point
@@ -75,16 +81,21 @@
void threadLoop() NO_THREAD_SAFETY_ANALYSIS { // thread safety doesn't cover unique_lock
std::unique_lock l(mLock);
while (!mQuit) {
- auto sleepUntilTime = std::chrono::time_point<std::chrono::steady_clock>::max();
+ auto sleepUntilTime = std::chrono::time_point<TimerClock>::max();
if (!mMap.empty()) {
sleepUntilTime = mMap.begin()->first;
- if (sleepUntilTime <= std::chrono::steady_clock::now()) {
+ const auto now = TimerClock::now();
+ if (sleepUntilTime <= now) {
auto node = mMap.extract(mMap.begin()); // removes from mMap.
l.unlock();
node.mapped()();
l.lock();
continue;
}
+ // Bionic uses CLOCK_MONOTONIC for its pthread_mutex regardless
+ // of REALTIME specification, use kWakeupInterval to ensure minimum
+ // granularity if suspended.
+ sleepUntilTime = std::min(sleepUntilTime, now + kWakeupInterval);
}
mCondition.wait_until(l, sleepUntilTime);
}
@@ -93,7 +104,7 @@
mutable std::mutex mLock;
std::condition_variable mCondition GUARDED_BY(mLock);
bool mQuit GUARDED_BY(mLock) = false;
- std::multimap<std::chrono::time_point<std::chrono::steady_clock>, std::function<void()>>
+ std::multimap<std::chrono::time_point<TimerClock>, std::function<void()>>
mMap GUARDED_BY(mLock); // multiple functions could execute at the same time.
// needs to be initialized after the variables above, done in constructor initializer list.
diff --git a/services/mediaresourcemanager/Android.bp b/services/mediaresourcemanager/Android.bp
index 73a96e9..7f66859 100644
--- a/services/mediaresourcemanager/Android.bp
+++ b/services/mediaresourcemanager/Android.bp
@@ -74,10 +74,15 @@
name: "libresourcemanagerservice",
srcs: [
+ "ClientImportanceReclaimPolicy.cpp",
+ "DefaultResourceModel.cpp",
+ "ProcessPriorityReclaimPolicy.cpp",
"ResourceManagerMetrics.cpp",
"ResourceManagerService.cpp",
+ "ResourceManagerServiceNew.cpp",
"ResourceObserverService.cpp",
"ResourceManagerServiceUtils.cpp",
+ "ResourceTracker.cpp",
"ServiceLog.cpp",
"UidObserver.cpp",
@@ -97,6 +102,7 @@
"libstatssocket",
"libprotobuf-cpp-lite",
"libactivitymanager_aidl",
+ "aconfig_mediacodec_flags_c_lib",
],
static_libs: [
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
new file mode 100644
index 0000000..a81b32f
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.cpp
@@ -0,0 +1,88 @@
+/*
+**
+** Copyright 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_NDEBUG 0
+#define LOG_TAG "ClientImportanceReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ClientImportanceReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ClientImportanceReclaimPolicy::ClientImportanceReclaimPolicy(
+ const std::shared_ptr<ResourceTracker>& resourceTracker)
+ : mResourceTracker(resourceTracker) {
+}
+
+ClientImportanceReclaimPolicy::~ClientImportanceReclaimPolicy() {
+}
+
+// Find the biggest client from the same process with the lowest importance
+// than that of the requesting client.
+bool ClientImportanceReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ pid_t callingPid = reclaimRequestInfo.mCallingPid;
+ int32_t callingImportance = reclaimRequestInfo.mCallingClientImportance;
+ MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+ ClientInfo targetClient;
+ // Look to find the biggest client with lowest importance from the same process that
+ // has the other resources and with the given primary type.
+ bool found = false;
+ MediaResource::SubType primarySubType = subType;
+ for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
+ MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, primarySubType,
+ clients, targetClient);
+ }
+ // If no success, then select the biggest client of primary type with lowest importance
+ // from the same process.
+ if (!found) {
+ found = mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ type, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient);
+ }
+ // If we haven't found a client yet, then select the biggest client of different type
+ // with lowest importance from the same process.
+ // This is applicable for codec type only.
+ if (!found) {
+ if (type != MediaResource::Type::kSecureCodec &&
+ type != MediaResource::Type::kNonSecureCodec) {
+ return false;
+ }
+ MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ if (!mResourceTracker->getLeastImportantBiggestClient(
+ callingPid, callingImportance,
+ otherType, subType, MediaResource::SubType::kUnspecifiedSubType,
+ clients, targetClient)) {
+ return false;
+ }
+ }
+ targetClients.emplace_back(targetClient);
+ return true;
+}
+} // namespace android
diff --git a/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
new file mode 100644
index 0000000..1a54c7d
--- /dev/null
+++ b/services/mediaresourcemanager/ClientImportanceReclaimPolicy.h
@@ -0,0 +1,64 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+#define ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of Reclaim Policy based on the client's importance.
+ *
+ * Find the least important (other than that of requesting client) client from the
+ * same process (that is requesting for the resource).
+ * If there are multiple clients with least importance, then pick the biggest
+ * client among them.
+ *
+ */
+class ClientImportanceReclaimPolicy : public IReclaimPolicy {
+public:
+ explicit ClientImportanceReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+ virtual ~ClientImportanceReclaimPolicy();
+
+ /*
+ * Based on the client importance, identify and return the least important client of
+ * the requesting process from the list of given clients that satisfy the resource requested.
+ *
+ * @param[in] reclaimRequestInfo Information about the resource request
+ * @param[in] client List of clients to select from.
+ * @param[out] targetClients Upon success, this will have the list of identified client(s).
+ *
+ * @return true on success, false otherwise
+ */
+ bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) override;
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_CLIENTIMPORTANCERECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/DefaultResourceModel.cpp b/services/mediaresourcemanager/DefaultResourceModel.cpp
new file mode 100644
index 0000000..7bad715
--- /dev/null
+++ b/services/mediaresourcemanager/DefaultResourceModel.cpp
@@ -0,0 +1,145 @@
+/*
+**
+** Copyright 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_NDEBUG 0
+#define LOG_TAG "DefaultResourceModel"
+#include <utils/Log.h>
+
+#include "ResourceManagerServiceUtils.h"
+#include "DefaultResourceModel.h"
+#include "ResourceTracker.h"
+
+namespace android {
+
+DefaultResourceModel::DefaultResourceModel(
+ const std::shared_ptr<ResourceTracker>& resourceTracker,
+ bool supportsMultipleSecureCodecs,
+ bool supportsSecureWithNonSecureCodec)
+ : mSupportsMultipleSecureCodecs(supportsMultipleSecureCodecs),
+ mSupportsSecureWithNonSecureCodec(supportsSecureWithNonSecureCodec),
+ mResourceTracker(resourceTracker) {
+}
+
+DefaultResourceModel::~DefaultResourceModel() {
+}
+
+bool DefaultResourceModel::getAllClients(
+ const ReclaimRequestInfo& reclimRequestInfo,
+ std::vector<ClientInfo>& clients) {
+
+ clients.clear();
+ MediaResourceParcel mediaResource{.type = reclimRequestInfo.mResources[0].type,
+ .subType = reclimRequestInfo.mResources[0].subType};
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+
+ // Resolve the secure-unsecure codec conflicts if there is any.
+ switch (reclimRequestInfo.mResources[0].type) {
+ case MediaResource::Type::kSecureCodec:
+ // Looking to start a secure codec.
+ // #1. Make sure if multiple secure codecs can coexist
+ if (!mSupportsMultipleSecureCodecs) {
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ // #2. Make sure a secure codec can coexist if there is an instance
+ // of non-secure codec running already.
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kNonSecureCodec;
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a non-secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ break;
+ case MediaResource::Type::kNonSecureCodec:
+ // Looking to start a non-secure codec.
+ // Make sure a non-secure codec can coexist if there is an instance
+ // of secure codec running already.
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kSecureCodec;
+ if (!mResourceTracker->getNonConflictingClients(resourceRequestInfo, clients)) {
+ // A higher priority process owns an instance of a secure codec.
+ // So this request can't be fulfilled.
+ return false;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!clients.empty()) {
+ // There is secure/unsecure codec co-existence conflict
+ // and we have only found processes with lower priority holding the
+ // resources. So, all of these need to be reclaimed.
+ return false;
+ }
+
+ // No more resource conflicts.
+ switch (reclimRequestInfo.mResources[0].type) {
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ // Handling Codec resource reclaim
+ return getCodecClients(reclimRequestInfo, clients);
+ case MediaResource::Type::kGraphicMemory:
+ case MediaResource::Type::kDrmSession:
+ // Handling DRM and GraphicMemory resource reclaim
+ mediaResource.id = reclimRequestInfo.mResources[0].id;
+ mediaResource.value = reclimRequestInfo.mResources[0].value;
+ return mResourceTracker->getAllClients(resourceRequestInfo, clients);
+ default:
+ break;
+ }
+
+ return !clients.empty();
+}
+
+bool DefaultResourceModel::getCodecClients(
+ const ReclaimRequestInfo& reclimRequestInfo,
+ std::vector<ClientInfo>& clients) {
+ MediaResourceParcel mediaResource;
+ ResourceRequestInfo resourceRequestInfo{reclimRequestInfo.mCallingPid, &mediaResource};
+
+ // 1. Look to find the client(s) with the other resources, for the given
+ // primary type.
+ MediaResource::SubType primarySubType = reclimRequestInfo.mResources[0].subType;
+ for (size_t index = 1; index < reclimRequestInfo.mResources.size(); index++) {
+ mediaResource.type = reclimRequestInfo.mResources[index].type;
+ mediaResource.subType = reclimRequestInfo.mResources[index].subType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients, primarySubType);
+ }
+
+ // 2. Get all clients of the same type.
+ mediaResource.type = reclimRequestInfo.mResources[0].type;
+ mediaResource.subType = reclimRequestInfo.mResources[0].subType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ // 3. Get all cliends of the different type.
+ MediaResourceType otherType =
+ (reclimRequestInfo.mResources[0].type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ mediaResource.type = otherType;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ return !clients.empty();
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/DefaultResourceModel.h b/services/mediaresourcemanager/DefaultResourceModel.h
new file mode 100644
index 0000000..1891eda
--- /dev/null
+++ b/services/mediaresourcemanager/DefaultResourceModel.h
@@ -0,0 +1,73 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
+#define ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
+
+#include "IResourceModel.h"
+
+namespace android {
+
+class ResourceTracker;
+
+/*
+ * Implements the Default Resource Model that handles:
+ * - coexistence of secure codec with another secure/non-secure codecs
+ * - sharing resources among other codecs
+ */
+class DefaultResourceModel : public IResourceModel {
+public:
+ DefaultResourceModel(const std::shared_ptr<ResourceTracker>& resourceTracker,
+ bool supportsMultipleSecureCodecs = true,
+ bool supportsSecureWithNonSecureCodec = true);
+ virtual ~DefaultResourceModel();
+
+ /*
+ * Set the codec co-existence properties
+ */
+ void config(bool supportsMultipleSecureCodecs, bool supportsSecureWithNonSecureCodec) {
+ mSupportsMultipleSecureCodecs = supportsMultipleSecureCodecs;
+ mSupportsSecureWithNonSecureCodec = supportsSecureWithNonSecureCodec;
+ }
+
+ /*
+ * Get a list of all clients that holds the resources requested.
+ * This implementation uses the ResourceModel to select the clients.
+ *
+ * @param[in] reclaimRequestInfo Information about the Reclaim request
+ * @param[out] cliens The list of clients that hold the resources in question.
+ *
+ * @return true if there aren't any resource conflicts and false otherwise.
+ */
+ bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients) override;
+
+protected:
+ bool getCodecClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients);
+
+protected:
+ // Keeping these protected to allow extending this implementation
+ // by other resource models.
+ bool mSupportsMultipleSecureCodecs;
+ bool mSupportsSecureWithNonSecureCodec;
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_DEFAULTRESOURCEMODEL_H_
diff --git a/services/mediaresourcemanager/IReclaimPolicy.h b/services/mediaresourcemanager/IReclaimPolicy.h
new file mode 100644
index 0000000..dfbfc12
--- /dev/null
+++ b/services/mediaresourcemanager/IReclaimPolicy.h
@@ -0,0 +1,58 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_IRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_IRECLAIMPOLICY_H_
+
+#include <memory>
+#include <aidl/android/media/IResourceManagerClient.h>
+
+namespace android {
+
+struct ClientInfo;
+struct ReclaimRequestInfo;
+
+/*
+ * Interface that defines Reclaim Policy.
+ *
+ * This provides an interface to select/identify a client based on a specific
+ * Reclaim policy.
+ */
+class IReclaimPolicy {
+public:
+ IReclaimPolicy() {}
+
+ virtual ~IReclaimPolicy() {}
+
+ /*
+ * Based on the Reclaim policy, identify and return a client from the list
+ * of given clients that satisfy the resource requested.
+ *
+ * @param[in] reclaimRequestInfo Information about the resource request
+ * @param[in] client List of clients to select from.
+ * @param[out] targetClients Upon success, this will have the list of identified client(s).
+ *
+ * @return true on success, false otherwise
+ */
+ virtual bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_IRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/IResourceModel.h b/services/mediaresourcemanager/IResourceModel.h
new file mode 100644
index 0000000..f865f54
--- /dev/null
+++ b/services/mediaresourcemanager/IResourceModel.h
@@ -0,0 +1,67 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_IRESOURCEMODEL_H_
+#define ANDROID_MEDIA_IRESOURCEMODEL_H_
+
+#include <memory>
+#include <vector>
+
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+namespace android {
+
+struct ClientInfo;
+struct ReclaimRequestInfo;
+
+/*
+ * Interface that defines Resource Model.
+ *
+ * This provides an interface that manages the resource model.
+ * The primary functionality of the implementation of this resource model is to:
+ * 1. Define a resource model for a device (or family of devices)
+ * For example (and not limited to):
+ * - Can a secure codec coexist with another secure or unsecured codec?
+ * - How many codecs can coexist?
+ * - Can one type of codecs (for example avc) coexist with another type of codec
+ * (for example hevc) independently? OR are they sharing the common
+ * resource pool?
+ * 2. Provide a list of clients that hold requesting resources.
+ */
+class IResourceModel {
+public:
+ IResourceModel() {}
+
+ virtual ~IResourceModel() {}
+
+ /*
+ * Get a list of all clients that holds the resources requested.
+ * This implementation uses the ResourceModel to select the clients.
+ *
+ * @param[in] reclaimRequestInfo Information about the Reclaim request
+ * @param[out] clients The list of clients that hold the resources in question.
+ *
+ * @return true if there aren't any resource conflicts and false otherwise.
+ */
+ virtual bool getAllClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ std::vector<ClientInfo>& clients) = 0;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_IRESOURCEMODEL_H_
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
new file mode 100644
index 0000000..5b776a6
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.cpp
@@ -0,0 +1,135 @@
+/*
+**
+** Copyright 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_NDEBUG 0
+#define LOG_TAG "ProcessPriorityReclaimPolicy"
+#include <utils/Log.h>
+
+#include "ResourceTracker.h"
+#include "ResourceManagerService.h"
+#include "ProcessPriorityReclaimPolicy.h"
+
+namespace android {
+
+using aidl::android::media::IResourceManagerClient;
+
+ProcessPriorityReclaimPolicy::ProcessPriorityReclaimPolicy(
+ const std::shared_ptr<ResourceTracker>& resourceTracker)
+ : mResourceTracker(resourceTracker) {
+}
+
+ProcessPriorityReclaimPolicy::~ProcessPriorityReclaimPolicy() {
+}
+
+// Process priority (oom score) based reclaim:
+// - Find a process with lowest priority (than that of calling process).
+// - Find the bigegst client (with required resources) from that process.
+bool ProcessPriorityReclaimPolicy::getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ // NOTE: This is the behavior of the existing reclaim policy.
+ // We can alter it to select more than one client to reclaim from, depending
+ // on the reclaim polocy.
+
+ MediaResource::Type type = reclaimRequestInfo.mResources[0].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[0].subType;
+ // Find one client to reclaim the needed resources from.
+ // 1. Get the priority of the (reclaim) requesting process.
+ int callingPid = reclaimRequestInfo.mCallingPid;
+ int callingPriority = -1;
+ if (!mResourceTracker->getPriority(callingPid, &callingPriority)) {
+ ALOGE("%s: can't get process priority for pid %d", __func__, callingPid);
+ return false;
+ }
+
+ ClientInfo clientInfo;
+ // 2 Look to find the biggest client from the lowest priority process that
+ // has the other resources and with the given primary type.
+ bool found = false;
+ int lowestPriority = -1;
+ MediaResource::SubType primarySubType = subType;
+ for (size_t index = 1; !found && (index < reclaimRequestInfo.mResources.size()); index++) {
+ MediaResource::Type type = reclaimRequestInfo.mResources[index].type;
+ MediaResource::SubType subType = reclaimRequestInfo.mResources[index].subType;
+ found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ type, subType, primarySubType,
+ clients, clientInfo, lowestPriority);
+ }
+ // 3 If we haven't found a client yet, then select the biggest client of primary type.
+ if (!found) {
+ found = getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ type, subType,
+ MediaResource::SubType::kUnspecifiedSubType,
+ clients, clientInfo, lowestPriority);
+ }
+ // 4 If we haven't found a client yet, then select the biggest client of different type.
+ // This is applicable for code type only.
+ if (!found) {
+ if (type != MediaResource::Type::kSecureCodec &&
+ type != MediaResource::Type::kNonSecureCodec) {
+ return false;
+ }
+ MediaResourceType otherType = (type == MediaResource::Type::kSecureCodec) ?
+ MediaResource::Type::kNonSecureCodec : MediaResource::Type::kSecureCodec;
+ if (!getBiggestClientFromLowestPriority(callingPid, callingPriority,
+ otherType, subType,
+ MediaResource::SubType::kUnspecifiedSubType,
+ clients, clientInfo, lowestPriority)) {
+ return false;
+ }
+ }
+
+ targetClients.emplace_back(clientInfo);
+ ALOGI("%s: CallingProcess(%d:%d) will reclaim from the lowestPriorityProcess(%d:%d)",
+ __func__, callingPid, callingPriority, clientInfo.mPid, lowestPriority);
+
+ return true;
+}
+
+bool ProcessPriorityReclaimPolicy::getBiggestClientFromLowestPriority(
+ pid_t callingPid,
+ int callingPriority,
+ MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& targetClient,
+ int& lowestPriority) {
+ // 1. Find the lowest priority process among all the clients with the
+ // requested resource type.
+ int lowestPriorityPid = -1;
+ lowestPriority = -1;
+ if (!mResourceTracker->getLowestPriorityPid(type, subType, primarySubType, clients,
+ lowestPriorityPid, lowestPriority)) {
+ ALOGD("%s: can't find a process with lower priority than that of the process[%d:%d]",
+ __func__, callingPid, callingPriority);
+ return false;
+ }
+
+ // 2. Make sure that the priority of the target process is less than
+ // requesting process.
+ if (lowestPriority <= callingPriority) {
+ ALOGD("%s: lowest priority %d vs caller priority %d",
+ __func__, lowestPriority, callingPriority);
+ return false;
+ }
+
+ // 3. Look to find the biggest client from that process for the given resources
+ return mResourceTracker->getBiggestClient(lowestPriorityPid, type, subType,
+ clients, targetClient, primarySubType);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
new file mode 100644
index 0000000..77bf7e1
--- /dev/null
+++ b/services/mediaresourcemanager/ProcessPriorityReclaimPolicy.h
@@ -0,0 +1,89 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
+#define ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
+
+#include <media/MediaResource.h>
+#include "IReclaimPolicy.h"
+
+namespace android {
+
+class ResourceTracker;
+struct ClientInfo;
+
+/*
+ * Implementation of the Reclaim Policy based on the process priority.
+ *
+ * Find the lowest priority process (lower than the calling/requesting process’s priority)
+ * that has the required resources.
+ * From that process, find the biggest client and return the same for reclaiming.
+ * If there is a codec co-existence policy, that is addressed as below:
+ * - if these are any conflicting codecs, reclaim all those conflicting clients.
+ * If no conflicting codecs, the reclaim policy will select a client in the order of:
+ * - Find the biggest client from the lowest priority process that
+ * has the other resources and with the given primary type.
+ * - select the biggest client from the lower priority process that
+ * has the primary type.
+ * - If it's a codec reclaim request, then:
+ * - select the biggest client from the lower priority process that
+ * has the othe type (for example secure for a non-secure and vice versa).
+ */
+class ProcessPriorityReclaimPolicy : public IReclaimPolicy {
+public:
+ ProcessPriorityReclaimPolicy(const std::shared_ptr<ResourceTracker>& resourceTracker);
+
+ virtual ~ProcessPriorityReclaimPolicy();
+
+ /*
+ * Based on the process priority, identify and return a client from the list
+ * of given clients that satisfy the resource requested.
+ *
+ * @param[in] reclaimRequestInfo Information about the resource request
+ * @param[in] client List of clients to select from.
+ * @param[out] targetClients Upon success, this will have the list of identified client(s).
+ *
+ * @return true on success, false otherwise
+ */
+ bool getClients(const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) override;
+
+private:
+
+ // Get the biggest client with the given resources from the given list of clients.
+ // The client should belong to lowest possible priority than that of the
+ // calling/requesting process.
+ // returns true on success, false otherwise
+ //
+ bool getBiggestClientFromLowestPriority(
+ pid_t callingPid,
+ int callingPriority,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& targetClient,
+ int& lowestPriority);
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_PROCESSPRIORITYRECLAIMPOLICY_H_
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 1953237..3a02443 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -29,37 +29,60 @@
#include <mediautils/BatteryNotifier.h>
#include <mediautils/ProcessInfo.h>
#include <mediautils/SchedulingPolicyService.h>
+#include <com_android_media_codec_flags.h>
-#include "IMediaResourceMonitor.h"
#include "ResourceManagerMetrics.h"
+#include "ResourceManagerServiceNew.h"
#include "ResourceObserverService.h"
#include "ServiceLog.h"
+namespace CodecFeatureFlags = com::android::media::codec::flags;
+
namespace android {
-static void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
- static const char* const kServiceName = "media_resource_monitor";
- sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
- if (binder != NULL) {
- sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
- for (size_t i = 0; i < resources.size(); ++i) {
- switch (resources[i].subType) {
- case MediaResource::SubType::kHwAudioCodec:
- case MediaResource::SubType::kSwAudioCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
- break;
- case MediaResource::SubType::kHwVideoCodec:
- case MediaResource::SubType::kSwVideoCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
- break;
- case MediaResource::SubType::kHwImageCodec:
- case MediaResource::SubType::kSwImageCodec:
- service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
- break;
- case MediaResource::SubType::kUnspecifiedSubType:
- break;
- }
+void ResourceManagerService::getResourceDump(std::string& resourceLog) const {
+ PidResourceInfosMap mapCopy;
+ std::map<int, int> overridePidMapCopy;
+ {
+ std::scoped_lock lock{mLock};
+ mapCopy = mMap; // Shadow copy, real copy will happen on write.
+ overridePidMapCopy = mOverridePidMap;
+ }
+
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ resourceLog.append(" Processes:\n");
+ for (const auto& [pid, infos] : mapCopy) {
+ snprintf(buffer, SIZE, " Pid: %d\n", pid);
+ resourceLog.append(buffer);
+ int priority = 0;
+ if (getPriority_l(pid, &priority)) {
+ snprintf(buffer, SIZE, " Priority: %d\n", priority);
+ } else {
+ snprintf(buffer, SIZE, " Priority: <unknown>\n");
}
+ resourceLog.append(buffer);
+
+ for (const auto& [infoKey, info] : infos) {
+ resourceLog.append(" Client:\n");
+ snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
+ resourceLog.append(buffer);
+
+ std::string clientName = info.name;
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
+ resourceLog.append(buffer);
+
+ const ResourceList& resources = info.resources;
+ resourceLog.append(" Resources:\n");
+ resourceLog.append(resources.toString());
+ }
+ }
+
+ resourceLog.append(" Process Pid override:\n");
+ for (auto it = overridePidMapCopy.begin(); it != overridePidMapCopy.end(); ++it) {
+ snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n",
+ it->first, it->second);
+ resourceLog.append(buffer);
}
}
@@ -75,20 +98,20 @@
return PERMISSION_DENIED;
}
- PidResourceInfosMap mapCopy;
bool supportsMultipleSecureCodecs;
bool supportsSecureWithNonSecureCodec;
- std::map<int, int> overridePidMapCopy;
String8 serviceLog;
{
std::scoped_lock lock{mLock};
- mapCopy = mMap; // Shadow copy, real copy will happen on write.
supportsMultipleSecureCodecs = mSupportsMultipleSecureCodecs;
supportsSecureWithNonSecureCodec = mSupportsSecureWithNonSecureCodec;
serviceLog = mServiceLog->toString(" " /* linePrefix */);
- overridePidMapCopy = mOverridePidMap;
}
+ // Get all the resource (and overload pid) logs
+ std::string resourceLog;
+ getResourceDump(resourceLog);
+
const size_t SIZE = 256;
char buffer[SIZE];
snprintf(buffer, SIZE, "ResourceManagerService: %p\n", this);
@@ -100,41 +123,8 @@
supportsSecureWithNonSecureCodec);
result.append(buffer);
- result.append(" Processes:\n");
- for (const auto& [pid, infos] : mapCopy) {
- snprintf(buffer, SIZE, " Pid: %d\n", pid);
- result.append(buffer);
- int priority = 0;
- if (getPriority_l(pid, &priority)) {
- snprintf(buffer, SIZE, " Priority: %d\n", priority);
- } else {
- snprintf(buffer, SIZE, " Priority: <unknown>\n");
- }
- result.append(buffer);
+ result.append(resourceLog.c_str());
- for (const auto& [infoKey, info] : infos) {
- result.append(" Client:\n");
- snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
- result.append(buffer);
-
- std::string clientName = info.name;
- snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
- result.append(buffer);
-
- const ResourceList& resources = info.resources;
- result.append(" Resources:\n");
- for (auto it = resources.begin(); it != resources.end(); it++) {
- snprintf(buffer, SIZE, " %s\n", toString(it->second).c_str());
- result.append(buffer);
- }
- }
- }
- result.append(" Process Pid override:\n");
- for (auto it = overridePidMapCopy.begin(); it != overridePidMapCopy.end(); ++it) {
- snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n",
- it->first, it->second);
- result.append(buffer);
- }
result.append(" Events logs (most recent at top):\n");
result.append(serviceLog);
@@ -212,9 +202,35 @@
std::shared_ptr<ResourceManagerService> ResourceManagerService::Create(
const sp<ProcessInfoInterface>& processInfo,
const sp<SystemCallbackInterface>& systemResource) {
- return ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo, systemResource);
+ std::shared_ptr<ResourceManagerService> service = nullptr;
+ // If codec importance feature is on, create the refactored implementation.
+ if (CodecFeatureFlags::codec_importance()) {
+ service = ::ndk::SharedRefBase::make<ResourceManagerServiceNew>(processInfo,
+ systemResource);
+ } else {
+ service = ::ndk::SharedRefBase::make<ResourceManagerService>(processInfo,
+ systemResource);
+ }
+
+ if (service != nullptr) {
+ service->init();
+ }
+
+ return service;
}
+// TEST only function.
+std::shared_ptr<ResourceManagerService> ResourceManagerService::CreateNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource) {
+ std::shared_ptr<ResourceManagerService> service =
+ ::ndk::SharedRefBase::make<ResourceManagerServiceNew>(processInfo, systemResource);
+ service->init();
+ return service;
+}
+
+void ResourceManagerService::init() {}
+
ResourceManagerService::~ResourceManagerService() {}
void ResourceManagerService::setObserverService(
@@ -296,31 +312,21 @@
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
ALOGW("Ignoring request to remove negative value of non-drm resource");
continue;
}
- if (info.resources.find(resType) == info.resources.end()) {
- if (res.value <= 0) {
- // We can't init a new entry with negative value, although it's allowed
- // to merge in negative values after the initial add.
- ALOGW("Ignoring request to add new resource entry with value <= 0");
- continue;
- }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
onFirstAdded(res, info.uid);
- info.resources[resType] = res;
- } else {
- mergeResources(info.resources[resType], res);
}
+
// Add it to the list of added resources for observers.
- auto it = resourceAdded.find(resType);
- if (it == resourceAdded.end()) {
- resourceAdded[resType] = res;
- } else {
- mergeResources(it->second, res);
- }
+ resourceAdded.add(res);
}
if (info.deathNotifier == nullptr && client != nullptr) {
info.deathNotifier = DeathNotifier::Create(
@@ -367,31 +373,22 @@
ResourceList resourceRemoved;
for (size_t i = 0; i < resources.size(); ++i) {
const auto &res = resources[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
if (res.value < 0) {
ALOGW("Ignoring request to remove negative value of resource");
continue;
}
- // ignore if we don't have it
- if (info.resources.find(resType) != info.resources.end()) {
- MediaResourceParcel &resource = info.resources[resType];
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
MediaResourceParcel actualRemoved = res;
- if (resource.value > res.value) {
- resource.value -= res.value;
- } else {
+ if (removedEntryValue != -1) {
onLastRemoved(res, info.uid);
- actualRemoved.value = resource.value;
- info.resources.erase(resType);
+ actualRemoved.value = removedEntryValue;
}
// Add it to the list of removed resources for observers.
- auto it = resourceRemoved.find(resType);
- if (it == resourceRemoved.end()) {
- resourceRemoved[resType] = actualRemoved;
- } else {
- mergeResources(it->second, actualRemoved);
- }
+ resourceRemoved.add(actualRemoved);
}
}
if (mObserverService != nullptr && !resourceRemoved.empty()) {
@@ -434,8 +431,8 @@
}
const ResourceInfo& info = foundClient->second;
- for (auto it = info.resources.begin(); it != info.resources.end(); it++) {
- onLastRemoved(it->second, info.uid);
+ for (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, info.uid);
}
// Since this client has been removed, update the metrics collector.
@@ -472,114 +469,130 @@
}
}
+bool ResourceManagerService::getTargetClients(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
+ callingPid, actualCallingPid);
+ callingPid = actualCallingPid;
+ }
+ const MediaResourceParcel *secureCodec = NULL;
+ const MediaResourceParcel *nonSecureCodec = NULL;
+ const MediaResourceParcel *graphicMemory = NULL;
+ const MediaResourceParcel *drmSession = NULL;
+ for (size_t i = 0; i < resources.size(); ++i) {
+ switch (resources[i].type) {
+ case MediaResource::Type::kSecureCodec:
+ secureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kNonSecureCodec:
+ nonSecureCodec = &resources[i];
+ break;
+ case MediaResource::Type::kGraphicMemory:
+ graphicMemory = &resources[i];
+ break;
+ case MediaResource::Type::kDrmSession:
+ drmSession = &resources[i];
+ break;
+ default:
+ break;
+ }
+ }
+
+ // first pass to handle secure/non-secure codec conflict
+ if (secureCodec != NULL) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = secureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ if (!mSupportsMultipleSecureCodecs) {
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ if (!mSupportsSecureWithNonSecureCodec) {
+ mediaResource.type = MediaResource::Type::kNonSecureCodec;
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ }
+ if (nonSecureCodec != NULL) {
+ if (!mSupportsSecureWithNonSecureCodec) {
+ MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
+ .subType = nonSecureCodec->subType};
+ ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
+ if (!getAllClients_l(resourceRequestInfo, targetClients)) {
+ return false;
+ }
+ }
+ }
+
+ if (drmSession != NULL) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ if (targetClients.size() == 0) {
+ return false;
+ }
+ }
+
+ if (targetClients.size() == 0 && graphicMemory != nullptr) {
+ // if no secure/non-secure codec conflict, run second pass to handle other resources.
+ ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+
+ if (targetClients.size() == 0) {
+ // if we are here, run the third pass to free one codec with the same type.
+ if (secureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ if (nonSecureCodec != nullptr) {
+ ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ }
+
+ if (targetClients.size() == 0) {
+ // if we are here, run the fourth pass to free one codec with the different type.
+ if (secureCodec != nullptr) {
+ MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ if (nonSecureCodec != nullptr) {
+ MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
+ ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
+ getClientForResource_l(resourceRequestInfo, targetClients);
+ }
+ }
+
+ return !targetClients.empty();
+}
+
Status ResourceManagerService::reclaimResource(const ClientInfoParcel& clientInfo,
const std::vector<MediaResourceParcel>& resources, bool* _aidl_return) {
- int32_t callingPid = clientInfo.pid;
std::string clientName = clientInfo.name;
String8 log = String8::format("reclaimResource(callingPid %d, uid %d resources %s)",
- callingPid, clientInfo.uid, getString(resources).c_str());
+ clientInfo.pid, clientInfo.uid, getString(resources).c_str());
mServiceLog->add(log);
*_aidl_return = false;
+ // Check if there are any resources to be reclaimed before processing.
+ if (resources.empty()) {
+ return Status::ok();
+ }
+
std::vector<ClientInfo> targetClients;
- {
- std::scoped_lock lock{mLock};
- if (!mProcessInfo->isPidTrusted(callingPid)) {
- pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
- ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
- callingPid, actualCallingPid);
- callingPid = actualCallingPid;
- }
- const MediaResourceParcel *secureCodec = NULL;
- const MediaResourceParcel *nonSecureCodec = NULL;
- const MediaResourceParcel *graphicMemory = NULL;
- const MediaResourceParcel *drmSession = NULL;
- for (size_t i = 0; i < resources.size(); ++i) {
- switch (resources[i].type) {
- case MediaResource::Type::kSecureCodec:
- secureCodec = &resources[i];
- break;
- case MediaResource::Type::kNonSecureCodec:
- nonSecureCodec = &resources[i];
- break;
- case MediaResource::Type::kGraphicMemory:
- graphicMemory = &resources[i];
- break;
- case MediaResource::Type::kDrmSession:
- drmSession = &resources[i];
- break;
- default:
- break;
- }
- }
-
- // first pass to handle secure/non-secure codec conflict
- if (secureCodec != NULL) {
- MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
- .subType = secureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
- if (!mSupportsMultipleSecureCodecs) {
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- if (!mSupportsSecureWithNonSecureCodec) {
- mediaResource.type = MediaResource::Type::kNonSecureCodec;
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- }
- if (nonSecureCodec != NULL) {
- if (!mSupportsSecureWithNonSecureCodec) {
- MediaResourceParcel mediaResource{.type = MediaResource::Type::kSecureCodec,
- .subType = nonSecureCodec->subType};
- ResourceRequestInfo resourceRequestInfo{callingPid, &mediaResource};
- if (!getAllClients_l(resourceRequestInfo, targetClients)) {
- return Status::ok();
- }
- }
- }
-
- if (drmSession != NULL) {
- ResourceRequestInfo resourceRequestInfo{callingPid, drmSession};
- getClientForResource_l(resourceRequestInfo, targetClients);
- if (targetClients.size() == 0) {
- return Status::ok();
- }
- }
-
- if (targetClients.size() == 0 && graphicMemory != nullptr) {
- // if no secure/non-secure codec conflict, run second pass to handle other resources.
- ResourceRequestInfo resourceRequestInfo{callingPid, graphicMemory};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
-
- if (targetClients.size() == 0) {
- // if we are here, run the third pass to free one codec with the same type.
- if (secureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, secureCodec};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- if (nonSecureCodec != nullptr) {
- ResourceRequestInfo resourceRequestInfo{callingPid, nonSecureCodec};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- }
-
- if (targetClients.size() == 0) {
- // if we are here, run the fourth pass to free one codec with the different type.
- if (secureCodec != nullptr) {
- MediaResource temp(MediaResource::Type::kNonSecureCodec, secureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- if (nonSecureCodec != nullptr) {
- MediaResource temp(MediaResource::Type::kSecureCodec, nonSecureCodec->subType, 1);
- ResourceRequestInfo resourceRequestInfo{callingPid, &temp};
- getClientForResource_l(resourceRequestInfo, targetClients);
- }
- }
+ if (!getTargetClients(clientInfo, resources, targetClients)) {
+ // Nothing to reclaim from.
+ ALOGI("%s: There aren't any clients to reclaim from", __func__);
+ return Status::ok();
}
*_aidl_return = reclaimUnconditionallyFrom(targetClients);
@@ -607,7 +620,7 @@
mResourceManagerMetrics->pushReclaimAtom(clientInfo, priorities, targetClients, reclaimed);
}
-std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient(
+std::shared_ptr<IResourceManagerClient> ResourceManagerService::getClient_l(
int pid, const int64_t& clientId) const {
std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
if (found == mMap.end()) {
@@ -625,7 +638,7 @@
return foundClient->second.client;
}
-bool ResourceManagerService::removeClient(int pid, const int64_t& clientId) {
+bool ResourceManagerService::removeClient_l(int pid, const int64_t& clientId) {
std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
if (found == mMap.end()) {
ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
@@ -652,8 +665,11 @@
int64_t failedClientId = -1;
int32_t failedClientPid = -1;
for (const ClientInfo& targetClient : targetClients) {
- std::shared_ptr<IResourceManagerClient> client = getClient(
- targetClient.mPid, targetClient.mClientId);
+ std::shared_ptr<IResourceManagerClient> client = nullptr;
+ {
+ std::scoped_lock lock{mLock};
+ client = getClient_l(targetClient.mPid, targetClient.mClientId);
+ }
if (client == nullptr) {
// skip already released clients.
continue;
@@ -675,7 +691,7 @@
{
std::scoped_lock lock{mLock};
- bool found = removeClient(failedClientPid, failedClientId);
+ bool found = removeClient_l(failedClientPid, failedClientId);
if (found) {
ALOGW("Failed to reclaim resources from client with pid %d", failedClientPid);
} else {
@@ -686,6 +702,16 @@
return false;
}
+bool ResourceManagerService::overridePid_l(int32_t originalPid, int32_t newPid) {
+ mOverridePidMap.erase(originalPid);
+ if (newPid != -1) {
+ mOverridePidMap.emplace(originalPid, newPid);
+ return true;
+ }
+
+ return false;
+}
+
Status ResourceManagerService::overridePid(int originalPid, int newPid) {
String8 log = String8::format("overridePid(originalPid %d, newPid %d)",
originalPid, newPid);
@@ -705,9 +731,7 @@
{
std::scoped_lock lock{mLock};
- mOverridePidMap.erase(originalPid);
- if (newPid != -1) {
- mOverridePidMap.emplace(originalPid, newPid);
+ if (overridePid_l(originalPid, newPid)) {
mResourceManagerMetrics->addPid(newPid);
}
}
@@ -715,6 +739,29 @@
return Status::ok();
}
+bool ResourceManagerService::overrideProcessInfo_l(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ removeProcessInfoOverride_l(pid);
+
+ if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ // Override value is rejected by ProcessInfo.
+ return false;
+ }
+
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+ .uid = 0,
+ .id = 0,
+ .name = "<unknown client>"};
+ auto deathNotifier = DeathNotifier::Create(
+ client, ref<ResourceManagerService>(), clientInfo, true);
+
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
+ return true;
+}
+
Status ResourceManagerService::overrideProcessInfo(
const std::shared_ptr<IResourceManagerClient>& client, int pid, int procState,
int oomScore) {
@@ -735,23 +782,12 @@
}
std::scoped_lock lock{mLock};
- removeProcessInfoOverride_l(pid);
-
- if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ if (!overrideProcessInfo_l(client, pid, procState, oomScore)) {
// Override value is rejected by ProcessInfo.
return Status::fromServiceSpecificError(BAD_VALUE);
}
-
- ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
- .uid = 0,
- .id = 0,
- .name = "<unknown client>"};
- auto deathNotifier = DeathNotifier::Create(
- client, ref<ResourceManagerService>(), clientInfo, true);
-
- mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
-
return Status::ok();
+
}
void ResourceManagerService::removeProcessInfoOverride(int pid) {
@@ -857,11 +893,12 @@
return Status::ok();
}
-bool ResourceManagerService::getPriority_l(int pid, int* priority) {
+bool ResourceManagerService::getPriority_l(int pid, int* priority) const {
int newPid = pid;
- if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
- newPid = mOverridePidMap[pid];
+ std::map<int, int>::const_iterator found = mOverridePidMap.find(pid);
+ if (found != mOverridePidMap.end()) {
+ newPid = found->second;
ALOGD("getPriority_l: use override pid %d instead original pid %d",
newPid, pid);
}
@@ -1000,8 +1037,7 @@
if (pendingRemovalOnly && !info.pendingRemoval) {
continue;
}
- for (auto it = resources.begin(); it != resources.end(); it++) {
- const MediaResourceParcel &resource = it->second;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
if (hasResourceType(type, subType, resource)) {
if (resource.value > largestValue) {
largestValue = resource.value;
@@ -1053,4 +1089,8 @@
return mResourceManagerMetrics->getCurrentConcurrentPixelCount(pid);
}
+void ResourceManagerService::notifyClientReleased(const ClientInfoParcel& clientInfo) {
+ mResourceManagerMetrics->notifyClientReleased(clientInfo);
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.h b/services/mediaresourcemanager/ResourceManagerService.h
index e22a6b3..dc1600a 100644
--- a/services/mediaresourcemanager/ResourceManagerService.h
+++ b/services/mediaresourcemanager/ResourceManagerService.h
@@ -73,7 +73,8 @@
const sp<SystemCallbackInterface> &systemResource);
virtual ~ResourceManagerService();
- void setObserverService(const std::shared_ptr<ResourceObserverService>& observerService);
+ virtual void setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService);
// IResourceManagerService interface
Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
@@ -103,8 +104,6 @@
Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override;
- Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
-
Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
@@ -113,88 +112,146 @@
Status notifyClientConfigChanged(const ClientConfigParcel& clientConfig) override;
+protected:
+ // To get notifications when a resource is added for the first time.
+ void onFirstAdded(const MediaResourceParcel& res, uid_t uid);
+ // To get notifications when a resource has been removed at last.
+ void onLastRemoved(const MediaResourceParcel& res, uid_t uid);
+
+ // Reclaims resources from |clients|. Returns true if reclaim succeeded
+ // for all clients.
+ bool reclaimUnconditionallyFrom(const std::vector<ClientInfo>& targetClients);
+
+ // A helper function that returns true if the callingPid has higher priority than pid.
+ // Returns false otherwise.
+ bool isCallingPriorityHigher_l(int callingPid, int pid);
+
+ // To notify the metrics about client being released.
+ void notifyClientReleased(const ClientInfoParcel& clientInfo);
+
+ virtual Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid);
+
private:
friend class ResourceManagerServiceTest;
friend class ResourceManagerServiceTestBase;
friend class DeathNotifier;
friend class OverrideProcessInfoDeathNotifier;
- // Reclaims resources from |clients|. Returns true if reclaim succeeded
- // for all clients.
- bool reclaimUnconditionallyFrom(
- const std::vector<ClientInfo>& targetClients);
-
- // Gets the list of all the clients who own the specified resource type.
- // Returns false if any client belongs to a process with higher priority than the
- // calling process. The clients will remain unchanged if returns false.
- bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
- std::vector<ClientInfo>& clientsInfo);
-
- // Gets the client who owns specified resource type from lowest possible priority process.
- // Returns false if the calling process priority is not higher than the lowest process
- // priority. The client will remain unchanged if returns false.
- bool getLowestPriorityBiggestClient_l(
- const ResourceRequestInfo& resourceRequestInfo,
- ClientInfo& clientInfo);
-
// Gets the client who owns biggest piece of specified resource type from pid.
// Returns false with no change to client if there are no clients holding resources of this
// type.
- bool getBiggestClient_l(int pid, MediaResource::Type type, MediaResource::SubType subType,
+ bool getBiggestClient_l(int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
ClientInfo& clientsInfo,
bool pendingRemovalOnly = false);
- // Same method as above, but with pendingRemovalOnly as true.
+
+ // A helper function that gets the biggest clients of the process pid that
+ // is marked to be (pending) removed and has the needed resources.
bool getBiggestClientPendingRemoval_l(int pid, MediaResource::Type type,
MediaResource::SubType subType,
ClientInfo& clientsInfo);
- // A helper function that returns true if the callingPid has higher priority than pid.
- // Returns false otherwise.
- bool isCallingPriorityHigher_l(int callingPid, int pid);
-
- // A helper function basically calls getLowestPriorityBiggestClient_l and adds
- // the result client to the given Vector.
+ // From the list of clients, pick/select client(s) based on the reclaim policy.
void getClientForResource_l(const ResourceRequestInfo& resourceRequestInfo,
std::vector<ClientInfo>& clientsInfo);
-
- void onFirstAdded(const MediaResourceParcel& res, uid_t uid);
- void onLastRemoved(const MediaResourceParcel& res, uid_t uid);
-
- // Get priority from process's pid
- bool getPriority_l(int pid, int* priority);
-
- void removeProcessInfoOverride(int pid);
-
- void removeProcessInfoOverride_l(int pid);
-
+ // A helper function that pushes Reclaim Atom (for metric collection).
void pushReclaimAtom(const ClientInfoParcel& clientInfo,
const std::vector<ClientInfo>& targetClients,
bool reclaimed);
- // Get the client for given pid and the clientId from the map
- std::shared_ptr<IResourceManagerClient> getClient(int pid, const int64_t& clientId) const;
+ // Remove the override info for the given process
+ void removeProcessInfoOverride_l(int pid);
- // Remove the client for given pid and the clientId from the map
- bool removeClient(int pid, const int64_t& clientId);
+ // Eventually we want to phase out this implementation of IResourceManagerService
+ // (ResourceManagerService) and replace that with the newer implementation
+ // (ResourceManagerServiceNew).
+ // So, marking the following methods as private virtual and for the newer implementation
+ // to override is the easiest way to maintain both implementation.
- // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // Initializes the internal state of the ResourceManagerService
+ virtual void init();
+
+ // Gets the list of all the clients who own the list of specified resource type
+ // and satisfy the resource model and the reclaim policy.
+ virtual bool getTargetClients(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients);
+
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ virtual bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo);
+
+ // Gets the client who owns specified resource type from lowest possible priority process.
+ // Returns false if the calling process priority is not higher than the lowest process
+ // priority. The client will remain unchanged if returns false.
+ virtual bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo);
+
+ // override the pid of given process
+ virtual bool overridePid_l(int32_t originalPid, int32_t newPid);
+
+ // override the process info of given process
+ virtual bool overrideProcessInfo_l(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore);
+
+ // Get priority from process's pid
+ virtual bool getPriority_l(int pid, int* priority) const;
+
// Gets lowest priority process that has the specified resource type.
// Returns false if failed. The output parameters will remain unchanged if failed.
- bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
- int* lowestPriorityPid, int* lowestPriority);
+ virtual bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority);
+
+ // Removes the pid from the override map.
+ virtual void removeProcessInfoOverride(int pid);
+
+ // Get the client for given pid and the clientId from the map
+ virtual std::shared_ptr<IResourceManagerClient> getClient_l(
+ int pid, const int64_t& clientId) const;
+
+ // Remove the client for given pid and the clientId from the map
+ virtual bool removeClient_l(int pid, const int64_t& clientId);
+
+ // Get all the resource status for dump
+ virtual void getResourceDump(std::string& resourceLog) const;
+
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // START: TEST only functions
// Get the peak concurrent pixel count (associated with the video codecs) for the process.
long getPeakConcurrentPixelCount(int pid) const;
// Get the current concurrent pixel count (associated with the video codecs) for the process.
long getCurrentConcurrentPixelCount(int pid) const;
+ // To create object of type ResourceManagerServiceNew
+ static std::shared_ptr<ResourceManagerService> CreateNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource);
+ // Returns a unmodifiable reference to the internal resource state as a map
+ virtual const std::map<int, ResourceInfos>& getResourceMap() const {
+ return mMap;
+ }
+ // enable/disable process priority based reclaim and client importance based reclaim
+ virtual void setReclaimPolicy(bool processPriority, bool clientImportance) {
+ // Implemented by the refactored/new RMService
+ (void)processPriority;
+ (void)clientImportance;
+ }
+ // END: TEST only functions
+protected:
mutable std::mutex mLock;
sp<ProcessInfoInterface> mProcessInfo;
sp<SystemCallbackInterface> mSystemCB;
sp<ServiceLog> mServiceLog;
- PidResourceInfosMap mMap;
bool mSupportsMultipleSecureCodecs;
bool mSupportsSecureWithNonSecureCodec;
int32_t mCpuBoostCount;
+
+private:
+ PidResourceInfosMap mMap;
struct ProcessInfoOverride {
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
std::shared_ptr<IResourceManagerClient> client;
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.cpp b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
new file mode 100644
index 0000000..af093ca
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.cpp
@@ -0,0 +1,385 @@
+/*
+**
+** Copyright 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_NDEBUG 0
+#define LOG_TAG "ResourceManagerServiceNew"
+#include <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <mediautils/ProcessInfo.h>
+
+#include "DefaultResourceModel.h"
+#include "ClientImportanceReclaimPolicy.h"
+#include "ProcessPriorityReclaimPolicy.h"
+#include "ResourceManagerServiceNew.h"
+#include "ResourceTracker.h"
+#include "ServiceLog.h"
+
+namespace android {
+
+ResourceManagerServiceNew::ResourceManagerServiceNew(
+ const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource) :
+ ResourceManagerService(processInfo, systemResource) {}
+
+ResourceManagerServiceNew::~ResourceManagerServiceNew() {}
+
+void ResourceManagerServiceNew::init() {
+ // Create the Resource Tracker
+ mResourceTracker = std::make_shared<ResourceTracker>(ref<ResourceManagerServiceNew>(),
+ mProcessInfo);
+ setUpResourceModels();
+ setUpReclaimPolicies();
+}
+
+void ResourceManagerServiceNew::setUpResourceModels() {
+ std::scoped_lock lock{mLock};
+ // Create/Configure the default resource model.
+ if (mDefaultResourceModel == nullptr) {
+ mDefaultResourceModel = std::make_unique<DefaultResourceModel>(
+ mResourceTracker,
+ mSupportsMultipleSecureCodecs,
+ mSupportsSecureWithNonSecureCodec);
+ } else {
+ DefaultResourceModel* resourceModel =
+ static_cast<DefaultResourceModel*>(mDefaultResourceModel.get());
+ resourceModel->config(mSupportsMultipleSecureCodecs, mSupportsSecureWithNonSecureCodec);
+ }
+}
+
+void ResourceManagerServiceNew::setUpReclaimPolicies() {
+ mReclaimPolicies.clear();
+ // Add Reclaim policies based on:
+ // - the Process priority (oom score)
+ // - the client/codec importance.
+ setReclaimPolicy(true /* processPriority */, true /* clientImportance */);
+}
+
+Status ResourceManagerServiceNew::config(const std::vector<MediaResourcePolicyParcel>& policies) {
+ Status status = ResourceManagerService::config(policies);
+ // Change in the config dictates update to the resource model.
+ setUpResourceModels();
+ return status;
+}
+
+void ResourceManagerServiceNew::setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) {
+ ResourceManagerService::setObserverService(observerService);
+ mResourceTracker->setResourceObserverService(observerService);
+}
+
+Status ResourceManagerServiceNew::addResource(
+ const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("addResource(pid %d, uid %d clientId %lld, resources %s)",
+ pid, uid, (long long) clientId, getString(resources).c_str());
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->addResource(clientInfo, client, resources);
+ notifyResourceGranted(pid, resources);
+
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeResource(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("removeResource(pid %d, uid %d clientId %lld, resources %s)",
+ pid, uid, (long long) clientId, getString(resources).c_str());
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->removeResource(clientInfo, resources);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeClient(const ClientInfoParcel& clientInfo) {
+ removeResource(clientInfo, true /*checkValid*/);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::removeResource(const ClientInfoParcel& clientInfo,
+ bool checkValid) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format("removeResource(pid %d, uid %d clientId %lld)",
+ pid, uid, (long long) clientId);
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ if (mResourceTracker->removeResource(clientInfo, checkValid)) {
+ notifyClientReleased(clientInfo);
+ }
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::reclaimResource(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) {
+ return ResourceManagerService::reclaimResource(clientInfo, resources, _aidl_return);
+}
+
+bool ResourceManagerServiceNew::overridePid_l(int32_t originalPid, int32_t newPid) {
+ return mResourceTracker->overridePid(originalPid, newPid);
+}
+
+Status ResourceManagerServiceNew::overridePid(int originalPid, int newPid) {
+ return ResourceManagerService::overridePid(originalPid, newPid);
+}
+
+bool ResourceManagerServiceNew::overrideProcessInfo_l(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ return mResourceTracker->overrideProcessInfo(client, pid, procState, oomScore);
+}
+
+Status ResourceManagerServiceNew::overrideProcessInfo(
+ const std::shared_ptr<IResourceManagerClient>& client,
+ int pid,
+ int procState,
+ int oomScore) {
+ return ResourceManagerService::overrideProcessInfo(client, pid, procState, oomScore);
+}
+
+void ResourceManagerServiceNew::removeProcessInfoOverride(int pid) {
+ std::scoped_lock lock{mLock};
+
+ mResourceTracker->removeProcessInfoOverride(pid);
+}
+
+Status ResourceManagerServiceNew::markClientForPendingRemoval(const ClientInfoParcel& clientInfo) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+ String8 log = String8::format(
+ "markClientForPendingRemoval(pid %d, clientId %lld)",
+ pid, (long long) clientId);
+ mServiceLog->add(log);
+
+ std::scoped_lock lock{mLock};
+ mResourceTracker->markClientForPendingRemoval(clientInfo);
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::reclaimResourcesFromClientsPendingRemoval(int32_t pid) {
+ String8 log = String8::format("reclaimResourcesFromClientsPendingRemoval(pid %d)", pid);
+ mServiceLog->add(log);
+
+ std::vector<ClientInfo> targetClients;
+ {
+ std::scoped_lock lock{mLock};
+ mResourceTracker->getClientsMarkedPendingRemoval(pid, targetClients);
+ }
+
+ if (!targetClients.empty()) {
+ reclaimUnconditionallyFrom(targetClients);
+ }
+ return Status::ok();
+}
+
+Status ResourceManagerServiceNew::notifyClientCreated(const ClientInfoParcel& clientInfo) {
+ return ResourceManagerService::notifyClientCreated(clientInfo);
+}
+
+Status ResourceManagerServiceNew::notifyClientStarted(const ClientConfigParcel& clientConfig) {
+ return ResourceManagerService::notifyClientStarted(clientConfig);
+}
+
+Status ResourceManagerServiceNew::notifyClientStopped(const ClientConfigParcel& clientConfig) {
+ return ResourceManagerService::notifyClientStopped(clientConfig);
+}
+
+Status ResourceManagerServiceNew::notifyClientConfigChanged(
+ const ClientConfigParcel& clientConfig) {
+ {
+ // Update the ResourceTracker about the change in the configuration.
+ std::scoped_lock lock{mLock};
+ mResourceTracker->updateResource(clientConfig.clientInfo);
+ }
+ return ResourceManagerService::notifyClientConfigChanged(clientConfig);
+}
+
+void ResourceManagerServiceNew::getResourceDump(std::string& resourceLog) const {
+ std::scoped_lock lock{mLock};
+ mResourceTracker->dump(resourceLog);
+}
+
+binder_status_t ResourceManagerServiceNew::dump(int fd, const char** args, uint32_t numArgs) {
+ return ResourceManagerService::dump(fd, args, numArgs);
+}
+
+bool ResourceManagerServiceNew::getTargetClients(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) {
+ int32_t callingPid = clientInfo.pid;
+ std::scoped_lock lock{mLock};
+ if (!mProcessInfo->isPidTrusted(callingPid)) {
+ pid_t actualCallingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using actual calling pid %d", __FUNCTION__,
+ callingPid, actualCallingPid);
+ callingPid = actualCallingPid;
+ }
+
+ // Use the Resource Model to get a list of all the clients that hold the
+ // needed/requested resources.
+ uint32_t callingImportance = std::max(0, clientInfo.importance);
+ ReclaimRequestInfo reclaimRequestInfo{callingPid, callingImportance, resources};
+ std::vector<ClientInfo> clients;
+ if (!mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients)) {
+ if (clients.empty()) {
+ ALOGI("%s: There aren't any clients with given resources. Nothing to reclaim",
+ __func__);
+ return false;
+ }
+ // Since there was a conflict, we need to reclaim all clients.
+ targetClients = std::move(clients);
+ } else {
+ // Select a client among those have the needed resources.
+ getClientForResource_l(reclaimRequestInfo, clients, targetClients);
+ }
+ return !targetClients.empty();
+}
+
+void ResourceManagerServiceNew::getClientForResource_l(
+ const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients) {
+ int callingPid = reclaimRequestInfo.mCallingPid;
+
+ // Before looking into other processes, check if we have clients marked for
+ // pending removal in the same process.
+ ClientInfo targetClient;
+ for (const MediaResourceParcel& resource : reclaimRequestInfo.mResources) {
+ if (mResourceTracker->getBiggestClientPendingRemoval(callingPid, resource.type,
+ resource.subType, targetClient)) {
+ targetClients.emplace_back(targetClient);
+ return;
+ }
+ }
+
+ // Run through all the reclaim policies until a client to reclaim from is identified.
+ for (std::unique_ptr<IReclaimPolicy>& reclaimPolicy : mReclaimPolicies) {
+ if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
+ return;
+ }
+ }
+}
+
+bool ResourceManagerServiceNew::getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ if (resourceRequestInfo.mResource == nullptr) {
+ return false;
+ }
+
+ // Use the DefaultResourceModel to get all the clients with the resources requested.
+ std::vector<MediaResourceParcel> resources{*resourceRequestInfo.mResource};
+ ReclaimRequestInfo reclaimRequestInfo{resourceRequestInfo.mCallingPid, 0, resources};
+ std::vector<ClientInfo> clients;
+ mDefaultResourceModel->getAllClients(reclaimRequestInfo, clients);
+
+ // Use the ProcessPriorityReclaimPolicy to select a client to reclaim from.
+ std::unique_ptr<IReclaimPolicy> reclaimPolicy
+ = std::make_unique<ProcessPriorityReclaimPolicy>(mResourceTracker);
+ std::vector<ClientInfo> targetClients;
+ if (reclaimPolicy->getClients(reclaimRequestInfo, clients, targetClients)) {
+ if (!targetClients.empty()) {
+ clientInfo = targetClients[0];
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool ResourceManagerServiceNew::getPriority_l(int pid, int* priority) const {
+ return mResourceTracker->getPriority(pid, priority);
+}
+
+bool ResourceManagerServiceNew::getLowestPriorityPid_l(
+ MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ return mResourceTracker->getLowestPriorityPid(type, subType,
+ *lowestPriorityPid,
+ *lowestPriority);
+}
+
+bool ResourceManagerServiceNew::getAllClients_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) {
+ //NOTE: This function is used only by the test: ResourceManagerServiceTest
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ // Get the list of all clients that has requested resources.
+ std::vector<ClientInfo> clients;
+ mResourceTracker->getAllClients(resourceRequestInfo, clients);
+
+ // Check is there any high priority process holding up the resources already.
+ for (const ClientInfo& info : clients) {
+ if (!isCallingPriorityHigher_l(resourceRequestInfo.mCallingPid, info.mPid)) {
+ // some higher/equal priority process owns the resource,
+ // this request can't be fulfilled.
+ ALOGE("%s: can't reclaim resource %s from pid %d", __func__, asString(type), info.mPid);
+ return false;
+ }
+ clientsInfo.emplace_back(info);
+ }
+ if (clientsInfo.size() == 0) {
+ ALOGV("%s: didn't find any resource %s", __func__, asString(type));
+ }
+ return true;
+}
+
+std::shared_ptr<IResourceManagerClient> ResourceManagerServiceNew::getClient_l(
+ int pid, const int64_t& clientId) const {
+ return mResourceTracker->getClient(pid, clientId);
+}
+
+bool ResourceManagerServiceNew::removeClient_l(int pid, const int64_t& clientId) {
+ return mResourceTracker->removeClient(pid, clientId);
+}
+
+const std::map<int, ResourceInfos>& ResourceManagerServiceNew::getResourceMap() const {
+ return mResourceTracker->getResourceMap();
+}
+
+void ResourceManagerServiceNew::setReclaimPolicy(bool processPriority, bool clientImportance) {
+ mReclaimPolicies.clear();
+ if (processPriority) {
+ // Process priority (oom score) as the Default reclaim policy.
+ mReclaimPolicies.push_back(std::make_unique<ProcessPriorityReclaimPolicy>(
+ mResourceTracker));
+ }
+ if (clientImportance) {
+ mReclaimPolicies.push_back(std::make_unique<ClientImportanceReclaimPolicy>(
+ mResourceTracker));
+ }
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceNew.h b/services/mediaresourcemanager/ResourceManagerServiceNew.h
new file mode 100644
index 0000000..0599936
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceManagerServiceNew.h
@@ -0,0 +1,174 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_RESOURCEMANAGERSERVICENEW_H
+#define ANDROID_MEDIA_RESOURCEMANAGERSERVICENEW_H
+
+#include "ResourceManagerService.h"
+
+namespace android {
+
+class IReclaimPolicy;
+class IResourceModel;
+class ResourceTracker;
+
+//
+// A newer implementation of IResourceManagerService, which
+// eventually will replace the older implementation in ResourceManagerService.
+//
+// To make the transition easier, this implementation overrides the
+// private virtual methods from ResourceManagerService.
+//
+// This implementation is devised to abstract and integrate:
+// - resources into an independent abstraction
+// - resource model as a separate interface (and implementation)
+// - reclaim policy as a separate interface (and implementation)
+//
+class ResourceManagerServiceNew : public ResourceManagerService {
+public:
+
+ explicit ResourceManagerServiceNew(const sp<ProcessInfoInterface>& processInfo,
+ const sp<SystemCallbackInterface>& systemResource);
+ virtual ~ResourceManagerServiceNew();
+
+ // IResourceManagerService interface
+ Status config(const std::vector<MediaResourcePolicyParcel>& policies) override;
+
+ Status addResource(const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) override;
+
+ Status removeResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) override;
+
+ Status removeClient(const ClientInfoParcel& clientInfo) override;
+
+ Status reclaimResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ bool* _aidl_return) override;
+
+ Status overridePid(int32_t originalPid, int32_t newPid) override;
+
+ Status overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client,
+ int32_t pid, int32_t procState, int32_t oomScore) override;
+
+ Status markClientForPendingRemoval(const ClientInfoParcel& clientInfo) override;
+
+ Status reclaimResourcesFromClientsPendingRemoval(int32_t pid) override;
+
+ Status notifyClientCreated(const ClientInfoParcel& clientInfo) override;
+
+ Status notifyClientStarted(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientStopped(const ClientConfigParcel& clientConfig) override;
+
+ Status notifyClientConfigChanged(const ClientConfigParcel& clientConfig) override;
+
+ binder_status_t dump(int fd, const char** args, uint32_t numArgs) override;
+
+ friend class ResourceTracker;
+
+private:
+
+ // Set up the Resource models.
+ void setUpResourceModels();
+
+ // Set up the Reclaim Policies.
+ void setUpReclaimPolicies();
+
+ // From the list of clients, pick/select client(s) based on the reclaim policy.
+ void getClientForResource_l(
+ const ReclaimRequestInfo& reclaimRequestInfo,
+ const std::vector<ClientInfo>& clients,
+ std::vector<ClientInfo>& targetClients);
+
+ // Initializes the internal state of the ResourceManagerService
+ void init() override;
+
+ void setObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) override;
+
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ bool getTargetClients(
+ const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources,
+ std::vector<ClientInfo>& targetClients) override;
+
+ // Removes the pid from the override map.
+ void removeProcessInfoOverride(int pid) override;
+
+ // override the pid of given process
+ bool overridePid_l(int32_t originalPid, int32_t newPid) override;
+
+ // override the process info of given process
+ bool overrideProcessInfo_l(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore) override;
+
+ // Get priority from process's pid
+ bool getPriority_l(int pid, int* priority) const override;
+
+ // Get the client for given pid and the clientId from the map
+ std::shared_ptr<IResourceManagerClient> getClient_l(
+ int pid, const int64_t& clientId) const override;
+
+ // Remove the client for given pid and the clientId from the map
+ bool removeClient_l(int pid, const int64_t& clientId) override;
+
+ // Get all the resource status for dump
+ void getResourceDump(std::string& resourceLog) const override;
+
+ // Returns a unmodifiable reference to the internal resource state as a map
+ const std::map<int, ResourceInfos>& getResourceMap() const override;
+
+ Status removeResource(const ClientInfoParcel& clientInfo, bool checkValid) override;
+
+ // The following utility functions are used only for testing by ResourceManagerServiceTest
+ // START: TEST only functions
+ // Gets the list of all the clients who own the specified resource type.
+ // Returns false if any client belongs to a process with higher priority than the
+ // calling process. The clients will remain unchanged if returns false.
+ bool getAllClients_l(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clientsInfo) override;
+
+ // Gets the client who owns specified resource type from lowest possible priority process.
+ // Returns false if the calling process priority is not higher than the lowest process
+ // priority. The client will remain unchanged if returns false.
+ bool getLowestPriorityBiggestClient_l(
+ const ResourceRequestInfo& resourceRequestInfo,
+ ClientInfo& clientInfo) override;
+
+ // Gets lowest priority process that has the specified resource type.
+ // Returns false if failed. The output parameters will remain unchanged if failed.
+ bool getLowestPriorityPid_l(MediaResource::Type type, MediaResource::SubType subType,
+ int* lowestPriorityPid, int* lowestPriority) override;
+
+ // enable/disable process priority based reclaim and client importance based reclaim
+ void setReclaimPolicy(bool processPriority, bool clientImportance) override;
+ // END: TEST only functions
+
+private:
+ std::shared_ptr<ResourceTracker> mResourceTracker;
+ std::unique_ptr<IResourceModel> mDefaultResourceModel;
+ std::vector<std::unique_ptr<IReclaimPolicy>> mReclaimPolicies;
+};
+
+// ----------------------------------------------------------------------------
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCEMANAGERSERVICENEW_H
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
index de682f8..679ab13 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.cpp
@@ -19,11 +19,101 @@
#define LOG_TAG "ResourceManagerServiceUtils"
#include <utils/Log.h>
+#include <binder/IServiceManager.h>
+
+#include "IMediaResourceMonitor.h"
#include "ResourceManagerService.h"
#include "ResourceManagerServiceUtils.h"
namespace android {
+bool ResourceList::add(const MediaResourceParcel& res, bool* isNewEntry) {
+ // See if it's an existing entry, if so, merge it.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ // We already have an item. Merge them and return
+ mergeResources(item, res);
+ return true;
+ }
+ }
+
+ // Since we have't found this resource yet, it is a new entry.
+ // We can't init a new entry with negative value, although it's allowed
+ // to merge in negative values after the initial add.
+ if (res.value <= 0) {
+ ALOGW("Ignoring request to add new resource entry with value <= 0");
+ return false;
+ }
+ if (isNewEntry) {
+ *isNewEntry = true;
+ }
+ mResourceList.push_back(res);
+ return true;
+}
+
+void ResourceList::addOrUpdate(const MediaResourceParcel& res) {
+ // See if it's an existing entry, just update the value.
+ for (MediaResourceParcel& item : mResourceList) {
+ if (item.type == res.type && item.subType == res.subType && item.id == res.id) {
+ item.value = res.value;
+ return;
+ }
+ }
+
+ // Add the new entry.
+ mResourceList.push_back(res);
+}
+
+bool ResourceList::remove(const MediaResourceParcel& res, long* removedEntryValue) {
+ // Make sure we have an entry for this resource.
+ for (std::vector<MediaResourceParcel>::iterator it = mResourceList.begin();
+ it != mResourceList.end(); it++) {
+ if (it->type == res.type && it->subType == res.subType && it->id == res.id) {
+ if (it->value > res.value) {
+ // Subtract the resource value by given value.
+ it->value -= res.value;
+ } else {
+ // This entry will be removed.
+ if (removedEntryValue) {
+ *removedEntryValue = it->value;
+ }
+ mResourceList.erase(it);
+ }
+ return true;
+ }
+ }
+
+ // No such entry.
+ return false;
+}
+
+std::string ResourceList::toString() const {
+ std::string str;
+ for (const ::aidl::android::media::MediaResourceParcel& res : mResourceList) {
+ str.append(android::toString(res).c_str());
+ str.append("\n");
+ }
+
+ return std::move(str);
+}
+
+bool ResourceList::operator==(const ResourceList& rhs) const {
+ // Make sure the size is the same.
+ if (mResourceList.size() != rhs.mResourceList.size()) {
+ return false;
+ }
+
+ // Create a set from this object and check for the items from the rhs.
+ std::set<::aidl::android::media::MediaResourceParcel> lhs(
+ mResourceList.begin(), mResourceList.end());
+ for (const ::aidl::android::media::MediaResourceParcel& res : rhs.mResourceList) {
+ if (lhs.find(res) == lhs.end()) {
+ return false;
+ }
+ }
+ return true;
+}
+
// Bunch of utility functions that looks for a specific Resource.
// Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -50,8 +140,8 @@
// Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
const ResourceList& resources) {
- for (auto it = resources.begin(); it != resources.end(); it++) {
- if (hasResourceType(type, subType, it->second)) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
return true;
}
}
@@ -88,7 +178,6 @@
const std::shared_ptr<IResourceManagerClient>& client,
ResourceInfos& infos) {
ResourceInfos::iterator found = infos.find(clientInfo.id);
-
if (found == infos.end()) {
ResourceInfo info{.pid = clientInfo.pid,
.uid = static_cast<uid_t>(clientInfo.uid),
@@ -96,7 +185,8 @@
.name = clientInfo.name.empty()? "<unknown client>" : clientInfo.name,
.client = client,
.deathNotifier = nullptr,
- .pendingRemoval = false};
+ .pendingRemoval = false,
+ .importance = static_cast<uint32_t>(std::max(0, clientInfo.importance))};
auto [it, inserted] = infos.emplace(clientInfo.id, info);
found = it;
}
@@ -202,4 +292,30 @@
return deathNotifier;
}
+void notifyResourceGranted(int pid, const std::vector<MediaResourceParcel>& resources) {
+ static const char* const kServiceName = "media_resource_monitor";
+ sp<IBinder> binder = defaultServiceManager()->checkService(String16(kServiceName));
+ if (binder != NULL) {
+ sp<IMediaResourceMonitor> service = interface_cast<IMediaResourceMonitor>(binder);
+ for (size_t i = 0; i < resources.size(); ++i) {
+ switch (resources[i].subType) {
+ case MediaResource::SubType::kHwAudioCodec:
+ case MediaResource::SubType::kSwAudioCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_AUDIO_CODEC);
+ break;
+ case MediaResource::SubType::kHwVideoCodec:
+ case MediaResource::SubType::kSwVideoCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_VIDEO_CODEC);
+ break;
+ case MediaResource::SubType::kHwImageCodec:
+ case MediaResource::SubType::kSwImageCodec:
+ service->notifyResourceGranted(pid, IMediaResourceMonitor::TYPE_IMAGE_CODEC);
+ break;
+ case MediaResource::SubType::kUnspecifiedSubType:
+ break;
+ }
+ }
+ }
+}
+
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerServiceUtils.h b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
index ac1e410..32cb219 100644
--- a/services/mediaresourcemanager/ResourceManagerServiceUtils.h
+++ b/services/mediaresourcemanager/ResourceManagerServiceUtils.h
@@ -18,6 +18,9 @@
#ifndef ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
#define ANDROID_MEDIA_RESOURCEMANAGERSERVICEUTILS_H_
+#include <map>
+#include <set>
+#include <memory>
#include <vector>
#include <aidl/android/media/BnResourceManagerService.h>
@@ -97,10 +100,47 @@
virtual void binderDied();
};
-// A map of tuple(type, sub-type, id) and the resource parcel.
-typedef std::map<std::tuple<
- MediaResource::Type, MediaResource::SubType, std::vector<uint8_t>>,
- ::aidl::android::media::MediaResourceParcel> ResourceList;
+// Encapsulate Resource List as vector of resources instead of map.
+// Since the number of resource is very limited, maintaining it as
+// std::vector helps with both performance and memory requiremnts.
+struct ResourceList {
+ // Add or Update an entry into ResourceList.
+ // If a new entry is added, isNewEntry will be set to true upon return
+ // returns true on successful update, false otherwise.
+ bool add(const ::aidl::android::media::MediaResourceParcel& res, bool* isNewEntry = nullptr);
+
+ // reduce the resource usage by subtracting the resource value.
+ // If the resource value is 0 after reducing the resource usage,
+ // that entry will be removed and removedEntryValue is set to the
+ // value before it was removed upon return otherwise it will be set to -1.
+ // returns true on successful removal of the resource, false otherwise.
+ bool remove(const ::aidl::android::media::MediaResourceParcel& res,
+ long* removedEntryValue = nullptr);
+
+ // Returns true if there aren't any resource entries.
+ bool empty() const {
+ return mResourceList.empty();
+ }
+
+ // Returns resource list as a non-modifiable vectors
+ const std::vector<::aidl::android::media::MediaResourceParcel>& getResources() const {
+ return mResourceList;
+ }
+
+ // Converts resource list into string format
+ std::string toString() const;
+
+ // BEGIN: Test only function
+ // Check if two resource lists are the same.
+ bool operator==(const ResourceList& rhs) const;
+
+ // Add or Update an entry into ResourceList.
+ void addOrUpdate(const ::aidl::android::media::MediaResourceParcel& res);
+ // END: Test only function
+
+private:
+ std::vector<::aidl::android::media::MediaResourceParcel> mResourceList;
+};
// Encapsulation for Resource Info, that contains
// - pid of the app
@@ -120,6 +160,19 @@
std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
ResourceList resources;
bool pendingRemoval{false};
+ uint32_t importance = 0;
+};
+
+/*
+ * Resource Reclaim request info that encapsulates
+ * - the calling/requesting process pid.
+ * - the calling/requesting client's importance.
+ * - the list of resources requesting (to be reclaimed from others)
+ */
+struct ReclaimRequestInfo {
+ int mCallingPid = -1;
+ uint32_t mCallingClientImportance = 0;
+ const std::vector<::aidl::android::media::MediaResourceParcel>& mResources;
};
/*
@@ -170,7 +223,7 @@
//Check whether a given resource (of type and subtype) is found in given resource parcel.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
- const MediaResourceParcel& resource);
+ const ::aidl::android::media::MediaResourceParcel& resource);
//Check whether a given resource (of type and subtype) is found in given resource list.
bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
@@ -193,7 +246,13 @@
ResourceInfos& infos);
// Merge resources from r2 into r1.
-void mergeResources(MediaResourceParcel& r1, const MediaResourceParcel& r2);
+void mergeResources(::aidl::android::media::MediaResourceParcel& r1,
+ const ::aidl::android::media::MediaResourceParcel& r2);
+
+// To notify the media_resource_monitor about the resource being granted.
+void notifyResourceGranted(
+ int pid,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
} // namespace android
diff --git a/services/mediaresourcemanager/ResourceObserverService.cpp b/services/mediaresourcemanager/ResourceObserverService.cpp
index 72e249f..21e61e9 100644
--- a/services/mediaresourcemanager/ResourceObserverService.cpp
+++ b/services/mediaresourcemanager/ResourceObserverService.cpp
@@ -286,9 +286,9 @@
{
std::scoped_lock lock{mObserverLock};
- for (auto &res : resources) {
+ for (const MediaResourceParcel& res : resources.getResources()) {
// Skip if this resource doesn't map to any observable type.
- MediaObservableType observableType = getObservableType(res.second);
+ MediaObservableType observableType = getObservableType(res);
if (observableType == MediaObservableType::kInvalid) {
continue;
}
@@ -303,9 +303,9 @@
auto calleeIt = calleeList.find(subscriber.first);
if (calleeIt == calleeList.end()) {
calleeList.emplace(subscriber.first, CalleeInfo{
- subscriber.second, {{observableType, res.second.value}}});
+ subscriber.second, {{observableType, res.value}}});
} else {
- calleeIt->second.monitors.push_back({observableType, res.second.value});
+ calleeIt->second.monitors.push_back({observableType, res.value});
}
}
}
diff --git a/services/mediaresourcemanager/ResourceTracker.cpp b/services/mediaresourcemanager/ResourceTracker.cpp
new file mode 100644
index 0000000..22381c3
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.cpp
@@ -0,0 +1,769 @@
+/*
+**
+** Copyright 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_NDEBUG 0
+#define LOG_TAG "ResourceTracker"
+#include <utils/Log.h>
+
+#include <binder/IPCThreadState.h>
+#include <mediautils/ProcessInfo.h>
+#include "ResourceTracker.h"
+#include "ResourceManagerServiceNew.h"
+#include "ResourceObserverService.h"
+
+namespace android {
+
+inline bool isHwCodec(MediaResource::SubType subType) {
+ return subType == MediaResource::SubType::kHwImageCodec ||
+ subType == MediaResource::SubType::kHwVideoCodec;
+}
+
+// Check whether a given resource (of type and subtype) is found in given resource list
+// that also has the given Primary SubType.
+static bool hasResourceType(MediaResource::Type type, MediaResource::SubType subType,
+ const ResourceList& resources, MediaResource::SubType primarySubType) {
+ bool foundResource = false;
+ bool matchedPrimary =
+ (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
+ for (const MediaResourceParcel& res : resources.getResources()) {
+ if (hasResourceType(type, subType, res)) {
+ foundResource = true;
+ } else if (res.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(res.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ }
+ if (matchedPrimary && foundResource) {
+ return true;
+ }
+ }
+ return false;
+}
+
+// See if the given client is already in the list of clients.
+inline bool contains(const std::vector<ClientInfo>& clients, const int64_t& clientId) {
+ std::vector<ClientInfo>::const_iterator found =
+ std::find_if(clients.begin(), clients.end(),
+ [clientId](const ClientInfo& client) -> bool {
+ return client.mClientId == clientId;
+ });
+
+ return found != clients.end();
+}
+
+
+ResourceTracker::ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
+ const sp<ProcessInfoInterface>& processInfo) :
+ mService(service),
+ mProcessInfo(processInfo) {
+}
+
+ResourceTracker::~ResourceTracker() {
+}
+
+void ResourceTracker::setResourceObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService) {
+ mObserverService = observerService;
+}
+
+ResourceInfos& ResourceTracker::getResourceInfosForEdit(int pid) {
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ // new pid
+ ResourceInfos infosForPid;
+ auto [it, inserted] = mMap.emplace(pid, infosForPid);
+ found = it;
+ }
+
+ return found->second;
+}
+
+bool ResourceTracker::addResource(const ClientInfoParcel& clientInfo,
+ const std::shared_ptr<IResourceManagerClient>& client,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int32_t uid = clientInfo.uid;
+
+ if (!mProcessInfo->isPidUidTrusted(pid, uid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ ALOGW("%s called with untrusted pid %d or uid %d, using calling pid %d, uid %d",
+ __func__, pid, uid, callingPid, callingUid);
+ pid = callingPid;
+ uid = callingUid;
+ }
+ ResourceInfos& infos = getResourceInfosForEdit(pid);
+ ResourceInfo& info = getResourceInfoForEdit(clientInfo, client, infos);
+ ResourceList resourceAdded;
+
+ for (const MediaResourceParcel& res : resources) {
+ if (res.value < 0 && res.type != MediaResource::Type::kDrmSession) {
+ ALOGV("%s: Ignoring request to remove negative value of non-drm resource", __func__);
+ continue;
+ }
+ bool isNewEntry = false;
+ if (!info.resources.add(res, &isNewEntry)) {
+ continue;
+ }
+ if (isNewEntry) {
+ onFirstAdded(res, info.uid);
+ }
+
+ // Add it to the list of added resources for observers.
+ resourceAdded.add(res);
+ }
+ if (info.deathNotifier == nullptr && client != nullptr) {
+ info.deathNotifier = DeathNotifier::Create(client, mService, clientInfo);
+ }
+ if (mObserverService != nullptr && !resourceAdded.empty()) {
+ mObserverService->onResourceAdded(uid, pid, resourceAdded);
+ }
+
+ return !resourceAdded.empty();
+}
+
+bool ResourceTracker::updateResource(const aidl::android::media::ClientInfoParcel& clientInfo) {
+ ResourceInfos& infos = getResourceInfosForEdit(clientInfo.pid);
+
+ ResourceInfos::iterator found = infos.find(clientInfo.id);
+ if (found == infos.end()) {
+ return false;
+ }
+ // Update the client importance.
+ found->second.importance = std::max(0, clientInfo.importance);
+ return true;
+}
+
+bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo,
+ const std::vector<MediaResourceParcel>& resources) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfo& info = foundClient->second;
+ ResourceList resourceRemoved;
+ for (const MediaResourceParcel& res : resources) {
+ if (res.value < 0) {
+ ALOGV("%s: Ignoring request to remove negative value of resource", __func__);
+ continue;
+ }
+
+ long removedEntryValue = -1;
+ if (info.resources.remove(res, &removedEntryValue)) {
+ MediaResourceParcel actualRemoved = res;
+ if (removedEntryValue != -1) {
+ onLastRemoved(res, info.uid);
+ actualRemoved.value = removedEntryValue;
+ }
+
+ // Add it to the list of removed resources for observers.
+ resourceRemoved.add(actualRemoved);
+ }
+ }
+ if (mObserverService != nullptr && !resourceRemoved.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, resourceRemoved);
+ }
+ return true;
+}
+
+bool ResourceTracker::removeResource(const ClientInfoParcel& clientInfo, bool validateCallingPid) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (validateCallingPid && !mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ const ResourceInfo& info = foundClient->second;
+ for (const MediaResourceParcel& res : info.resources.getResources()) {
+ onLastRemoved(res, info.uid);
+ }
+
+ if (mObserverService != nullptr && !info.resources.empty()) {
+ mObserverService->onResourceRemoved(info.uid, pid, info.resources);
+ }
+
+ infos.erase(foundClient);
+ return true;
+}
+
+std::shared_ptr<IResourceManagerClient> ResourceTracker::getClient(
+ int pid, const int64_t& clientId) const {
+ std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return nullptr;
+ }
+
+ const ResourceInfos& infos = found->second;
+ ResourceInfos::const_iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return nullptr;
+ }
+
+ return foundClient->second.client;
+}
+
+bool ResourceTracker::removeClient(int pid, const int64_t& clientId) {
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ infos.erase(foundClient);
+ return true;
+}
+
+bool ResourceTracker::markClientForPendingRemoval(const ClientInfoParcel& clientInfo) {
+ int32_t pid = clientInfo.pid;
+ int64_t clientId = clientInfo.id;
+
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__,
+ pid, callingPid);
+ pid = callingPid;
+ }
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long)clientId);
+ return false;
+ }
+
+ ResourceInfos& infos = found->second;
+ ResourceInfos::iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return false;
+ }
+
+ ResourceInfo& info = foundClient->second;
+ info.pendingRemoval = true;
+ return true;
+}
+
+bool ResourceTracker::getClientsMarkedPendingRemoval(int32_t pid,
+ std::vector<ClientInfo>& targetClients) {
+ if (!mProcessInfo->isPidTrusted(pid)) {
+ pid_t callingPid = IPCThreadState::self()->getCallingPid();
+ ALOGW("%s called with untrusted pid %d, using calling pid %d", __func__, pid, callingPid);
+ pid = callingPid;
+ }
+
+ // Go through all the MediaResource types (and corresponding subtypes for
+ // each, if applicable) and see if the process (with given pid) holds any
+ // such resources that are marked as pending removal.
+ // Since the use-case of this function is to get all such resources (pending
+ // removal) and reclaim them all - the order in which we look for the
+ // resource type doesn't matter.
+ for (MediaResource::Type type : {MediaResource::Type::kSecureCodec,
+ MediaResource::Type::kNonSecureCodec,
+ MediaResource::Type::kGraphicMemory,
+ MediaResource::Type::kDrmSession}) {
+ switch (type) {
+ // Codec resources are segregated by audio, video and image domains.
+ case MediaResource::Type::kSecureCodec:
+ case MediaResource::Type::kNonSecureCodec:
+ for (MediaResource::SubType subType : {MediaResource::SubType::kHwAudioCodec,
+ MediaResource::SubType::kSwAudioCodec,
+ MediaResource::SubType::kHwVideoCodec,
+ MediaResource::SubType::kSwVideoCodec,
+ MediaResource::SubType::kHwImageCodec,
+ MediaResource::SubType::kSwImageCodec}) {
+ ClientInfo clientInfo;
+ if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+ if (!contains(targetClients, clientInfo.mClientId)) {
+ targetClients.emplace_back(clientInfo);
+ }
+ continue;
+ }
+ }
+ break;
+ // Non-codec resources are shared by audio, video and image codecs (no subtype).
+ default:
+ ClientInfo clientInfo;
+ MediaResource::SubType subType = MediaResource::SubType::kUnspecifiedSubType;
+ if (getBiggestClientPendingRemoval(pid, type, subType, clientInfo)) {
+ if (!contains(targetClients, clientInfo.mClientId)) {
+ targetClients.emplace_back(clientInfo);
+ }
+ }
+ break;
+ }
+ }
+
+ return true;
+}
+
+bool ResourceTracker::overridePid(int originalPid, int newPid) {
+ mOverridePidMap.erase(originalPid);
+ if (newPid != -1) {
+ mOverridePidMap.emplace(originalPid, newPid);
+ return true;
+ }
+ return false;
+}
+
+bool ResourceTracker::overrideProcessInfo(const std::shared_ptr<IResourceManagerClient>& client,
+ int pid, int procState, int oomScore) {
+ removeProcessInfoOverride(pid);
+
+ if (!mProcessInfo->overrideProcessInfo(pid, procState, oomScore)) {
+ // Override value is rejected by ProcessInfo.
+ return false;
+ }
+
+ ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(pid),
+ .uid = 0,
+ .id = 0,
+ .name = "<unknown client>"};
+ std::shared_ptr<DeathNotifier> deathNotifier =
+ DeathNotifier::Create(client, mService, clientInfo, true);
+
+ mProcessInfoOverrideMap.emplace(pid, ProcessInfoOverride{deathNotifier, client});
+
+ return true;
+}
+
+void ResourceTracker::removeProcessInfoOverride(int pid) {
+ auto it = mProcessInfoOverrideMap.find(pid);
+ if (it == mProcessInfoOverrideMap.end()) {
+ return;
+ }
+
+ mProcessInfo->removeProcessInfoOverride(pid);
+ mProcessInfoOverrideMap.erase(pid);
+}
+
+bool ResourceTracker::getAllClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients,
+ MediaResource::SubType primarySubType) {
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
+ bool foundClient = false;
+
+ for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ for (auto& [id, /* ResourceInfo */ info] : infos) {
+ if (hasResourceType(type, subType, info.resources, primarySubType)) {
+ if (!contains(clients, info.clientId)) {
+ clients.emplace_back(info.pid, info.uid, info.clientId);
+ foundClient = true;
+ }
+ }
+ }
+ }
+
+ return foundClient;
+}
+
+bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ int& lowestPriorityPid, int& lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (auto& [tempPid, /* ResourceInfos */ infos] : mMap) {
+ if (infos.size() == 0) {
+ // no client on this process.
+ continue;
+ }
+ if (!hasResourceType(type, subType, infos)) {
+ // doesn't have the requested resource type
+ continue;
+ }
+ int tempPriority = -1;
+ if (!getPriority(tempPid, &tempPriority)) {
+ ALOGV("%s: can't get priority of pid %d, skipped", __func__, tempPid);
+ // TODO: remove this pid from mMap?
+ continue;
+ }
+ if (pid == -1 || tempPriority > priority) {
+ // initial the value
+ pid = tempPid;
+ priority = tempPriority;
+ }
+ }
+
+ bool success = (pid != -1);
+
+ if (success) {
+ lowestPriorityPid = pid;
+ lowestPriority = priority;
+ }
+ return success;
+}
+
+bool ResourceTracker::getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ int& lowestPriorityPid, int& lowestPriority) {
+ int pid = -1;
+ int priority = -1;
+ for (const ClientInfo& client : clients) {
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+ if (!hasResourceType(type, subType, info->resources, primarySubType)) {
+ // doesn't have the requested resource type
+ continue;
+ }
+ int tempPriority = -1;
+ if (!getPriority(client.mPid, &tempPriority)) {
+ ALOGV("%s: can't get priority of pid %d, skipped", __func__, client.mPid);
+ // TODO: remove this pid from mMap?
+ continue;
+ }
+ if (pid == -1 || tempPriority > priority) {
+ // initial the value
+ pid = client.mPid;
+ priority = tempPriority;
+ }
+ }
+
+ bool success = (pid != -1);
+
+ if (success) {
+ lowestPriorityPid = pid;
+ lowestPriority = priority;
+ }
+ return success;
+}
+
+bool ResourceTracker::getBiggestClientPendingRemoval(int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
+ ClientInfo& clientInfo) {
+ std::map<int, ResourceInfos>::iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ return false;
+ }
+
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+ const ResourceInfos& infos = found->second;
+ for (const auto& [id, /* ResourceInfo */ info] : infos) {
+ const ResourceList& resources = info.resources;
+ // Skip if the client is not marked pending removal.
+ if (!info.pendingRemoval) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info.clientId;
+ uid = info.uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ return false;
+ }
+
+ clientInfo.mPid = pid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+bool ResourceTracker::getBiggestClient(int targetPid,
+ MediaResource::Type type, MediaResource::SubType subType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo,
+ MediaResource::SubType primarySubType) {
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+
+ for (const ClientInfo& client : clients) {
+ // Skip the clients that doesn't belong go the targetPid
+ if (client.mPid != targetPid) {
+ continue;
+ }
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+
+ const ResourceList& resources = info->resources;
+ bool matchedPrimary =
+ (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
+ matchedPrimary = true;
+ break;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ break;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info->clientId;
+ uid = info->uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+ __func__, asString(type), asString(subType), targetPid);
+ return false;
+ }
+
+ clientInfo.mPid = targetPid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+bool ResourceTracker::getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo) {
+ uid_t uid = -1;
+ int64_t clientId = -1;
+ uint64_t largestValue = 0;
+
+ for (const ClientInfo& client : clients) {
+ // Skip the clients that doesn't belong go the targetPid
+ if (client.mPid != targetPid) {
+ continue;
+ }
+ const ResourceInfo* info = getResourceInfo(client.mPid, client.mClientId);
+ if (info == nullptr) {
+ continue;
+ }
+
+ // Make sure the importance is lower.
+ if (info->importance <= importance) {
+ continue;
+ }
+ const ResourceList& resources = info->resources;
+ bool matchedPrimary =
+ (primarySubType == MediaResource::SubType::kUnspecifiedSubType) ? true : false;
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (resource.subType == primarySubType) {
+ matchedPrimary = true;
+ } else if (isHwCodec(resource.subType) == isHwCodec(primarySubType)) {
+ matchedPrimary = true;
+ }
+ }
+ // Primary type doesn't match, skip the client
+ if (!matchedPrimary) {
+ continue;
+ }
+ for (const MediaResourceParcel& resource : resources.getResources()) {
+ if (hasResourceType(type, subType, resource)) {
+ if (resource.value > largestValue) {
+ largestValue = resource.value;
+ clientId = info->clientId;
+ uid = info->uid;
+ }
+ }
+ }
+ }
+
+ if (clientId == -1) {
+ ALOGE("%s: can't find resource type %s and subtype %s for pid %d",
+ __func__, asString(type), asString(subType), targetPid);
+ return false;
+ }
+
+ clientInfo.mPid = targetPid;
+ clientInfo.mUid = uid;
+ clientInfo.mClientId = clientId;
+ return true;
+}
+
+void ResourceTracker::dump(std::string& resourceLogs) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ resourceLogs.append(" Processes:\n");
+ for (const auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ snprintf(buffer, SIZE, " Pid: %d\n", pid);
+ resourceLogs.append(buffer);
+ int priority = 0;
+ if (getPriority(pid, &priority)) {
+ snprintf(buffer, SIZE, " Priority: %d\n", priority);
+ } else {
+ snprintf(buffer, SIZE, " Priority: <unknown>\n");
+ }
+ resourceLogs.append(buffer);
+
+ for (const auto& [infoKey, /* ResourceInfo */ info] : infos) {
+ resourceLogs.append(" Client:\n");
+ snprintf(buffer, SIZE, " Id: %lld\n", (long long)info.clientId);
+ resourceLogs.append(buffer);
+
+ std::string clientName = info.name;
+ snprintf(buffer, SIZE, " Name: %s\n", clientName.c_str());
+ resourceLogs.append(buffer);
+
+ const ResourceList& resources = info.resources;
+ resourceLogs.append(" Resources:\n");
+ resourceLogs.append(resources.toString());
+ }
+ }
+ resourceLogs.append(" Process Pid override:\n");
+ for (const auto& [oldPid, newPid] : mOverridePidMap) {
+ snprintf(buffer, SIZE, " Original Pid: %d, Override Pid: %d\n", oldPid, newPid);
+ resourceLogs.append(buffer);
+ }
+}
+
+void ResourceTracker::onFirstAdded(const MediaResourceParcel& resource, uid_t uid) {
+ std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("%s: ResourceManagerService is invalid!", __func__);
+ return;
+ }
+
+ service->onFirstAdded(resource, uid);
+}
+
+void ResourceTracker::onLastRemoved(const MediaResourceParcel& resource, uid_t uid) {
+ std::shared_ptr<ResourceManagerServiceNew> service = mService.lock();
+ if (service == nullptr) {
+ ALOGW("%s: ResourceManagerService is invalid!", __func__);
+ return;
+ }
+
+ service->onLastRemoved(resource, uid);
+}
+
+bool ResourceTracker::getPriority(int pid, int* priority) {
+ int newPid = pid;
+
+ if (mOverridePidMap.find(pid) != mOverridePidMap.end()) {
+ newPid = mOverridePidMap[pid];
+ ALOGD("%s: use override pid %d instead original pid %d", __func__, newPid, pid);
+ }
+
+ return mProcessInfo->getPriority(newPid, priority);
+}
+
+bool ResourceTracker::getNonConflictingClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients) {
+ MediaResource::Type type = resourceRequestInfo.mResource->type;
+ MediaResource::SubType subType = resourceRequestInfo.mResource->subType;
+ for (auto& [pid, /* ResourceInfos */ infos] : mMap) {
+ for (const auto& [id, /* ResourceInfo */ info] : infos) {
+ if (hasResourceType(type, subType, info.resources)) {
+ if (!isCallingPriorityHigher(resourceRequestInfo.mCallingPid, pid)) {
+ // some higher/equal priority process owns the resource,
+ // this is a conflict.
+ ALOGE("%s: The resource (%s) request from pid %d is conflicting",
+ __func__, asString(type), pid);
+ clients.clear();
+ return false;
+ } else {
+ if (!contains(clients, info.clientId)) {
+ clients.emplace_back(info.pid, info.uid, info.clientId);
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+const ResourceInfo* ResourceTracker::getResourceInfo(int pid, const int64_t& clientId) const {
+ std::map<int, ResourceInfos>::const_iterator found = mMap.find(pid);
+ if (found == mMap.end()) {
+ ALOGV("%s: didn't find pid %d for clientId %lld", __func__, pid, (long long) clientId);
+ return nullptr;
+ }
+
+ const ResourceInfos& infos = found->second;
+ ResourceInfos::const_iterator foundClient = infos.find(clientId);
+ if (foundClient == infos.end()) {
+ ALOGV("%s: didn't find clientId %lld", __func__, (long long) clientId);
+ return nullptr;
+ }
+
+ return &foundClient->second;
+}
+
+bool ResourceTracker::isCallingPriorityHigher(int callingPid, int pid) {
+ int callingPidPriority;
+ if (!getPriority(callingPid, &callingPidPriority)) {
+ return false;
+ }
+
+ int priority;
+ if (!getPriority(pid, &priority)) {
+ return false;
+ }
+
+ return (callingPidPriority < priority);
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceTracker.h b/services/mediaresourcemanager/ResourceTracker.h
new file mode 100644
index 0000000..20c904d
--- /dev/null
+++ b/services/mediaresourcemanager/ResourceTracker.h
@@ -0,0 +1,256 @@
+/*
+**
+** Copyright 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 ANDROID_MEDIA_RESOURCETRACKER_H_
+#define ANDROID_MEDIA_RESOURCETRACKER_H_
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+#include <media/MediaResource.h>
+#include <aidl/android/media/ClientInfoParcel.h>
+#include <aidl/android/media/IResourceManagerClient.h>
+#include <aidl/android/media/MediaResourceParcel.h>
+
+#include "ResourceManagerServiceUtils.h"
+
+namespace android {
+
+class DeathNotifier;
+class ResourceManagerServiceNew;
+class ResourceObserverService;
+struct ProcessInfoInterface;
+struct ResourceRequestInfo;
+struct ClientInfo;
+
+/*
+ * ResourceTracker abstracts the resources managed by the ResourceManager.
+ * It keeps track of the resource used by the clients (clientid) and by the process (pid)
+ */
+class ResourceTracker {
+public:
+ ResourceTracker(const std::shared_ptr<ResourceManagerServiceNew>& service,
+ const sp<ProcessInfoInterface>& processInfo);
+ ~ResourceTracker();
+
+ /**
+ * Add or update resources for |clientInfo|.
+ *
+ * If |clientInfo| is not tracked yet, it records its associated |client| and adds
+ * |resources| to the tracked resources. If |clientInfo| is already tracked,
+ * it updates the tracked resources by adding |resources| to them (|client| in
+ * this case is unused and unchecked).
+ *
+ * @param clientInfo Info of the calling client.
+ * @param client Interface for the client.
+ * @param resources An array of resources to be added.
+ *
+ * @return true upon successfully adding/updating the resources, false
+ * otherwise.
+ */
+ bool addResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ const std::shared_ptr<::aidl::android::media::IResourceManagerClient>& client,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
+
+ // Update the resource info, if there is any changes.
+ bool updateResource(const aidl::android::media::ClientInfoParcel& clientInfo);
+
+ // Remove a set of resources from the given client.
+ // returns true on success, false otherwise.
+ bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ const std::vector<::aidl::android::media::MediaResourceParcel>& resources);
+
+ /**
+ * Remove all resources tracked for |clientInfo|.
+ *
+ * If |validateCallingPid| is true, the (pid of the) calling process is validated that it
+ * is from a trusted process.
+ * Returns true on success (|clientInfo| was tracked and optionally the caller
+ * was a validated trusted process), false otherwise (|clientInfo| was not tracked,
+ * or the caller was not a trusted process)
+ */
+ bool removeResource(const aidl::android::media::ClientInfoParcel& clientInfo,
+ bool validateCallingPid);
+
+ // Mark the client for pending removal.
+ // Such clients are primary candidate for reclaim.
+ // returns true on success, false otherwise.
+ bool markClientForPendingRemoval(const aidl::android::media::ClientInfoParcel& clientInfo);
+
+ // Get a list of clients that belong to process with given pid and are maked to be
+ // pending removal by markClientForPendingRemoval.
+ // returns true on success, false otherwise.
+ bool getClientsMarkedPendingRemoval(int32_t pid, std::vector<ClientInfo>& targetClients);
+
+ // Override the pid of originalPid with newPid
+ // To remove the pid entry from the override list, set newPid as -1
+ // returns true on successful override, false otherwise.
+ bool overridePid(int originalPid, int newPid);
+
+ // Override the process info {state, oom score} of the process with pid.
+ // returns true on success, false otherwise.
+ bool overrideProcessInfo(
+ const std::shared_ptr<aidl::android::media::IResourceManagerClient>& client,
+ int pid, int procState, int oomScore);
+
+ // Remove the overridden process info.
+ void removeProcessInfoOverride(int pid);
+
+ // Find all clients that have given resources.
+ // If applicable, match the primary type too.
+ // The |clients| (list) isn't cleared by this function to allow calling this
+ // function multiple times for different resources.
+ // returns true upon finding at lease one client with the given resource request info,
+ // false otherwise (no clients)
+ bool getAllClients(
+ const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients,
+ MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+
+ // Look for the lowest priority process with the given resources.
+ // Upon success lowestPriorityPid and lowestPriority are
+ // set accordingly and it returns true.
+ // If there isn't a lower priority process with the given resources, it will return false
+ // with out updating lowestPriorityPid and lowerPriority.
+ bool getLowestPriorityPid(MediaResource::Type type, MediaResource::SubType subType,
+ int& lowestPriorityPid, int& lowestPriority);
+
+ // Look for the lowest priority process with the given resources
+ // among the given client list.
+ // If applicable, match the primary type too.
+ // returns true on success, false otherwise.
+ bool getLowestPriorityPid(
+ MediaResource::Type type, MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ int& lowestPriorityPid, int& lowestPriority);
+
+ // Find the biggest client of the given process with given resources,
+ // that is marked as pending to be removed.
+ // returns true on success, false otherwise.
+ bool getBiggestClientPendingRemoval(
+ int pid, MediaResource::Type type,
+ MediaResource::SubType subType,
+ ClientInfo& clientInfo);
+
+ // Find the biggest client from the process pid, selecting them from the list of clients.
+ // If applicable, match the primary type too.
+ // Returns true when a client is found and clientInfo is updated accordingly.
+ // Upon failure to find a client, it will return false without updating
+ // clientInfo.
+ // Upon failure to find a client, it will return false.
+ bool getBiggestClient(
+ int targetPid,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo,
+ MediaResource::SubType primarySubType = MediaResource::SubType::kUnspecifiedSubType);
+
+ // Find the biggest client from the process pid, that has the least importance
+ // (than given importance) among the given list of clients.
+ // If applicable, match the primary type too.
+ // returns true on success, false otherwise.
+ bool getLeastImportantBiggestClient(int targetPid, int32_t importance,
+ MediaResource::Type type,
+ MediaResource::SubType subType,
+ MediaResource::SubType primarySubType,
+ const std::vector<ClientInfo>& clients,
+ ClientInfo& clientInfo);
+
+ // Find the client that belongs to given process(pid) and with the given clientId.
+ // A nullptr is returned upon failure to find the client.
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> getClient(
+ int pid, const int64_t& clientId) const;
+
+ // Removes the client from the given process(pid) with the given clientId.
+ // returns true on success, false otherwise.
+ bool removeClient(int pid, const int64_t& clientId);
+
+ // Set the resource observer service, to which to notify when the resources
+ // are added and removed.
+ void setResourceObserverService(
+ const std::shared_ptr<ResourceObserverService>& observerService);
+
+ // Dump all the resource allocations for all the processes into a given string
+ void dump(std::string& resourceLogs);
+
+ // get the priority of the process.
+ // If we can't get the priority of the process (with given pid), it will
+ // return false.
+ bool getPriority(int pid, int* priority);
+
+ // Check if the given resource request has conflicting clients.
+ // The resource conflict is defined by the ResourceModel (such as
+ // co-existence of secure codec with another secure or non-secure codec).
+ // But here, the ResourceTracker only looks for resources from lower
+ // priority processes.
+ // If is/are only higher or same priority process/es with the given resource,
+ // it will return false.
+ // Otherwise, adds all the clients to the list of clients and return true.
+ bool getNonConflictingClients(const ResourceRequestInfo& resourceRequestInfo,
+ std::vector<ClientInfo>& clients);
+
+ // Returns unmodifiable reference to the resource map.
+ const std::map<int, ResourceInfos>& getResourceMap() const {
+ return mMap;
+ }
+
+private:
+ // Get ResourceInfos associated with the given process.
+ // If none exists, this method will create and associate an empty object and return it.
+ ResourceInfos& getResourceInfosForEdit(int pid);
+
+ // A helper function that returns true if the callingPid has higher priority than pid.
+ // Returns false otherwise.
+ bool isCallingPriorityHigher(int callingPid, int pid);
+
+ // Locate the resource info corresponding to the process pid and
+ // the client clientId.
+ const ResourceInfo* getResourceInfo(int pid, const int64_t& clientId) const;
+
+ // Notify when a resource is added for the first time.
+ void onFirstAdded(const MediaResourceParcel& resource, uid_t uid);
+ // Notify when a resource is removed for the last time.
+ void onLastRemoved(const MediaResourceParcel& resource, uid_t uid);
+
+private:
+ // Structure that defines process info that needs to be overridden.
+ struct ProcessInfoOverride {
+ std::shared_ptr<DeathNotifier> deathNotifier = nullptr;
+ std::shared_ptr<::aidl::android::media::IResourceManagerClient> client;
+ };
+
+ // Map of Resource information indexed through the process id.
+ std::map<int, ResourceInfos> mMap;
+ // A weak reference (to avoid cyclic dependency) to the ResourceManagerService.
+ // ResourceTracker uses this to communicate back with the ResourceManagerService.
+ std::weak_ptr<ResourceManagerServiceNew> mService;
+ // To notify the ResourceObserverService abour resources are added or removed.
+ std::shared_ptr<ResourceObserverService> mObserverService;
+ // Map of pid and their overrided id.
+ std::map<int, int> mOverridePidMap;
+ // Map of pid and their overridden process info.
+ std::map<pid_t, ProcessInfoOverride> mProcessInfoOverrideMap;
+ // Interface that gets process specific information.
+ sp<ProcessInfoInterface> mProcessInfo;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_RESOURCETRACKER_H_
diff --git a/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
index eb4bc42..aa14ace 100644
--- a/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
+++ b/services/mediaresourcemanager/aidl/android/media/ClientInfoParcel.aidl
@@ -41,4 +41,11 @@
* Name of the resource associated with the client.
*/
@utf8InCpp String name;
+
+ /*
+ * Client importance, which ranges from 0 to int_max.
+ * The default importance is high (0)
+ * Based on the reclaim policy, this could be used during reclaim.
+ */
+ int importance = 0;
}
diff --git a/services/mediaresourcemanager/fuzzer/Android.bp b/services/mediaresourcemanager/fuzzer/Android.bp
index bbbc737..5bac062 100644
--- a/services/mediaresourcemanager/fuzzer/Android.bp
+++ b/services/mediaresourcemanager/fuzzer/Android.bp
@@ -43,6 +43,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "aconfig_mediacodec_flags_c_lib",
],
fuzz_config: {
cc: [
diff --git a/services/mediaresourcemanager/test/Android.bp b/services/mediaresourcemanager/test/Android.bp
index f903c62..6a64823 100644
--- a/services/mediaresourcemanager/test/Android.bp
+++ b/services/mediaresourcemanager/test/Android.bp
@@ -12,7 +12,10 @@
name: "ResourceManagerService_test",
srcs: ["ResourceManagerService_test.cpp"],
test_suites: ["device-tests"],
- static_libs: ["libresourcemanagerservice"],
+ static_libs: [
+ "libresourcemanagerservice",
+ "aconfig_mediacodec_flags_c_lib",
+ ],
shared_libs: [
"libbinder",
"libbinder_ndk",
@@ -24,6 +27,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "server_configurable_flags",
],
include_dirs: [
"frameworks/av/include",
@@ -62,6 +66,7 @@
static_libs: [
"libresourcemanagerservice",
"resourceobserver_aidl_interface-V1-ndk",
+ "aconfig_mediacodec_flags_c_lib",
],
shared_libs: [
"libbinder",
@@ -74,6 +79,7 @@
"libstatspull",
"libstatssocket",
"libactivitymanager_aidl",
+ "server_configurable_flags",
],
include_dirs: [
"frameworks/av/include",
diff --git a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
index 52d82b8..7e8a4a0 100644
--- a/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
+++ b/services/mediaresourcemanager/test/ResourceManagerServiceTestUtils.h
@@ -123,14 +123,16 @@
struct TestClient : public BnResourceManagerClient {
- TestClient(int pid, int uid, const std::shared_ptr<ResourceManagerService> &service)
- : mPid(pid), mUid(uid), mService(service) {}
+ TestClient(int pid, int uid, int32_t clientImportance,
+ const std::shared_ptr<ResourceManagerService> &service)
+ : mPid(pid), mUid(uid), mClientImportance(clientImportance), mService(service) {}
Status reclaimResource(bool* _aidl_return) override {
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(mPid),
.uid = static_cast<int32_t>(mUid),
.id = getId(ref<TestClient>()),
- .name = "none"};
+ .name = "none",
+ .importance = mClientImportance};
mService->removeClient(clientInfo);
mWasReclaimResourceCalled = true;
*_aidl_return = true;
@@ -150,10 +152,15 @@
virtual ~TestClient() {}
+ inline int pid() const { return mPid; }
+ inline int uid() const { return mUid; }
+ inline int32_t clientImportance() const { return mClientImportance; }
+
private:
bool mWasReclaimResourceCalled = false;
int mPid;
int mUid;
+ int32_t mClientImportance = 0;
std::shared_ptr<ResourceManagerService> mService;
DISALLOW_EVIL_CONSTRUCTORS(TestClient);
};
@@ -168,6 +175,10 @@
static const int kMidPriorityPid = 25;
static const int kHighPriorityPid = 10;
+static const int32_t kHighestCodecImportance = 0;
+static const int32_t kLowestCodecImportance = 100;
+static const int32_t kMidCodecImportance = 50;
+
using EventType = TestSystemCallback::EventType;
using EventEntry = TestSystemCallback::EventEntry;
bool operator== (const EventEntry& lhs, const EventEntry& rhs) {
@@ -198,8 +209,8 @@
return static_cast<TestClient*>(testClient.get());
}
- ResourceManagerServiceTestBase() {
- ALOGI("ResourceManagerServiceTestBase created");
+ ResourceManagerServiceTestBase(bool newRM = false) : mNewRM(newRM) {
+ ALOGI("ResourceManagerServiceTestBase created with %s RM", newRM ? "new" : "old");
}
void SetUp() override {
@@ -207,14 +218,19 @@
// silently ignored.
ABinderProcess_startThreadPool();
mSystemCB = new TestSystemCallback();
- mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
- mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, mService);
- mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
- mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, mService);
+ if (mNewRM) {
+ mService = ResourceManagerService::CreateNew(new TestProcessInfo, mSystemCB);
+ } else {
+ mService = ResourceManagerService::Create(new TestProcessInfo, mSystemCB);
+ }
+ mTestClient1 = ::ndk::SharedRefBase::make<TestClient>(kTestPid1, kTestUid1, 0, mService);
+ mTestClient2 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
+ mTestClient3 = ::ndk::SharedRefBase::make<TestClient>(kTestPid2, kTestUid2, 0, mService);
}
- std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid) {
- return ::ndk::SharedRefBase::make<TestClient>(pid, uid, mService);
+ std::shared_ptr<IResourceManagerClient> createTestClient(int pid, int uid,
+ int32_t importance = 0) {
+ return ::ndk::SharedRefBase::make<TestClient>(pid, uid, importance, mService);
}
sp<TestSystemCallback> mSystemCB;
@@ -229,9 +245,7 @@
// convert resource1 to ResourceList
ResourceList r1;
for (size_t i = 0; i < resources1.size(); ++i) {
- const auto &res = resources1[i];
- const auto resType = std::tuple(res.type, res.subType, res.id);
- r1[resType] = res;
+ r1.addOrUpdate(resources1[i]);
}
return r1 == resources2;
}
@@ -244,6 +258,8 @@
EXPECT_EQ(client, info.client);
EXPECT_TRUE(isEqualResources(resources, info.resources));
}
+
+ bool mNewRM = false;
};
} // namespace android
diff --git a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
index 8f05b13..b3a0932 100644
--- a/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
+++ b/services/mediaresourcemanager/test/ResourceManagerService_test.cpp
@@ -77,8 +77,20 @@
}
public:
- ResourceManagerServiceTest() : ResourceManagerServiceTestBase() {}
+ ResourceManagerServiceTest(bool newRM = false) : ResourceManagerServiceTestBase(newRM) {}
+ void updateConfig(bool bSupportsMultipleSecureCodecs, bool bSupportsSecureWithNonSecureCodec) {
+ std::vector<MediaResourcePolicyParcel> policies;
+ policies.push_back(
+ MediaResourcePolicy(
+ IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
+ bSupportsMultipleSecureCodecs ? "true" : "false"));
+ policies.push_back(
+ MediaResourcePolicy(
+ IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
+ bSupportsSecureWithNonSecureCodec ? "true" : "false"));
+ mService->config(policies);
+ }
// test set up
// ---------------------------------------------------------------------------------
@@ -129,7 +141,7 @@
resources3.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 100));
mService->addResource(client3Info, mTestClient3, resources3);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(2u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -159,7 +171,7 @@
// Expected result:
// 1) the client should have been added;
// 2) both resource entries should have been rejected, resource list should be empty.
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -197,7 +209,6 @@
resources1.clear();
resources1.push_back(MediaResource(MediaResource::Type::kDrmSession, INT64_MIN));
- expected.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, INT64_MIN));
mService->addResource(client1Info, mTestClient1, resources1);
// Expected result:
@@ -213,29 +224,11 @@
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
- std::vector<MediaResourcePolicyParcel> policies1;
- policies1.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
- "true"));
- policies1.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
- "false"));
- mService->config(policies1);
+ updateConfig(true, false);
EXPECT_TRUE(mService->mSupportsMultipleSecureCodecs);
EXPECT_FALSE(mService->mSupportsSecureWithNonSecureCodec);
- std::vector<MediaResourcePolicyParcel> policies2;
- policies2.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsMultipleSecureCodecs,
- "false"));
- policies2.push_back(
- MediaResourcePolicy(
- IResourceManagerService::kPolicySupportsSecureWithNonSecureCodec,
- "true"));
- mService->config(policies2);
+ updateConfig(false, true);
EXPECT_FALSE(mService->mSupportsMultipleSecureCodecs);
EXPECT_TRUE(mService->mSupportsSecureWithNonSecureCodec);
}
@@ -254,7 +247,7 @@
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(client1Info, mTestClient1, resources11);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -299,7 +292,7 @@
resources11.push_back(MediaResource(MediaResource::Type::kGraphicMemory, 200));
mService->addResource(client1Info, mTestClient1, resources11);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(1u, map.size());
const auto& mapIndex1 = map.find(kTestPid1);
EXPECT_TRUE(mapIndex1 != map.end());
@@ -339,8 +332,7 @@
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(false, true);
// priority too low to reclaim resource
ClientInfoParcel clientInfo{.pid = static_cast<int32_t>(kLowPriorityPid),
@@ -374,7 +366,7 @@
.name = "none"};
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -402,7 +394,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -428,7 +420,7 @@
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
mService->markClientForPendingRemoval(client2Info);
@@ -466,7 +458,7 @@
.name = "none"};
mService->removeClient(client2Info);
- const PidResourceInfosMap &map = mService->mMap;
+ const PidResourceInfosMap &map = mService->getResourceMap();
EXPECT_EQ(2u, map.size());
const ResourceInfos &infos1 = map.at(kTestPid1);
const ResourceInfos &infos2 = map.at(kTestPid2);
@@ -520,8 +512,7 @@
// ### secure codec can't coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(false, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -546,8 +537,7 @@
// ### secure codecs can't coexist and secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = false;
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(false, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -567,8 +557,7 @@
// ### secure codecs can coexist but secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(true, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -599,8 +588,7 @@
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -630,8 +618,7 @@
// ### secure codecs can coexist and secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsMultipleSecureCodecs = true;
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kSecureCodec, 1));
@@ -677,7 +664,7 @@
// ### secure codec can't coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = false;
+ updateConfig(true, false);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -703,7 +690,7 @@
// ### secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
// priority too low
CHECK_STATUS_FALSE(mService->reclaimResource(lowPriorityClient, resources, &result));
@@ -733,7 +720,7 @@
// ### secure codec can coexist with non-secure codec ###
{
addResource();
- mService->mSupportsSecureWithNonSecureCodec = true;
+ updateConfig(true, true);
std::vector<MediaResourceParcel> resources;
resources.push_back(MediaResource(MediaResource::Type::kNonSecureCodec, 1));
@@ -1510,6 +1497,269 @@
client3Config.width * client3Config.height));
EXPECT_TRUE(currentPixelCountP2 == 0);
}
+
+ void addNonSecureVideoCodecResource(std::shared_ptr<IResourceManagerClient>& client,
+ std::vector<ClientInfoParcel>& infos) {
+ std::vector<MediaResourceParcel> resources;
+ resources.push_back(createNonSecureVideoCodecResource(1));
+
+ TestClient* testClient = toTestClient(client);
+ ClientInfoParcel clientInfo {.pid = static_cast<int32_t>(testClient->pid()),
+ .uid = static_cast<int32_t>(testClient->uid()),
+ .id = getId(client),
+ .name = "none",
+ .importance = testClient->clientImportance()};
+ mService->addResource(clientInfo, client, resources);
+ infos.push_back(clientInfo);
+ }
+
+ bool doReclaimResource(const ClientInfoParcel& clientInfo) {
+ bool result = false;
+ std::vector<MediaResourceParcel> reclaimResources;
+ reclaimResources.push_back(createNonSecureVideoCodecResource(1));
+ bool success = mService->reclaimResource(clientInfo, reclaimResources, &result).isOk();
+ return success && result;
+ }
+
+ // Verifies the resource reclaim policies
+ // - this verifies the reclaim policies based on:
+ // - process priority (oom score)
+ // - client priority
+ void testReclaimPolicies() {
+ // Create 3 clients with codec importance high, mid and low for a low
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> lowPriPidClients;
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kMidCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kLowestCodecImportance));
+
+ // Create 3 clients with codec importance high, mid and low for a high
+ // priority pid.
+ std::vector<std::shared_ptr<IResourceManagerClient>> highPriPidClients;
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kHighestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kMidCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ std::vector<ClientInfoParcel> lowPriPidClientInfos;
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ std::vector<ClientInfoParcel> highPriPidClientInfos;
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 1. Set reclaim policy as "Process Priority".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // 1.A:
+ // - high priority process should be able to reclaim successfully.
+ // - A process should be reclaiming from the low priority process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ bool success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 1.B:
+ // - low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+
+ // 2. Set reclaim policy as "Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(false /*process priority*/, true /*codec importance*/);
+
+ // 2.A:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the low priority pid's clients are untouched.
+ success = true;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the high priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.B:
+ // - high priority process should be able to reclaim successfully.
+ // - Process should be reclaiming from a lower priority client from the
+ // same process.
+ EXPECT_TRUE(doReclaimResource(lowPriPidClientInfos[0]));
+ // Verify that the high priority pid's clients are untouched.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the low priority client from the low priority
+ // pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 2.C:
+ // - lowest priority client from high priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[2]));
+
+ // 2.D:
+ // - lowest priority client from low priority process should fail to reclaim.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[2]));
+
+ // 3. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - a lower priority process if there is any
+ // - else a lower priority client from the same process if any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the low priority process so that we have
+ // only one process (with high priority) with all the resources.
+ for (const auto& clientInfo : lowPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ lowPriPidClientInfos.clear();
+ lowPriPidClients.clear();
+ // 3.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Verify that the one of the client from the high priority pid has been reclaimed.
+ success = false;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 3.B, set the policy back to ReclaimPolicyProcessPriority
+ mService->setReclaimPolicy(true /*process priority*/, false /*codec importance*/);
+
+ // Since there is only one process, the reclaim should fail.
+ EXPECT_FALSE(doReclaimResource(highPriPidClientInfos[0]));
+
+ // 4. Set reclaim policy as "Process Priority and Client Importance".
+ // - A process should be reclaiming from:
+ // - from a lower priority process if there are any
+ // - else from a lower priority client from the same process if there are any
+ // - else fail.
+ mService->setReclaimPolicy(true /*process priority*/, true /*codec importance*/);
+
+ // Remove all clients from the high priority process so that we can
+ // start a new/fresh resource allocation.
+ for (const auto& clientInfo : highPriPidClientInfos) {
+ mService->removeClient(clientInfo);
+ }
+ highPriPidClientInfos.clear();
+ highPriPidClients.clear();
+
+ // Create 3 clients with codec importance high for a low priority pid.
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+ lowPriPidClients.push_back(
+ createTestClient(kLowPriorityPid, kTestUid1, kHighestCodecImportance));
+
+ // Create 3 clients with codec importance low for a high priority pid.
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+ highPriPidClients.push_back(
+ createTestClient(kHighPriorityPid, kTestUid2, kLowestCodecImportance));
+
+ // Add non secure video codec resources for all the 3 clients of low priority pid.
+ for (auto& client : lowPriPidClients) {
+ addNonSecureVideoCodecResource(client, lowPriPidClientInfos);
+ }
+ // Add non secure video codec resources for all the 3 clients of high priority pid.
+ for (auto& client : highPriPidClients) {
+ addNonSecureVideoCodecResource(client, highPriPidClientInfos);
+ }
+
+ // 4.A:
+ // - high priority process should be able to reclaim successfully.
+ EXPECT_TRUE(doReclaimResource(highPriPidClientInfos[0]));
+ // Since all clients are of same priority with in high priority process,
+ // none of the clients should be reclaimed.
+ success = true;
+ for (auto& client : highPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = false;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+ // Verify that the one of the client from the low priority pid has been reclaimed.
+ success = false;
+ for (auto& client : lowPriPidClients) {
+ if (toTestClient(client)->checkIfReclaimedAndReset()) {
+ success = true;
+ break;
+ }
+ }
+ EXPECT_TRUE(success);
+
+ // 4.B, set the policy back to ReclaimPolicyProcessPriority
+ // If low priority process tries to reclaim, it should fail as there
+ // aren't any lower priority clients or lower priority processes.
+ EXPECT_FALSE(doReclaimResource(lowPriPidClientInfos[0]));
+ }
+};
+
+class ResourceManagerServiceNewTest : public ResourceManagerServiceTest {
+public:
+ ResourceManagerServiceNewTest(bool newRM = true) : ResourceManagerServiceTest(newRM) {}
};
TEST_F(ResourceManagerServiceTest, config) {
@@ -1598,4 +1848,95 @@
testConcurrentCodecs();
}
+/////// test cases for ResourceManagerServiceNew ////
+TEST_F(ResourceManagerServiceNewTest, config) {
+ testConfig();
+}
+
+TEST_F(ResourceManagerServiceNewTest, addResource) {
+ addResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, combineResource) {
+ testCombineResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, combineResourceNegative) {
+ testCombineResourceWithNegativeValues();
+}
+
+TEST_F(ResourceManagerServiceNewTest, removeResource) {
+ testRemoveResource();
+}
+
+TEST_F(ResourceManagerServiceNewTest, removeClient) {
+ testRemoveClient();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResource) {
+ testReclaimResourceSecure();
+ testReclaimResourceNonSecure();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getAllClients_l) {
+ testGetAllClients();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getLowestPriorityBiggestClient_l) {
+ testGetLowestPriorityBiggestClient();
+}
+
+TEST_F(ResourceManagerServiceNewTest, getLowestPriorityPid_l) {
+ testGetLowestPriorityPid();
+}
+
+TEST_F(ResourceManagerServiceNewTest, isCallingPriorityHigher_l) {
+ testIsCallingPriorityHigher();
+}
+
+TEST_F(ResourceManagerServiceNewTest, batteryStats) {
+ testBatteryStats();
+}
+
+TEST_F(ResourceManagerServiceNewTest, cpusetBoost) {
+ testCpusetBoost();
+}
+
+TEST_F(ResourceManagerServiceNewTest, overridePid) {
+ testOverridePid();
+}
+
+TEST_F(ResourceManagerServiceNewTest, markClientForPendingRemoval) {
+ testMarkClientForPendingRemoval();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withVideoCodec_reclaimsOnlyVideoCodec) {
+ testReclaimResources_withVideoCodec_reclaimsOnlyVideoCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withAudioCodec_reclaimsOnlyAudioCodec) {
+ testReclaimResources_withAudioCodec_reclaimsOnlyAudioCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_withImageCodec_reclaimsOnlyImageCodec) {
+ testReclaimResources_withImageCodec_reclaimsOnlyImageCodec();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimResources_whenPartialResourceMatch_reclaims) {
+ testReclaimResources_whenPartialResourceMatch_reclaims();
+}
+
+TEST_F(ResourceManagerServiceNewTest,
+ reclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources) {
+ testReclaimResourcesFromMarkedClients_removesBiggestMarkedClientForSomeResources();
+}
+
+TEST_F(ResourceManagerServiceNewTest, concurrentCodecs) {
+ testConcurrentCodecs();
+}
+
+TEST_F(ResourceManagerServiceNewTest, reclaimPolicies) {
+ testReclaimPolicies();
+}
+
} // namespace android
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index 2ef6fe5..6b48075 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -76,7 +76,8 @@
const static std::map<audio_format_t, audio_format_t> NEXT_FORMAT_TO_TRY = {
{AUDIO_FORMAT_PCM_FLOAT, AUDIO_FORMAT_PCM_32_BIT},
{AUDIO_FORMAT_PCM_32_BIT, AUDIO_FORMAT_PCM_24_BIT_PACKED},
- {AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_16_BIT}
+ {AUDIO_FORMAT_PCM_24_BIT_PACKED, AUDIO_FORMAT_PCM_8_24_BIT},
+ {AUDIO_FORMAT_PCM_8_24_BIT, AUDIO_FORMAT_PCM_16_BIT}
};
audio_format_t getNextFormatToTry(audio_format_t curFormat) {
@@ -421,10 +422,17 @@
ALOGD("%s() called with dev %d, old = %d", __func__, deviceId, getDeviceId());
if (getDeviceId() != deviceId) {
if (getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
+ // When there is a routing changed, mmap stream should be disconnected. Set `mConnected`
+ // as false here so that there won't be a new stream connect to this endpoint.
+ mConnected.store(false);
const android::sp<AAudioServiceEndpointMMAP> holdEndpoint(this);
std::thread asyncTask([holdEndpoint, deviceId]() {
ALOGD("onRoutingChanged() asyncTask launched");
- holdEndpoint->disconnectRegisteredStreams();
+ // When routing changed, the stream is disconnected and cannot be used except for
+ // closing. In that case, it should be safe to release all registered streams.
+ // This can help release service side resource in case the client doesn't close
+ // the stream after receiving disconnect event.
+ holdEndpoint->releaseRegisteredStreams();
holdEndpoint->setDeviceId(deviceId);
});
asyncTask.detach();
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index 1dd0c3a..5e1e594 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -219,9 +219,13 @@
void AAudioServiceEndpointShared::handleDisconnectRegisteredStreamsAsync() {
android::sp<AAudioServiceEndpointShared> holdEndpoint(this);
+ // When there is a routing changed, mmap stream should be disconnected. Set `mConnected`
+ // as false here so that there won't be a new stream connect to this endpoint.
+ mConnected.store(false);
std::thread asyncTask([holdEndpoint]() {
- // We do not need the returned vector.
- holdEndpoint->disconnectRegisteredStreams();
+ // When handling disconnection, the service side has disconnected. In that case,
+ // it should be safe to release all registered streams.
+ holdEndpoint->releaseRegisteredStreams();
});
asyncTask.detach();
}
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 3521979..9fe06b7 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -55,7 +55,7 @@
"modernize-use-emplace",
"modernize-use-equals-default",
"modernize-use-equals-delete",
- // "modernize-use-nodiscard", // Maybe add this in the future
+ "modernize-use-nodiscard",
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index cd3e579..63ae4c0 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index 1cc3b2b..d58143e 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,8 +16,8 @@
# tunables
-DEV_BRANCH=master
-MAINLINE_BRANCH=tm-mainline-prod
+DEV_BRANCH=main
+MAINLINE_BRANCH=udc-mainline-prod
###
RED=$(tput setaf 1)