Merge "Camera: Disable composite Jpeg/R support in case of Hal support" into udc-dev
diff --git a/apex/TEST_MAPPING b/apex/TEST_MAPPING
index 4b7c019..bb4f089 100644
--- a/apex/TEST_MAPPING
+++ b/apex/TEST_MAPPING
@@ -7,16 +7,16 @@
"presubmit": [
// The following tests validate codec and drm path.
{
- "name": "GtsMediaTestCases",
+ "name": "WvtsDeviceTestCases",
"options" : [
{
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
+ "include-filter": "com.google.android.media.wvts.WidevineH264PlaybackTests"
}
]
}
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index d1618e4..2244682 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -71,10 +71,11 @@
}
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
- int clientUid, int clientPid, int targetSdkVersion, bool overrideToPortrait)
+ int clientUid, int clientPid, int targetSdkVersion, bool overrideToPortrait,
+ bool forceSlowJpegMode)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait);
+ clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode);
}
status_t Camera::reconnect()
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 0a5bc12..9ae4607 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -163,7 +163,7 @@
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait)
+ bool overrideToPortrait, bool forceSlowJpegMode)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
@@ -173,9 +173,11 @@
binder::Status ret;
if (cs != nullptr) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
- ALOGI("Connect camera (legacy API) - overrideToPortrait %d", overrideToPortrait);
+ ALOGI("Connect camera (legacy API) - overrideToPortrait %d, forceSlowJpegMode %d",
+ overrideToPortrait, forceSlowJpegMode);
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
- clientPid, targetSdkVersion, overrideToPortrait, /*out*/ &c->mCamera);
+ clientPid, targetSdkVersion, overrideToPortrait, forceSlowJpegMode,
+ /*out*/ &c->mCamera);
}
if (ret.isOk() && c->mCamera != nullptr) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
diff --git a/camera/aidl/android/hardware/ICameraService.aidl b/camera/aidl/android/hardware/ICameraService.aidl
index 01baba1..9f32595 100644
--- a/camera/aidl/android/hardware/ICameraService.aidl
+++ b/camera/aidl/android/hardware/ICameraService.aidl
@@ -84,7 +84,8 @@
String opPackageName,
int clientUid, int clientPid,
int targetSdkVersion,
- boolean overrideToPortrait);
+ boolean overrideToPortrait,
+ boolean forceSlowJpegMode);
/**
* Open a camera device through the new camera API
diff --git a/camera/include/camera/Camera.h b/camera/include/camera/Camera.h
index 26c36a7..21b57af 100644
--- a/camera/include/camera/Camera.h
+++ b/camera/include/camera/Camera.h
@@ -58,7 +58,7 @@
typedef ::android::hardware::ICameraClient TCamCallbacks;
typedef ::android::binder::Status(::android::hardware::ICameraService::*TCamConnectService)
(const sp<::android::hardware::ICameraClient>&,
- int, const String16&, int, int, int, bool,
+ int, const String16&, int, int, int, bool, bool,
/*out*/
sp<::android::hardware::ICamera>*);
static TCamConnectService fnConnectService;
@@ -82,7 +82,7 @@
static sp<Camera> connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait);
+ bool overrideToPortrait, bool forceSlowJpegMode);
virtual ~Camera();
diff --git a/camera/include/camera/CameraBase.h b/camera/include/camera/CameraBase.h
index 9d0721b..b20dc1b 100644
--- a/camera/include/camera/CameraBase.h
+++ b/camera/include/camera/CameraBase.h
@@ -120,7 +120,7 @@
static sp<TCam> connect(int cameraId,
const String16& clientPackageName,
int clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait);
+ bool overrideToPortrait, bool forceSlowJpegMode);
virtual void disconnect();
void setListener(const sp<TCamListener>& listener);
diff --git a/camera/tests/CameraZSLTests.cpp b/camera/tests/CameraZSLTests.cpp
index bdfb84a..6423709 100644
--- a/camera/tests/CameraZSLTests.cpp
+++ b/camera/tests/CameraZSLTests.cpp
@@ -211,7 +211,7 @@
String16("ZSLTest"), hardware::ICameraService::USE_CALLING_UID,
hardware::ICameraService::USE_CALLING_PID,
/*targetSdkVersion*/__ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, &cameraDevice);
+ /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, &cameraDevice);
EXPECT_TRUE(rc.isOk());
CameraParameters params(cameraDevice->getParameters());
diff --git a/camera/tests/fuzzer/camera_fuzzer.cpp b/camera/tests/fuzzer/camera_fuzzer.cpp
index d41e6b6..f9ef98e 100644
--- a/camera/tests/fuzzer/camera_fuzzer.cpp
+++ b/camera/tests/fuzzer/camera_fuzzer.cpp
@@ -152,7 +152,7 @@
String16("CAMERAFUZZ"), hardware::ICameraService::USE_CALLING_UID,
hardware::ICameraService::USE_CALLING_PID,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__,
- /*overrideToPortrait*/false, &cameraDevice);
+ /*overrideToPortrait*/false, /*forceSlowJpegMode*/false, &cameraDevice);
mCamera = Camera::create(cameraDevice);
if (!mCamera) {
return false;
diff --git a/drm/TEST_MAPPING b/drm/TEST_MAPPING
index b2d4d6e..a9b4b2a 100644
--- a/drm/TEST_MAPPING
+++ b/drm/TEST_MAPPING
@@ -2,16 +2,16 @@
"presubmit": [
// The following tests validate codec and drm path.
{
- "name": "GtsMediaTestCases",
+ "name": "WvtsDeviceTestCases",
"options" : [
{
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
+ "include-filter": "com.google.android.media.wvts.WidevineH264PlaybackTests"
}
]
}
diff --git a/drm/libmediadrm/DrmMetricsLogger.cpp b/drm/libmediadrm/DrmMetricsLogger.cpp
index bc004c8..ce4d730 100644
--- a/drm/libmediadrm/DrmMetricsLogger.cpp
+++ b/drm/libmediadrm/DrmMetricsLogger.cpp
@@ -41,49 +41,59 @@
DrmMetricsLogger::~DrmMetricsLogger() {}
-int MediaErrorToJavaError(status_t err) {
+int MediaErrorToEnum(status_t err) {
+#define ERROR_BAD_VALUE (BAD_VALUE)
+#define ERROR_DEAD_OBJECT (DEAD_OBJECT)
#define STATUS_CASE(status) \
- case status: \
- return J##status
+ case ERROR_##status: \
+ return ENUM_##status
switch (err) {
- STATUS_CASE(ERROR_DRM_UNKNOWN);
- STATUS_CASE(ERROR_DRM_NO_LICENSE);
- STATUS_CASE(ERROR_DRM_LICENSE_EXPIRED);
- STATUS_CASE(ERROR_DRM_RESOURCE_BUSY);
- STATUS_CASE(ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION);
- STATUS_CASE(ERROR_DRM_SESSION_NOT_OPENED);
- STATUS_CASE(ERROR_DRM_CANNOT_HANDLE);
- STATUS_CASE(ERROR_DRM_INSUFFICIENT_SECURITY);
- STATUS_CASE(ERROR_DRM_FRAME_TOO_LARGE);
- STATUS_CASE(ERROR_DRM_SESSION_LOST_STATE);
- STATUS_CASE(ERROR_DRM_CERTIFICATE_MALFORMED);
- STATUS_CASE(ERROR_DRM_CERTIFICATE_MISSING);
- STATUS_CASE(ERROR_DRM_CRYPTO_LIBRARY);
- STATUS_CASE(ERROR_DRM_GENERIC_OEM);
- STATUS_CASE(ERROR_DRM_GENERIC_PLUGIN);
- STATUS_CASE(ERROR_DRM_INIT_DATA);
- STATUS_CASE(ERROR_DRM_KEY_NOT_LOADED);
- STATUS_CASE(ERROR_DRM_LICENSE_PARSE);
- STATUS_CASE(ERROR_DRM_LICENSE_POLICY);
- STATUS_CASE(ERROR_DRM_LICENSE_RELEASE);
- STATUS_CASE(ERROR_DRM_LICENSE_REQUEST_REJECTED);
- STATUS_CASE(ERROR_DRM_LICENSE_RESTORE);
- STATUS_CASE(ERROR_DRM_LICENSE_STATE);
- STATUS_CASE(ERROR_DRM_MEDIA_FRAMEWORK);
- STATUS_CASE(ERROR_DRM_PROVISIONING_CERTIFICATE);
- STATUS_CASE(ERROR_DRM_PROVISIONING_CONFIG);
- STATUS_CASE(ERROR_DRM_PROVISIONING_PARSE);
- STATUS_CASE(ERROR_DRM_PROVISIONING_REQUEST_REJECTED);
- STATUS_CASE(ERROR_DRM_PROVISIONING_RETRY);
- STATUS_CASE(ERROR_DRM_RESOURCE_CONTENTION);
- STATUS_CASE(ERROR_DRM_SECURE_STOP_RELEASE);
- STATUS_CASE(ERROR_DRM_STORAGE_READ);
- STATUS_CASE(ERROR_DRM_STORAGE_WRITE);
- STATUS_CASE(ERROR_DRM_ZERO_SUBSAMPLES);
+ STATUS_CASE(DRM_UNKNOWN);
+ STATUS_CASE(DRM_NO_LICENSE);
+ STATUS_CASE(DRM_LICENSE_EXPIRED);
+ STATUS_CASE(DRM_RESOURCE_BUSY);
+ STATUS_CASE(DRM_INSUFFICIENT_OUTPUT_PROTECTION);
+ STATUS_CASE(DRM_SESSION_NOT_OPENED);
+ STATUS_CASE(DRM_CANNOT_HANDLE);
+ STATUS_CASE(DRM_INSUFFICIENT_SECURITY);
+ STATUS_CASE(DRM_FRAME_TOO_LARGE);
+ STATUS_CASE(DRM_SESSION_LOST_STATE);
+ STATUS_CASE(DRM_CERTIFICATE_MALFORMED);
+ STATUS_CASE(DRM_CERTIFICATE_MISSING);
+ STATUS_CASE(DRM_CRYPTO_LIBRARY);
+ STATUS_CASE(DRM_GENERIC_OEM);
+ STATUS_CASE(DRM_GENERIC_PLUGIN);
+ STATUS_CASE(DRM_INIT_DATA);
+ STATUS_CASE(DRM_KEY_NOT_LOADED);
+ STATUS_CASE(DRM_LICENSE_PARSE);
+ STATUS_CASE(DRM_LICENSE_POLICY);
+ STATUS_CASE(DRM_LICENSE_RELEASE);
+ STATUS_CASE(DRM_LICENSE_REQUEST_REJECTED);
+ STATUS_CASE(DRM_LICENSE_RESTORE);
+ STATUS_CASE(DRM_LICENSE_STATE);
+ STATUS_CASE(DRM_MEDIA_FRAMEWORK);
+ STATUS_CASE(DRM_PROVISIONING_CERTIFICATE);
+ STATUS_CASE(DRM_PROVISIONING_CONFIG);
+ STATUS_CASE(DRM_PROVISIONING_PARSE);
+ STATUS_CASE(DRM_PROVISIONING_REQUEST_REJECTED);
+ STATUS_CASE(DRM_PROVISIONING_RETRY);
+ STATUS_CASE(DRM_RESOURCE_CONTENTION);
+ STATUS_CASE(DRM_SECURE_STOP_RELEASE);
+ STATUS_CASE(DRM_STORAGE_READ);
+ STATUS_CASE(DRM_STORAGE_WRITE);
+ STATUS_CASE(DRM_ZERO_SUBSAMPLES);
+ STATUS_CASE(DRM_INVALID_STATE);
+ STATUS_CASE(BAD_VALUE);
+ STATUS_CASE(DRM_NOT_PROVISIONED);
+ STATUS_CASE(DRM_DEVICE_REVOKED);
+ STATUS_CASE(DRM_DECRYPT);
+ STATUS_CASE(DEAD_OBJECT);
+#undef ERROR_BAD_VALUE
+#undef ERROR_DEAD_OBJECT
#undef STATUS_CASE
}
- return static_cast<int>(err);
+ return ENUM_DRM_UNKNOWN;
}
int DrmPluginSecurityLevelToJavaSecurityLevel(DrmPlugin::SecurityLevel securityLevel) {
@@ -187,12 +197,12 @@
DrmStatus DrmMetricsLogger::closeSession(Vector<uint8_t> const& sessionId) {
std::vector<uint8_t> sid = toStdVec(sessionId);
- {
+ DrmStatus status = mImpl->closeSession(sessionId);
+ if (status == OK) {
const std::lock_guard<std::mutex> lock(mSessionMapMutex);
mSessionMap.erase(sid);
- }
- DrmStatus status = mImpl->closeSession(sessionId);
- if (status != OK) {
+ } else {
+ // TODO(b/275729711): reclaim sessions that failed to close
reportMediaDrmErrored(status, __func__, sid);
}
return status;
@@ -582,7 +592,7 @@
}
}
mediametrics_setCString(handle, "api", api);
- mediametrics_setInt32(handle, "error_code", MediaErrorToJavaError(error_code));
+ mediametrics_setInt32(handle, "error_code", MediaErrorToEnum(error_code));
mediametrics_setInt32(handle, "cdm_err", error_code.getCdmErr());
mediametrics_setInt32(handle, "oem_err", error_code.getOemErr());
mediametrics_setInt32(handle, "error_context", error_code.getContext());
diff --git a/drm/libmediadrm/TEST_MAPPING b/drm/libmediadrm/TEST_MAPPING
index bc15879..8d7be22 100644
--- a/drm/libmediadrm/TEST_MAPPING
+++ b/drm/libmediadrm/TEST_MAPPING
@@ -1,19 +1,19 @@
{
"presubmit": [
{
- "name": "GtsMediaTestCases",
+ "name": "WvtsDeviceTestCases",
"options" : [
{
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.MediaDrmTest"
+ "include-filter": "com.google.android.media.wvts.MediaDrmTest"
},
{
- "include-filter": "com.google.android.media.gts.WidevineDashPolicyTests"
+ "include-filter": "com.google.android.media.wvts.WidevineDashPolicyTests"
}
]
}
diff --git a/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h b/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h
index 7666f04..e72f7f7 100644
--- a/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h
+++ b/drm/libmediadrm/include/mediadrm/DrmMetricsLogger.h
@@ -25,41 +25,49 @@
namespace android {
+// Keep enums in sync with frameworks/proto_logging/stats/enums/media/drm/enums.proto
+
enum {
- JERROR_DRM_UNKNOWN = 0,
- JERROR_DRM_NO_LICENSE = 1,
- JERROR_DRM_LICENSE_EXPIRED = 2,
- JERROR_DRM_RESOURCE_BUSY = 3,
- JERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 4,
- JERROR_DRM_SESSION_NOT_OPENED = 5,
- JERROR_DRM_CANNOT_HANDLE = 6,
- JERROR_DRM_INSUFFICIENT_SECURITY = 7,
- JERROR_DRM_FRAME_TOO_LARGE = 8,
- JERROR_DRM_SESSION_LOST_STATE = 9,
- JERROR_DRM_CERTIFICATE_MALFORMED = 10,
- JERROR_DRM_CERTIFICATE_MISSING = 11,
- JERROR_DRM_CRYPTO_LIBRARY = 12,
- JERROR_DRM_GENERIC_OEM = 13,
- JERROR_DRM_GENERIC_PLUGIN = 14,
- JERROR_DRM_INIT_DATA = 15,
- JERROR_DRM_KEY_NOT_LOADED = 16,
- JERROR_DRM_LICENSE_PARSE = 17,
- JERROR_DRM_LICENSE_POLICY = 18,
- JERROR_DRM_LICENSE_RELEASE = 19,
- JERROR_DRM_LICENSE_REQUEST_REJECTED = 20,
- JERROR_DRM_LICENSE_RESTORE = 21,
- JERROR_DRM_LICENSE_STATE = 22,
- JERROR_DRM_MEDIA_FRAMEWORK = 23,
- JERROR_DRM_PROVISIONING_CERTIFICATE = 24,
- JERROR_DRM_PROVISIONING_CONFIG = 25,
- JERROR_DRM_PROVISIONING_PARSE = 26,
- JERROR_DRM_PROVISIONING_REQUEST_REJECTED = 27,
- JERROR_DRM_PROVISIONING_RETRY = 28,
- JERROR_DRM_RESOURCE_CONTENTION = 29,
- JERROR_DRM_SECURE_STOP_RELEASE = 30,
- JERROR_DRM_STORAGE_READ = 31,
- JERROR_DRM_STORAGE_WRITE = 32,
- JERROR_DRM_ZERO_SUBSAMPLES = 33,
+ ENUM_DRM_UNKNOWN = 0,
+ ENUM_DRM_NO_LICENSE = 1,
+ ENUM_DRM_LICENSE_EXPIRED = 2,
+ ENUM_DRM_RESOURCE_BUSY = 3,
+ ENUM_DRM_INSUFFICIENT_OUTPUT_PROTECTION = 4,
+ ENUM_DRM_SESSION_NOT_OPENED = 5,
+ ENUM_DRM_CANNOT_HANDLE = 6,
+ ENUM_DRM_INSUFFICIENT_SECURITY = 7,
+ ENUM_DRM_FRAME_TOO_LARGE = 8,
+ ENUM_DRM_SESSION_LOST_STATE = 9,
+ ENUM_DRM_CERTIFICATE_MALFORMED = 10,
+ ENUM_DRM_CERTIFICATE_MISSING = 11,
+ ENUM_DRM_CRYPTO_LIBRARY = 12,
+ ENUM_DRM_GENERIC_OEM = 13,
+ ENUM_DRM_GENERIC_PLUGIN = 14,
+ ENUM_DRM_INIT_DATA = 15,
+ ENUM_DRM_KEY_NOT_LOADED = 16,
+ ENUM_DRM_LICENSE_PARSE = 17,
+ ENUM_DRM_LICENSE_POLICY = 18,
+ ENUM_DRM_LICENSE_RELEASE = 19,
+ ENUM_DRM_LICENSE_REQUEST_REJECTED = 20,
+ ENUM_DRM_LICENSE_RESTORE = 21,
+ ENUM_DRM_LICENSE_STATE = 22,
+ ENUM_DRM_MEDIA_FRAMEWORK = 23,
+ ENUM_DRM_PROVISIONING_CERTIFICATE = 24,
+ ENUM_DRM_PROVISIONING_CONFIG = 25,
+ ENUM_DRM_PROVISIONING_PARSE = 26,
+ ENUM_DRM_PROVISIONING_REQUEST_REJECTED = 27,
+ ENUM_DRM_PROVISIONING_RETRY = 28,
+ ENUM_DRM_RESOURCE_CONTENTION = 29,
+ ENUM_DRM_SECURE_STOP_RELEASE = 30,
+ ENUM_DRM_STORAGE_READ = 31,
+ ENUM_DRM_STORAGE_WRITE = 32,
+ ENUM_DRM_ZERO_SUBSAMPLES = 33,
+ ENUM_DRM_INVALID_STATE = 34,
+ ENUM_BAD_VALUE = 35,
+ ENUM_DRM_NOT_PROVISIONED = 36,
+ ENUM_DRM_DEVICE_REVOKED = 37,
+ ENUM_DRM_DECRYPT = 38,
+ ENUM_DEAD_OBJECT = 39,
};
enum {
diff --git a/include/drm/TEST_MAPPING b/include/drm/TEST_MAPPING
index 74fa50d..8595f12 100644
--- a/include/drm/TEST_MAPPING
+++ b/include/drm/TEST_MAPPING
@@ -1,16 +1,16 @@
{
"presubmit": [
{
- "name": "GtsMediaTestCases",
+ "name": "WvtsDeviceTestCases",
"options" : [
{
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
+ "include-filter": "com.google.android.media.wvts.WidevineH264PlaybackTests"
}
]
}
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index 71e7604..0ee8779 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -122,7 +122,7 @@
// monotonic computation.
// we use lazy computation here - if we precompute in
// a single pass, duplicate secant computations may be avoided.
- S sec, sec0, sec1;
+ S sec{}, sec0{}, sec1{}; // initialization not needed, used for clang-tidy
if (!catmullRom || monotonic) {
sec = (high->second - low->second) / interval;
sec0 = low2 != this->end()
@@ -269,7 +269,7 @@
// Note: We don't need to check size is within some bounds as
// the Parcel read will fail if size is incorrectly specified too large.
- float lastx;
+ float lastx = 0.f; // initialization not needed, used for clang tidy
for (uint32_t i = 0; i < size; ++i) {
float x = config.xy[i * 2];
float y = config.xy[i * 2 + 1];
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 9e51cff..5b1bd91 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -21,16 +21,16 @@
],
"presubmit": [
{
- "name": "GtsMediaTestCases",
+ "name": "WvtsDeviceTestCases",
"options" : [
{
"include-annotation": "android.platform.test.annotations.Presubmit"
},
{
- "include-filter": "com.google.android.media.gts.WidevineGenericOpsTests"
+ "include-filter": "com.google.android.media.wvts.WidevineGenericOpsTests"
},
{
- "include-filter": "com.google.android.media.gts.WidevineH264PlaybackTests"
+ "include-filter": "com.google.android.media.wvts.WidevineH264PlaybackTests"
}
],
"file_patterns": ["(?i)drm|crypto"]
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 951a0e7..3b06245 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -14,6 +14,8 @@
* limitations under the License.
*/
+#include <stdio.h>
+
#include <algorithm>
#include <map>
#include <utility>
@@ -570,7 +572,6 @@
GET_DEVICE_DESC_CONNECTION(BT_LE));
return pairs;
}();
-#undef GET_DEVICE_DESC_CONNECTION
return pairs;
}
@@ -998,55 +999,161 @@
}
}
+AudioDeviceAddress::Tag suggestDeviceAddressTag(const AudioDeviceDescription& description) {
+ using Tag = AudioDeviceAddress::Tag;
+ if (std::string connection = description.connection;
+ connection == GET_DEVICE_DESC_CONNECTION(BT_A2DP) ||
+ // Note: BT LE Broadcast uses a "group id".
+ (description.type != AudioDeviceType::OUT_BROADCAST &&
+ connection == GET_DEVICE_DESC_CONNECTION(BT_LE)) ||
+ connection == GET_DEVICE_DESC_CONNECTION(BT_SCO) ||
+ connection == GET_DEVICE_DESC_CONNECTION(WIRELESS)) {
+ return Tag::mac;
+ } else if (connection == GET_DEVICE_DESC_CONNECTION(IP_V4)) {
+ return Tag::ipv4;
+ } else if (connection == GET_DEVICE_DESC_CONNECTION(USB)) {
+ return Tag::alsa;
+ }
+ return Tag::id;
+}
+
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, char* legacyAddress) {
- *legacyType = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- return aidl2legacy_string(
- aidl.address.get<AudioDeviceAddress::id>(),
- legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
+ std::string stringAddress;
+ RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl, legacyType, &stringAddress));
+ return aidl2legacy_string(stringAddress, legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN);
}
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, String8* legacyAddress) {
- *legacyType = VALUE_OR_RETURN_STATUS(
- aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(
- aidl.address.get<AudioDeviceAddress::id>()));
+ std::string stringAddress;
+ RETURN_STATUS_IF_ERROR(aidl2legacy_AudioDevice_audio_device(
+ aidl, legacyType, &stringAddress));
+ *legacyAddress = VALUE_OR_RETURN_STATUS(aidl2legacy_string_view_String8(stringAddress));
return OK;
}
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, std::string* legacyAddress) {
+ using Tag = AudioDeviceAddress::Tag;
*legacyType = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl.type));
- *legacyAddress = aidl.address.get<AudioDeviceAddress::id>();
+ char addressBuffer[AUDIO_DEVICE_MAX_ADDRESS_LEN]{};
+ // 'aidl.address' can be empty even when the connection type is not.
+ // This happens for device ports that act as "blueprints". In this case
+ // we pass an empty string using the 'id' variant.
+ switch (aidl.address.getTag()) {
+ case Tag::mac: {
+ const std::vector<uint8_t>& mac = aidl.address.get<AudioDeviceAddress::mac>();
+ if (mac.size() != 6) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ } break;
+ case Tag::ipv4: {
+ const std::vector<uint8_t>& ipv4 = aidl.address.get<AudioDeviceAddress::ipv4>();
+ if (ipv4.size() != 4) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%u.%u.%u.%u",
+ ipv4[0], ipv4[1], ipv4[2], ipv4[3]);
+ } break;
+ case Tag::ipv6: {
+ const std::vector<int32_t>& ipv6 = aidl.address.get<AudioDeviceAddress::ipv6>();
+ if (ipv6.size() != 8) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+ "%04X:%04X:%04X:%04X:%04X:%04X:%04X:%04X",
+ ipv6[0], ipv6[1], ipv6[2], ipv6[3], ipv6[4], ipv6[5], ipv6[6], ipv6[7]);
+ } break;
+ case Tag::alsa: {
+ const std::vector<int32_t>& alsa = aidl.address.get<AudioDeviceAddress::alsa>();
+ if (alsa.size() != 2) return BAD_VALUE;
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "card=%d;device=%d",
+ alsa[0], alsa[1]);
+ } break;
+ case Tag::id: {
+ RETURN_STATUS_IF_ERROR(aidl2legacy_string(aidl.address.get<AudioDeviceAddress::id>(),
+ addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN));
+ } break;
+ }
+ *legacyAddress = addressBuffer;
return OK;
}
ConversionResult<AudioDevice> legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const char* legacyAddress) {
- AudioDevice aidl;
- aidl.type = VALUE_OR_RETURN(
- legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
- const std::string aidl_id = VALUE_OR_RETURN(
+ const std::string stringAddress = VALUE_OR_RETURN(
legacy2aidl_string(legacyAddress, AUDIO_DEVICE_MAX_ADDRESS_LEN));
- aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
- return aidl;
+ return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
}
ConversionResult<AudioDevice>
legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const String8& legacyAddress) {
+ const std::string stringAddress = VALUE_OR_RETURN(legacy2aidl_String8_string(legacyAddress));
+ return legacy2aidl_audio_device_AudioDevice(legacyType, stringAddress);
+}
+
+ConversionResult<AudioDevice>
+legacy2aidl_audio_device_AudioDevice(
+ audio_devices_t legacyType, const std::string& legacyAddress) {
+ using Tag = AudioDeviceAddress::Tag;
AudioDevice aidl;
aidl.type = VALUE_OR_RETURN(
legacy2aidl_audio_devices_t_AudioDeviceDescription(legacyType));
- const std::string aidl_id = VALUE_OR_RETURN(
- legacy2aidl_String8_string(legacyAddress));
- aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(aidl_id);
+ // 'legacyAddress' can be empty even when the connection type is not.
+ // This happens for device ports that act as "blueprints". In this case
+ // we pass an empty string using the 'id' variant.
+ if (!legacyAddress.empty()) {
+ switch (suggestDeviceAddressTag(aidl.type)) {
+ case Tag::mac: {
+ std::vector<uint8_t> mac(6);
+ int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+ &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
+ if (status != mac.size()) {
+ ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::mac>(std::move(mac));
+ } break;
+ case Tag::ipv4: {
+ std::vector<uint8_t> ipv4(4);
+ int status = sscanf(legacyAddress.c_str(), "%hhu.%hhu.%hhu.%hhu",
+ &ipv4[0], &ipv4[1], &ipv4[2], &ipv4[3]);
+ if (status != ipv4.size()) {
+ ALOGE("%s: malformed IPv4 address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv4>(std::move(ipv4));
+ } break;
+ case Tag::ipv6: {
+ std::vector<int32_t> ipv6(8);
+ int status = sscanf(legacyAddress.c_str(), "%X:%X:%X:%X:%X:%X:%X:%X",
+ &ipv6[0], &ipv6[1], &ipv6[2], &ipv6[3], &ipv6[4], &ipv6[5], &ipv6[6],
+ &ipv6[7]);
+ if (status != ipv6.size()) {
+ ALOGE("%s: malformed IPv6 address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::ipv6>(std::move(ipv6));
+ } break;
+ case Tag::alsa: {
+ std::vector<int32_t> alsa(2);
+ int status = sscanf(legacyAddress.c_str(), "card=%d;device=%d", &alsa[0], &alsa[1]);
+ if (status != alsa.size()) {
+ ALOGE("%s: malformed ALSA address: \"%s\"", __func__, legacyAddress.c_str());
+ return unexpected(BAD_VALUE);
+ }
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::alsa>(std::move(alsa));
+ } break;
+ case Tag::id: {
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
+ } break;
+ }
+ } else {
+ aidl.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(legacyAddress);
+ }
return aidl;
}
@@ -3025,6 +3132,8 @@
} // namespace android
+#undef GET_DEVICE_DESC_CONNECTION
+
#if defined(BACKEND_NDK)
} // aidl
#endif
diff --git a/media/audioaidlconversion/AidlConversionNdk.cpp b/media/audioaidlconversion/AidlConversionNdk.cpp
index 71c547c..9b14a5e 100644
--- a/media/audioaidlconversion/AidlConversionNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionNdk.cpp
@@ -79,39 +79,42 @@
} // namespace
// buffer_provider_t is not supported thus skipped
-ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
- const media::audio::common::AudioConfigBase& aidl, bool isInput) {
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfig_buffer_config_t(
+ const media::audio::common::AudioConfig& aidl, bool isInput) {
buffer_config_t legacy;
- legacy.samplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.samplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.base.sampleRate));
legacy.mask |= EFFECT_CONFIG_SMP_RATE;
legacy.channels = VALUE_OR_RETURN(
- aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.channelMask, isInput));
+ aidl2legacy_AudioChannelLayout_audio_channel_mask_t(aidl.base.channelMask, isInput));
legacy.mask |= EFFECT_CONFIG_CHANNELS;
- legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.format));
+ legacy.format =
+ VALUE_OR_RETURN(aidl2legacy_AudioFormatDescription_audio_format_t(aidl.base.format));
legacy.mask |= EFFECT_CONFIG_FORMAT;
+ legacy.buffer.frameCount = aidl.frameCount;
// TODO: add accessMode and mask
return legacy;
}
-ConversionResult<media::audio::common::AudioConfigBase>
-legacy2aidl_buffer_config_t_AudioConfigBase(const buffer_config_t& legacy, bool isInput) {
- media::audio::common::AudioConfigBase aidl;
+ConversionResult<media::audio::common::AudioConfig>
+legacy2aidl_buffer_config_t_AudioConfig(const buffer_config_t& legacy, bool isInput) {
+ media::audio::common::AudioConfig aidl;
if (legacy.mask & EFFECT_CONFIG_SMP_RATE) {
- aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.samplingRate));
+ aidl.base.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.samplingRate));
}
if (legacy.mask & EFFECT_CONFIG_CHANNELS) {
- aidl.channelMask = VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
+ aidl.base.channelMask = VALUE_OR_RETURN(legacy2aidl_audio_channel_mask_t_AudioChannelLayout(
static_cast<audio_channel_mask_t>(legacy.channels), isInput));
}
if (legacy.mask & EFFECT_CONFIG_FORMAT) {
- aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(
+ aidl.base.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormatDescription(
static_cast<audio_format_t>(legacy.format)));
}
+ aidl.frameCount = legacy.buffer.frameCount;
// TODO: add accessMode and mask
return aidl;
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 9100892..ec1f75c 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -190,6 +190,9 @@
ConversionResult<media::audio::common::AudioDeviceDescription>
legacy2aidl_audio_devices_t_AudioDeviceDescription(audio_devices_t legacy);
+media::audio::common::AudioDeviceAddress::Tag suggestDeviceAddressTag(
+ const media::audio::common::AudioDeviceDescription& description);
+
::android::status_t aidl2legacy_AudioDevice_audio_device(
const media::audio::common::AudioDevice& aidl, audio_devices_t* legacyType,
char* legacyAddress);
@@ -204,6 +207,8 @@
audio_devices_t legacyType, const char* legacyAddress);
ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
audio_devices_t legacyType, const ::android::String8& legacyAddress);
+ConversionResult<media::audio::common::AudioDevice> legacy2aidl_audio_device_AudioDevice(
+ audio_devices_t legacyType, const std::string& legacyAddress);
ConversionResult<audio_extra_audio_descriptor>
aidl2legacy_ExtraAudioDescriptor_audio_extra_audio_descriptor(
diff --git a/media/audioaidlconversion/include/media/AidlConversionNdk.h b/media/audioaidlconversion/include/media/AidlConversionNdk.h
index e92f1a9..813a728 100644
--- a/media/audioaidlconversion/include/media/AidlConversionNdk.h
+++ b/media/audioaidlconversion/include/media/AidlConversionNdk.h
@@ -34,9 +34,9 @@
namespace aidl {
namespace android {
-ConversionResult<buffer_config_t> aidl2legacy_AudioConfigBase_buffer_config_t(
- const media::audio::common::AudioConfigBase& aidl, bool isInput);
-ConversionResult<media::audio::common::AudioConfigBase> legacy2aidl_buffer_config_t_AudioConfigBase(
+ConversionResult<buffer_config_t> aidl2legacy_AudioConfig_buffer_config_t(
+ const media::audio::common::AudioConfig& aidl, bool isInput);
+ConversionResult<media::audio::common::AudioConfig> legacy2aidl_buffer_config_t_AudioConfig(
const buffer_config_t& legacy, bool isInput);
::android::status_t aidl2legacy_AudioAttributesTags(
diff --git a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
index ed91e2c..b179cbb 100644
--- a/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionUtil-impl.h
@@ -58,15 +58,15 @@
ConversionResult<To> convertIntegral(From from) {
// Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
// have the signed converted to unsigned and produce wrong results.
- if (std::is_signed_v<From> && !std::is_signed_v<To>) {
+ if constexpr (std::is_signed_v<From> && !std::is_signed_v<To>) {
if (from < 0 || from > std::numeric_limits<To>::max()) {
return ::android::base::unexpected(::android::BAD_VALUE);
}
- } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
+ } else if constexpr (std::is_signed_v<To> && !std::is_signed_v<From>) {
if (from > std::numeric_limits<To>::max()) {
return ::android::base::unexpected(::android::BAD_VALUE);
}
- } else {
+ } else /* constexpr */ {
if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
return ::android::base::unexpected(::android::BAD_VALUE);
}
diff --git a/media/codec2/components/avc/C2SoftAvcEnc.cpp b/media/codec2/components/avc/C2SoftAvcEnc.cpp
index 5d2856a..9c054f0 100644
--- a/media/codec2/components/avc/C2SoftAvcEnc.cpp
+++ b/media/codec2/components/avc/C2SoftAvcEnc.cpp
@@ -356,7 +356,7 @@
needsUpdate = true;
}
}
- if (!found) {
+ if (!found || me.v.level > LEVEL_AVC_5) {
// We set to the highest supported level.
me.set().level = LEVEL_AVC_5;
}
diff --git a/media/codec2/components/hevc/C2SoftHevcEnc.cpp b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
index 9c26c02..56e6e8a 100644
--- a/media/codec2/components/hevc/C2SoftHevcEnc.cpp
+++ b/media/codec2/components/hevc/C2SoftHevcEnc.cpp
@@ -362,7 +362,7 @@
needsUpdate = true;
}
}
- if (!found) {
+ if (!found || me.v.level > LEVEL_HEVC_MAIN_5_2) {
// We set to the highest supported level.
me.set().level = LEVEL_HEVC_MAIN_5_2;
}
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 4955e13..eb1b4b5 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -2557,17 +2557,6 @@
}
void CCodec::initiateReleaseIfStuck() {
- std::string name;
- bool pendingDeadline = false;
- {
- Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
- if (deadline->get() < std::chrono::steady_clock::now()) {
- name = deadline->getName();
- }
- if (deadline->get() != TimePoint::max()) {
- pendingDeadline = true;
- }
- }
bool tunneled = false;
bool isMediaTypeKnown = false;
{
@@ -2605,6 +2594,17 @@
tunneled = config->mTunneled;
isMediaTypeKnown = (kKnownMediaTypes.count(config->mCodingMediaType) != 0);
}
+ std::string name;
+ bool pendingDeadline = false;
+ {
+ Mutexed<NamedTimePoint>::Locked deadline(mDeadline);
+ if (deadline->get() < std::chrono::steady_clock::now()) {
+ name = deadline->getName();
+ }
+ if (deadline->get() != TimePoint::max()) {
+ pendingDeadline = true;
+ }
+ }
if (!tunneled && isMediaTypeKnown && name.empty()) {
constexpr std::chrono::steady_clock::duration kWorkDurationThreshold = 3s;
std::chrono::steady_clock::duration elapsed = mChannel->elapsed();
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index e800ccd..d2df4f3 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -426,7 +426,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer) {
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg) {
static const C2MemoryUsage kSecureUsage{C2MemoryUsage::READ_PROTECTED, 0};
static const C2MemoryUsage kDefaultReadWriteUsage{
C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE};
@@ -456,7 +457,6 @@
ssize_t result = -1;
ssize_t codecDataOffset = 0;
if (mCrypto) {
- AString errorDetailMsg;
int32_t heapSeqNum = getHeapSeqNum(memory);
hardware::drm::V1_0::SharedBuffer src{(uint32_t)heapSeqNum, offset, size};
hardware::drm::V1_0::DestinationBuffer dst;
@@ -470,7 +470,7 @@
}
result = mCrypto->decrypt(
key, iv, mode, pattern, src, 0, subSamples, numSubSamples,
- dst, &errorDetailMsg);
+ dst, errorDetailMsg);
if (result < 0) {
ALOGI("[%s] attachEncryptedBuffer: decrypt failed: result = %zd", mName, result);
return result;
@@ -515,7 +515,9 @@
result = (ssize_t)_bytesWritten;
detailedError = _detailedError;
});
-
+ if (errorDetailMsg) {
+ errorDetailMsg->setTo(detailedError.c_str(), detailedError.size());
+ }
if (!returnVoid.isOk() || status != CasStatus::OK || result < 0) {
ALOGI("[%s] descramble failed, trans=%s, status=%d, result=%zd",
mName, returnVoid.description().c_str(), status, result);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index e2e55b9..20dca2b 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -86,7 +86,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer) override;
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg) override;
virtual status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
virtual void pollForRenderedBuffers() override;
diff --git a/media/codec2/sfplugin/CCodecConfig.cpp b/media/codec2/sfplugin/CCodecConfig.cpp
index cfadc95..a893bc0 100644
--- a/media/codec2/sfplugin/CCodecConfig.cpp
+++ b/media/codec2/sfplugin/CCodecConfig.cpp
@@ -285,6 +285,12 @@
}
}
+ // Updates or adds a mapper for a "sdkkey"
+ void updateConfigMappersForKey(const SdkKey& key,
+ const std::vector<ConfigMapper>& vec_cm) {
+ mConfigMappers.insert_or_assign(key, vec_cm);
+ }
+
/**
* Returns all paths for a specific domain.
*
@@ -1914,6 +1920,67 @@
const sp<AMessage> &sdkParams, Domain configDomain,
c2_blocking_t blocking,
std::vector<std::unique_ptr<C2Param>> *configUpdate) const {
+ // update the mappers if we know something more of this format.
+ // AV1 10b or 8b encoding request.
+ AString mime;
+ int32_t requestedSdkProfile = -1;
+ if ((mDomain == (IS_VIDEO | IS_ENCODER)) &&
+ sdkParams->findString(KEY_MIME, &mime) &&
+ mime == MIMETYPE_VIDEO_AV1) {
+
+ sdkParams->findInt32(KEY_PROFILE, &requestedSdkProfile);
+ bool is10bAv1EncodeRequested = (requestedSdkProfile == AV1ProfileMain10);
+
+ int32_t bitDepth = (is10bAv1EncodeRequested) ? 10 : 8;
+ // we always initilze with an 8b mapper. Update this only if needed.
+ if (bitDepth != 8) {
+ std::shared_ptr<C2Mapper::ProfileLevelMapper> mapper =
+ C2Mapper::GetBitDepthProfileLevelMapper(mCodingMediaType, bitDepth);
+ mStandardParams->updateConfigMappersForKey(StandardParams::SdkKey(KEY_PROFILE),
+ {
+ ConfigMapper(KEY_PROFILE, C2_PARAMKEY_PROFILE_LEVEL, "profile")
+ .limitTo(Domain::CODED)
+ .withMappers([mapper](C2Value v) -> C2Value {
+ C2Config::profile_t c2 = PROFILE_UNUSED;
+ int32_t sdk;
+ if (mapper && v.get(&sdk) && mapper->mapProfile(sdk, &c2)) {
+ return c2;
+ }
+ return PROFILE_UNUSED;
+ }, [mapper](C2Value v) -> C2Value {
+ C2Config::profile_t c2;
+ int32_t sdk;
+ using C2ValueType =
+ typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
+ if (mapper && v.get((C2ValueType*)&c2) && mapper->mapProfile(c2, &sdk)) {
+ return sdk;
+ }
+ return C2Value();
+ })});
+ mStandardParams->updateConfigMappersForKey(StandardParams::SdkKey(KEY_LEVEL),
+ {
+ ConfigMapper(KEY_LEVEL, C2_PARAMKEY_PROFILE_LEVEL, "level")
+ .limitTo(Domain::CODED)
+ .withMappers([mapper](C2Value v) -> C2Value {
+ C2Config::level_t c2 = LEVEL_UNUSED;
+ int32_t sdk;
+ if (mapper && v.get(&sdk) && mapper->mapLevel(sdk, &c2)) {
+ return c2;
+ }
+ return LEVEL_UNUSED;
+ }, [mapper](C2Value v) -> C2Value {
+ C2Config::level_t c2;
+ int32_t sdk;
+ using C2ValueType =
+ typename _c2_reduce_enum_to_underlying_type<decltype(c2)>::type;
+ if (mapper && v.get((C2ValueType*)&c2) && mapper->mapLevel(c2, &sdk)) {
+ return sdk;
+ }
+ return C2Value();
+ })});
+ }
+ }
+
ReflectedParamUpdater::Dict params = getReflectedFormat(sdkParams, configDomain);
std::vector<C2Param::Index> indices;
diff --git a/media/codec2/vndk/C2Store.cpp b/media/codec2/vndk/C2Store.cpp
index d7a9764..f6f97da 100644
--- a/media/codec2/vndk/C2Store.cpp
+++ b/media/codec2/vndk/C2Store.cpp
@@ -15,7 +15,7 @@
*/
#define LOG_TAG "C2Store"
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
#include <utils/Log.h>
#include <C2AllocatorBlob.h>
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 28d76d7..b731702 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -264,6 +264,12 @@
return af->setMode(mode);
}
+status_t AudioSystem::setSimulateDeviceConnections(bool enabled) {
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ return af->setSimulateDeviceConnections(enabled);
+}
+
status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
@@ -1576,6 +1582,15 @@
return OK;
}
+status_t AudioSystem::listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* result) {
+ if (result == nullptr) return BAD_VALUE;
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(aps->listDeclaredDevicePorts(role, result)));
+ return OK;
+}
+
status_t AudioSystem::getAudioPort(struct audio_port_v7* port) {
if (port == nullptr) {
return BAD_VALUE;
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 9386b9b..d8219a8 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -1702,13 +1702,21 @@
status_t AudioTrack::setOutputDevice(audio_port_handle_t deviceId) {
AutoMutex lock(mLock);
- ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d",
- __func__, mPortId, deviceId, mSelectedDeviceId);
+ ALOGV("%s(%d): deviceId=%d mSelectedDeviceId=%d mRoutedDeviceId %d",
+ __func__, mPortId, deviceId, mSelectedDeviceId, mRoutedDeviceId);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
- if (mStatus == NO_ERROR) {
- android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
- mProxy->interrupt();
+ if (mStatus == NO_ERROR && mSelectedDeviceId != mRoutedDeviceId) {
+ if (isPlaying_l()) {
+ 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
+ if (restoreTrack_l("setOutputDevice") != OK) {
+ android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
+ }
+ }
}
}
return NO_ERROR;
@@ -2185,7 +2193,6 @@
// obtainBuffer() is called with mutex unlocked, so keep extra references to these fields to
// keep them from going away if another thread re-creates the track during obtainBuffer()
sp<AudioTrackClientProxy> proxy;
- sp<IMemory> iMem;
{ // start of lock scope
AutoMutex lock(mLock);
@@ -2211,8 +2218,9 @@
}
// Keep the extra references
+ mProxyObtainBufferRef = mProxy;
proxy = mProxy;
- iMem = mCblkMemory;
+ mCblkMemoryObtainBufferRef = mCblkMemory;
if (mState == STATE_STOPPING) {
status = -EINTR;
@@ -2260,6 +2268,8 @@
buffer.mFrameCount = stepCount;
buffer.mRaw = audioBuffer->raw;
+ sp<IMemory> tempMemory;
+ sp<AudioTrackClientProxy> tempProxy;
AutoMutex lock(mLock);
if (audioBuffer->sequence != mSequence) {
// This Buffer came from a different IAudioTrack instance, so ignore the releaseBuffer
@@ -2269,7 +2279,12 @@
}
mReleased += stepCount;
mInUnderrun = false;
- mProxy->releaseBuffer(&buffer);
+ mProxyObtainBufferRef->releaseBuffer(&buffer);
+ // The extra reference of shared memory and proxy from `obtainBuffer` is not used after
+ // calling `releaseBuffer`. Move the extra reference to a temp strong pointer so that it
+ // will be cleared outside `releaseBuffer`.
+ tempMemory = std::move(mCblkMemoryObtainBufferRef);
+ tempProxy = std::move(mProxyObtainBufferRef);
// restart track if it was disabled by audioflinger due to previous underrun
restartIfDisabled();
@@ -2507,11 +2522,22 @@
timeout.tv_sec = WAIT_STREAM_END_TIMEOUT_SEC;
timeout.tv_nsec = 0;
+ // Use timestamp progress to safeguard we don't falsely time out.
+ AudioTimestamp timestamp{};
+ const bool isTimestampValid = getTimestamp(timestamp) == OK;
+ const auto frameCount = isTimestampValid ? timestamp.mPosition : 0;
+
status_t status = proxy->waitStreamEndDone(&timeout);
switch (status) {
+ case TIMED_OUT:
+ if (isTimestampValid
+ && getTimestamp(timestamp) == OK && frameCount != timestamp.mPosition) {
+ ALOGD("%s: waitStreamEndDone retrying", __func__);
+ break; // we retry again (and recheck possible state change).
+ }
+ [[fallthrough]];
case NO_ERROR:
case DEAD_OBJECT:
- case TIMED_OUT:
if (status != DEAD_OBJECT) {
// for DEAD_OBJECT, we do not send a EVENT_STREAM_END after stop();
// instead, the application should handle the EVENT_NEW_IAUDIOTRACK.
@@ -2529,6 +2555,7 @@
}
}
if (waitStreamEnd && status != DEAD_OBJECT) {
+ ALOGV("%s: waitStreamEndDone complete", __func__);
return NS_INACTIVE;
}
break;
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index bbc39e8..620cdc2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -816,6 +816,10 @@
return statusTFromBinderStatus(mDelegate->setDeviceConnectedState(aidlPort, connected));
}
+status_t AudioFlingerClientAdapter::setSimulateDeviceConnections(bool enabled) {
+ return statusTFromBinderStatus(mDelegate->setSimulateDeviceConnections(enabled));
+}
+
status_t AudioFlingerClientAdapter::setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) {
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
@@ -1370,6 +1374,10 @@
return Status::fromStatusT(mDelegate->setDeviceConnectedState(&portLegacy, connected));
}
+Status AudioFlingerServerAdapter::setSimulateDeviceConnections(bool enabled) {
+ return Status::fromStatusT(mDelegate->setSimulateDeviceConnections(enabled));
+}
+
Status AudioFlingerServerAdapter::setRequestedLatencyMode(
int32_t output, media::audio::common::AudioLatencyMode modeAidl) {
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 568c865..4d9fef4 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -229,6 +229,9 @@
void setDeviceConnectedState(in AudioPortFw devicePort, boolean connected);
+ // Used for tests only. Requires AIDL HAL to work.
+ void setSimulateDeviceConnections(boolean enabled);
+
/**
* Requests a given latency mode (See AudioLatencyMode.aidl) on an output stream.
* This can be used when some use case on a given mixer/stream can only be enabled
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index fa6c733..90ede8b 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -203,7 +203,9 @@
in AudioAttributesInternal attributes);
/**
- * List available audio ports and their attributes. Returns the generation.
+ * List currently attached audio ports and their attributes. Returns the generation.
+ * The generation is incremented each time when anything changes in the ports
+ * configuration.
*
* On input, count represents the maximum length of the returned array.
* On output, count is the total number of elements, which may be larger than the array size.
@@ -215,6 +217,13 @@
inout Int count,
out AudioPortFw[] ports);
+ /**
+ * List all device ports declared in the configuration (including currently detached ones)
+ * 'role' can be 'NONE' to get both input and output devices,
+ * 'SINK' for output devices, and 'SOURCE' for input devices.
+ */
+ AudioPortFw[] listDeclaredDevicePorts(AudioPortRole role);
+
/** Get attributes for the audio port with the given id (AudioPort.hal.id field). */
AudioPortFw getAudioPort(int /* audio_port_handle_t */ portId);
diff --git a/media/libaudioclient/fuzzer/Android.bp b/media/libaudioclient/fuzzer/Android.bp
index b1feb60..6080314 100644
--- a/media/libaudioclient/fuzzer/Android.bp
+++ b/media/libaudioclient/fuzzer/Android.bp
@@ -80,5 +80,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libaudioflinger",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index d033d4f..1bfe34d 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -23,6 +23,7 @@
#include <vector>
#include <android/content/AttributionSourceState.h>
+#include <android/media/AudioPortFw.h>
#include <android/media/AudioVibratorInfo.h>
#include <android/media/BnAudioFlingerClient.h>
#include <android/media/BnAudioPolicyServiceClient.h>
@@ -126,6 +127,9 @@
// set audio mode in audio hardware
static status_t setMode(audio_mode_t mode);
+ // test API: switch HALs into the mode which simulates external device connections
+ static status_t setSimulateDeviceConnections(bool enabled);
+
// returns true in *state if tracks are active on the specified stream or have been active
// in the past inPastMs milliseconds
static status_t isStreamActive(audio_stream_type_t stream, bool *state, uint32_t inPastMs);
@@ -425,6 +429,9 @@
struct audio_port_v7 *ports,
unsigned int *generation);
+ static status_t listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* result);
+
/* Get attributes for a given audio port. On input, the port
* only needs the 'id' field to be filled in. */
static status_t getAudioPort(struct audio_port_v7 *port);
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 31f81be..8f712db 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -1126,6 +1126,9 @@
bool isPlaying() {
AutoMutex lock(mLock);
+ return isPlaying_l();
+ }
+ bool isPlaying_l() {
return mState == STATE_ACTIVE || mState == STATE_STOPPING;
}
@@ -1262,6 +1265,11 @@
audio_track_cblk_t* mCblk; // re-load after mLock.unlock()
audio_io_handle_t mOutput = AUDIO_IO_HANDLE_NONE; // from AudioSystem::getOutputForAttr()
+ // A copy of shared memory and proxy between obtainBuffer and releaseBuffer to keep the
+ // shared memory valid when processing data.
+ sp<IMemory> mCblkMemoryObtainBufferRef GUARDED_BY(mLock);
+ sp<AudioTrackClientProxy> mProxyObtainBufferRef GUARDED_BY(mLock);
+
sp<AudioTrackThread> mAudioTrackThread;
bool mThreadCanCallJava;
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 02d0511..1803862 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -363,6 +363,8 @@
virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) = 0;
+ virtual status_t setSimulateDeviceConnections(bool enabled) = 0;
+
virtual status_t setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode) = 0;
@@ -480,6 +482,7 @@
int32_t getAAudioMixerBurstCount() override;
int32_t getAAudioHardwareBurstMinUsec() override;
status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected) override;
+ status_t setSimulateDeviceConnections(bool enabled) override;
status_t setRequestedLatencyMode(audio_io_handle_t output,
audio_latency_mode_t mode) override;
status_t getSupportedLatencyModes(
@@ -578,6 +581,7 @@
GET_AAUDIO_MIXER_BURST_COUNT = media::BnAudioFlingerService::TRANSACTION_getAAudioMixerBurstCount,
GET_AAUDIO_HARDWARE_BURST_MIN_USEC = media::BnAudioFlingerService::TRANSACTION_getAAudioHardwareBurstMinUsec,
SET_DEVICE_CONNECTED_STATE = media::BnAudioFlingerService::TRANSACTION_setDeviceConnectedState,
+ SET_SIMULATE_DEVICE_CONNECTIONS = media::BnAudioFlingerService::TRANSACTION_setSimulateDeviceConnections,
SET_REQUESTED_LATENCY_MODE = media::BnAudioFlingerService::TRANSACTION_setRequestedLatencyMode,
GET_SUPPORTED_LATENCY_MODES = media::BnAudioFlingerService::TRANSACTION_getSupportedLatencyModes,
SET_BLUETOOTH_VARIABLE_LATENCY_ENABLED =
@@ -708,6 +712,7 @@
Status getAAudioMixerBurstCount(int32_t* _aidl_return) override;
Status getAAudioHardwareBurstMinUsec(int32_t* _aidl_return) override;
Status setDeviceConnectedState(const media::AudioPortFw& port, bool connected) override;
+ Status setSimulateDeviceConnections(bool enabled) override;
Status setRequestedLatencyMode(
int output, media::audio::common::AudioLatencyMode mode) override;
Status getSupportedLatencyModes(int output,
diff --git a/media/libaudioclient/tests/Android.bp b/media/libaudioclient/tests/Android.bp
index 2189521..1e8dcca 100644
--- a/media/libaudioclient/tests/Android.bp
+++ b/media/libaudioclient/tests/Android.bp
@@ -14,6 +14,12 @@
"-Wall",
"-Werror",
],
+ shared_libs: [
+ "libbinder",
+ "libcutils",
+ "liblog",
+ "libutils",
+ ],
sanitize: {
misc_undefined: [
"unsigned-integer-overflow",
@@ -22,37 +28,35 @@
},
}
-cc_test {
- name: "audio_aidl_conversion_tests",
+cc_defaults {
+ name: "audio_aidl_conversion_test_defaults",
defaults: [
"libaudioclient_tests_defaults",
"latest_android_media_audio_common_types_cpp_static",
],
- srcs: ["audio_aidl_legacy_conversion_tests.cpp"],
- shared_libs: [
- "libbinder",
- "libcutils",
- "liblog",
- "libutils",
- ],
static_libs: [
- "libaudioclient_aidl_conversion",
- "libaudio_aidl_conversion_common_cpp",
"audioclient-types-aidl-cpp",
"av-types-aidl-cpp",
+ "libaudio_aidl_conversion_common_cpp",
+ "libaudioclient_aidl_conversion",
"libstagefright_foundation",
],
}
cc_test {
+ name: "audio_aidl_conversion_tests",
+ defaults: [
+ "audio_aidl_conversion_test_defaults",
+ ],
+ srcs: ["audio_aidl_legacy_conversion_tests.cpp"],
+}
+
+cc_test {
name: "audio_aidl_status_tests",
defaults: ["libaudioclient_tests_defaults"],
srcs: ["audio_aidl_status_tests.cpp"],
shared_libs: [
"libaudioclient_aidl_conversion",
- "libbinder",
- "libcutils",
- "libutils",
],
}
@@ -70,9 +74,6 @@
shared_libs: [
"framework-permission-aidl-cpp",
"libaudioclient",
- "libbinder",
- "libcutils",
- "libutils",
],
data: ["track_test_input_*.txt"],
}
@@ -89,35 +90,23 @@
"libmediametrics_headers",
],
shared_libs: [
- "libaudioclient",
- "libbinder",
- "libcutils",
- "libutils",
"framework-permission-aidl-cpp",
+ "libaudioclient",
],
data: ["record_test_input_*.txt"],
}
cc_defaults {
name: "libaudioclient_gtests_defaults",
- cflags: [
- "-Wall",
- "-Werror",
- ],
defaults: [
- "latest_android_media_audio_common_types_cpp_static",
+ "audio_aidl_conversion_test_defaults",
],
shared_libs: [
"capture_state_listener-aidl-cpp",
"framework-permission-aidl-cpp",
- "libaudioclient_aidl_conversion",
- "libaudio_aidl_conversion_common_cpp",
"libbase",
- "libbinder",
"libcgrouprc",
- "libcutils",
"libdl",
- "liblog",
"libmedia",
"libmediametrics",
"libmediautils",
@@ -125,8 +114,6 @@
"libnblog",
"libprocessgroup",
"libshmemcompat",
- "libstagefright_foundation",
- "libutils",
"libxml2",
"mediametricsservice-aidl-cpp",
"packagemanager_aidl-cpp",
@@ -148,7 +135,6 @@
],
data: ["bbb*.raw"],
test_config_template: "audio_test_template.xml",
- test_suites: ["device-tests"],
}
cc_test {
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index f651a37..0d12f9d 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -15,6 +15,7 @@
*/
#include <iostream>
+#include <string>
#include <gtest/gtest.h>
@@ -32,6 +33,7 @@
using media::AudioPortType;
using media::audio::common::AudioChannelLayout;
using media::audio::common::AudioDevice;
+using media::audio::common::AudioDeviceAddress;
using media::audio::common::AudioDeviceDescription;
using media::audio::common::AudioDeviceType;
using media::audio::common::AudioEncapsulationMetadataType;
@@ -131,6 +133,14 @@
return make_AudioDeviceDescription(AudioDeviceType::IN_DEFAULT);
}
+AudioDeviceDescription make_ADD_MicIn() {
+ return make_AudioDeviceDescription(AudioDeviceType::IN_MICROPHONE);
+}
+
+AudioDeviceDescription make_ADD_RSubmixIn() {
+ return make_AudioDeviceDescription(AudioDeviceType::IN_SUBMIX);
+}
+
AudioDeviceDescription make_ADD_DefaultOut() {
return make_AudioDeviceDescription(AudioDeviceType::OUT_DEFAULT);
}
@@ -145,6 +155,39 @@
AudioDeviceDescription::CONNECTION_BT_SCO());
}
+AudioDeviceDescription make_ADD_BtA2dpHeadphone() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADPHONE,
+ AudioDeviceDescription::CONNECTION_BT_A2DP());
+}
+
+AudioDeviceDescription make_ADD_BtLeHeadset() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_BT_LE());
+}
+
+AudioDeviceDescription make_ADD_BtLeBroadcast() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_BROADCAST,
+ AudioDeviceDescription::CONNECTION_BT_LE());
+}
+
+AudioDeviceDescription make_ADD_IpV4Device() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_DEVICE,
+ AudioDeviceDescription::CONNECTION_IP_V4());
+}
+
+AudioDeviceDescription make_ADD_UsbHeadset() {
+ return make_AudioDeviceDescription(AudioDeviceType::OUT_HEADSET,
+ AudioDeviceDescription::CONNECTION_USB());
+}
+
+AudioDevice make_AudioDevice(const AudioDeviceDescription& type,
+ const AudioDeviceAddress& address) {
+ AudioDevice result;
+ result.type = type;
+ result.address = address;
+ return result;
+}
+
AudioFormatDescription make_AudioFormatDescription(AudioFormatType type) {
AudioFormatDescription result;
result.type = type;
@@ -390,6 +433,48 @@
make_ADD_DefaultOut(), make_ADD_WiredHeadset(),
make_ADD_BtScoHeadset()));
+class AudioDeviceRoundTripTest : public testing::TestWithParam<AudioDevice> {};
+TEST_P(AudioDeviceRoundTripTest, Aidl2Legacy2Aidl) {
+ const auto initial = GetParam();
+ audio_devices_t legacyType;
+ String8 legacyAddress;
+ status_t status = aidl2legacy_AudioDevice_audio_device(initial, &legacyType, &legacyAddress);
+ ASSERT_EQ(OK, status);
+ auto convBack = legacy2aidl_audio_device_AudioDevice(legacyType, legacyAddress);
+ ASSERT_TRUE(convBack.ok());
+ EXPECT_EQ(initial, convBack.value());
+}
+INSTANTIATE_TEST_SUITE_P(
+ AudioDeviceRoundTrip, AudioDeviceRoundTripTest,
+ testing::Values(
+ make_AudioDevice(make_ADD_MicIn(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("bottom")),
+ make_AudioDevice(make_ADD_RSubmixIn(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("1:2-in-3")),
+ // The case of a "blueprint" device port for an external device.
+ make_AudioDevice(make_ADD_BtScoHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
+ make_AudioDevice(make_ADD_BtScoHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ // Another "blueprint"
+ make_AudioDevice(make_ADD_BtA2dpHeadphone(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("")),
+ make_AudioDevice(make_ADD_BtA2dpHeadphone(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ make_AudioDevice(make_ADD_BtLeHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, 6})),
+ make_AudioDevice(make_ADD_BtLeBroadcast(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::id>("42")),
+ make_AudioDevice(make_ADD_IpV4Device(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::ipv4>(
+ std::vector<uint8_t>{192, 168, 0, 1})),
+ make_AudioDevice(make_ADD_UsbHeadset(),
+ AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
+ std::vector<int32_t>{1, 2}))));
+
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
};
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
diff --git a/media/libaudioclient/tests/audiosystem_tests.cpp b/media/libaudioclient/tests/audiosystem_tests.cpp
index 2b9b4fa..45baa94 100644
--- a/media/libaudioclient/tests/audiosystem_tests.cpp
+++ b/media/libaudioclient/tests/audiosystem_tests.cpp
@@ -18,12 +18,19 @@
#include <string.h>
+#include <set>
+
#include <gtest/gtest.h>
+#include <media/AidlConversionCppNdk.h>
#include <media/IAudioFlinger.h>
#include <utils/Log.h>
#include "audio_test_utils.h"
+using android::media::audio::common::AudioDeviceAddress;
+using android::media::audio::common::AudioDeviceDescription;
+using android::media::audio::common::AudioDeviceType;
+using android::media::audio::common::AudioPortExt;
using namespace android;
void anyPatchContainsInputDevice(audio_port_handle_t deviceId, bool& res) {
@@ -579,3 +586,106 @@
EXPECT_EQ(NO_ERROR, AudioSystem::setUserIdDeviceAffinities(userId, outputDevices));
EXPECT_EQ(NO_ERROR, AudioSystem::removeUserIdDeviceAffinities(userId));
}
+
+namespace {
+
+class WithSimulatedDeviceConnections {
+ public:
+ WithSimulatedDeviceConnections()
+ : mIsSupported(AudioSystem::setSimulateDeviceConnections(true) == OK) {}
+ ~WithSimulatedDeviceConnections() {
+ if (mIsSupported) {
+ if (status_t status = AudioSystem::setSimulateDeviceConnections(false); status != OK) {
+ ALOGE("Error restoring device connections simulation state: %d", status);
+ }
+ }
+ }
+ bool isSupported() const { return mIsSupported; }
+
+ private:
+ const bool mIsSupported;
+};
+
+android::media::audio::common::AudioPort GenerateUniqueDeviceAddress(
+ const android::media::audio::common::AudioPort& port) {
+ static int nextId = 0;
+ using Tag = AudioDeviceAddress::Tag;
+ AudioDeviceAddress address;
+ switch (suggestDeviceAddressTag(port.ext.get<AudioPortExt::Tag::device>().device.type)) {
+ case Tag::id:
+ address = AudioDeviceAddress::make<Tag::id>(std::to_string(++nextId));
+ break;
+ case Tag::mac:
+ address = AudioDeviceAddress::make<Tag::mac>(
+ std::vector<uint8_t>{1, 2, 3, 4, 5, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv4:
+ address = AudioDeviceAddress::make<Tag::ipv4>(
+ std::vector<uint8_t>{192, 168, 0, static_cast<uint8_t>(++nextId & 0xff)});
+ break;
+ case Tag::ipv6:
+ address = AudioDeviceAddress::make<Tag::ipv6>(std::vector<int32_t>{
+ 0xfc00, 0x0123, 0x4567, 0x89ab, 0xcdef, 0, 0, ++nextId & 0xffff});
+ break;
+ case Tag::alsa:
+ address = AudioDeviceAddress::make<Tag::alsa>(std::vector<int32_t>{1, ++nextId});
+ break;
+ }
+ android::media::audio::common::AudioPort result = port;
+ result.ext.get<AudioPortExt::Tag::device>().device.address = std::move(address);
+ return result;
+}
+
+} // namespace
+
+TEST_F(AudioSystemTest, SetDeviceConnectedState) {
+ WithSimulatedDeviceConnections connSim;
+ if (!connSim.isSupported()) {
+ GTEST_SKIP() << "Simulation of external device connections not supported";
+ }
+ std::vector<media::AudioPortFw> ports;
+ ASSERT_EQ(OK, AudioSystem::listDeclaredDevicePorts(media::AudioPortRole::NONE, &ports));
+ if (ports.empty()) {
+ GTEST_SKIP() << "No ports returned by the audio system";
+ }
+ const std::set<AudioDeviceType> typesToUse{
+ AudioDeviceType::IN_DEVICE, AudioDeviceType::IN_HEADSET,
+ AudioDeviceType::IN_MICROPHONE, AudioDeviceType::OUT_DEVICE,
+ AudioDeviceType::OUT_HEADPHONE, AudioDeviceType::OUT_HEADSET,
+ AudioDeviceType::OUT_HEARING_AID, AudioDeviceType::OUT_SPEAKER};
+ std::vector<media::AudioPortFw> externalDevicePorts;
+ for (const auto& port : ports) {
+ if (const auto& device = port.hal.ext.get<AudioPortExt::device>().device;
+ !device.type.connection.empty() && typesToUse.count(device.type.type)) {
+ externalDevicePorts.push_back(port);
+ }
+ }
+ if (externalDevicePorts.empty()) {
+ GTEST_SKIP() << "No ports for considered non-attached devices";
+ }
+ for (auto& port : externalDevicePorts) {
+ android::media::audio::common::AudioPort aidlPort = GenerateUniqueDeviceAddress(port.hal);
+ SCOPED_TRACE(aidlPort.toString());
+ audio_devices_t type;
+ char address[AUDIO_DEVICE_MAX_ADDRESS_LEN];
+ status_t status = aidl2legacy_AudioDevice_audio_device(
+ aidlPort.ext.get<AudioPortExt::Tag::device>().device, &type, address);
+ ASSERT_EQ(OK, status);
+ audio_policy_dev_state_t deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, deviceState);
+ if (deviceState != AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) continue;
+ // !!! Instead of the default format, use each format from 'ext.encodedFormats'
+ // !!! if they are not empty
+ status = AudioSystem::setDeviceConnectionState(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ aidlPort, AUDIO_FORMAT_DEFAULT);
+ EXPECT_EQ(OK, status);
+ if (status != OK) continue;
+ deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE, deviceState);
+ status = AudioSystem::setDeviceConnectionState(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ aidlPort, AUDIO_FORMAT_DEFAULT);
+ EXPECT_EQ(OK, status);
+ deviceState = AudioSystem::getDeviceConnectionState(type, address);
+ EXPECT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, deviceState);
+ }
+}
diff --git a/media/libaudiohal/Android.bp b/media/libaudiohal/Android.bp
index f47dd0b..1dbcb86 100644
--- a/media/libaudiohal/Android.bp
+++ b/media/libaudiohal/Android.bp
@@ -76,3 +76,11 @@
export_include_dirs: ["include"],
}
+
+cc_library_headers {
+ name: "libaudiohalimpl_headers",
+
+ header_libs: ["libaudiohal_headers"],
+ export_header_lib_headers: ["libaudiohal_headers"],
+ export_include_dirs: ["impl"],
+}
diff --git a/media/libaudiohal/impl/Android.bp b/media/libaudiohal/impl/Android.bp
index ff817d4..15726ff 100644
--- a/media/libaudiohal/impl/Android.bp
+++ b/media/libaudiohal/impl/Android.bp
@@ -280,6 +280,7 @@
"EffectsFactoryHalAidl.cpp",
"EffectsFactoryHalEntry.cpp",
"StreamHalAidl.cpp",
+ ":audio_effectproxy_src_files"
],
static_libs: [
"android.hardware.common-V2-ndk",
@@ -303,3 +304,8 @@
"-DBACKEND_CPP_NDK",
],
}
+
+filegroup {
+ name: "audio_effectproxy_src_files",
+ srcs: ["EffectProxy.cpp"],
+}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 0d6bb3f..25ee61a 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -23,6 +23,8 @@
#include <aidl/android/hardware/audio/core/BnStreamCallback.h>
#include <aidl/android/hardware/audio/core/BnStreamOutEventCallback.h>
#include <aidl/android/hardware/audio/core/StreamDescriptor.h>
+#include <android/binder_enums.h>
+#include <binder/Enums.h>
#include <error/expected_utils.h>
#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionUtil.h>
@@ -34,32 +36,42 @@
#include "StreamHalAidl.h"
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::AudioDevice;
+using aidl::android::media::audio::common::AudioDeviceAddress;
using aidl::android::media::audio::common::AudioDeviceType;
+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::AudioLatencyMode;
+using aidl::android::media::audio::common::AudioMMapPolicy;
+using aidl::android::media::audio::common::AudioMMapPolicyInfo;
+using aidl::android::media::audio::common::AudioMMapPolicyType;
using aidl::android::media::audio::common::AudioMode;
using aidl::android::media::audio::common::AudioOutputFlags;
using aidl::android::media::audio::common::AudioPort;
using aidl::android::media::audio::common::AudioPortConfig;
using aidl::android::media::audio::common::AudioPortDeviceExt;
+using aidl::android::media::audio::common::AudioPortExt;
using aidl::android::media::audio::common::AudioPortMixExt;
using aidl::android::media::audio::common::AudioPortMixExtUseCase;
-using aidl::android::media::audio::common::AudioPortExt;
+using aidl::android::media::audio::common::AudioProfile;
using aidl::android::media::audio::common::AudioSource;
-using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::Float;
-using aidl::android::hardware::audio::common::getFrameSizeInBytes;
-using aidl::android::hardware::audio::common::isBitPositionFlagSet;
-using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
+using aidl::android::media::audio::common::Int;
using aidl::android::media::audio::common::MicrophoneDynamicInfo;
using aidl::android::media::audio::common::MicrophoneInfo;
+using aidl::android::hardware::audio::common::getFrameSizeInBytes;
+using aidl::android::hardware::audio::common::isBitPositionFlagSet;
+using aidl::android::hardware::audio::common::isDefaultAudioFormat;
+using aidl::android::hardware::audio::common::makeBitPositionFlagMask;
using aidl::android::hardware::audio::common::RecordTrackMetadata;
using aidl::android::hardware::audio::core::AudioPatch;
+using aidl::android::hardware::audio::core::AudioRoute;
using aidl::android::hardware::audio::core::IModule;
using aidl::android::hardware::audio::core::ITelephony;
+using aidl::android::hardware::audio::core::ModuleDebug;
using aidl::android::hardware::audio::core::StreamDescriptor;
namespace android {
@@ -84,6 +96,75 @@
portConfig->format = config.base.format;
}
+template<typename OutEnum, typename OutEnumRange, typename InEnum>
+ConversionResult<OutEnum> convertEnum(const OutEnumRange& range, InEnum e) {
+ using InIntType = std::underlying_type_t<InEnum>;
+ static_assert(std::is_same_v<InIntType, std::underlying_type_t<OutEnum>>);
+
+ InIntType inEnumIndex = static_cast<InIntType>(e);
+ OutEnum outEnum = static_cast<OutEnum>(inEnumIndex);
+ if (std::find(range.begin(), range.end(), outEnum) == range.end()) {
+ return ::android::base::unexpected(BAD_VALUE);
+ }
+ return outEnum;
+}
+
+template<typename NdkEnum, typename CppEnum>
+ConversionResult<NdkEnum> cpp2ndk_Enum(CppEnum e) {
+ return convertEnum<NdkEnum>(::ndk::enum_range<NdkEnum>(), e);
+}
+
+template<typename CppEnum, typename NdkEnum>
+ConversionResult<CppEnum> ndk2cpp_Enum(NdkEnum e) {
+ return convertEnum<CppEnum>(::android::enum_range<CppEnum>(), e);
+}
+
+ConversionResult<android::media::audio::common::AudioDeviceAddress>
+ndk2cpp_AudioDeviceAddress(const AudioDeviceAddress& ndk) {
+ using CppTag = android::media::audio::common::AudioDeviceAddress::Tag;
+ using NdkTag = AudioDeviceAddress::Tag;
+
+ CppTag cppTag = VALUE_OR_RETURN(ndk2cpp_Enum<CppTag>(ndk.getTag()));
+
+ switch (cppTag) {
+ case CppTag::id:
+ return android::media::audio::common::AudioDeviceAddress::make<CppTag::id>(
+ ndk.get<NdkTag::id>());
+ case CppTag::mac:
+ return android::media::audio::common::AudioDeviceAddress::make<CppTag::mac>(
+ ndk.get<NdkTag::mac>());
+ case CppTag::ipv4:
+ return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv4>(
+ ndk.get<NdkTag::ipv4>());
+ case CppTag::ipv6:
+ return android::media::audio::common::AudioDeviceAddress::make<CppTag::ipv6>(
+ ndk.get<NdkTag::ipv6>());
+ case CppTag::alsa:
+ return android::media::audio::common::AudioDeviceAddress::make<CppTag::alsa>(
+ ndk.get<NdkTag::alsa>());
+ }
+
+ return ::android::base::unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::audio::common::AudioDevice> ndk2cpp_AudioDevice(const AudioDevice& ndk) {
+ media::audio::common::AudioDevice cpp;
+ cpp.type.type = VALUE_OR_RETURN(
+ ndk2cpp_Enum<media::audio::common::AudioDeviceType>(ndk.type.type));
+ cpp.type.connection = ndk.type.connection;
+ cpp.address = VALUE_OR_RETURN(ndk2cpp_AudioDeviceAddress(ndk.address));
+ return cpp;
+}
+
+ConversionResult<media::audio::common::AudioMMapPolicyInfo>
+ndk2cpp_AudioMMapPolicyInfo(const AudioMMapPolicyInfo& ndk) {
+ media::audio::common::AudioMMapPolicyInfo cpp;
+ cpp.device = VALUE_OR_RETURN(ndk2cpp_AudioDevice(ndk.device));
+ cpp.mmapPolicy = VALUE_OR_RETURN(
+ ndk2cpp_Enum<media::audio::common::AudioMMapPolicy>(ndk.mmapPolicy));
+ return cpp;
+}
+
} // namespace
status_t DeviceHalAidl::getSupportedDevices(uint32_t*) {
@@ -116,6 +197,7 @@
}
ALOGI("%s: module %s default port ids: input %d, output %d",
__func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId);
+ RETURN_STATUS_IF_ERROR(updateRoutes());
std::vector<AudioPortConfig> portConfigs;
RETURN_STATUS_IF_ERROR(
statusTFromBinderStatus(mModule->getAudioPortConfigs(&portConfigs))); // OK if empty
@@ -257,9 +339,9 @@
AudioPortConfig mixPortConfig;
Cleanups cleanups;
audio_config writableConfig = *config;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(0 /*handle*/, aidlDevice, aidlFlags, aidlSource,
- &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ &writableConfig, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
*size = aidlConfig.frameCount *
getFrameSizeInBytes(aidlConfig.base.format, aidlConfig.base.channelMask);
// Do not disarm cleanups to release temporary port configs.
@@ -270,7 +352,11 @@
int32_t aidlHandle, const AudioDevice& aidlDevice, const AudioIoFlags& aidlFlags,
AudioSource aidlSource, struct audio_config* config,
Cleanups* cleanups, AudioConfig* aidlConfig, AudioPortConfig* mixPortConfig,
- int32_t* nominalLatency) {
+ AudioPatch* aidlPatch) {
+ ALOGD("%p %s::%s: handle %d, device %s, flags %s, source %s, config %s, mix port config %s",
+ this, getClassName().c_str(), __func__, aidlHandle, aidlDevice.toString().c_str(),
+ aidlFlags.toString().c_str(), toString(aidlSource).c_str(),
+ aidlConfig->toString().c_str(), mixPortConfig->toString().c_str());
const bool isInput = aidlFlags.getTag() == AudioIoFlags::Tag::input;
// Find / create AudioPortConfigs for the device port and the mix port,
// then find / create a patch between them, and open a stream on the mix port.
@@ -281,25 +367,23 @@
cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, devicePortConfig.id);
}
RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(*aidlConfig, aidlFlags, aidlHandle, aidlSource,
- mixPortConfig, &created));
+ std::set<int32_t>{devicePortConfig.portId}, mixPortConfig, &created));
if (created) {
cleanups->emplace_front(this, &DeviceHalAidl::resetPortConfig, mixPortConfig->id);
}
setConfigFromPortConfig(aidlConfig, *mixPortConfig);
- AudioPatch patch;
if (isInput) {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {devicePortConfig.id}, {mixPortConfig->id}, &patch, &created));
+ {devicePortConfig.id}, {mixPortConfig->id}, aidlPatch, &created));
} else {
RETURN_STATUS_IF_ERROR(findOrCreatePatch(
- {mixPortConfig->id}, {devicePortConfig.id}, &patch, &created));
+ {mixPortConfig->id}, {devicePortConfig.id}, aidlPatch, &created));
}
if (created) {
- cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, patch.id);
+ cleanups->emplace_front(this, &DeviceHalAidl::resetPatch, aidlPatch->id);
}
- *nominalLatency = patch.latenciesMs[0];
if (aidlConfig->frameCount <= 0) {
- aidlConfig->frameCount = patch.minimumStreamBufferSizeFrames;
+ aidlConfig->frameCount = aidlPatch->minimumStreamBufferSizeFrames;
}
*config = VALUE_OR_RETURN_STATUS(
::aidl::android::aidl2legacy_AudioConfig_audio_config_t(*aidlConfig, isInput));
@@ -445,10 +529,10 @@
AudioIoFlags aidlFlags = AudioIoFlags::make<AudioIoFlags::Tag::output>(aidlOutputFlags);
AudioPortConfig mixPortConfig;
Cleanups cleanups;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags,
AudioSource::SYS_RESERVED_INVALID /*only needed for input*/,
- config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
::aidl::android::hardware::audio::core::IModule::OpenOutputStreamArguments args;
args.portConfigId = mixPortConfig.id;
const bool isOffload = isBitPositionFlagSet(
@@ -472,8 +556,9 @@
__func__, ret.desc.toString().c_str());
return NO_INIT;
}
- *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), nominalLatency,
+ *outStream = sp<StreamOutHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), this /*callbackBroker*/);
+ mStreams.insert(std::pair(*outStream, aidlPatch.id));
void* cbCookie = (*outStream).get();
{
std::lock_guard l(mLock);
@@ -510,9 +595,9 @@
::aidl::android::legacy2aidl_audio_source_t_AudioSource(source));
AudioPortConfig mixPortConfig;
Cleanups cleanups;
- int32_t nominalLatency;
+ AudioPatch aidlPatch;
RETURN_STATUS_IF_ERROR(prepareToOpenStream(aidlHandle, aidlDevice, aidlFlags, aidlSource,
- config, &cleanups, &aidlConfig, &mixPortConfig, &nominalLatency));
+ config, &cleanups, &aidlConfig, &mixPortConfig, &aidlPatch));
::aidl::android::hardware::audio::core::IModule::OpenInputStreamArguments args;
args.portConfigId = mixPortConfig.id;
RecordTrackMetadata aidlTrackMetadata{
@@ -532,8 +617,9 @@
__func__, ret.desc.toString().c_str());
return NO_INIT;
}
- *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), nominalLatency,
+ *inStream = sp<StreamInHalAidl>::make(*config, std::move(context), aidlPatch.latenciesMs[0],
std::move(ret.stream), this /*micInfoProvider*/);
+ mStreams.insert(std::pair(*inStream, aidlPatch.id));
cleanups.disarmAll();
return OK;
}
@@ -601,20 +687,41 @@
__func__, ::android::internal::ToString(aidlSources).c_str(),
::android::internal::ToString(aidlSinks).c_str());
auto fillPortConfigs = [&](
- const std::vector<AudioPortConfig>& configs, std::vector<int32_t>* ids) -> status_t {
+ const std::vector<AudioPortConfig>& configs,
+ const std::set<int32_t>& destinationPortIds,
+ std::vector<int32_t>* ids, std::set<int32_t>* portIds) -> status_t {
for (const auto& s : configs) {
AudioPortConfig portConfig;
bool created = false;
- RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(s, &portConfig, &created));
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+ s, destinationPortIds, &portConfig, &created));
if (created) {
cleanups.emplace_front(this, &DeviceHalAidl::resetPortConfig, portConfig.id);
}
ids->push_back(portConfig.id);
+ if (portIds != nullptr) {
+ portIds->insert(portConfig.portId);
+ }
}
return OK;
};
- RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSources, &aidlPatch.sourcePortConfigIds));
- RETURN_STATUS_IF_ERROR(fillPortConfigs(aidlSinks, &aidlPatch.sinkPortConfigIds));
+ // When looking up port configs, the destinationPortId is only used for mix ports.
+ // Thus, we process device port configs first, and look up the destination port ID from them.
+ bool sourceIsDevice = std::any_of(aidlSources.begin(), aidlSources.end(),
+ [](const auto& config) { return config.ext.getTag() == AudioPortExt::device; });
+ const std::vector<AudioPortConfig>& devicePortConfigs =
+ sourceIsDevice ? aidlSources : aidlSinks;
+ std::vector<int32_t>* devicePortConfigIds =
+ sourceIsDevice ? &aidlPatch.sourcePortConfigIds : &aidlPatch.sinkPortConfigIds;
+ const std::vector<AudioPortConfig>& mixPortConfigs =
+ sourceIsDevice ? aidlSinks : aidlSources;
+ std::vector<int32_t>* mixPortConfigIds =
+ sourceIsDevice ? &aidlPatch.sinkPortConfigIds : &aidlPatch.sourcePortConfigIds;
+ std::set<int32_t> devicePortIds;
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(
+ devicePortConfigs, std::set<int32_t>(), devicePortConfigIds, &devicePortIds));
+ RETURN_STATUS_IF_ERROR(fillPortConfigs(
+ mixPortConfigs, devicePortIds, mixPortConfigIds, nullptr));
if (existingPatchIt != mPatches.end()) {
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
mModule->setAudioPatch(aidlPatch, &aidlPatch)));
@@ -649,22 +756,68 @@
return OK;
}
-status_t DeviceHalAidl::getAudioPort(struct audio_port* port __unused) {
- TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port __unused) {
- TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return INVALID_OPERATION;
-}
-
-status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config __unused) {
+status_t DeviceHalAidl::getAudioPort(struct audio_port* port) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mModule) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ audio_port_v7 portV7;
+ audio_populate_audio_port_v7(port, &portV7);
+ RETURN_STATUS_IF_ERROR(getAudioPort(&portV7));
+ return audio_populate_audio_port(&portV7, port) ? OK : BAD_VALUE;
+}
+
+status_t DeviceHalAidl::getAudioPort(struct audio_port_v7 *port) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(port->role, port->type)) ==
+ ::aidl::android::AudioPortDirection::INPUT;
+ auto 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;
+ }
+ const auto& matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ // It seems that we don't have to call HAL since all valid ports have been added either
+ // during initialization, or while handling connection of an external device.
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGE("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ const int32_t fwkId = aidlPort.id;
+ aidlPort = portsIt->second;
+ aidlPort.id = fwkId;
+ *port = VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioPort_audio_port_v7(
+ aidlPort, isInput));
+ return OK;
+}
+
+status_t DeviceHalAidl::setAudioPortConfig(const struct audio_port_config* config) {
+ ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (config == nullptr) {
+ return BAD_VALUE;
+ }
+ bool isInput = VALUE_OR_RETURN_STATUS(::aidl::android::portDirection(
+ config->role, config->type)) == ::aidl::android::AudioPortDirection::INPUT;
+ AudioPortConfig requestedPortConfig = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::legacy2aidl_audio_port_config_AudioPortConfig(
+ *config, isInput, 0 /*portId*/));
+ AudioPortConfig portConfig;
+ bool created = false;
+ RETURN_STATUS_IF_ERROR(findOrCreatePortConfig(
+ requestedPortConfig, std::set<int32_t>(), &portConfig, &created));
return OK;
}
@@ -732,23 +885,41 @@
}
status_t DeviceHalAidl::getMmapPolicyInfos(
- media::audio::common::AudioMMapPolicyType policyType __unused,
- std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos __unused) {
+ media::audio::common::AudioMMapPolicyType policyType,
+ std::vector<media::audio::common::AudioMMapPolicyInfo>* policyInfos) {
TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
+ AudioMMapPolicyType mmapPolicyType =
+ VALUE_OR_RETURN_STATUS(cpp2ndk_Enum<AudioMMapPolicyType>(policyType));
+
+ std::vector<AudioMMapPolicyInfo> mmapPolicyInfos;
+
+ if (status_t status = statusTFromBinderStatus(
+ mModule->getMmapPolicyInfos(mmapPolicyType, &mmapPolicyInfos)); status != OK) {
+ return status;
+ }
+
+ *policyInfos = VALUE_OR_RETURN_STATUS(
+ convertContainer<std::vector<media::audio::common::AudioMMapPolicyInfo>>(
+ mmapPolicyInfos, ndk2cpp_AudioMMapPolicyInfo));
return OK;
}
int32_t DeviceHalAidl::getAAudioMixerBurstCount() {
TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return OK;
+ int32_t mixerBurstCount = 0;
+ if (mModule->getAAudioMixerBurstCount(&mixerBurstCount).isOk()) {
+ return mixerBurstCount;
+ }
+ return 0;
}
int32_t DeviceHalAidl::getAAudioHardwareBurstMinUsec() {
TIME_CHECK();
- ALOGE("%s not implemented yet", __func__);
- return OK;
+ int32_t hardwareBurstMinUsec = 0;
+ if (mModule->getAAudioHardwareBurstMinUsec(&hardwareBurstMinUsec).isOk()) {
+ return hardwareBurstMinUsec;
+ }
+ return 0;
}
error::Result<audio_hw_sync_t> DeviceHalAidl::getHwAvSync() {
@@ -764,7 +935,7 @@
TIME_CHECK();
if (!mModule) return NO_INIT;
return mModule->dump(fd, Args(args).args(), args.size());
-};
+}
int32_t DeviceHalAidl::supportsBluetoothVariableLatency(bool* supports __unused) {
TIME_CHECK();
@@ -792,6 +963,73 @@
return OK;
}
+status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ if (port == nullptr) {
+ return BAD_VALUE;
+ }
+ 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;
+ }
+ if (connected) {
+ AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ // Reset the device address to find the "template" port.
+ matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>();
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGW("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ // Use the ID of the "template" port, use all the information from the provided port.
+ aidlPort.id = portsIt->first;
+ AudioPort connectedPort;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice(
+ aidlPort, &connectedPort)));
+ const auto [it, inserted] = mPorts.insert(std::make_pair(connectedPort.id, connectedPort));
+ LOG_ALWAYS_FATAL_IF(!inserted,
+ "%s: module %s, duplicate port ID received from HAL: %s, existing port: %s",
+ __func__, mInstance.c_str(), connectedPort.toString().c_str(),
+ it->second.toString().c_str());
+ } else { // !connected
+ AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device;
+ auto portsIt = findPort(matchDevice);
+ if (portsIt == mPorts.end()) {
+ ALOGW("%s: device port for device %s is not found in the module %s",
+ __func__, matchDevice.toString().c_str(), mInstance.c_str());
+ return BAD_VALUE;
+ }
+ // Any streams opened on the external device must be closed by this time,
+ // thus we can clean up patches and port configs that were created for them.
+ resetUnusedPatchesAndPortConfigs();
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice(
+ portsIt->second.id)));
+ mPorts.erase(portsIt);
+ }
+ return updateRoutes();
+}
+
+status_t DeviceHalAidl::setSimulateDeviceConnections(bool enabled) {
+ TIME_CHECK();
+ if (!mModule) return NO_INIT;
+ ModuleDebug debug{ .simulateDeviceConnections = enabled };
+ status_t status = statusTFromBinderStatus(mModule->setModuleDebug(debug));
+ // This is important to log as it affects HAL behavior.
+ if (status == OK) {
+ ALOGI("%s: set enabled: %d", __func__, enabled);
+ } else {
+ ALOGW("%s: set enabled to %d failed: %d", __func__, enabled, status);
+ }
+ return status;
+}
+
bool DeviceHalAidl::audioDeviceMatches(const AudioDevice& device, const AudioPort& p) {
if (p.ext.getTag() != AudioPortExt::Tag::device) return false;
return p.ext.get<AudioPortExt::Tag::device>().device == device;
@@ -807,8 +1045,8 @@
return p.ext.get<AudioPortExt::Tag::device>().device == device;
}
-status_t DeviceHalAidl::createPortConfig(
- const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result) {
+status_t DeviceHalAidl::createOrUpdatePortConfig(
+ const AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool* created) {
TIME_CHECK();
AudioPortConfig appliedPortConfig;
bool applied = false;
@@ -823,11 +1061,17 @@
return NO_INIT;
}
}
- auto id = appliedPortConfig.id;
- auto [it, inserted] = mPortConfigs.emplace(std::move(id), std::move(appliedPortConfig));
- LOG_ALWAYS_FATAL_IF(!inserted, "%s: port config with id %d already exists",
- __func__, it->first);
+
+ int32_t id = appliedPortConfig.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;
+ *created = inserted;
return OK;
}
@@ -874,8 +1118,8 @@
}
AudioPortConfig requestedPortConfig;
requestedPortConfig.portId = portsIt->first;
- RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
- *created = true;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
} else {
*created = false;
}
@@ -885,7 +1129,8 @@
status_t DeviceHalAidl::findOrCreatePortConfig(
const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
- AudioSource source, AudioPortConfig* portConfig, bool* created) {
+ 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 };
@@ -893,7 +1138,7 @@
if (portConfigIt == mPortConfigs.end() && flags.has_value()) {
auto optionalInputFlagsIt = kOptionalInputFlags.begin();
AudioIoFlags matchFlags = flags.value();
- auto portsIt = findPort(config, matchFlags);
+ auto portsIt = findPort(config, matchFlags, destinationPortIds);
while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
&& optionalInputFlagsIt != kOptionalInputFlags.end()) {
if (!isBitPositionFlagSet(
@@ -903,7 +1148,7 @@
}
matchFlags.set<AudioIoFlags::Tag::input>(matchFlags.get<AudioIoFlags::Tag::input>() &
~makeBitPositionFlagMask(*optionalInputFlagsIt++));
- portsIt = findPort(config, matchFlags);
+ portsIt = findPort(config, matchFlags, destinationPortIds);
ALOGI("%s: mix port for config %s, flags %s was not found in the module %s, "
"retried with flags %s", __func__, config.toString().c_str(),
flags.value().toString().c_str(), mInstance.c_str(),
@@ -924,22 +1169,37 @@
requestedPortConfig.ext.get<AudioPortExt::Tag::mix>().usecase =
AudioPortMixExtUseCase::make<AudioPortMixExtUseCase::Tag::source>(source);
}
- RETURN_STATUS_IF_ERROR(createPortConfig(requestedPortConfig, &portConfigIt));
- *created = true;
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
} else if (!flags.has_value()) {
ALOGW("%s: mix port config for %s, handle %d not found in the module %s, "
"and was not created as flags are not specified",
__func__, config.toString().c_str(), ioHandle, mInstance.c_str());
return BAD_VALUE;
} else {
- *created = false;
+ 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;
+ }
+ }
+
+ if (requestedPortConfig != portConfigIt->second) {
+ RETURN_STATUS_IF_ERROR(createOrUpdatePortConfig(requestedPortConfig, &portConfigIt,
+ created));
+ } else {
+ *created = false;
+ }
}
*portConfig = portConfigIt->second;
return OK;
}
status_t DeviceHalAidl::findOrCreatePortConfig(
- const AudioPortConfig& requestedPortConfig, AudioPortConfig* portConfig, bool* created) {
+ const AudioPortConfig& requestedPortConfig, const std::set<int32_t>& destinationPortIds,
+ AudioPortConfig* portConfig, bool* created) {
using Tag = AudioPortExt::Tag;
if (requestedPortConfig.ext.getTag() == Tag::mix) {
if (const auto& p = requestedPortConfig;
@@ -956,7 +1216,8 @@
requestedPortConfig.ext.get<Tag::mix>().usecase.
get<AudioPortMixExtUseCase::Tag::source>() : AudioSource::SYS_RESERVED_INVALID;
return findOrCreatePortConfig(config, requestedPortConfig.flags,
- requestedPortConfig.ext.get<Tag::mix>().handle, source, portConfig, created);
+ 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, portConfig, created);
@@ -988,20 +1249,30 @@
[&](const auto& pair) { return audioDeviceMatches(device, pair.second); });
}
+
DeviceHalAidl::Ports::iterator DeviceHalAidl::findPort(
- const AudioConfig& config, const AudioIoFlags& flags) {
+ const AudioConfig& config, const AudioIoFlags& flags,
+ const std::set<int32_t>& destinationPortIds) {
+ auto belongsToProfile = [&config](const AudioProfile& prof) {
+ return (isDefaultAudioFormat(config.base.format) || prof.format == config.base.format) &&
+ (config.base.channelMask.getTag() == AudioChannelLayout::none ||
+ std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
+ config.base.channelMask) != prof.channelMasks.end()) &&
+ (config.base.sampleRate == 0 ||
+ std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
+ config.base.sampleRate) != prof.sampleRates.end());
+ };
auto matcher = [&](const auto& pair) {
const auto& p = pair.second;
return p.ext.getTag() == AudioPortExt::Tag::mix &&
p.flags == flags &&
- std::find_if(p.profiles.begin(), p.profiles.end(),
- [&](const auto& prof) {
- return prof.format == config.base.format &&
- std::find(prof.channelMasks.begin(), prof.channelMasks.end(),
- config.base.channelMask) != prof.channelMasks.end() &&
- std::find(prof.sampleRates.begin(), prof.sampleRates.end(),
- config.base.sampleRate) != prof.sampleRates.end();
- }) != p.profiles.end(); };
+ (destinationPortIds.empty() ||
+ std::any_of(destinationPortIds.begin(), destinationPortIds.end(),
+ [&](const int32_t destId) { return mRoutingMatrix.count(
+ std::make_pair(p.id, destId)) != 0; })) &&
+ (p.profiles.empty() ||
+ std::find_if(p.profiles.begin(), p.profiles.end(), belongsToProfile) !=
+ p.profiles.end()); };
return std::find_if(mPorts.begin(), mPorts.end(), matcher);
}
@@ -1026,34 +1297,7 @@
(!flags.has_value() || p.flags.value() == flags.value()) &&
p.ext.template get<Tag::mix>().handle == ioHandle; });
}
-/*
-DeviceHalAidl::PortConfigs::iterator DeviceHalAidl::findPortConfig(
- const AudioPortConfig& portConfig) {
- using Tag = AudioPortExt::Tag;
- if (portConfig.ext.getTag() == Tag::mix) {
- return std::find_if(mPortConfigs.begin(), mPortConfigs.end(),
- [&](const auto& pair) {
- const auto& p = pair.second;
- LOG_ALWAYS_FATAL_IF(p.ext.getTag() == Tag::mix &&
- !p.sampleRate.has_value() || !p.channelMask.has_value() ||
- !p.format.has_value() || !p.flags.has_value(),
- "%s: stored mix port config is not fully specified: %s",
- __func__, p.toString().c_str());
- return p.ext.getTag() == Tag::mix &&
- (!portConfig.sampleRate.has_value() ||
- p.sampleRate == portConfig.sampleRate) &&
- (!portConfig.channelMask.has_value() ||
- p.channelMask == portConfig.channelMask) &&
- (!portConfig.format.has_value() || p.format == portConfig.format) &&
- (!portConfig.flags.has_value() || p.flags == portConfig.flags) &&
- p.ext.template get<Tag::mix>().handle ==
- portConfig.ext.template get<Tag::mix>().handle; });
- } else if (portConfig.ext.getTag() == Tag::device) {
- return findPortConfig(portConfig.ext.get<Tag::device>().device);
- }
- return mPortConfigs.end();
-}
-*/
+
void DeviceHalAidl::resetPatch(int32_t patchId) {
if (auto it = mPatches.find(patchId); it != mPatches.end()) {
mPatches.erase(it);
@@ -1081,6 +1325,56 @@
ALOGE("%s: port config id %d not found", __func__, portConfigId);
}
+void DeviceHalAidl::resetUnusedPatches() {
+ // Since patches can be created independently of streams via 'createAudioPatch',
+ // here we only clean up patches for released streams.
+ for (auto it = mStreams.begin(); it != mStreams.end(); ) {
+ if (auto streamSp = it->first.promote(); streamSp) {
+ ++it;
+ } else {
+ resetPatch(it->second);
+ it = mStreams.erase(it);
+ }
+ }
+}
+
+void DeviceHalAidl::resetUnusedPatchesAndPortConfigs() {
+ resetUnusedPatches();
+ resetUnusedPortConfigs();
+}
+
+void DeviceHalAidl::resetUnusedPortConfigs() {
+ // 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.
+ std::set<int32_t> portConfigIds;
+ std::transform(mPortConfigs.begin(), mPortConfigs.end(),
+ std::inserter(portConfigIds, portConfigIds.end()),
+ [](const auto& pcPair) { return pcPair.first; });
+ for (const auto& p : mPatches) {
+ for (int32_t id : p.second.sourcePortConfigIds) portConfigIds.erase(id);
+ for (int32_t id : p.second.sinkPortConfigIds) portConfigIds.erase(id);
+ }
+ for (int32_t id : portConfigIds) resetPortConfig(id);
+}
+
+status_t DeviceHalAidl::updateRoutes() {
+ TIME_CHECK();
+ std::vector<AudioRoute> routes;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mModule->getAudioRoutes(&routes)));
+ ALOGW_IF(routes.empty(), "%s: module %s returned an empty list of audio routes",
+ __func__, mInstance.c_str());
+ mRoutingMatrix.clear();
+ for (const auto& r : routes) {
+ for (auto portId : r.sourcePortIds) {
+ mRoutingMatrix.emplace(r.sinkPortId, portId);
+ mRoutingMatrix.emplace(portId, r.sinkPortId);
+ }
+ }
+ return OK;
+}
+
void DeviceHalAidl::clearCallbacks(void* cookie) {
std::lock_guard l(mLock);
mCallbacks.erase(cookie);
diff --git a/media/libaudiohal/impl/DeviceHalAidl.h b/media/libaudiohal/impl/DeviceHalAidl.h
index 9687ec9..e4d5ec6 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.h
+++ b/media/libaudiohal/impl/DeviceHalAidl.h
@@ -25,6 +25,7 @@
#include <android-base/thread_annotations.h>
#include <media/audiohal/DeviceHalInterface.h>
#include <media/audiohal/EffectHalInterface.h>
+#include <media/audiohal/StreamHalInterface.h>
#include "ConversionHelperAidl.h"
@@ -139,7 +140,7 @@
status_t setAudioPortConfig(const struct audio_port_config* config) override;
// List microphones
- status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones);
+ status_t getMicrophones(std::vector<audio_microphone_characteristic_t>* microphones) override;
status_t addDeviceEffect(audio_port_handle_t device, sp<EffectHalInterface> effect) override;
@@ -155,13 +156,17 @@
error::Result<audio_hw_sync_t> getHwAvSync() override;
- status_t dump(int __unused, const Vector<String16>& __unused) override;
-
int32_t supportsBluetoothVariableLatency(bool* supports __unused) override;
status_t getSoundDoseInterface(const std::string& module,
::ndk::SpAIBinder* soundDoseBinder) override;
+ status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+
+ status_t setSimulateDeviceConnections(bool enabled) override;
+
+ status_t dump(int __unused, const Vector<String16>& __unused) override;
+
private:
friend class sp<DeviceHalAidl>;
@@ -180,6 +185,10 @@
using PortConfigs = std::map<int32_t /*port config ID*/,
::aidl::android::media::audio::common::AudioPortConfig>;
using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>;
+ // Answers the question "whether portID 'first' is reachable from portID 'second'?"
+ // It's not a map because both portIDs are known. The matrix is symmetric.
+ using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>;
+ using Streams = std::map<wp<StreamHalInterface>, int32_t /*patch ID*/>;
class Cleanups;
// Must not be constructed directly by clients.
@@ -194,9 +203,9 @@
const ::aidl::android::media::audio::common::AudioPort& p);
bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device,
const ::aidl::android::media::audio::common::AudioPortConfig& p);
- status_t createPortConfig(
+ status_t createOrUpdatePortConfig(
const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig,
- PortConfigs::iterator* result);
+ PortConfigs::iterator* result, bool *created);
status_t findOrCreatePatch(
const std::set<int32_t>& sourcePortConfigIds,
const std::set<int32_t>& sinkPortConfigIds,
@@ -213,25 +222,25 @@
const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
int32_t ioHandle,
::aidl::android::media::audio::common::AudioSource aidlSource,
+ 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);
Ports::iterator findPort(
const ::aidl::android::media::audio::common::AudioConfig& config,
- const ::aidl::android::media::audio::common::AudioIoFlags& flags);
+ const ::aidl::android::media::audio::common::AudioIoFlags& flags,
+ const std::set<int32_t>& destinationPortIds);
PortConfigs::iterator findPortConfig(
const ::aidl::android::media::audio::common::AudioDevice& device);
PortConfigs::iterator findPortConfig(
const ::aidl::android::media::audio::common::AudioConfig& config,
const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags,
int32_t ioHandle);
- // Currently unused but may be useful for implementing setAudioPortConfig
- // PortConfigs::iterator findPortConfig(
- // const ::aidl::android::media::audio::common::AudioPortConfig& portConfig);
status_t prepareToOpenStream(
int32_t aidlHandle,
const ::aidl::android::media::audio::common::AudioDevice& aidlDevice,
@@ -241,9 +250,13 @@
Cleanups* cleanups,
::aidl::android::media::audio::common::AudioConfig* aidlConfig,
::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig,
- int32_t* nominalLatency);
+ ::aidl::android::hardware::audio::core::AudioPatch* aidlPatch);
void resetPatch(int32_t patchId);
void resetPortConfig(int32_t portConfigId);
+ void resetUnusedPatches();
+ void resetUnusedPatchesAndPortConfigs();
+ void resetUnusedPortConfigs();
+ status_t updateRoutes();
// CallbackBroker implementation
void clearCallbacks(void* cookie) override;
@@ -272,6 +285,8 @@
int32_t mDefaultOutputPortId = -1;
PortConfigs mPortConfigs;
Patches mPatches;
+ RoutingMatrix mRoutingMatrix;
+ Streams mStreams;
Microphones mMicrophones;
std::mutex mLock;
std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock);
diff --git a/media/libaudiohal/impl/DeviceHalHidl.h b/media/libaudiohal/impl/DeviceHalHidl.h
index 30fbd6d..afaad51 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.h
+++ b/media/libaudiohal/impl/DeviceHalHidl.h
@@ -126,6 +126,11 @@
status_t setConnectedState(const struct audio_port_v7 *port, bool connected) override;
+ status_t setSimulateDeviceConnections(bool enabled __unused) override {
+ // Only supported by AIDL HALs.
+ return INVALID_OPERATION;
+ }
+
error::Result<audio_hw_sync_t> getHwAvSync() override;
status_t dump(int fd, const Vector<String16>& args) override;
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index 519b871..5ab7c84 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -29,6 +29,7 @@
#include <utils/Log.h>
#include "EffectConversionHelperAidl.h"
+#include "EffectProxy.h"
namespace android {
namespace effect {
@@ -37,7 +38,9 @@
using ::aidl::android::hardware::audio::effect::CommandId;
using ::aidl::android::hardware::audio::effect::Descriptor;
using ::aidl::android::hardware::audio::effect::Flags;
+using ::aidl::android::hardware::audio::effect::IEffect;
using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::State;
using ::aidl::android::media::audio::common::AudioDeviceDescription;
using ::aidl::android::media::audio::common::AudioMode;
using ::aidl::android::media::audio::common::AudioSource;
@@ -72,7 +75,9 @@
mIoId(ioId),
mDesc(desc),
mEffect(std::move(effect)),
- mIsInputStream(mDesc.common.flags.type == Flags::Type::PRE_PROC) {
+ mIsInputStream(mDesc.common.flags.type == Flags::Type::PRE_PROC),
+ mIsProxyEffect(mDesc.common.id.proxy.has_value() &&
+ mDesc.common.id.proxy.value() == mDesc.common.id.uuid) {
mCommon.session = sessionId;
mCommon.ioHandle = ioId;
mCommon.input = mCommon.output = kDefaultAudioConfig;
@@ -96,8 +101,8 @@
return BAD_VALUE;
}
- return *(status_t*)pReplyData =
- statusTFromBinderStatus(mEffect->open(mCommon, std::nullopt, &mOpenReturn));
+ // Do nothing for EFFECT_CMD_INIT, call IEffect.open() with EFFECT_CMD_SET_CONFIG
+ return *(status_t*)pReplyData = OK;
}
status_t EffectConversionHelperAidl::handleSetParameter(uint32_t cmdSize, const void* pCmdData,
@@ -154,22 +159,55 @@
}
effect_config_t* config = (effect_config_t*)pCmdData;
- Parameter::Common aidlCommon = {
- .session = mSessionId,
- .ioHandle = mIoId,
- .input = {.base = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
- config->inputCfg, mIsInputStream))},
- .output = {.base = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_buffer_config_t_AudioConfigBase(
- config->outputCfg, mIsInputStream))}};
+ Parameter::Common common = {
+ .input =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfig(
+ config->inputCfg, mIsInputStream)),
+ .output =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_buffer_config_t_AudioConfig(
+ config->outputCfg, mIsInputStream)),
+ .session = mCommon.session,
+ .ioHandle = mCommon.ioHandle};
- Parameter aidlParam = UNION_MAKE(Parameter, common, aidlCommon);
+ 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, closing effect", __func__,
+ android::internal::ToString(state).c_str());
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->close()));
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->getState(&state)));
+ mStatusQ.reset();
+ mInputQ.reset();
+ mOutputQ.reset();
+ }
- status_t ret = statusTFromBinderStatus(mEffect->setParameter(aidlParam));
- EffectParamWriter writer(*(effect_param_t*)pReplyData);
- writer.setStatus(ret);
- return ret;
+ if (state == State::INIT) {
+ ALOGI("%s at state %s, opening effect", __func__,
+ android::internal::ToString(state).c_str());
+ IEffect::OpenEffectReturn openReturn;
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mEffect->open(common, std::nullopt, &openReturn)));
+
+ if (mIsProxyEffect) {
+ const auto& ret =
+ std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam();
+ mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ);
+ mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ);
+ mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ);
+ } else {
+ mStatusQ = std::make_shared<StatusMQ>(openReturn.statusMQ);
+ mInputQ = std::make_shared<DataMQ>(openReturn.inputDataMQ);
+ mOutputQ = std::make_shared<DataMQ>(openReturn.outputDataMQ);
+ }
+ mCommon = common;
+ } else if (mCommon != common) {
+ ALOGI("%s at state %s, setParameter", __func__, android::internal::ToString(state).c_str());
+ Parameter aidlParam = UNION_MAKE(Parameter, common, mCommon);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mEffect->setParameter(aidlParam)));
+ }
+
+ return *static_cast<int32_t*>(pReplyData) = OK;
}
status_t EffectConversionHelperAidl::handleGetConfig(uint32_t cmdSize __unused,
@@ -187,11 +225,9 @@
const auto& common = param.get<Parameter::common>();
effect_config_t* pConfig = (effect_config_t*)pReplyData;
pConfig->inputCfg = VALUE_OR_RETURN_STATUS(
- ::aidl::android::aidl2legacy_AudioConfigBase_buffer_config_t(common.input.base, true));
- pConfig->outputCfg =
- VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_AudioConfigBase_buffer_config_t(
- common.output.base, false));
- mCommon = common;
+ ::aidl::android::aidl2legacy_AudioConfig_buffer_config_t(common.input, true));
+ pConfig->outputCfg = VALUE_OR_RETURN_STATUS(
+ ::aidl::android::aidl2legacy_AudioConfig_buffer_config_t(common.output, false));
return OK;
}
@@ -294,7 +330,20 @@
pReplyData);
return BAD_VALUE;
}
- // TODO: handle this after effectproxy implemented in libaudiohal
+ effect_offload_param_t* offload = (effect_offload_param_t*)pCmdData;
+ // send to proxy to update active sub-effect
+ if (mIsProxyEffect) {
+ ALOGI("%s offload param offload %s ioHandle %d", __func__,
+ offload->isOffload ? "true" : "false", offload->ioHandle);
+ mCommon.ioHandle = offload->ioHandle;
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(
+ std::static_pointer_cast<EffectProxy>(mEffect)->setOffloadParam(offload)));
+ // update FMQs
+ const auto& ret = std::static_pointer_cast<EffectProxy>(mEffect)->getEffectReturnParam();
+ mStatusQ = std::make_shared<StatusMQ>(ret->statusMQ);
+ mInputQ = std::make_shared<DataMQ>(ret->inputDataMQ);
+ mOutputQ = std::make_shared<DataMQ>(ret->outputDataMQ);
+ }
return *static_cast<int32_t*>(pReplyData) = OK;
}
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 54df1b8..1200264 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -19,6 +19,7 @@
#include <utils/Errors.h>
#include <aidl/android/hardware/audio/effect/BpEffect.h>
+#include <fmq/AidlMessageQueue.h>
#include <system/audio_effect.h>
#include <system/audio_effects/audio_effects_utils.h>
@@ -30,10 +31,15 @@
status_t handleCommand(uint32_t cmdCode, uint32_t cmdSize, void* pCmdData, uint32_t* replySize,
void* pReplyData);
virtual ~EffectConversionHelperAidl() {}
- const ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn&
- getEffectReturnParam() const {
- return mOpenReturn;
- }
+
+ using StatusMQ = ::android::AidlMessageQueue<
+ ::aidl::android::hardware::audio::effect::IEffect::Status,
+ ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
+ using DataMQ = ::android::AidlMessageQueue<
+ float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
+ std::shared_ptr<StatusMQ> getStatusMQ() { return mStatusQ; }
+ std::shared_ptr<DataMQ> getInputMQ() { return mInputQ; }
+ std::shared_ptr<DataMQ> getOutputMQ() { return mOutputQ; }
protected:
const int32_t mSessionId;
@@ -42,7 +48,6 @@
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> mEffect;
// whether the effect is instantiated on an input stream
const bool mIsInputStream;
- ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn mOpenReturn;
::aidl::android::hardware::audio::effect::Parameter::Common mCommon;
EffectConversionHelperAidl(
@@ -59,6 +64,7 @@
const aidl::android::media::audio::common::AudioFormatDescription kDefaultFormatDescription = {
.type = aidl::android::media::audio::common::AudioFormatType::PCM,
.pcm = aidl::android::media::audio::common::PcmType::FLOAT_32_BIT};
+ const bool mIsProxyEffect;
static constexpr int kDefaultframeCount = 0x100;
@@ -75,6 +81,9 @@
uint32_t* /* replySize */,
void* /* pReplyData */);
static const std::map<uint32_t /* effect_command_e */, CommandHandler> mCommandHandlerMap;
+ // data and status FMQ
+ std::shared_ptr<StatusMQ> mStatusQ = nullptr;
+ std::shared_ptr<DataMQ> mInputQ = nullptr, mOutputQ = nullptr;
status_t handleInit(uint32_t cmdSize, const void* pCmdData, uint32_t* replySize,
void* pReplyData);
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index 0c19ac8..d6135af 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -31,6 +31,7 @@
#include <utils/Log.h>
#include "EffectHalAidl.h"
+#include "EffectProxy.h"
#include <aidl/android/hardware/audio/effect/IEffect.h>
@@ -61,19 +62,22 @@
EffectHalAidl::EffectHalAidl(const std::shared_ptr<IFactory>& factory,
const std::shared_ptr<IEffect>& effect, uint64_t effectId,
- int32_t sessionId, int32_t ioId, const Descriptor& desc)
+ int32_t sessionId, int32_t ioId, const Descriptor& desc,
+ bool isProxyEffect)
: mFactory(factory),
mEffect(effect),
mEffectId(effectId),
mSessionId(sessionId),
mIoId(ioId),
- mDesc(desc) {
+ mDesc(desc),
+ mIsProxyEffect(isProxyEffect) {
createAidlConversion(effect, sessionId, ioId, desc);
}
EffectHalAidl::~EffectHalAidl() {
- if (mFactory) {
- mFactory->destroyEffect(mEffect);
+ if (mEffect) {
+ mIsProxyEffect ? std::static_pointer_cast<EffectProxy>(mEffect)->destroy()
+ : mFactory->destroyEffect(mEffect);
}
}
@@ -160,34 +164,49 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
- size_t available = mInputQ->availableToWrite();
+ auto statusQ = mConversion->getStatusMQ();
+ auto inputQ = mConversion->getInputMQ();
+ auto outputQ = mConversion->getOutputMQ();
+ if (!statusQ || !statusQ->isValid() || !inputQ || !inputQ->isValid() || !outputQ ||
+ !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;
+ }
+
+ size_t available = inputQ->availableToWrite();
size_t floatsToWrite = std::min(available, mInBuffer->getSize() / sizeof(float));
if (floatsToWrite == 0) {
- ALOGW("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
+ ALOGE("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
mInBuffer->getSize() / sizeof(float), available);
return INVALID_OPERATION;
}
- if (!mInputQ->write((float*)mInBuffer->ptr(), floatsToWrite)) {
- ALOGW("%s failed to write %zu into inputQ", __func__, floatsToWrite);
+ if (!mInBuffer->audioBuffer() ||
+ !inputQ->write((float*)mInBuffer->audioBuffer()->f32, floatsToWrite)) {
+ ALOGE("%s failed to write %zu floats from audiobuffer %p to inputQ [avail %zu]", __func__,
+ floatsToWrite, mInBuffer->audioBuffer(), inputQ->availableToWrite());
return INVALID_OPERATION;
}
IEffect::Status retStatus{};
- if (!mStatusQ->readBlocking(&retStatus, 1) || retStatus.status != OK ||
+ if (!statusQ->readBlocking(&retStatus, 1) || retStatus.status != OK ||
(size_t)retStatus.fmqConsumed != floatsToWrite || retStatus.fmqProduced == 0) {
- ALOGW("%s read status failed: %s", __func__, retStatus.toString().c_str());
+ ALOGE("%s read status failed: %s", __func__, retStatus.toString().c_str());
return INVALID_OPERATION;
}
- available = mOutputQ->availableToRead();
+ available = outputQ->availableToRead();
size_t floatsToRead = std::min(available, mOutBuffer->getSize() / sizeof(float));
if (floatsToRead == 0) {
- ALOGW("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
+ ALOGE("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
mOutBuffer->getSize() / sizeof(float), available);
return INVALID_OPERATION;
}
- if (!mOutputQ->read((float*)mOutBuffer->ptr(), floatsToRead)) {
- ALOGW("%s failed to read %zu from outputQ", __func__, floatsToRead);
+ // always read floating point data for AIDL
+ if (!mOutBuffer->audioBuffer() ||
+ !outputQ->read(mOutBuffer->audioBuffer()->f32, floatsToRead)) {
+ ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", __func__, floatsToRead,
+ mOutBuffer->audioBuffer());
return INVALID_OPERATION;
}
@@ -210,20 +229,7 @@
return INVALID_OPERATION;
}
- status_t ret = mConversion->handleCommand(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
- // update FMQs when effect open successfully
- if (ret == OK && cmdCode == EFFECT_CMD_INIT) {
- const auto& retParam = mConversion->getEffectReturnParam();
- mStatusQ = std::make_unique<StatusMQ>(retParam.statusMQ);
- mInputQ = std::make_unique<DataMQ>(retParam.inputDataMQ);
- mOutputQ = std::make_unique<DataMQ>(retParam.outputDataMQ);
- if (!mStatusQ->isValid() || !mInputQ->isValid() || !mOutputQ->isValid()) {
- ALOGE("%s return with invalid FMQ", __func__);
- return NO_INIT;
- }
- }
-
- return ret;
+ return mConversion->handleCommand(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
status_t EffectHalAidl::getDescriptor(effect_descriptor_t* pDescriptor) {
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 194150d..8966363 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -31,11 +31,6 @@
class EffectHalAidl : public EffectHalInterface {
public:
- using StatusMQ = ::android::AidlMessageQueue<
- ::aidl::android::hardware::audio::effect::IEffect::Status,
- ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
- using DataMQ = ::android::AidlMessageQueue<
- float, ::aidl::android::hardware::common::fmq::SynchronizedReadWrite>;
// Set the input buffer.
status_t setInBuffer(const sp<EffectBufferHalInterface>& buffer) override;
@@ -83,12 +78,11 @@
const int32_t mSessionId;
const int32_t mIoId;
const ::aidl::android::hardware::audio::effect::Descriptor mDesc;
+ const bool mIsProxyEffect;
+
std::unique_ptr<EffectConversionHelperAidl> mConversion;
- std::unique_ptr<StatusMQ> mStatusQ;
- std::unique_ptr<DataMQ> mInputQ, mOutputQ;
sp<EffectBufferHalInterface> mInBuffer, mOutBuffer;
- effect_config_t mConfig;
status_t createAidlConversion(
std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect> effect,
@@ -99,8 +93,10 @@
const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory,
const std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>& effect,
uint64_t effectId, int32_t sessionId, int32_t ioId,
- const ::aidl::android::hardware::audio::effect::Descriptor& desc);
+ const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+ bool isProxyEffect);
bool setEffectReverse(bool reverse);
+ bool needUpdateReturnParam(uint32_t cmdCode);
// The destructor automatically releases the effect.
virtual ~EffectHalAidl();
diff --git a/media/libaudiohal/impl/EffectProxy.cpp b/media/libaudiohal/impl/EffectProxy.cpp
new file mode 100644
index 0000000..c4d85e5
--- /dev/null
+++ b/media/libaudiohal/impl/EffectProxy.cpp
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <memory>
+#define LOG_TAG "EffectProxy"
+//#define LOG_NDEBUG 0
+
+#include <fmq/AidlMessageQueue.h>
+#include <utils/Log.h>
+
+#include "EffectProxy.h"
+
+using ::aidl::android::hardware::audio::effect::CommandId;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Flags;
+using ::aidl::android::hardware::audio::effect::IEffect;
+using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::State;
+using ::aidl::android::media::audio::common::AudioUuid;
+
+namespace android {
+namespace effect {
+
+EffectProxy::EffectProxy(const Descriptor::Identity& id, const std::shared_ptr<IFactory>& factory)
+ : mIdentity([](const Descriptor::Identity& subId) {
+ // update EffectProxy implementation UUID to the sub-effect proxy UUID
+ ALOG_ASSERT(subId.proxy.has_value(), "Sub-effect Identity must have valid proxy UUID");
+ Descriptor::Identity tempId = subId;
+ tempId.uuid = subId.proxy.value();
+ return tempId;
+ }(id)),
+ mFactory(factory) {}
+
+EffectProxy::~EffectProxy() {
+ close();
+ destroy();
+ mSubEffects.clear();
+}
+
+// sub effect must have same proxy UUID as EffectProxy, and the type UUID must match.
+ndk::ScopedAStatus EffectProxy::addSubEffect(const Descriptor& sub) {
+ ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+ if (0 != mSubEffects.count(sub.common.id) || !sub.common.id.proxy.has_value() ||
+ sub.common.id.proxy.value() != mIdentity.uuid) {
+ ALOGE("%s sub effect already exist or mismatch %s", __func__, sub.toString().c_str());
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_ILLEGAL_ARGUMENT,
+ "illegalSubEffect");
+ }
+
+ // not create sub-effect yet
+ std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[sub.common.id]) = nullptr;
+ std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[sub.common.id]) = sub;
+ // set the last added sub-effect to active before setOffloadParam()
+ mActiveSub = sub.common.id;
+ ALOGI("%s add %s to proxy %s flag %s", __func__, mActiveSub.toString().c_str(),
+ mIdentity.toString().c_str(), sub.common.flags.toString().c_str());
+
+ if (sub.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL) {
+ mSubFlags.hwAcceleratorMode = Flags::HardwareAccelerator::TUNNEL;
+ }
+
+ // initial flag values before we know which sub-effect to active (with setOffloadParam)
+ // same as HIDL EffectProxy flags
+ mSubFlags.type = Flags::Type::INSERT;
+ mSubFlags.insert = Flags::Insert::LAST;
+ mSubFlags.volume = Flags::Volume::CTRL;
+
+ // set indication if any sub-effect indication was set
+ mSubFlags.offloadIndication |= sub.common.flags.offloadIndication;
+ mSubFlags.deviceIndication |= sub.common.flags.deviceIndication;
+ mSubFlags.audioModeIndication |= sub.common.flags.audioModeIndication;
+ mSubFlags.audioSourceIndication |= sub.common.flags.audioSourceIndication;
+
+ // set bypass when all sub-effects are bypassing
+ mSubFlags.bypass &= sub.common.flags.bypass;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus EffectProxy::create() {
+ ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+ ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
+
+ for (auto& sub : mSubEffects) {
+ auto& effectHandle = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
+ ALOGI("%s sub-effect %s", __func__, sub.first.uuid.toString().c_str());
+ status = mFactory->createEffect(sub.first.uuid, &effectHandle);
+ if (!status.isOk() || !effectHandle) {
+ ALOGE("%s sub-effect failed %s", __func__, sub.first.uuid.toString().c_str());
+ break;
+ }
+ }
+
+ // destroy all created effects if failure
+ if (!status.isOk()) {
+ destroy();
+ }
+ return status;
+}
+
+ndk::ScopedAStatus EffectProxy::destroy() {
+ ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+ return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
+ ndk::ScopedAStatus status = mFactory->destroyEffect(effect);
+ if (status.isOk()) {
+ effect.reset();
+ }
+ return status;
+ });
+}
+
+const IEffect::OpenEffectReturn* EffectProxy::getEffectReturnParam() {
+ return &std::get<SubEffectTupleIndex::RETURN>(mSubEffects[mActiveSub]);
+}
+
+ndk::ScopedAStatus EffectProxy::setOffloadParam(const effect_offload_param_t* offload) {
+ const auto& itor = std::find_if(mSubEffects.begin(), mSubEffects.end(), [&](const auto& sub) {
+ const auto& desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(sub.second);
+ ALOGI("%s: isOffload %d sub-effect: %s, flags %s", __func__, offload->isOffload,
+ desc.common.id.uuid.toString().c_str(), desc.common.flags.toString().c_str());
+ return offload->isOffload ==
+ (desc.common.flags.hwAcceleratorMode == Flags::HardwareAccelerator::TUNNEL);
+ });
+ if (itor == mSubEffects.end()) {
+ ALOGE("%s no %soffload sub-effect found", __func__, offload->isOffload ? "" : "non-");
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
+ "noActiveEffctFound");
+ }
+
+ mActiveSub = itor->first;
+ ALOGI("%s: active %soffload sub-effect: %s, flags %s", __func__,
+ offload->isOffload ? "" : "non-", mActiveSub.uuid.toString().c_str(),
+ std::get<SubEffectTupleIndex::DESCRIPTOR>(itor->second).common.flags.toString().c_str());
+ return ndk::ScopedAStatus::ok();
+}
+
+// EffectProxy go over sub-effects and call IEffect interfaces
+ndk::ScopedAStatus EffectProxy::open(const Parameter::Common& common,
+ const std::optional<Parameter::Specific>& specific,
+ IEffect::OpenEffectReturn* ret __unused) {
+ ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+ ndk::ScopedAStatus status = ndk::ScopedAStatus::fromExceptionCodeWithMessage(
+ EX_ILLEGAL_ARGUMENT, "nullEffectHandle");
+ for (auto& sub : mSubEffects) {
+ auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
+ auto& openRet = std::get<SubEffectTupleIndex::RETURN>(sub.second);
+ if (!effect ||
+ (status = effect->open(common, specific, &openRet)).isOk()) {
+ ALOGE("%s: failed to open UUID %s", __func__, sub.first.uuid.toString().c_str());
+ break;
+ }
+ }
+
+ // close all opened effects if failure
+ if (!status.isOk()) {
+ close();
+ }
+
+ return status;
+}
+
+ndk::ScopedAStatus EffectProxy::close() {
+ ALOGV("%s: %s", __func__, mIdentity.type.toString().c_str());
+ return runWithAllSubEffects([&](std::shared_ptr<IEffect>& effect) {
+ return effect->close();
+ });
+}
+
+ndk::ScopedAStatus EffectProxy::getDescriptor(Descriptor* desc) {
+ if (!desc) {
+ ALOGE("%s: nuull descriptor pointer", __func__);
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER, "nullptr");
+ }
+
+ auto& activeSubEffect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]);
+ // return initial descriptor if no active sub-effect exist
+ if (!activeSubEffect) {
+ desc->common.id = mIdentity;
+ desc->common.flags = mSubFlags;
+ desc->common.name = "Proxy";
+ desc->common.implementor = "AOSP";
+ } else {
+ *desc = std::get<SubEffectTupleIndex::DESCRIPTOR>(mSubEffects[mActiveSub]);
+ desc->common.id = mIdentity;
+ }
+
+ ALOGI("%s with %s", __func__, desc->toString().c_str());
+ return ndk::ScopedAStatus::ok();
+}
+
+// Handle with active sub-effect first, only send to other sub-effects when success
+ndk::ScopedAStatus EffectProxy::command(CommandId id) {
+ ALOGV("%s: %s, command %s", __func__, mIdentity.type.toString().c_str(),
+ android::internal::ToString(id).c_str());
+ return runWithActiveSubEffectThenOthers(
+ [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus {
+ return effect->command(id);
+ });
+}
+
+// Return the active sub-effect state
+ndk::ScopedAStatus EffectProxy::getState(State* state) {
+ return runWithActiveSubEffect(
+ [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus {
+ return effect->getState(state);
+ });
+}
+
+// Handle with active sub-effect first, only send to other sub-effects when success
+ndk::ScopedAStatus EffectProxy::setParameter(const Parameter& param) {
+ return runWithActiveSubEffectThenOthers(
+ [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus {
+ return effect->setParameter(param);
+ });
+}
+
+// Return the active sub-effect parameter
+ndk::ScopedAStatus EffectProxy::getParameter(const Parameter::Id& id, Parameter* param) {
+ return runWithActiveSubEffect(
+ [&](const std::shared_ptr<IEffect>& effect) -> ndk::ScopedAStatus {
+ return effect->getParameter(id, param);
+ });
+}
+
+ndk::ScopedAStatus EffectProxy::runWithActiveSubEffectThenOthers(
+ std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) {
+ ndk::ScopedAStatus status = runWithActiveSubEffect(func);
+ if (!status.isOk()) {
+ return status;
+ }
+
+ // proceed with others if active sub-effect success
+ for (const auto& sub : mSubEffects) {
+ auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
+ if (sub.first != mActiveSub) {
+ if (!effect) {
+ ALOGE("%s null sub-effect interface for %s", __func__,
+ sub.first.toString().c_str());
+ continue;
+ }
+ func(effect);
+ }
+ }
+ return status;
+}
+
+ndk::ScopedAStatus EffectProxy::runWithActiveSubEffect(
+ std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func) {
+ auto& effect = std::get<SubEffectTupleIndex::HANDLE>(mSubEffects[mActiveSub]);
+ if (!effect) {
+ ALOGE("%s null active sub-effect interface, active %s", __func__,
+ mActiveSub.toString().c_str());
+ return ndk::ScopedAStatus::fromExceptionCodeWithMessage(EX_NULL_POINTER,
+ "activeSubEffectNull");
+ }
+ return func(effect);
+}
+
+ndk::ScopedAStatus EffectProxy::runWithAllSubEffects(
+ std::function<ndk::ScopedAStatus(std::shared_ptr<IEffect>&)> const& func) {
+ ndk::ScopedAStatus status = ndk::ScopedAStatus::ok();
+ // proceed with others if active sub-effect success
+ for (auto& sub : mSubEffects) {
+ auto& effect = std::get<SubEffectTupleIndex::HANDLE>(sub.second);
+ if (!effect) {
+ ALOGW("%s null sub-effect interface for %s", __func__, sub.first.toString().c_str());
+ continue;
+ }
+ ndk::ScopedAStatus temp = func(effect);
+ if (!temp.isOk()) {
+ status = ndk::ScopedAStatus::fromStatus(temp.getStatus());
+ }
+ }
+ return status;
+}
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectProxy.h b/media/libaudiohal/impl/EffectProxy.h
new file mode 100644
index 0000000..ffb8a19
--- /dev/null
+++ b/media/libaudiohal/impl/EffectProxy.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+
+#include <aidl/android/hardware/audio/effect/BnEffect.h>
+#include <aidl/android/hardware/audio/effect/BnFactory.h>
+#include <fmq/AidlMessageQueue.h>
+#include <system/audio_effect.h>
+
+namespace android {
+namespace effect {
+
+/**
+ * EffectProxy is the proxy for one or more effect AIDL implementations (sub effect) of same type.
+ * The audio framework use EffectProxy as a composite implementation of all sub effect
+ * implementations.
+ *
+ * At any given time, there is only one active effect which consuming and producing data for each
+ * proxy. All setter commands (except the legacy EFFECT_CMD_OFFLOAD, it will be handled by the audio
+ * framework directly) and parameters will be pass through to all sub effects, the getter commands
+ * and parameters will only passthrough to the active sub-effect.
+ *
+ */
+class EffectProxy final : public ::aidl::android::hardware::audio::effect::BnEffect {
+ public:
+ EffectProxy(const ::aidl::android::hardware::audio::effect::Descriptor::Identity& id,
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory>& factory);
+
+ /**
+ * Add a sub effect into the proxy, the descriptor of candidate sub-effect need to have same
+ * proxy UUID as mUuid.
+ */
+ ndk::ScopedAStatus addSubEffect(
+ const ::aidl::android::hardware::audio::effect::Descriptor& sub);
+
+ /**
+ * Create all sub-effects via AIDL IFactory, always call create() after all sub-effects added
+ * successfully with addSubEffect.
+ */
+ ndk::ScopedAStatus create();
+
+ /**
+ * Destroy all sub-effects via AIDL IFactory, always call create() after all sub-effects added
+ * successfully with addSubEffect.
+ */
+ ndk::ScopedAStatus destroy();
+
+ /**
+ * Handle offload parameter setting from framework.
+ */
+ ndk::ScopedAStatus setOffloadParam(const effect_offload_param_t* offload);
+
+ /**
+ * Get the const reference of the active sub-effect return parameters.
+ * Always use this interface to get the effect open return parameters (FMQs) after a success
+ * setOffloadParam() call.
+ */
+ const IEffect::OpenEffectReturn* getEffectReturnParam();
+
+ // IEffect interfaces override
+ ndk::ScopedAStatus open(
+ const ::aidl::android::hardware::audio::effect::Parameter::Common& common,
+ const std::optional<::aidl::android::hardware::audio::effect::Parameter::Specific>&
+ specific,
+ ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn* ret) override;
+ ndk::ScopedAStatus close() override;
+ ndk::ScopedAStatus getDescriptor(
+ ::aidl::android::hardware::audio::effect::Descriptor* desc) override;
+ ndk::ScopedAStatus command(::aidl::android::hardware::audio::effect::CommandId id) override;
+ ndk::ScopedAStatus getState(::aidl::android::hardware::audio::effect::State* state) override;
+ ndk::ScopedAStatus setParameter(
+ const ::aidl::android::hardware::audio::effect::Parameter& param) override;
+ ndk::ScopedAStatus getParameter(
+ const ::aidl::android::hardware::audio::effect::Parameter::Id& id,
+ ::aidl::android::hardware::audio::effect::Parameter* param) override;
+
+ private:
+ // Proxy identity, copy from one sub-effect, and update the implementation UUID to proxy UUID
+ const ::aidl::android::hardware::audio::effect::Descriptor::Identity mIdentity;
+ const std::shared_ptr<::aidl::android::hardware::audio::effect::IFactory> mFactory;
+
+ // A map of sub effects descriptor to the IEffect handle and return FMQ
+ enum SubEffectTupleIndex { HANDLE, DESCRIPTOR, RETURN };
+ using EffectProxySub =
+ std::tuple<std::shared_ptr<::aidl::android::hardware::audio::effect::IEffect>,
+ ::aidl::android::hardware::audio::effect::Descriptor,
+ ::aidl::android::hardware::audio::effect::IEffect::OpenEffectReturn>;
+ std::map<const ::aidl::android::hardware::audio::effect::Descriptor::Identity, EffectProxySub>
+ mSubEffects;
+
+ // Descriptor of the only active effect in the mSubEffects map
+ ::aidl::android::hardware::audio::effect::Descriptor::Identity mActiveSub;
+
+ // keep the flag of sub-effects
+ ::aidl::android::hardware::audio::effect::Flags mSubFlags;
+
+ ndk::ScopedAStatus runWithActiveSubEffectThenOthers(
+ std::function<ndk::ScopedAStatus(
+ const std::shared_ptr<
+ ::aidl::android::hardware::audio::effect::IEffect>&)> const& func);
+
+ ndk::ScopedAStatus runWithActiveSubEffect(
+ std::function<ndk::ScopedAStatus(const std::shared_ptr<IEffect>&)> const& func);
+
+ ndk::ScopedAStatus runWithAllSubEffects(
+ std::function<ndk::ScopedAStatus(std::shared_ptr<IEffect>&)> const& func);
+
+ // close and release all sub-effects
+ ~EffectProxy();
+};
+
+} // namespace effect
+} // namespace android
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
index f289f24..bc05aa0 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.cpp
@@ -15,7 +15,9 @@
*/
#include <algorithm>
+#include <cstddef>
#include <cstdint>
+#include <iterator>
#include <memory>
#define LOG_TAG "EffectsFactoryHalAidl"
//#define LOG_NDEBUG 0
@@ -29,10 +31,12 @@
#include "EffectBufferHalAidl.h"
#include "EffectHalAidl.h"
+#include "EffectProxy.h"
#include "EffectsFactoryHalAidl.h"
using ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid;
using aidl::android::aidl_utils::statusTFromBinderStatus;
+using aidl::android::hardware::audio::effect::Descriptor;
using aidl::android::hardware::audio::effect::IFactory;
using aidl::android::media::audio::common::AudioUuid;
using android::detail::AudioHalVersionInfo;
@@ -42,12 +46,56 @@
EffectsFactoryHalAidl::EffectsFactoryHalAidl(std::shared_ptr<IFactory> effectsFactory)
: mFactory(effectsFactory),
- mHalVersion(AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, [this]() {
- int32_t majorVersion = 0;
- return (mFactory && mFactory->getInterfaceVersion(&majorVersion).isOk()) ? majorVersion
- : 0;
- }())) {
- ALOG_ASSERT(effectsFactory != nullptr, "Provided IEffectsFactory service is NULL");
+ mHalVersion(AudioHalVersionInfo(
+ AudioHalVersionInfo::Type::AIDL,
+ [this]() {
+ int32_t majorVersion = 0;
+ return (mFactory && mFactory->getInterfaceVersion(&majorVersion).isOk())
+ ? majorVersion
+ : 0;
+ }())),
+ mHalDescList([this]() {
+ std::vector<Descriptor> list;
+ if (mFactory) {
+ mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &list).isOk();
+ }
+ return list;
+ }()),
+ mUuidProxyMap([this]() {
+ std::map<AudioUuid, std::shared_ptr<EffectProxy>> proxyMap;
+ for (const auto& desc : mHalDescList) {
+ // create EffectProxy
+ if (desc.common.id.proxy.has_value()) {
+ const auto& uuid = desc.common.id.proxy.value();
+ if (0 == proxyMap.count(uuid)) {
+ proxyMap.insert({uuid, ndk::SharedRefBase::make<EffectProxy>(desc.common.id,
+ mFactory)});
+ }
+ proxyMap[uuid]->addSubEffect(desc);
+ ALOGI("%s addSubEffect %s", __func__, desc.common.toString().c_str());
+ }
+ }
+ return proxyMap;
+ }()),
+ mProxyDescList([this]() {
+ std::vector<Descriptor> list;
+ for (const auto& proxy : mUuidProxyMap) {
+ if (Descriptor desc; proxy.second && proxy.second->getDescriptor(&desc).isOk()) {
+ list.emplace_back(std::move(desc));
+ }
+ }
+ return list;
+ }()),
+ mNonProxyDescList([this]() {
+ std::vector<Descriptor> list;
+ std::copy_if(mHalDescList.begin(), mHalDescList.end(), std::back_inserter(list),
+ [](const Descriptor& desc) { return !desc.common.id.proxy.has_value(); });
+ return list;
+ }()),
+ mEffectCount(mNonProxyDescList.size() + mProxyDescList.size()) {
+ ALOG_ASSERT(mFactory != nullptr, "Provided IEffectsFactory service is NULL");
+ ALOGI("%s with %zu nonProxyEffects and %zu proxyEffects", __func__, mNonProxyDescList.size(),
+ mProxyDescList.size());
}
status_t EffectsFactoryHalAidl::queryNumberEffects(uint32_t *pNumEffects) {
@@ -55,11 +103,7 @@
return BAD_VALUE;
}
- {
- std::lock_guard lg(mLock);
- RETURN_STATUS_IF_ERROR(queryEffectList_l());
- *pNumEffects = mDescList->size();
- }
+ *pNumEffects = mEffectCount;
ALOGI("%s %d", __func__, *pNumEffects);
return OK;
}
@@ -69,42 +113,43 @@
return BAD_VALUE;
}
- std::lock_guard lg(mLock);
- RETURN_STATUS_IF_ERROR(queryEffectList_l());
-
- auto listSize = mDescList->size();
- if (index >= listSize) {
- ALOGE("%s index %d exceed size DescList %zd", __func__, index, listSize);
+ if (index >= mEffectCount) {
+ ALOGE("%s index %d exceed max number %zu", __func__, index, mEffectCount);
return INVALID_OPERATION;
}
- *pDescriptor = VALUE_OR_RETURN_STATUS(
- ::aidl::android::aidl2legacy_Descriptor_effect_descriptor(mDescList->at(index)));
+ if (index >= mNonProxyDescList.size()) {
+ *pDescriptor =
+ VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_Descriptor_effect_descriptor(
+ mProxyDescList.at(index - mNonProxyDescList.size())));
+ } else {
+ *pDescriptor =
+ VALUE_OR_RETURN_STATUS(::aidl::android::aidl2legacy_Descriptor_effect_descriptor(
+ mNonProxyDescList.at(index)));
+ }
return OK;
}
status_t EffectsFactoryHalAidl::getDescriptor(const effect_uuid_t* halUuid,
effect_descriptor_t* pDescriptor) {
- if (halUuid == nullptr || pDescriptor == nullptr) {
+ if (halUuid == nullptr) {
return BAD_VALUE;
}
- AudioUuid uuid = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halUuid));
- std::lock_guard lg(mLock);
- return getHalDescriptorWithImplUuid_l(uuid, pDescriptor);
+ AudioUuid uuid =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halUuid));
+ return getHalDescriptorWithImplUuid(uuid, pDescriptor);
}
status_t EffectsFactoryHalAidl::getDescriptors(const effect_uuid_t* halType,
std::vector<effect_descriptor_t>* descriptors) {
- if (halType == nullptr || descriptors == nullptr) {
+ if (halType == nullptr) {
return BAD_VALUE;
}
- AudioUuid type = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halType));
- std::lock_guard lg(mLock);
- return getHalDescriptorWithTypeUuid_l(type, descriptors);
+ AudioUuid type =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*halType));
+ return getHalDescriptorWithTypeUuid(type, descriptors);
}
status_t EffectsFactoryHalAidl::createEffect(const effect_uuid_t* uuid, int32_t sessionId,
@@ -116,18 +161,25 @@
if (sessionId == AUDIO_SESSION_DEVICE && ioId == AUDIO_IO_HANDLE_NONE) {
return INVALID_OPERATION;
}
-
ALOGI("%s session %d ioId %d", __func__, sessionId, ioId);
- AudioUuid aidlUuid = VALUE_OR_RETURN_STATUS(
- ::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*uuid));
+ AudioUuid aidlUuid =
+ VALUE_OR_RETURN_STATUS(::aidl::android::legacy2aidl_audio_uuid_t_AudioUuid(*uuid));
std::shared_ptr<IEffect> aidlEffect;
- Descriptor desc;
- RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect)));
+ // Use EffectProxy interface instead of IFactory to create
+ const bool isProxy = isProxyEffect(aidlUuid);
+ if (isProxy) {
+ aidlEffect = mUuidProxyMap.at(aidlUuid);
+ RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mUuidProxyMap.at(aidlUuid)->create()));
+ } else {
+ RETURN_STATUS_IF_ERROR(
+ statusTFromBinderStatus(mFactory->createEffect(aidlUuid, &aidlEffect)));
+ }
if (aidlEffect == nullptr) {
- ALOGE("%s IFactory::createFactory failed UUID %s", __func__, aidlUuid.toString().c_str());
+ ALOGE("%s failed to create effect with UUID: %s", __func__, aidlUuid.toString().c_str());
return NAME_NOT_FOUND;
}
+ Descriptor desc;
RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(aidlEffect->getDescriptor(&desc)));
uint64_t effectId;
@@ -136,13 +188,23 @@
effectId = ++mEffectIdCounter;
}
- *effect = sp<EffectHalAidl>::make(mFactory, aidlEffect, effectId, sessionId, ioId, desc);
+ *effect =
+ sp<EffectHalAidl>::make(mFactory, aidlEffect, effectId, sessionId, ioId, desc, isProxy);
return OK;
}
status_t EffectsFactoryHalAidl::dumpEffects(int fd) {
- // TODO: add proxy dump here because AIDL service EffectFactory doesn't have proxy handle
- return mFactory->dump(fd, nullptr, 0);
+ status_t ret = OK;
+ // record the error ret and continue dump as many effects as possible
+ for (const auto& proxy : mUuidProxyMap) {
+ if (proxy.second) {
+ if (status_t temp = proxy.second->dump(fd, nullptr, 0); temp != OK) {
+ ret = temp;
+ }
+ }
+ }
+ RETURN_STATUS_IF_ERROR(mFactory->dump(fd, nullptr, 0));
+ return ret;
}
status_t EffectsFactoryHalAidl::allocateBuffer(size_t size, sp<EffectBufferHalInterface>* buffer) {
@@ -160,56 +222,42 @@
return mHalVersion;
}
-status_t EffectsFactoryHalAidl::queryEffectList_l() {
- if (!mDescList) {
- std::vector<Descriptor> list;
- auto status = mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &list);
- if (!status.isOk()) {
- ALOGE("%s IFactory::queryEffects failed %s", __func__, status.getDescription().c_str());
- return status.getStatus();
- }
-
- mDescList = std::make_unique<std::vector<Descriptor>>(list);
- }
- return OK;
-}
-
-status_t EffectsFactoryHalAidl::getHalDescriptorWithImplUuid_l(const AudioUuid& uuid,
- effect_descriptor_t* pDescriptor) {
+status_t EffectsFactoryHalAidl::getHalDescriptorWithImplUuid(const AudioUuid& uuid,
+ effect_descriptor_t* pDescriptor) {
if (pDescriptor == nullptr) {
return BAD_VALUE;
}
- if (!mDescList) {
- RETURN_STATUS_IF_ERROR(queryEffectList_l());
- }
- auto matchIt = std::find_if(mDescList->begin(), mDescList->end(),
- [&](const auto& desc) { return desc.common.id.uuid == uuid; });
- if (matchIt == mDescList->end()) {
- ALOGE("%s UUID %s not found", __func__, uuid.toString().c_str());
+ const auto& list = isProxyEffect(uuid) ? mProxyDescList : mNonProxyDescList;
+ auto matchIt = std::find_if(list.begin(), list.end(),
+ [&](const auto& desc) { return desc.common.id.uuid == uuid; });
+ if (matchIt == list.end()) {
+ ALOGE("%s UUID not found in HAL and proxy list %s", __func__, uuid.toString().c_str());
return BAD_VALUE;
}
+ ALOGI("%s UUID impl found %s", __func__, uuid.toString().c_str());
*pDescriptor = VALUE_OR_RETURN_STATUS(
::aidl::android::aidl2legacy_Descriptor_effect_descriptor(*matchIt));
return OK;
}
-status_t EffectsFactoryHalAidl::getHalDescriptorWithTypeUuid_l(
+status_t EffectsFactoryHalAidl::getHalDescriptorWithTypeUuid(
const AudioUuid& type, std::vector<effect_descriptor_t>* descriptors) {
if (descriptors == nullptr) {
return BAD_VALUE;
}
- if (!mDescList) {
- RETURN_STATUS_IF_ERROR(queryEffectList_l());
- }
+
std::vector<Descriptor> result;
- std::copy_if(mDescList->begin(), mDescList->end(), std::back_inserter(result),
+ std::copy_if(mNonProxyDescList.begin(), mNonProxyDescList.end(), std::back_inserter(result),
[&](auto& desc) { return desc.common.id.type == type; });
- if (result.size() == 0) {
- ALOGE("%s type UUID %s not found", __func__, type.toString().c_str());
+ std::copy_if(mProxyDescList.begin(), mProxyDescList.end(), std::back_inserter(result),
+ [&](auto& desc) { return desc.common.id.type == type; });
+ if (result.empty()) {
+ ALOGW("%s UUID type not found in HAL and proxy list %s", __func__, type.toString().c_str());
return BAD_VALUE;
}
+ ALOGI("%s UUID type found %zu \n %s", __func__, result.size(), type.toString().c_str());
*descriptors = VALUE_OR_RETURN_STATUS(
aidl::android::convertContainer<std::vector<effect_descriptor_t>>(
@@ -217,6 +265,10 @@
return OK;
}
+bool EffectsFactoryHalAidl::isProxyEffect(const AudioUuid& uuid) const {
+ return 0 != mUuidProxyMap.count(uuid);
+}
+
} // namespace effect
// When a shared library is built from a static library, even explicit
diff --git a/media/libaudiohal/impl/EffectsFactoryHalAidl.h b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
index 9c3643b..debfacf 100644
--- a/media/libaudiohal/impl/EffectsFactoryHalAidl.h
+++ b/media/libaudiohal/impl/EffectsFactoryHalAidl.h
@@ -25,6 +25,8 @@
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <system/thread_defs.h>
+#include "EffectProxy.h"
+
namespace android {
namespace effect {
@@ -60,24 +62,35 @@
detail::AudioHalVersionInfo getHalVersion() const override;
- // for TIME_CHECK
- const std::string getClassName() const { return "EffectHalAidl"; }
-
private:
- std::mutex mLock;
const std::shared_ptr<IFactory> mFactory;
- uint64_t mEffectIdCounter GUARDED_BY(mLock) = 0; // Align with HIDL (0 is INVALID_ID)
- std::unique_ptr<std::vector<Descriptor>> mDescList GUARDED_BY(mLock) = nullptr;
const detail::AudioHalVersionInfo mHalVersion;
+ // Full list of HAL effect descriptors
+ const std::vector<Descriptor> mHalDescList;
+ // Map of proxy UUID (key) to the proxy object
+ const std::map<::aidl::android::media::audio::common::AudioUuid /* proxy impl UUID */,
+ std::shared_ptr<EffectProxy>>
+ mUuidProxyMap;
+ // List of effect proxy, initialize after mUuidProxyMap because it need to have all sub-effects
+ const std::vector<Descriptor> mProxyDescList;
+ // List of non-proxy effects
+ const std::vector<Descriptor> mNonProxyDescList;
+ // total number of effects including proxy effects
+ const size_t mEffectCount;
+
+ std::mutex mLock;
+ uint64_t mEffectIdCounter GUARDED_BY(mLock) = 0; // Align with HIDL (0 is INVALID_ID)
virtual ~EffectsFactoryHalAidl() = default;
- status_t queryEffectList_l() REQUIRES(mLock);
- status_t getHalDescriptorWithImplUuid_l(
+ status_t getHalDescriptorWithImplUuid(
const aidl::android::media::audio::common::AudioUuid& uuid,
- effect_descriptor_t* pDescriptor) REQUIRES(mLock);
- status_t getHalDescriptorWithTypeUuid_l(
+ effect_descriptor_t* pDescriptor);
+
+ status_t getHalDescriptorWithTypeUuid(
const aidl::android::media::audio::common::AudioUuid& type,
- std::vector<effect_descriptor_t>* descriptors) REQUIRES(mLock);
+ std::vector<effect_descriptor_t>* descriptors);
+
+ bool isProxyEffect(const aidl::android::media::audio::common::AudioUuid& uuid) const;
};
} // namespace effect
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index cbc1578..3048580 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -40,6 +40,7 @@
using ::aidl::android::hardware::audio::core::IStreamIn;
using ::aidl::android::hardware::audio::core::IStreamOut;
using ::aidl::android::hardware::audio::core::StreamDescriptor;
+using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
using ::aidl::android::media::audio::common::MicrophoneDynamicInfo;
namespace android {
@@ -255,16 +256,23 @@
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mStream) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
- return OK;
+ const auto state = getState();
+ StreamDescriptor::Reply reply;
+ if (state == StreamDescriptor::State::STANDBY) {
+ if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::start>(), &reply, true);
+ status != OK) {
+ return status;
+ }
+ return sendCommand(makeHalCommand<HalCommand::Tag::burst>(0), &reply, true);
+ }
+
+ return INVALID_OPERATION;
}
status_t StreamHalAidl::stop() {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
- TIME_CHECK();
if (!mStream) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
- return OK;
+ return standby();
}
status_t StreamHalAidl::getLatency(uint32_t *latency) {
@@ -290,6 +298,20 @@
return OK;
}
+status_t StreamHalAidl::getHardwarePosition(int64_t *frames, int64_t *timestamp) {
+ ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
+ if (!mStream) return NO_INIT;
+ StreamDescriptor::Reply reply;
+ // TODO: switch to updateCountersIfNeeded once we sort out mWorkerTid initialization
+ if (status_t status = sendCommand(makeHalCommand<HalCommand::Tag::getStatus>(), &reply, true);
+ status != OK) {
+ return status;
+ }
+ *frames = reply.hardware.frames;
+ *timestamp = reply.hardware.timeNs;
+ return OK;
+}
+
status_t StreamHalAidl::getXruns(int32_t *frames) {
ALOGV("%p %s::%s", this, getClassName().c_str(), __func__);
if (!mStream) return NO_INIT;
@@ -419,19 +441,35 @@
}
status_t StreamHalAidl::createMmapBuffer(int32_t minSizeFrames __unused,
- struct audio_mmap_buffer_info *info __unused) {
+ struct audio_mmap_buffer_info *info) {
ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
TIME_CHECK();
if (!mStream) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
+ if (!mContext.isMmapped()) {
+ return BAD_VALUE;
+ }
+ const MmapBufferDescriptor& bufferDescriptor = mContext.getMmapBufferDescriptor();
+ info->shared_memory_fd = bufferDescriptor.sharedMemory.fd.get();
+ info->buffer_size_frames = mContext.getBufferSizeFrames();
+ info->burst_size_frames = bufferDescriptor.burstSizeFrames;
+ info->flags = static_cast<audio_mmap_buffer_flag>(bufferDescriptor.flags);
+
return OK;
}
-status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position __unused) {
- ALOGD("%p %s::%s", this, getClassName().c_str(), __func__);
+status_t StreamHalAidl::getMmapPosition(struct audio_mmap_position *position) {
TIME_CHECK();
if (!mStream) return NO_INIT;
- ALOGE("%s not implemented yet", __func__);
+ if (!mContext.isMmapped()) {
+ return BAD_VALUE;
+ }
+ int64_t aidlPosition = 0, aidlTimestamp = 0;
+ if (status_t status = getHardwarePosition(&aidlPosition, &aidlTimestamp); status != OK) {
+ return status;
+ }
+
+ position->time_nanoseconds = aidlTimestamp;
+ position->position_frames = static_cast<int32_t>(aidlPosition);
return OK;
}
diff --git a/media/libaudiohal/impl/StreamHalAidl.h b/media/libaudiohal/impl/StreamHalAidl.h
index 157e8bb..147c131 100644
--- a/media/libaudiohal/impl/StreamHalAidl.h
+++ b/media/libaudiohal/impl/StreamHalAidl.h
@@ -25,6 +25,7 @@
#include <aidl/android/hardware/audio/core/BpStreamCommon.h>
#include <aidl/android/hardware/audio/core/BpStreamIn.h>
#include <aidl/android/hardware/audio/core/BpStreamOut.h>
+#include <aidl/android/hardware/audio/core/MmapBufferDescriptor.h>
#include <fmq/AidlMessageQueue.h>
#include <media/audiohal/EffectHalInterface.h>
#include <media/audiohal/StreamHalInterface.h>
@@ -34,6 +35,7 @@
#include "StreamPowerLog.h"
using ::aidl::android::hardware::audio::common::AudioOffloadMetadata;
+using ::aidl::android::hardware::audio::core::MmapBufferDescriptor;
namespace android {
@@ -47,21 +49,25 @@
::aidl::android::hardware::common::fmq::SynchronizedReadWrite> DataMQ;
explicit StreamContextAidl(
- const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
+ ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor,
bool isAsynchronous)
: mFrameSizeBytes(descriptor.frameSizeBytes),
mCommandMQ(new CommandMQ(descriptor.command)),
mReplyMQ(new ReplyMQ(descriptor.reply)),
mBufferSizeFrames(descriptor.bufferSizeFrames),
mDataMQ(maybeCreateDataMQ(descriptor)),
- mIsAsynchronous(isAsynchronous) {}
+ mIsAsynchronous(isAsynchronous),
+ mIsMmapped(isMmapped(descriptor)),
+ mMmapBufferDescriptor(maybeGetMmapBuffer(descriptor)) {}
StreamContextAidl(StreamContextAidl&& other) :
mFrameSizeBytes(other.mFrameSizeBytes),
mCommandMQ(std::move(other.mCommandMQ)),
mReplyMQ(std::move(other.mReplyMQ)),
mBufferSizeFrames(other.mBufferSizeFrames),
mDataMQ(std::move(other.mDataMQ)),
- mIsAsynchronous(other.mIsAsynchronous) {}
+ mIsAsynchronous(other.mIsAsynchronous),
+ mIsMmapped(other.mIsMmapped),
+ mMmapBufferDescriptor(std::move(other.mMmapBufferDescriptor)) {}
StreamContextAidl& operator=(StreamContextAidl&& other) {
mFrameSizeBytes = other.mFrameSizeBytes;
mCommandMQ = std::move(other.mCommandMQ);
@@ -69,16 +75,19 @@
mBufferSizeFrames = other.mBufferSizeFrames;
mDataMQ = std::move(other.mDataMQ);
mIsAsynchronous = other.mIsAsynchronous;
+ mIsMmapped = other.mIsMmapped;
+ mMmapBufferDescriptor = std::move(other.mMmapBufferDescriptor);
return *this;
}
bool isValid() const {
return mFrameSizeBytes != 0 &&
mCommandMQ != nullptr && mCommandMQ->isValid() &&
mReplyMQ != nullptr && mReplyMQ->isValid() &&
- (mDataMQ != nullptr || (
+ (mDataMQ == nullptr || (
mDataMQ->isValid() &&
mDataMQ->getQuantumCount() * mDataMQ->getQuantumSize() >=
- mFrameSizeBytes * mBufferSizeFrames));
+ mFrameSizeBytes * mBufferSizeFrames)) &&
+ (!mIsMmapped || mMmapBufferDescriptor.sharedMemory.fd.get() >= 0);
}
size_t getBufferSizeBytes() const { return mFrameSizeBytes * mBufferSizeFrames; }
size_t getBufferSizeFrames() const { return mBufferSizeFrames; }
@@ -87,6 +96,8 @@
size_t getFrameSizeBytes() const { return mFrameSizeBytes; }
ReplyMQ* getReplyMQ() const { return mReplyMQ.get(); }
bool isAsynchronous() const { return mIsAsynchronous; }
+ bool isMmapped() const { return mIsMmapped; }
+ const MmapBufferDescriptor& getMmapBufferDescriptor() const { return mMmapBufferDescriptor; }
private:
static std::unique_ptr<DataMQ> maybeCreateDataMQ(
@@ -97,6 +108,19 @@
}
return nullptr;
}
+ static bool isMmapped(
+ const ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
+ using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
+ return descriptor.audio.getTag() == Tag::mmap;
+ }
+ static MmapBufferDescriptor maybeGetMmapBuffer(
+ ::aidl::android::hardware::audio::core::StreamDescriptor& descriptor) {
+ using Tag = ::aidl::android::hardware::audio::core::StreamDescriptor::AudioBuffer::Tag;
+ if (descriptor.audio.getTag() == Tag::mmap) {
+ return std::move(descriptor.audio.get<Tag::mmap>());
+ }
+ return {};
+ }
size_t mFrameSizeBytes;
std::unique_ptr<CommandMQ> mCommandMQ;
@@ -104,6 +128,8 @@
size_t mBufferSizeFrames;
std::unique_ptr<DataMQ> mDataMQ;
bool mIsAsynchronous;
+ bool mIsMmapped;
+ MmapBufferDescriptor mMmapBufferDescriptor;
};
class StreamHalAidl : public virtual StreamHalInterface, public ConversionHelperAidl {
@@ -181,6 +207,8 @@
status_t getObservablePosition(int64_t *frames, int64_t *timestamp);
+ status_t getHardwarePosition(int64_t *frames, int64_t *timestamp);
+
status_t getXruns(int32_t *frames);
status_t transfer(void *buffer, size_t bytes, size_t *transferred);
diff --git a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
index 2df2f5d..e8d8998 100644
--- a/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
+++ b/media/libaudiohal/include/media/audiohal/DeviceHalInterface.h
@@ -132,13 +132,14 @@
std::vector<media::audio::common::AudioMMapPolicyInfo> *policyInfos) = 0;
virtual int32_t getAAudioMixerBurstCount() = 0;
virtual int32_t getAAudioHardwareBurstMinUsec() = 0;
+
virtual int32_t supportsBluetoothVariableLatency(bool* supports) = 0;
// Update the connection status of an external device.
- virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) {
- ALOGE("%s override me port %p connected %d", __func__, port, connected);
- return OK;
- }
+ virtual status_t setConnectedState(const struct audio_port_v7* port, bool connected) = 0;
+
+ // Enable simulation of external devices connection at the HAL level.
+ virtual status_t setSimulateDeviceConnections(bool enabled) = 0;
virtual error::Result<audio_hw_sync_t> getHwAvSync() = 0;
diff --git a/media/libaudiohal/tests/Android.bp b/media/libaudiohal/tests/Android.bp
index 2f78dd0..8210f7d 100644
--- a/media/libaudiohal/tests/Android.bp
+++ b/media/libaudiohal/tests/Android.bp
@@ -20,18 +20,12 @@
default_applicable_licenses: ["frameworks_av_license"],
}
-cc_test {
- name: "EffectsFactoryHalInterfaceTest",
+cc_defaults {
+ name: "AudioHalTestDefaults",
test_suites: ["device-tests"],
-
- srcs: [
- "EffectsFactoryHalInterface_test.cpp",
- ],
-
defaults: [
"latest_android_media_audio_common_types_ndk_shared",
],
-
cflags: [
"-Wall",
"-Wextra",
@@ -48,8 +42,31 @@
"libutils",
"libvibrator",
],
+}
- header_libs: [
- "libaudiohal_headers",
+cc_test {
+ name: "EffectsFactoryHalInterfaceTest",
+ srcs: ["EffectsFactoryHalInterface_test.cpp"],
+ defaults: ["AudioHalTestDefaults"],
+ header_libs: ["libaudiohal_headers"],
+}
+
+cc_test {
+ name: "EffectProxyTest",
+ srcs: [
+ "EffectProxy_test.cpp",
+ ":audio_effectproxy_src_files",
],
+ defaults: [
+ "AudioHalTestDefaults",
+ "latest_android_hardware_audio_effect_ndk_shared",
+ "libaudiohal_default",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ shared_libs: [
+ "android.hardware.common.fmq-V1-ndk",
+ "libbinder_ndk",
+ "libfmq",
+ ],
+ header_libs: ["libaudiohalimpl_headers"],
}
diff --git a/media/libaudiohal/tests/EffectProxy_test.cpp b/media/libaudiohal/tests/EffectProxy_test.cpp
new file mode 100644
index 0000000..92e3dce
--- /dev/null
+++ b/media/libaudiohal/tests/EffectProxy_test.cpp
@@ -0,0 +1,357 @@
+/*
+ * 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
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <utility>
+#define LOG_TAG "EffectProxyTest"
+
+#include <aidl/android/media/audio/common/AudioUuid.h>
+#include <aidl/Vintf.h>
+#include <android/binder_manager.h>
+#include <gtest/gtest.h>
+#include <utils/RefBase.h>
+
+#include "EffectProxy.h"
+
+/**
+ * This test suite is depending on audio effect AIDL service.
+ */
+namespace android {
+
+using ::aidl::android::hardware::audio::effect::CommandId;
+using ::aidl::android::hardware::audio::effect::Descriptor;
+using ::aidl::android::hardware::audio::effect::Flags;
+using ::aidl::android::hardware::audio::effect::IEffect;
+using ::aidl::android::hardware::audio::effect::IFactory;
+using ::aidl::android::hardware::audio::effect::Parameter;
+using ::aidl::android::hardware::audio::effect::State;
+using ::aidl::android::media::audio::common::AudioChannelLayout;
+using ::aidl::android::media::audio::common::AudioFormatDescription;
+using ::aidl::android::media::audio::common::AudioFormatType;
+using ::aidl::android::media::audio::common::AudioUuid;
+using ::aidl::android::media::audio::common::PcmType;
+using ::android::effect::EffectProxy;
+
+class EffectProxyTest : public testing::Test {
+ public:
+ void SetUp() override {
+ auto serviceName = android::getAidlHalInstanceNames(IFactory::descriptor);
+ // only unit test with the first one in case more than one EffectFactory service exist
+ ASSERT_NE(0ul, serviceName.size());
+ mFactory = IFactory::fromBinder(
+ ndk::SpAIBinder(AServiceManager_waitForService(serviceName[0].c_str())));
+ ASSERT_NE(nullptr, mFactory);
+ mFactory->queryEffects(std::nullopt, std::nullopt, std::nullopt, &mDescs);
+ for (const auto& desc : mDescs) {
+ if (desc.common.id.proxy.has_value()) {
+ mProxyDescs.insert({desc.common.id, desc});
+ }
+ }
+ }
+
+ void TearDown() override {}
+
+ const AudioFormatDescription kDefaultFormatDescription = {
+ .type = AudioFormatType::PCM, .pcm = PcmType::FLOAT_32_BIT, .encoding = ""};
+
+ Parameter::Common createParamCommon(
+ int session = 0, int ioHandle = -1, int iSampleRate = 48000, int oSampleRate = 48000,
+ long iFrameCount = 0x100, long oFrameCount = 0x100,
+ AudioChannelLayout inputChannelLayout =
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO),
+ AudioChannelLayout outputChannelLayout =
+ AudioChannelLayout::make<AudioChannelLayout::layoutMask>(
+ AudioChannelLayout::LAYOUT_STEREO)) {
+ Parameter::Common common;
+ common.session = session;
+ common.ioHandle = ioHandle;
+
+ auto& input = common.input;
+ auto& output = common.output;
+ input.base.sampleRate = iSampleRate;
+ input.base.channelMask = inputChannelLayout;
+ input.base.format = kDefaultFormatDescription;
+ input.frameCount = iFrameCount;
+ output.base.sampleRate = oSampleRate;
+ output.base.channelMask = outputChannelLayout;
+ output.base.format = kDefaultFormatDescription;
+ output.frameCount = oFrameCount;
+ return common;
+ }
+
+ static bool isFlagSet(const ::aidl::android::hardware::audio::effect::Descriptor& desc,
+ Flags::HardwareAccelerator flag) {
+ return desc.common.flags.hwAcceleratorMode == flag;
+ }
+
+ enum TupleIndex { HANDLE, DESCRIPTOR };
+ using EffectProxyTuple = std::tuple<std::shared_ptr<EffectProxy>, std::vector<Descriptor>>;
+
+ std::map<AudioUuid, EffectProxyTuple> createAllProxies() {
+ std::map<AudioUuid, EffectProxyTuple> proxyMap;
+ for (const auto& itor : mProxyDescs) {
+ const auto& uuid = itor.first.proxy.value();
+ if (proxyMap.end() == proxyMap.find(uuid)) {
+ std::get<TupleIndex::HANDLE>(proxyMap[uuid]) =
+ ndk::SharedRefBase::make<EffectProxy>(itor.first, mFactory);
+ }
+ }
+ return proxyMap;
+ }
+
+ bool addAllSubEffects(std::map<AudioUuid, EffectProxyTuple> proxyMap) {
+ for (auto& itor : mProxyDescs) {
+ const auto& uuid = itor.first.proxy.value();
+ if (proxyMap.end() == proxyMap.find(uuid)) {
+ return false;
+ }
+ auto& proxy = std::get<TupleIndex::HANDLE>(proxyMap[uuid]);
+ if (!proxy->addSubEffect(itor.second).isOk()) {
+ return false;
+ }
+ std::get<TupleIndex::DESCRIPTOR>(proxyMap[uuid]).emplace_back(itor.second);
+ }
+ return true;
+ }
+
+ std::shared_ptr<IFactory> mFactory;
+ std::vector<Descriptor> mDescs;
+ std::map<Descriptor::Identity, Descriptor> mProxyDescs;
+};
+
+TEST_F(EffectProxyTest, createProxy) {
+ auto proxyMap = createAllProxies();
+ // if there are some descriptor defined with proxy, then proxyMap can not be empty
+ EXPECT_EQ(mProxyDescs.size() == 0, proxyMap.size() == 0);
+}
+
+TEST_F(EffectProxyTest, addSubEffectsCreateAndDestroy) {
+ auto proxyMap = createAllProxies();
+ ASSERT_TRUE(addAllSubEffects(proxyMap));
+
+ for (const auto& itor : proxyMap) {
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+TEST_F(EffectProxyTest, addSubEffectsCreateOpenCloseDestroy) {
+ auto proxyMap = createAllProxies();
+ EXPECT_TRUE(addAllSubEffects(proxyMap));
+
+ Parameter::Common common = createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ for (const auto& itor : proxyMap) {
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+// Add sub-effects, set active sub-effect with different checkers
+TEST_F(EffectProxyTest, setOffloadParam) {
+ auto proxyMap = createAllProxies();
+ EXPECT_TRUE(addAllSubEffects(proxyMap));
+
+ // Any flag exist should be able to set successfully
+ bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
+ for (const auto& itor : mProxyDescs) {
+ isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
+ isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
+ isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
+ }
+
+ Parameter::Common common = createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ for (const auto& itor : proxyMap) {
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
+ effect_offload_param_t offloadParam{false, 0};
+ EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+ offloadParam.isOffload = true;
+ EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+TEST_F(EffectProxyTest, destroyWithoutCreate) {
+ auto proxyMap = createAllProxies();
+ ASSERT_TRUE(addAllSubEffects(proxyMap));
+
+ for (const auto& itor : proxyMap) {
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+TEST_F(EffectProxyTest, closeWithoutOpen) {
+ auto proxyMap = createAllProxies();
+ ASSERT_TRUE(addAllSubEffects(proxyMap));
+
+ for (const auto& itor : proxyMap) {
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+// Add sub-effects, set active sub-effect, create, open, and send command, expect success handling
+TEST_F(EffectProxyTest, normalSequency) {
+ auto proxyMap = createAllProxies();
+ ASSERT_TRUE(addAllSubEffects(proxyMap));
+
+ bool isTunnelExist = [&]() {
+ for (const auto& itor : mProxyDescs) {
+ if (isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL)) {
+ return true;
+ }
+ }
+ return false;
+ }();
+
+ Parameter::Common common = createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ Parameter::VolumeStereo volumeStereo({.left = .1f, .right = -0.8f});
+ Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
+ Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
+ State state;
+ for (const auto& itor : proxyMap) {
+ Parameter expect;
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ effect_offload_param_t offloadParam{true, 0};
+ EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
+
+ EXPECT_TRUE(proxy->setParameter(param).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
+ EXPECT_EQ(expect, param);
+
+ EXPECT_TRUE(proxy->command(CommandId::START).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::PROCESSING, state);
+
+ EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::IDLE, state);
+
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+// setParameter, change active sub-effect, verify with getParameter
+TEST_F(EffectProxyTest, changeActiveSubAndVerifyParameter) {
+ auto proxyMap = createAllProxies();
+ EXPECT_TRUE(addAllSubEffects(proxyMap));
+
+ bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
+ for (const auto& itor : mProxyDescs) {
+ isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
+ isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
+ isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
+ }
+
+ Parameter::Common common = createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ Parameter::VolumeStereo volumeStereo({.left = .5f, .right = .8f});
+ Parameter param = Parameter::make<Parameter::volumeStereo>(volumeStereo);
+ Parameter::Id id = Parameter::Id::make<Parameter::Id::commonTag>(Parameter::volumeStereo);
+ for (const auto& itor : proxyMap) {
+ Parameter expect;
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
+ EXPECT_TRUE(proxy->setParameter(param).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
+ EXPECT_EQ(expect, param);
+
+ effect_offload_param_t offloadParam{false, 0};
+ EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
+ EXPECT_EQ(expect, param);
+
+ offloadParam.isOffload = true;
+ EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+ EXPECT_TRUE(proxy->getParameter(id, &expect).isOk());
+ EXPECT_EQ(expect, param);
+
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+// send command, change active sub-effect, then verify the state with getState
+TEST_F(EffectProxyTest, changeActiveSubAndVerifyState) {
+ auto proxyMap = createAllProxies();
+ ASSERT_TRUE(addAllSubEffects(proxyMap));
+
+ bool isNoneExist = false, isSimpleExist = false, isTunnelExist = false;
+ for (const auto& itor : mProxyDescs) {
+ isNoneExist = isNoneExist || isFlagSet(itor.second, Flags::HardwareAccelerator::NONE);
+ isSimpleExist = isSimpleExist || isFlagSet(itor.second, Flags::HardwareAccelerator::SIMPLE);
+ isTunnelExist = isTunnelExist || isFlagSet(itor.second, Flags::HardwareAccelerator::TUNNEL);
+ }
+
+ Parameter::Common common = createParamCommon();
+ IEffect::OpenEffectReturn ret;
+ State state;
+ for (const auto& itor : proxyMap) {
+ Parameter expect;
+ auto& proxy = std::get<TupleIndex::HANDLE>(itor.second);
+ EXPECT_TRUE(proxy->create().isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::INIT, state);
+ EXPECT_TRUE(proxy->open(common, std::nullopt, &ret).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::IDLE, state);
+ EXPECT_TRUE(proxy->command(CommandId::START).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::PROCESSING, state);
+
+ effect_offload_param_t offloadParam{false, 0};
+ EXPECT_EQ(isNoneExist || isSimpleExist, proxy->setOffloadParam(&offloadParam).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::PROCESSING, state);
+
+ offloadParam.isOffload = true;
+ EXPECT_EQ(isTunnelExist, proxy->setOffloadParam(&offloadParam).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::PROCESSING, state);
+
+ EXPECT_TRUE(proxy->command(CommandId::STOP).isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::IDLE, state);
+
+ EXPECT_TRUE(proxy->close().isOk());
+ EXPECT_TRUE(proxy->getState(&state).isOk());
+ EXPECT_EQ(State::INIT, state);
+ EXPECT_TRUE(proxy->destroy().isOk());
+ }
+}
+
+} // namespace android
diff --git a/media/libeffects/dynamicsproc/Android.bp b/media/libeffects/dynamicsproc/Android.bp
index 736a086..7838117 100644
--- a/media/libeffects/dynamicsproc/Android.bp
+++ b/media/libeffects/dynamicsproc/Android.bp
@@ -92,6 +92,10 @@
"dynamicsprocessingdefaults",
],
+ static_libs: [
+ "libaudioaidlranges",
+ ],
+
visibility: [
"//hardware/interfaces/audio/aidl/default",
],
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
index e508d48..f1619a8 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.cpp
@@ -62,32 +62,135 @@
const std::string DynamicsProcessingImpl::kEffectName = "DynamicsProcessing";
-const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMin =
+static const Range::DynamicsProcessingRange kEngineConfigRange = {
+ .min = DynamicsProcessing::make<
+ DynamicsProcessing::engineArchitecture>(DynamicsProcessing::EngineArchitecture(
+ {.resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = 0,
+ .preEqStage = {.inUse = false, .bandCount = 0},
+ .postEqStage = {.inUse = false, .bandCount = 0},
+ .mbcStage = {.inUse = false, .bandCount = 0},
+ .limiterInUse = false})),
+ .max = DynamicsProcessing::make<
+ DynamicsProcessing::engineArchitecture>(DynamicsProcessing::EngineArchitecture(
+ {.resolutionPreference =
+ DynamicsProcessing::ResolutionPreference::FAVOR_FREQUENCY_RESOLUTION,
+ .preferredProcessingDurationMs = std::numeric_limits<float>::max(),
+ .preEqStage = {.inUse = true, .bandCount = std::numeric_limits<int>::max()},
+ .postEqStage = {.inUse = true, .bandCount = std::numeric_limits<int>::max()},
+ .mbcStage = {.inUse = true, .bandCount = std::numeric_limits<int>::max()},
+ .limiterInUse = true}))};
+
+static const DynamicsProcessing::ChannelConfig kChannelConfigMin =
+ DynamicsProcessing::ChannelConfig({.channel = 0, .enable = false});
+
+static const DynamicsProcessing::ChannelConfig kChannelConfigMax =
+ DynamicsProcessing::ChannelConfig(
+ {.channel = std::numeric_limits<int>::max(), .enable = true});
+
+static const Range::DynamicsProcessingRange kPreEqChannelConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::preEq>({kChannelConfigMin}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::preEq>({kChannelConfigMax})};
+
+static const Range::DynamicsProcessingRange kPostEqChannelConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::postEq>({kChannelConfigMin}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::postEq>({kChannelConfigMax})};
+
+static const Range::DynamicsProcessingRange kMbcChannelConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::mbc>({kChannelConfigMin}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::mbc>({kChannelConfigMax})};
+
+static const DynamicsProcessing::EqBandConfig kEqBandConfigMin =
DynamicsProcessing::EqBandConfig({.channel = 0,
.band = 0,
.enable = false,
.cutoffFrequencyHz = 220,
- .gainDb = std::numeric_limits<float>::min()});
-const DynamicsProcessing::EqBandConfig DynamicsProcessingImpl::kEqBandConfigMax =
+ .gainDb = std::numeric_limits<float>::lowest()});
+
+static const DynamicsProcessing::EqBandConfig kEqBandConfigMax =
DynamicsProcessing::EqBandConfig({.channel = std::numeric_limits<int>::max(),
.band = std::numeric_limits<int>::max(),
.enable = true,
.cutoffFrequencyHz = 20000,
.gainDb = std::numeric_limits<float>::max()});
-const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPreEqBandRange = {
- .min = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
- {DynamicsProcessingImpl::kEqBandConfigMin}),
- .max = DynamicsProcessing::make<DynamicsProcessing::preEqBand>(
- {DynamicsProcessingImpl::kEqBandConfigMax})};
-const Range::DynamicsProcessingRange DynamicsProcessingImpl::kPostEqBandRange = {
- .min = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
- {DynamicsProcessingImpl::kEqBandConfigMin}),
- .max = DynamicsProcessing::make<DynamicsProcessing::postEqBand>(
- {DynamicsProcessingImpl::kEqBandConfigMax})};
-const Range DynamicsProcessingImpl::kRange =
- Range::make<Range::dynamicsProcessing>({DynamicsProcessingImpl::kPreEqBandRange});
-const Capability DynamicsProcessingImpl::kCapability = {.range = {DynamicsProcessingImpl::kRange}};
+static const Range::DynamicsProcessingRange kPreEqBandConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::preEqBand>({kEqBandConfigMin}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::preEqBand>({kEqBandConfigMax})};
+
+static const Range::DynamicsProcessingRange kPostEqBandConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::postEqBand>({kEqBandConfigMin}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::postEqBand>({kEqBandConfigMax})};
+
+static const Range::DynamicsProcessingRange kMbcBandConfigRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::mbcBand>(
+ {DynamicsProcessing::MbcBandConfig(
+ {.channel = 0,
+ .band = 0,
+ .enable = false,
+ .cutoffFrequencyHz = 220,
+ .attackTimeMs = 0,
+ .releaseTimeMs = 0,
+ .ratio = 0,
+ .thresholdDb = std::numeric_limits<float>::lowest(),
+ .kneeWidthDb = 0,
+ .noiseGateThresholdDb = std::numeric_limits<float>::lowest(),
+ .expanderRatio = 0,
+ .preGainDb = std::numeric_limits<float>::lowest(),
+ .postGainDb = std::numeric_limits<float>::lowest()})}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::mbcBand>(
+ {DynamicsProcessing::MbcBandConfig(
+ {.channel = std::numeric_limits<int>::max(),
+ .band = std::numeric_limits<int>::max(),
+ .enable = true,
+ .cutoffFrequencyHz = 20000,
+ .attackTimeMs = std::numeric_limits<float>::max(),
+ .releaseTimeMs = std::numeric_limits<float>::max(),
+ .ratio = std::numeric_limits<float>::max(),
+ .thresholdDb = 0,
+ .kneeWidthDb = std::numeric_limits<float>::max(),
+ .noiseGateThresholdDb = 0,
+ .expanderRatio = std::numeric_limits<float>::max(),
+ .preGainDb = std::numeric_limits<float>::max(),
+ .postGainDb = std::numeric_limits<float>::max()})})};
+
+static const Range::DynamicsProcessingRange kInputGainRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::inputGain>(
+ {DynamicsProcessing::InputGain(
+ {.channel = 0, .gainDb = std::numeric_limits<float>::lowest()})}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::inputGain>(
+ {DynamicsProcessing::InputGain({.channel = std::numeric_limits<int>::max(),
+ .gainDb = std::numeric_limits<float>::max()})})};
+
+static const Range::DynamicsProcessingRange kLimiterRange = {
+ .min = DynamicsProcessing::make<DynamicsProcessing::limiter>(
+ {DynamicsProcessing::LimiterConfig(
+ {.channel = 0,
+ .enable = false,
+ .linkGroup = std::numeric_limits<int>::min(),
+ .attackTimeMs = 0,
+ .releaseTimeMs = 0,
+ .ratio = 0,
+ .thresholdDb = std::numeric_limits<float>::min(),
+ .postGainDb = std::numeric_limits<float>::min()})}),
+ .max = DynamicsProcessing::make<DynamicsProcessing::limiter>(
+ {DynamicsProcessing::LimiterConfig(
+ {.channel = std::numeric_limits<int>::max(),
+ .enable = true,
+ .linkGroup = std::numeric_limits<int>::max(),
+ .attackTimeMs = std::numeric_limits<float>::max(),
+ .releaseTimeMs = std::numeric_limits<float>::max(),
+ .ratio = std::numeric_limits<float>::max(),
+ .thresholdDb = 0,
+ .postGainDb = std::numeric_limits<float>::max()})})};
+
+const std::vector<Range::DynamicsProcessingRange> kRanges = {
+ kEngineConfigRange, kPreEqChannelConfigRange, kPostEqChannelConfigRange,
+ kMbcChannelConfigRange, kPreEqBandConfigRange, kPostEqBandConfigRange,
+ kMbcBandConfigRange, kInputGainRange, kLimiterRange};
+
+const Capability DynamicsProcessingImpl::kCapability = {.range = kRanges};
const Descriptor DynamicsProcessingImpl::kDescriptor = {
.common = {.id = {.type = getEffectTypeUuidDynamicsProcessing(),
@@ -158,14 +261,19 @@
}
}
+bool DynamicsProcessingImpl::isParamInRange(const Parameter::Specific& specific) {
+ auto& dp = specific.get<Parameter::Specific::dynamicsProcessing>();
+ return DynamicsProcessingRanges::isParamInRange(dp, kRanges);
+}
+
ndk::ScopedAStatus DynamicsProcessingImpl::setParameterSpecific(
const Parameter::Specific& specific) {
RETURN_IF(Parameter::Specific::dynamicsProcessing != specific.getTag(), EX_ILLEGAL_ARGUMENT,
"EffectNotSupported");
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
+ RETURN_IF(!isParamInRange(specific), EX_ILLEGAL_ARGUMENT, "outOfRange");
auto& param = specific.get<Parameter::Specific::dynamicsProcessing>();
- // TODO: check range here, dynamicsProcessing need customized method for nested parameters.
auto tag = param.getTag();
switch (tag) {
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
index d094c69..1e1e72e 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessing.h
@@ -18,8 +18,9 @@
#include <aidl/android/hardware/audio/effect/BnEffect.h>
-#include "effect-impl/EffectImpl.h"
#include "DynamicsProcessingContext.h"
+#include "EffectRangeSpecific.h"
+#include "effect-impl/EffectImpl.h"
namespace aidl::android::hardware::audio::effect {
@@ -51,14 +52,10 @@
std::string getEffectName() override { return kEffectName; }
private:
- static const DynamicsProcessing::EqBandConfig kEqBandConfigMin;
- static const DynamicsProcessing::EqBandConfig kEqBandConfigMax;
- static const Range::DynamicsProcessingRange kPreEqBandRange;
- static const Range::DynamicsProcessingRange kPostEqBandRange;
- static const Range kRange;
std::shared_ptr<DynamicsProcessingContext> mContext;
ndk::ScopedAStatus getParameterDynamicsProcessing(const DynamicsProcessing::Tag& tag,
Parameter::Specific* specific);
+ bool isParamInRange(const Parameter::Specific& specific);
};
} // namespace aidl::android::hardware::audio::effect
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
index 69ff522..9d77135 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.cpp
@@ -16,11 +16,11 @@
#define LOG_TAG "AHAL_DPLibEffectsContext"
-#include "DynamicsProcessing.h"
#include "DynamicsProcessingContext.h"
+#include "DynamicsProcessing.h"
-#include <functional>
#include <sys/param.h>
+#include <functional>
#include <unordered_set>
namespace aidl::android::hardware::audio::effect {
@@ -83,7 +83,7 @@
if (block < minBlockSize) {
block = minBlockSize;
} else if (!powerof2(block)) {
- //find next highest power of 2.
+ // find next highest power of 2.
block = 1 << (32 - __builtin_clz(block));
}
mDpFreq->configure(block, block >> 1, sampleRate);
@@ -91,9 +91,6 @@
RetCode DynamicsProcessingContext::setEngineArchitecture(
const DynamicsProcessing::EngineArchitecture& engineArchitecture) {
- RETURN_VALUE_IF(!validateEngineConfig(engineArchitecture), RetCode::ERROR_ILLEGAL_PARAMETER,
- "illegalEngineConfig");
-
std::lock_guard lg(mMutex);
if (!mEngineInited || mEngineArchitecture != engineArchitecture) {
if (engineArchitecture.resolutionPreference ==
@@ -134,10 +131,12 @@
RetCode DynamicsProcessingContext::setPreEqBand(
const std::vector<DynamicsProcessing::EqBandConfig>& bands) {
std::lock_guard lg(mMutex);
- RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
- "postEqNotInUse");
- return setBands_l<DynamicsProcessing::EqBandConfig>(
- bands, mEngineArchitecture.preEqStage.bandCount, StageType::PREEQ);
+ RETURN_VALUE_IF(!mEngineArchitecture.preEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
+ "preEqNotInUse");
+ RETURN_VALUE_IF(
+ !validateBandConfig(bands, mChannelCount, mEngineArchitecture.preEqStage.bandCount),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
+ return setBands_l<DynamicsProcessing::EqBandConfig>(bands, StageType::PREEQ);
}
RetCode DynamicsProcessingContext::setPostEqBand(
@@ -145,8 +144,10 @@
std::lock_guard lg(mMutex);
RETURN_VALUE_IF(!mEngineArchitecture.postEqStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
"postEqNotInUse");
- return setBands_l<DynamicsProcessing::EqBandConfig>(
- bands, mEngineArchitecture.postEqStage.bandCount, StageType::POSTEQ);
+ RETURN_VALUE_IF(
+ !validateBandConfig(bands, mChannelCount, mEngineArchitecture.postEqStage.bandCount),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
+ return setBands_l<DynamicsProcessing::EqBandConfig>(bands, StageType::POSTEQ);
}
RetCode DynamicsProcessingContext::setMbcBand(
@@ -154,8 +155,10 @@
std::lock_guard lg(mMutex);
RETURN_VALUE_IF(!mEngineArchitecture.mbcStage.inUse, RetCode::ERROR_ILLEGAL_PARAMETER,
"mbcNotInUse");
- return setBands_l<DynamicsProcessing::MbcBandConfig>(
- bands, mEngineArchitecture.preEqStage.bandCount, StageType::MBC);
+ RETURN_VALUE_IF(
+ !validateBandConfig(bands, mChannelCount, mEngineArchitecture.mbcStage.bandCount),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
+ return setBands_l<DynamicsProcessing::MbcBandConfig>(bands, StageType::MBC);
}
RetCode DynamicsProcessingContext::setLimiter(
@@ -163,13 +166,17 @@
std::lock_guard lg(mMutex);
RETURN_VALUE_IF(!mEngineArchitecture.limiterInUse, RetCode::ERROR_ILLEGAL_PARAMETER,
"limiterNotInUse");
- return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, -1, StageType::LIMITER);
+ RETURN_VALUE_IF(!validateLimiterConfig(limiters, mChannelCount),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "limiterConfigNotValid");
+ return setBands_l<DynamicsProcessing::LimiterConfig>(limiters, StageType::LIMITER);
}
RetCode DynamicsProcessingContext::setInputGain(
const std::vector<DynamicsProcessing::InputGain>& inputGains) {
std::lock_guard lg(mMutex);
- return setBands_l<DynamicsProcessing::InputGain>(inputGains, -1, StageType::INPUTGAIN);
+ RETURN_VALUE_IF(!validateInputGainConfig(inputGains, mChannelCount),
+ RetCode::ERROR_ILLEGAL_PARAMETER, "inputGainNotValid");
+ return setBands_l<DynamicsProcessing::InputGain>(inputGains, StageType::INPUTGAIN);
}
DynamicsProcessing::EngineArchitecture DynamicsProcessingContext::getEngineArchitecture() {
@@ -406,45 +413,33 @@
return eqBands;
}
-/**
- * When StageEnablement is in use, bandCount needs to be positive.
- */
-bool DynamicsProcessingContext::validateStageEnablement(
- const DynamicsProcessing::StageEnablement& enablement) {
- return !enablement.inUse || (enablement.inUse && enablement.bandCount > 0);
-}
-
-bool DynamicsProcessingContext::validateEngineConfig(
- const DynamicsProcessing::EngineArchitecture& engine) {
- return engine.preferredProcessingDurationMs >= 0 &&
- validateStageEnablement(engine.preEqStage) &&
- validateStageEnablement(engine.postEqStage) && validateStageEnablement(engine.mbcStage);
-}
-
-bool DynamicsProcessingContext::validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band,
- int maxChannel, int maxBand) {
- return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand);
-}
-
-bool DynamicsProcessingContext::validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band,
- int maxChannel, int maxBand) {
- return validateChannel(band.channel, maxChannel) && validateBand(band.band, maxBand) &&
- validateTime(band.attackTimeMs) && validateTime(band.releaseTimeMs) &&
- validateRatio(band.ratio) && validateBandDb(band.thresholdDb) &&
- validateBandDb(band.kneeWidthDb) && validateBandDb(band.noiseGateThresholdDb) &&
- validateRatio(band.expanderRatio);
+template <typename T>
+bool DynamicsProcessingContext::validateBandConfig(const std::vector<T>& bands, int maxChannel,
+ int maxBand) {
+ std::vector<float> freqs(bands.size(), -1);
+ for (auto band : bands) {
+ if (!validateChannel(band.channel, maxChannel)) return false;
+ if (!validateBand(band.band, maxBand)) return false;
+ freqs[band.band] = band.cutoffFrequencyHz;
+ }
+ if (std::count(freqs.begin(), freqs.end(), -1)) return false;
+ return std::is_sorted(freqs.begin(), freqs.end());
}
bool DynamicsProcessingContext::validateLimiterConfig(
- const DynamicsProcessing::LimiterConfig& limiter, int maxChannel) {
- return validateChannel(limiter.channel, maxChannel) && validateTime(limiter.attackTimeMs) &&
- validateTime(limiter.releaseTimeMs) && validateRatio(limiter.ratio) &&
- validateBandDb(limiter.thresholdDb);
+ const std::vector<DynamicsProcessing::LimiterConfig>& cfgs, int maxChannel) {
+ for (auto cfg : cfgs) {
+ if (!validateChannel(cfg.channel, maxChannel)) return false;
+ }
+ return true;
}
-bool DynamicsProcessingContext::validateInputGainConfig(const DynamicsProcessing::InputGain& gain,
- int maxChannel) {
- return validateChannel(gain.channel, maxChannel);
+bool DynamicsProcessingContext::validateInputGainConfig(
+ const std::vector<DynamicsProcessing::InputGain>& cfgs, int maxChannel) {
+ for (auto cfg : cfgs) {
+ if (!validateChannel(cfg.channel, maxChannel)) return false;
+ }
+ return true;
}
template <typename D>
@@ -483,7 +478,6 @@
}
RetCode DynamicsProcessingContext::setDpChannelBand_l(const std::any& anyConfig, StageType type,
- int maxCh, int maxBand,
std::set<std::pair<int, int>>& chBandSet) {
RETURN_VALUE_IF(!anyConfig.has_value(), RetCode::ERROR_ILLEGAL_PARAMETER, "bandInvalid");
RetCode ret = RetCode::SUCCESS;
@@ -494,8 +488,6 @@
case StageType::POSTEQ: {
dp_fx::DPEq* dp;
const auto& config = std::any_cast<DynamicsProcessing::EqBandConfig>(anyConfig);
- RETURN_VALUE_IF(!validateEqBandConfig(config, maxCh, maxBand),
- RetCode::ERROR_ILLEGAL_PARAMETER, "eqBandNotValid");
RETURN_VALUE_IF(
nullptr == (dp = getEqWithType_l(type, config.channel)) || !dp->isEnabled(),
RetCode::ERROR_ILLEGAL_PARAMETER, "dpEqNotExist");
@@ -508,8 +500,6 @@
case StageType::MBC: {
dp_fx::DPMbc* dp;
const auto& config = std::any_cast<DynamicsProcessing::MbcBandConfig>(anyConfig);
- RETURN_VALUE_IF(!validateMbcBandConfig(config, maxCh, maxBand),
- RetCode::ERROR_ILLEGAL_PARAMETER, "mbcBandNotValid");
RETURN_VALUE_IF(nullptr == (dp = getMbc_l(config.channel)) || !dp->isEnabled(),
RetCode::ERROR_ILLEGAL_PARAMETER, "dpMbcNotExist");
dp_fx::DPMbcBand band;
@@ -524,8 +514,6 @@
case StageType::LIMITER: {
dp_fx::DPChannel* dp;
const auto& config = std::any_cast<DynamicsProcessing::LimiterConfig>(anyConfig);
- RETURN_VALUE_IF(!validateLimiterConfig(config, maxCh),
- RetCode::ERROR_ILLEGAL_PARAMETER, "limiterBandNotValid");
RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
dp_fx::DPLimiter limiter;
@@ -539,8 +527,6 @@
case StageType::INPUTGAIN: {
dp_fx::DPChannel* dp;
const auto& config = std::any_cast<DynamicsProcessing::InputGain>(anyConfig);
- RETURN_VALUE_IF(!validateInputGainConfig(config, maxCh),
- RetCode::ERROR_ILLEGAL_PARAMETER, "inputGainNotValid");
RETURN_VALUE_IF(nullptr == (dp = getChannel_l(config.channel)),
RetCode::ERROR_ILLEGAL_PARAMETER, "dpChNotExist");
dp->setInputGain(config.gainDb);
@@ -555,14 +541,12 @@
}
template <typename T /* BandConfig */>
-RetCode DynamicsProcessingContext::setBands_l(
- const std::vector<T>& bands, int maxBand, StageType type) {
+RetCode DynamicsProcessingContext::setBands_l(const std::vector<T>& bands, StageType type) {
RetCode ret = RetCode::SUCCESS;
std::set<std::pair<int /* channel */, int /* band */>> bandSet;
for (const auto& it : bands) {
- if (RetCode::SUCCESS !=
- setDpChannelBand_l(std::make_any<T>(it), type, mChannelCount, maxBand, bandSet)) {
+ if (RetCode::SUCCESS != setDpChannelBand_l(std::make_any<T>(it), type, bandSet)) {
LOG(WARNING) << __func__ << " skipping band " << it.toString();
ret = RetCode::ERROR_ILLEGAL_PARAMETER;
continue;
diff --git a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
index 8be784e..b8539f6 100644
--- a/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
+++ b/media/libeffects/dynamicsproc/aidl/DynamicsProcessingContext.h
@@ -103,28 +103,22 @@
RetCode setDpChannels_l(const std::vector<DynamicsProcessing::ChannelConfig>& channels,
bool stageInUse, StageType type) REQUIRES(mMutex);
template <typename T /* BandConfig */>
- RetCode setBands_l(const std::vector<T>& bands, int maxBand, StageType type) REQUIRES(mMutex);
- RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type, int maxCh, int maxBand,
+ RetCode setBands_l(const std::vector<T>& bands, StageType type) REQUIRES(mMutex);
+ RetCode setDpChannelBand_l(const std::any& anyConfig, StageType type,
std::set<std::pair<int, int>>& chBandSet) REQUIRES(mMutex);
std::vector<DynamicsProcessing::EqBandConfig> getEqBandConfigs(StageType type);
std::vector<DynamicsProcessing::ChannelConfig> getChannelConfig(StageType type);
- bool validateStageEnablement(const DynamicsProcessing::StageEnablement& enablement);
- bool validateEngineConfig(const DynamicsProcessing::EngineArchitecture& engine);
- bool validateEqBandConfig(const DynamicsProcessing::EqBandConfig& band, int maxChannel,
- int maxBand);
- bool validateMbcBandConfig(const DynamicsProcessing::MbcBandConfig& band, int maxChannel,
- int maxBand);
- bool validateLimiterConfig(const DynamicsProcessing::LimiterConfig& limiter, int maxChannel);
- bool validateInputGainConfig(const DynamicsProcessing::InputGain& gain, int maxChannel);
+ template <typename T /* BandConfig */>
+ bool validateBandConfig(const std::vector<T>& bands, int maxChannel, int maxBand);
+ bool validateLimiterConfig(const std::vector<DynamicsProcessing::LimiterConfig>& cfgs,
+ int maxChannel);
+ bool validateInputGainConfig(const std::vector<DynamicsProcessing::InputGain>& cfgs,
+ int maxChannel);
- inline bool validateCutoffFrequency(float freq);
inline bool validateChannel(int ch, int maxCh) { return ch >= 0 && ch < maxCh; }
inline bool validateBand(int band, int maxBand) { return band >= 0 && band < maxBand; }
- inline bool validateTime(int time) { return time >= 0; }
- inline bool validateRatio(int ratio) { return ratio >= 0; }
- inline bool validateBandDb(int db) { return db <= 0; }
};
} // namespace aidl::android::hardware::audio::effect
\ No newline at end of file
diff --git a/media/libheadtracking/PosePredictor.cpp b/media/libheadtracking/PosePredictor.cpp
index f67a966..5209d54 100644
--- a/media/libheadtracking/PosePredictor.cpp
+++ b/media/libheadtracking/PosePredictor.cpp
@@ -91,20 +91,23 @@
// Formatting
static inline std::vector<size_t> createDelimiterIdx(size_t predictors, size_t lookaheads) {
- if (predictors == 0) return {};
- --predictors;
- std::vector<size_t> delimiterIdx(predictors);
- for (size_t i = 0; i < predictors; ++i) {
- delimiterIdx[i] = (i + 1) * lookaheads;
+ if (lookaheads == 0) return {};
+ --lookaheads;
+ std::vector<size_t> delimiterIdx(lookaheads);
+ for (size_t i = 0; i < lookaheads; ++i) {
+ delimiterIdx[i] = (i + 1) * predictors;
}
return delimiterIdx;
}
PosePredictor::PosePredictor()
- : mPredictors{ // must match switch in getCurrentPredictor()
+ : mPredictors{
+ // First predictors must match switch in getCurrentPredictor()
std::make_shared<LastPredictor>(),
std::make_shared<TwistPredictor>(),
std::make_shared<LeastSquaresPredictor>(),
+ // After this, can place additional predictors here for comparison such as
+ // std::make_shared<LeastSquaresPredictor>(0.25),
}
, mLookaheadMs(kLookAheadMs.begin(), kLookAheadMs.end())
, mVerifiers(std::size(mLookaheadMs) * std::size(mPredictors))
@@ -195,7 +198,12 @@
if constexpr (kEnableVerification) {
// dump verification
ss.append(prefixSpace)
- .append(" Prediction abs error (L1) degrees [ type (last twist least-squares) x ( ");
+ .append(" Prediction abs error (L1) degrees [ type (");
+ for (size_t i = 0; i < mPredictors.size(); ++i) {
+ if (i > 0) ss.append(" , ");
+ ss.append(mPredictors[i]->name());
+ }
+ ss.append(" ) x ( ");
for (size_t i = 0; i < mLookaheadMs.size(); ++i) {
if (i > 0) ss.append(" : ");
ss.append(std::to_string(mLookaheadMs[i]));
diff --git a/media/libheadtracking/PosePredictor.h b/media/libheadtracking/PosePredictor.h
index 06983cc..53211e3 100644
--- a/media/libheadtracking/PosePredictor.h
+++ b/media/libheadtracking/PosePredictor.h
@@ -32,6 +32,7 @@
virtual void add(int64_t atNs, const Pose3f& pose, const Twist3f& twist) = 0;
virtual Pose3f predict(int64_t atNs) const = 0;
virtual void reset() = 0;
+ virtual std::string name() const = 0;
virtual std::string toString(size_t index) const = 0;
};
@@ -57,6 +58,10 @@
mLastPose = {};
}
+ std::string name() const override {
+ return "LAST";
+ }
+
std::string toString(size_t index) const override {
std::string s(index, ' ');
s.append("LastPredictor using last pose: ")
@@ -92,6 +97,10 @@
mLastTwist = {};
}
+ std::string name() const override {
+ return "TWIST";
+ }
+
std::string toString(size_t index) const override {
std::string s(index, ' ');
s.append("TwistPredictor using last pose: ")
@@ -130,13 +139,16 @@
void add(int64_t atNs, const Pose3f& pose, const Twist3f& twist) override;
Pose3f predict(int64_t atNs) const override;
void reset() override;
+ std::string name() const override {
+ return "LEAST_SQUARES(" + std::to_string(mAlpha) + ")";
+ }
std::string toString(size_t index) const override;
private:
const double mAlpha;
int64_t mLastAtNs{};
Pose3f mLastPose;
- static constexpr double kDefaultAlphaEstimator = 0.5;
+ static constexpr double kDefaultAlphaEstimator = 0.2;
static constexpr size_t kMinimumSamplesForPrediction = 4;
audio_utils::LinearLeastSquaresFit<double> mRw;
audio_utils::LinearLeastSquaresFit<double> mRx;
diff --git a/media/libheif/HeifDecoderImpl.cpp b/media/libheif/HeifDecoderImpl.cpp
index 7c78900..2ba1fc3 100644
--- a/media/libheif/HeifDecoderImpl.cpp
+++ b/media/libheif/HeifDecoderImpl.cpp
@@ -26,7 +26,6 @@
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
#include <drm/drm_framework_common.h>
-#include <log/log.h>
#include <media/mediametadataretriever.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/foundation/ADebug.h>
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index bdf1cbc..9e9e9d8 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -1837,7 +1837,6 @@
} else {
mAttributes = NULL;
}
-
setMinBufferCount();
}
diff --git a/media/libmediaplayerservice/fuzzer/Android.bp b/media/libmediaplayerservice/fuzzer/Android.bp
index 5abac81..5e95c87 100644
--- a/media/libmediaplayerservice/fuzzer/Android.bp
+++ b/media/libmediaplayerservice/fuzzer/Android.bp
@@ -46,6 +46,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmediaplayerservice",
+ vector: "remote",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libnbaio/AudioStreamOutSink.cpp b/media/libnbaio/AudioStreamOutSink.cpp
index 8c54a3a..0ab5874 100644
--- a/media/libnbaio/AudioStreamOutSink.cpp
+++ b/media/libnbaio/AudioStreamOutSink.cpp
@@ -103,19 +103,24 @@
void AudioStreamOutSink::startMelComputation(const sp<audio_utils::MelProcessor>& processor)
{
ALOGV("%s start mel computation for device %d", __func__, processor->getDeviceId());
- mMelProcessor = processor;
- // update format for MEL computation
+
+ mMelProcessor.store(processor);
if (processor) {
- processor->updateAudioFormat(mFormat.mSampleRate, mFormat.mChannelCount, mFormat.mFormat);
+ // update format for MEL computation
+ processor->updateAudioFormat(mFormat.mSampleRate,
+ mFormat.mChannelCount,
+ mFormat.mFormat);
+ processor->resume();
}
+
}
void AudioStreamOutSink::stopMelComputation()
{
auto melProcessor = mMelProcessor.load();
if (melProcessor != nullptr) {
- ALOGV("%s stop mel computation for device %d", __func__, melProcessor->getDeviceId());
- mMelProcessor = nullptr;
+ ALOGV("%s pause mel computation for device %d", __func__, melProcessor->getDeviceId());
+ melProcessor->pause();
}
}
diff --git a/media/libstagefright/ACodecBufferChannel.cpp b/media/libstagefright/ACodecBufferChannel.cpp
index 57f26d0..8f2bed2 100644
--- a/media/libstagefright/ACodecBufferChannel.cpp
+++ b/media/libstagefright/ACodecBufferChannel.cpp
@@ -347,7 +347,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer) {
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg) {
std::shared_ptr<const std::vector<const BufferInfo>> array(
std::atomic_load(&mInputBuffers));
BufferInfoIterator it = findClientBuffer(array, buffer);
@@ -371,7 +372,6 @@
ssize_t result = -1;
ssize_t codecDataOffset = 0;
if (mCrypto != NULL) {
- AString errorDetailMsg;
hardware::drm::V1_0::DestinationBuffer destination;
if (secure) {
destination.type = DrmBufferType::NATIVE_HANDLE;
@@ -387,7 +387,7 @@
result = mCrypto->decrypt(key, iv, mode, pattern,
source, it->mClientBuffer->offset(),
- subSamples, numSubSamples, destination, &errorDetailMsg);
+ subSamples, numSubSamples, destination, errorDetailMsg);
if (result < 0) {
return result;
@@ -441,7 +441,9 @@
result = (ssize_t)_bytesWritten;
detailedError = _detailedError;
});
-
+ if (errorDetailMsg) {
+ errorDetailMsg->setTo(detailedError.c_str(), detailedError.size());
+ }
if (!returnVoid.isOk() || status != Status::OK || result < 0) {
ALOGE("descramble failed, trans=%s, status=%d, result=%zd",
returnVoid.description().c_str(), status, result);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 88e3362..967c316 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -150,7 +150,8 @@
if (camera == 0) {
mCamera = Camera::connect(cameraId, clientName, clientUid, clientPid,
- /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false);
+ /*targetSdkVersion*/__ANDROID_API_FUTURE__, /*overrideToPortrait*/false,
+ /*forceSlowJpegMode*/false);
if (mCamera == 0) return -EBUSY;
mCameraFlags &= ~FLAGS_HOT_CAMERA;
} else {
diff --git a/media/libstagefright/CryptoAsync.cpp b/media/libstagefright/CryptoAsync.cpp
index 32fd3be..8b5c8ed 100644
--- a/media/libstagefright/CryptoAsync.cpp
+++ b/media/libstagefright/CryptoAsync.cpp
@@ -153,7 +153,7 @@
// attach buffer
err = channel->attachEncryptedBuffer(
memory, secure, key, iv, mode, pattern,
- offset, subSamples, numSubSamples, buffer);
+ offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
// a generic error
auto handleError = [this, &err, &msg]() {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index e5cc991..38df5d0 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -4290,11 +4290,10 @@
mFlags |= kFlagUseBlockModel;
}
if (flags & CONFIGURE_FLAG_USE_CRYPTO_ASYNC) {
- // silently disable crytoasync with blockmodel
- if (!(mFlags & kFlagUseBlockModel)) {
- mFlags |= kFlagUseCryptoAsync;
- } else {
- ALOGW("CrytoAsync not yet enabled for block model, falling back to normal");
+ mFlags |= kFlagUseCryptoAsync;
+ if ((mFlags & kFlagUseBlockModel)) {
+ ALOGW("CrytoAsync not yet enabled for block model,\
+ falling back to normal");
}
}
}
@@ -4324,17 +4323,23 @@
mBufferChannel->setDescrambler(mDescrambler);
if ((mFlags & kFlagUseCryptoAsync) &&
mCrypto && (mDomain == DOMAIN_VIDEO)) {
- mCryptoAsync = new CryptoAsync(mBufferChannel);
- mCryptoAsync->setCallback(
- std::make_unique<CryptoAsyncCallback>(new AMessage(kWhatCodecNotify, this)));
- mCryptoLooper = new ALooper();
- mCryptoLooper->setName("CryptoAsyncLooper");
- mCryptoLooper->registerHandler(mCryptoAsync);
- status_t err = mCryptoLooper->start();
- if (err != OK) {
- ALOGE("Crypto Looper failed to start");
- mCryptoAsync = nullptr;
- mCryptoLooper = nullptr;
+ // set kFlagUseCryptoAsync but do-not use this for block model
+ // this is to propagate the error in onCryptoError()
+ // TODO (b/274628160): Enable Use of CONFIG_FLAG_USE_CRYPTO_ASYNC
+ // with CONFIGURE_FLAG_USE_BLOCK_MODEL)
+ if (!(mFlags & kFlagUseBlockModel)) {
+ mCryptoAsync = new CryptoAsync(mBufferChannel);
+ mCryptoAsync->setCallback(
+ std::make_unique<CryptoAsyncCallback>(new AMessage(kWhatCodecNotify, this)));
+ mCryptoLooper = new ALooper();
+ mCryptoLooper->setName("CryptoAsyncLooper");
+ mCryptoLooper->registerHandler(mCryptoAsync);
+ status_t err = mCryptoLooper->start();
+ if (err != OK) {
+ ALOGE("Crypto Looper failed to start");
+ mCryptoAsync = nullptr;
+ mCryptoLooper = nullptr;
+ }
}
}
@@ -5510,9 +5515,24 @@
if (c2Buffer) {
err = mBufferChannel->attachBuffer(c2Buffer, buffer);
} else if (memory) {
+ AString errorDetailMsg;
err = mBufferChannel->attachEncryptedBuffer(
memory, (mFlags & kFlagIsSecure), key, iv, mode, pattern,
- offset, subSamples, numSubSamples, buffer);
+ offset, subSamples, numSubSamples, buffer, &errorDetailMsg);
+ if (err != OK && hasCryptoOrDescrambler()
+ && (mFlags & kFlagUseCryptoAsync)) {
+ // create error detail
+ AString errorDetailMsg;
+ sp<AMessage> cryptoErrorInfo = new AMessage();
+ buildCryptoInfoAMessage(cryptoErrorInfo, CryptoAsync::kActionDecrypt);
+ cryptoErrorInfo->setInt32("err", err);
+ cryptoErrorInfo->setInt32("actionCode", ACTION_CODE_FATAL);
+ cryptoErrorInfo->setString("errorDetail", errorDetailMsg);
+ onCryptoError(cryptoErrorInfo);
+ // we want cryptoError to be in the callback
+ // but Codec IllegalStateException to be triggered.
+ err = INVALID_OPERATION;
+ }
} else {
err = UNKNOWN_ERROR;
}
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 0536f2a..d736734 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -639,9 +639,11 @@
numPageSamples = -1;
}
+ // insert, including accounting for the space used.
memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
&numPageSamples,
sizeof(numPageSamples));
+ buffer->setRange(buffer->offset(), buffer->size() + sizeof(numPageSamples));
uint32_t type;
const void *data;
@@ -690,6 +692,8 @@
ssize_t minIndex = fetchAllTrackSamples();
+ buffer->setRange(0, 0); // start with an empty buffer
+
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
@@ -705,25 +709,25 @@
sampleSize += sizeof(int32_t);
}
+ // capacity() is ok since we cleared out the buffer
if (buffer->capacity() < sampleSize) {
return -ENOMEM;
}
+ const size_t srclen = it->mBuffer->range_length();
const uint8_t *src =
(const uint8_t *)it->mBuffer->data()
+ it->mBuffer->range_offset();
- memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
+ memcpy((uint8_t *)buffer->data(), src, srclen);
+ buffer->setRange(0, srclen);
status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
+ // adjusts range when it inserts the extra bits
err = appendVorbisNumPageSamples(it->mBuffer, buffer);
}
- if (err == OK) {
- buffer->setRange(0, sampleSize);
- }
-
return err;
}
diff --git a/media/libstagefright/httplive/fuzzer/Android.bp b/media/libstagefright/httplive/fuzzer/Android.bp
index 85fd8b7..dd49714 100644
--- a/media/libstagefright/httplive/fuzzer/Android.bp
+++ b/media/libstagefright/httplive/fuzzer/Android.bp
@@ -62,5 +62,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_httplive",
+ vector: "remote",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/libstagefright/include/ACodecBufferChannel.h b/media/libstagefright/include/ACodecBufferChannel.h
index f3b0600..903280f 100644
--- a/media/libstagefright/include/ACodecBufferChannel.h
+++ b/media/libstagefright/include/ACodecBufferChannel.h
@@ -94,7 +94,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer) override;
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg) override;
virtual status_t renderOutputBuffer(
const sp<MediaCodecBuffer> &buffer, int64_t timestampNs) override;
virtual void pollForRenderedBuffers() override;
diff --git a/media/libstagefright/include/media/stagefright/CodecBase.h b/media/libstagefright/include/media/stagefright/CodecBase.h
index aa02151..916d41e 100644
--- a/media/libstagefright/include/media/stagefright/CodecBase.h
+++ b/media/libstagefright/include/media/stagefright/CodecBase.h
@@ -385,7 +385,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer) {
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg) {
(void)memory;
(void)secure;
(void)key;
@@ -396,6 +397,7 @@
(void)subSamples;
(void)numSubSamples;
(void)buffer;
+ (void)errorDetailMsg;
return -ENOSYS;
}
/**
diff --git a/media/libstagefright/tests/HEVC/Android.bp b/media/libstagefright/tests/HEVC/Android.bp
index 7f2ff12..7a0ba52 100644
--- a/media/libstagefright/tests/HEVC/Android.bp
+++ b/media/libstagefright/tests/HEVC/Android.bp
@@ -56,7 +56,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/HEVCUtils/HEVCUtilsUnitTest.zip?unzip=true",
- ],
}
diff --git a/media/libstagefright/tests/extractorFactory/Android.bp b/media/libstagefright/tests/extractorFactory/Android.bp
index 20ebe44..a067284 100644
--- a/media/libstagefright/tests/extractorFactory/Android.bp
+++ b/media/libstagefright/tests/extractorFactory/Android.bp
@@ -66,7 +66,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor.zip?unzip=true",
- ],
}
diff --git a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
index ecdaac5..71ddbe5 100644
--- a/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
+++ b/media/libstagefright/tests/mediacodec/MediaCodecTest.cpp
@@ -62,7 +62,8 @@
size_t offset,
const CryptoPlugin::SubSample *subSamples,
size_t numSubSamples,
- const sp<MediaCodecBuffer> &buffer),
+ const sp<MediaCodecBuffer> &buffer,
+ AString* errorDetailMsg),
(override));
MOCK_METHOD(status_t, renderOutputBuffer,
(const sp<MediaCodecBuffer> &buffer, int64_t timestampNs),
diff --git a/media/libstagefright/timedtext/test/Android.bp b/media/libstagefright/timedtext/test/Android.bp
index 953da79..ae97c50 100644
--- a/media/libstagefright/timedtext/test/Android.bp
+++ b/media/libstagefright/timedtext/test/Android.bp
@@ -62,7 +62,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/timedtext/test/TimedTextUnitTest.zip?unzip=true",
- ],
}
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index b81f27e..58aa7cd 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -57,6 +57,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzers target the APIs of all the various writers",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/amrnb/dec/test/Android.bp b/media/module/codecs/amrnb/dec/test/Android.bp
index de69cfc..74258e0 100644
--- a/media/module/codecs/amrnb/dec/test/Android.bp
+++ b/media/module/codecs/amrnb/dec/test/Android.bp
@@ -58,7 +58,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrnb/dec/test/AmrnbDecoderTest.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/amrnb/enc/fuzzer/Android.bp b/media/module/codecs/amrnb/enc/fuzzer/Android.bp
index 2c041b7..bcbcee2 100644
--- a/media/module/codecs/amrnb/enc/fuzzer/Android.bp
+++ b/media/module/codecs/amrnb/enc/fuzzer/Android.bp
@@ -48,5 +48,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_amrnbenc library",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/amrnb/enc/test/Android.bp b/media/module/codecs/amrnb/enc/test/Android.bp
index 5871486..7e393e3 100644
--- a/media/module/codecs/amrnb/enc/test/Android.bp
+++ b/media/module/codecs/amrnb/enc/test/Android.bp
@@ -58,7 +58,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrnb/enc/test/AmrnbEncoderTest.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/amrnb/fuzzer/Android.bp b/media/module/codecs/amrnb/fuzzer/Android.bp
index 833a7ba..3f29267 100644
--- a/media/module/codecs/amrnb/fuzzer/Android.bp
+++ b/media/module/codecs/amrnb/fuzzer/Android.bp
@@ -48,5 +48,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_amrnbdec library",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/amrwb/dec/fuzzer/Android.bp b/media/module/codecs/amrwb/dec/fuzzer/Android.bp
index 16f08fa..31a20ff 100644
--- a/media/module/codecs/amrwb/dec/fuzzer/Android.bp
+++ b/media/module/codecs/amrwb/dec/fuzzer/Android.bp
@@ -48,5 +48,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_amrwbdec library",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/amrwb/dec/test/Android.bp b/media/module/codecs/amrwb/dec/test/Android.bp
index 7ea39ef..7d0c964 100644
--- a/media/module/codecs/amrwb/dec/test/Android.bp
+++ b/media/module/codecs/amrwb/dec/test/Android.bp
@@ -57,7 +57,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwb/test/AmrwbDecoderTest.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/amrwb/enc/fuzzer/Android.bp b/media/module/codecs/amrwb/enc/fuzzer/Android.bp
index f74fa4f..c2c13e1 100644
--- a/media/module/codecs/amrwb/enc/fuzzer/Android.bp
+++ b/media/module/codecs/amrwb/enc/fuzzer/Android.bp
@@ -48,5 +48,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_amrwbenc library",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/amrwb/enc/test/Android.bp b/media/module/codecs/amrwb/enc/test/Android.bp
index f095d62..942f6c9 100644
--- a/media/module/codecs/amrwb/enc/test/Android.bp
+++ b/media/module/codecs/amrwb/enc/test/Android.bp
@@ -57,7 +57,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/amrwbenc/test/AmrwbEncoderTest.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/g711/fuzzer/Android.bp b/media/module/codecs/g711/fuzzer/Android.bp
index 376cce7..397fb9a 100644
--- a/media/module/codecs/g711/fuzzer/Android.bp
+++ b/media/module/codecs/g711/fuzzer/Android.bp
@@ -44,6 +44,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of codecs_g711dec library with a special focus on Alaw APIs",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
@@ -61,5 +69,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of codecs_g711dec library with a special focus on Mlaw APIs",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/m4v_h263/dec/test/Android.bp b/media/module/codecs/m4v_h263/dec/test/Android.bp
index 9dc756c..d8de569 100644
--- a/media/module/codecs/m4v_h263/dec/test/Android.bp
+++ b/media/module/codecs/m4v_h263/dec/test/Android.bp
@@ -76,7 +76,4 @@
],
cfi: true,
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/m4v_h263/enc/test/Android.bp b/media/module/codecs/m4v_h263/enc/test/Android.bp
index d75e2d1..2b5e49c 100644
--- a/media/module/codecs/m4v_h263/enc/test/Android.bp
+++ b/media/module/codecs/m4v_h263/enc/test/Android.bp
@@ -55,7 +55,4 @@
],
cfi: true,
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/enc/test/Mpeg4H263Encoder.zip?unzip=true",
- ],
}
diff --git a/media/module/codecs/m4v_h263/fuzzer/Android.bp b/media/module/codecs/m4v_h263/fuzzer/Android.bp
index a052c11..4d0ed18 100644
--- a/media/module/codecs/m4v_h263/fuzzer/Android.bp
+++ b/media/module/codecs/m4v_h263/fuzzer/Android.bp
@@ -50,6 +50,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzers target the APIs of libstagefright_m4vh263dec library",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
@@ -98,6 +106,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzers target the APIs of libstagefright_m4vh263enc library",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/mp3dec/fuzzer/Android.bp b/media/module/codecs/mp3dec/fuzzer/Android.bp
index 514a8a8..c5e0b1f 100644
--- a/media/module/codecs/mp3dec/fuzzer/Android.bp
+++ b/media/module/codecs/mp3dec/fuzzer/Android.bp
@@ -44,5 +44,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libstagefright_mp3dec",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/codecs/mp3dec/test/Android.bp b/media/module/codecs/mp3dec/test/Android.bp
index dd06bdc..f10b6ae 100644
--- a/media/module/codecs/mp3dec/test/Android.bp
+++ b/media/module/codecs/mp3dec/test/Android.bp
@@ -56,7 +56,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mp3dec/test/Mp3DecoderTest-1.2.zip?unzip=true",
- ],
}
diff --git a/media/module/codecserviceregistrant/fuzzer/Android.bp b/media/module/codecserviceregistrant/fuzzer/Android.bp
index 0b9affd..1cb8c2b 100644
--- a/media/module/codecserviceregistrant/fuzzer/Android.bp
+++ b/media/module/codecserviceregistrant/fuzzer/Android.bp
@@ -41,5 +41,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmedia_codecserviceregistrant",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index b3e34d2..91ca7b1 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -72,6 +72,14 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzers targets the APIs of all the various extractors",
+ vector: "remote",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/media/module/extractors/tests/Android.bp b/media/module/extractors/tests/Android.bp
index f5eadbd..d6e79c7 100644
--- a/media/module/extractors/tests/Android.bp
+++ b/media/module/extractors/tests/Android.bp
@@ -100,7 +100,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/extractors/tests/extractor-1.4.zip?unzip=true",
- ],
}
diff --git a/media/module/foundation/AMessage.cpp b/media/module/foundation/AMessage.cpp
index b61dc47..7cc7c41 100644
--- a/media/module/foundation/AMessage.cpp
+++ b/media/module/foundation/AMessage.cpp
@@ -961,6 +961,11 @@
return mItems.size();
}
+/* static */
+size_t AMessage::maxAllowedEntries() {
+ return kMaxNumItems;
+}
+
const char *AMessage::getEntryNameAt(size_t index, Type *type) const {
if (index >= mItems.size()) {
*type = kTypeInt32;
diff --git a/media/module/foundation/include/media/stagefright/foundation/AMessage.h b/media/module/foundation/include/media/stagefright/foundation/AMessage.h
index 6f73597..7594565 100644
--- a/media/module/foundation/include/media/stagefright/foundation/AMessage.h
+++ b/media/module/foundation/include/media/stagefright/foundation/AMessage.h
@@ -199,6 +199,7 @@
};
size_t countEntries() const;
+ static size_t maxAllowedEntries();
const char *getEntryNameAt(size_t index, Type *type) const;
/**
diff --git a/media/module/foundation/tests/AMessage_test.cpp b/media/module/foundation/tests/AMessage_test.cpp
index e08ed77..08062e5 100644
--- a/media/module/foundation/tests/AMessage_test.cpp
+++ b/media/module/foundation/tests/AMessage_test.cpp
@@ -53,6 +53,28 @@
MOCK_METHOD(void, onMessageReceived, (const sp<AMessage>&), (override));
};
+TEST(AMessage_tests, countsAndLimits) {
+ sp<AMessage> m1 = new AMessage();
+
+ // clear, countEntries, maxAllowedEntries
+
+ EXPECT_EQ(0, m1->countEntries());
+
+ m1->setInt32("smaller", INT32_MAX - 2);
+ m1->setInt64("big", INT64_MAX);
+ m1->setString("bigBallOfString", "whatever");
+ EXPECT_EQ(3, m1->countEntries());
+
+ m1->clear();
+ EXPECT_EQ(0, m1->countEntries());
+
+ EXPECT_TRUE(m1->maxAllowedEntries() > 0);
+ EXPECT_TRUE(AMessage::maxAllowedEntries() > 0);
+
+ // static function, make sure we get a consistent answer
+ EXPECT_EQ(m1->maxAllowedEntries(), AMessage::maxAllowedEntries());
+}
+
TEST(AMessage_tests, settersAndGetters) {
sp<AMessage> m1 = new AMessage();
diff --git a/media/module/foundation/tests/OpusHeader/Android.bp b/media/module/foundation/tests/OpusHeader/Android.bp
index f052650..fa2b40e 100644
--- a/media/module/foundation/tests/OpusHeader/Android.bp
+++ b/media/module/foundation/tests/OpusHeader/Android.bp
@@ -54,7 +54,4 @@
],
cfi: true,
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/foundation/tests/OpusHeader/OpusHeader.zip?unzip=true",
- ],
}
diff --git a/media/module/id3/test/Android.bp b/media/module/id3/test/Android.bp
index 0481e48..52cdfa5 100644
--- a/media/module/id3/test/Android.bp
+++ b/media/module/id3/test/Android.bp
@@ -57,7 +57,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/id3/test/ID3Test-1.2.zip?unzip=true",
- ],
}
diff --git a/media/module/libmediatranscoding/transcoder/benchmark/Android.bp b/media/module/libmediatranscoding/transcoder/benchmark/Android.bp
index f98b27d..459f0ae 100644
--- a/media/module/libmediatranscoding/transcoder/benchmark/Android.bp
+++ b/media/module/libmediatranscoding/transcoder/benchmark/Android.bp
@@ -26,25 +26,16 @@
name: "MediaTranscoderBenchmark",
srcs: ["MediaTranscoderBenchmark.cpp"],
defaults: ["benchmarkdefaults"],
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libmediatranscoding/transcoder/benchmark/TranscodingBenchmark-1.2.zip?unzip=true",
- ],
}
cc_test {
name: "MediaSampleReaderBenchmark",
srcs: ["MediaSampleReaderBenchmark.cpp"],
defaults: ["benchmarkdefaults"],
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libmediatranscoding/transcoder/benchmark/TranscodingBenchmark-1.2.zip?unzip=true",
- ],
}
cc_test {
name: "MediaTrackTranscoderBenchmark",
srcs: ["MediaTrackTranscoderBenchmark.cpp"],
defaults: ["benchmarkdefaults"],
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libmediatranscoding/transcoder/benchmark/TranscodingBenchmark-1.2.zip?unzip=true",
- ],
}
diff --git a/media/module/mpeg2ts/test/Android.bp b/media/module/mpeg2ts/test/Android.bp
index 4b1bacd..34a8d3e 100644
--- a/media/module/mpeg2ts/test/Android.bp
+++ b/media/module/mpeg2ts/test/Android.bp
@@ -74,7 +74,4 @@
"signed-integer-overflow",
],
},
- data: [
- ":https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/mpeg2ts/test/Mpeg2tsUnitTest.zip?unzip=true",
- ],
}
diff --git a/media/utils/include/mediautils/MethodStatistics.h b/media/utils/include/mediautils/MethodStatistics.h
index 6d7e990..c8b36d8 100644
--- a/media/utils/include/mediautils/MethodStatistics.h
+++ b/media/utils/include/mediautils/MethodStatistics.h
@@ -59,7 +59,7 @@
void event(C&& code, FloatType executeMs) {
std::lock_guard lg(mLock);
auto it = mStatisticsMap.lower_bound(code);
- if (it != mStatisticsMap.end() && it->first == code) {
+ if (it != mStatisticsMap.end() && it->first == static_cast<Code>(code)) {
it->second.add(executeMs);
} else {
// StatsType ctor takes an optional array of data for initialization.
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 43ef311..663df69 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -19,12 +19,128 @@
],
}
+tidy_errors = [
+ // https://clang.llvm.org/extra/clang-tidy/checks/list.html
+ // For many categories, the checks are too many to specify individually.
+ // Feel free to disable as needed - as warnings are generally ignored,
+ // we treat warnings as errors.
+ "android-*",
+ "bugprone-*",
+ "cert-*",
+ "clang-analyzer-security*",
+ "google-*",
+ "misc-*",
+ //"modernize-*", // explicitly list the modernize as they can be subjective.
+ "modernize-avoid-bind",
+ //"modernize-avoid-c-arrays", // std::array<> can be verbose
+ "modernize-concat-nested-namespaces",
+ //"modernize-deprecated-headers", // C headers still ok even if there is C++ equivalent.
+ "modernize-deprecated-ios-base-aliases",
+ "modernize-loop-convert",
+ "modernize-make-shared",
+ "modernize-make-unique",
+ // "modernize-pass-by-value",
+ "modernize-raw-string-literal",
+ "modernize-redundant-void-arg",
+ "modernize-replace-auto-ptr",
+ "modernize-replace-random-shuffle",
+ "modernize-return-braced-init-list",
+ "modernize-shrink-to-fit",
+ "modernize-unary-static-assert",
+ // "modernize-use-auto", // found in MediaMetricsService.h, debatable - auto can obscure type
+ "modernize-use-bool-literals",
+ "modernize-use-default-member-init",
+ "modernize-use-emplace",
+ "modernize-use-equals-default",
+ "modernize-use-equals-delete",
+ // "modernize-use-nodiscard",
+ "modernize-use-noexcept",
+ "modernize-use-nullptr",
+ "modernize-use-override",
+ //"modernize-use-trailing-return-type", // not necessarily more readable
+ "modernize-use-transparent-functors",
+ "modernize-use-uncaught-exceptions",
+ "modernize-use-using",
+ "performance-*",
+
+ // Remove some pedantic stylistic requirements.
+ "-google-readability-casting", // C++ casts not always necessary and may be verbose
+ "-google-readability-todo", // do not require TODO(info)
+
+ "-bugprone-unhandled-self-assignment",
+ "-bugprone-suspicious-string-compare",
+ "-cert-oop54-cpp", // found in TransactionLog.h
+ "-bugprone-narrowing-conversions", // b/182410845
+
+ // TODO(b/275642749) Reenable these warnings
+ "-bugprone-assignment-in-if-condition",
+ "-bugprone-forward-declaration-namespace",
+ "-bugprone-parent-virtual-call",
+ "-cert-dcl59-cpp",
+ "-cert-err34-c",
+ "-google-build-namespaces",
+ "-google-build-using-namespace",
+ "-google-default-arguments",
+ "-google-runtime-int",
+ "-misc-const-correctness",
+ "-misc-non-private-member-variables-in-classes",
+ "-modernize-concat-nested-namespaces",
+ "-modernize-loop-convert",
+ "-modernize-use-default-member-init",
+ "-modernize-use-equals-default",
+ "-modernize-use-nullptr",
+ "-modernize-use-override",
+ "-modernize-use-using",
+ "-performance-no-int-to-ptr",
+]
+
+// Eventually use common tidy defaults
+cc_defaults {
+ name: "audioflinger_flags_defaults",
+ // https://clang.llvm.org/docs/UsersManual.html#command-line-options
+ // https://clang.llvm.org/docs/DiagnosticsReference.html
+ cflags: [
+ "-Wall",
+ "-Wdeprecated",
+ "-Werror",
+ "-Werror=implicit-fallthrough",
+ "-Werror=sometimes-uninitialized",
+ "-Werror=conditional-uninitialized",
+ "-Wextra",
+
+ // suppress some warning chatter.
+ "-Wno-deprecated-copy-with-dtor",
+ "-Wno-deprecated-copy-with-user-provided-dtor",
+
+ "-Wredundant-decls",
+ "-Wshadow",
+ "-Wstrict-aliasing",
+ "-fstrict-aliasing",
+ "-Wthread-safety",
+ //"-Wthread-safety-negative", // experimental - looks broken in R.
+ "-Wunreachable-code",
+ "-Wunreachable-code-break",
+ "-Wunreachable-code-return",
+ "-Wunused",
+ "-Wused-but-marked-unused",
+ "-D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS",
+ ],
+ // https://clang.llvm.org/extra/clang-tidy/
+ tidy: true,
+ tidy_checks: tidy_errors,
+ tidy_checks_as_errors: tidy_errors,
+ tidy_flags: [
+ "-format-style=file",
+ ],
+}
+
cc_library_shared {
name: "libaudioflinger",
defaults: [
"latest_android_media_audio_common_types_cpp_shared",
"latest_android_hardware_audio_core_sounddose_ndk_shared",
+ "audioflinger_flags_defaults",
],
srcs: [
@@ -67,6 +183,7 @@
"av-types-aidl-cpp",
"effect-aidl-cpp",
"libaudioclient_aidl_conversion",
+ "libactivitymanager_aidl",
"libaudioflinger_timing",
"libaudiofoundation",
"libaudiohal",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 57392c9..3c0f8f3 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -229,6 +229,7 @@
BINDER_METHOD_ENTRY(getAAudioMixerBurstCount) \
BINDER_METHOD_ENTRY(getAAudioHardwareBurstMinUsec) \
BINDER_METHOD_ENTRY(setDeviceConnectedState) \
+BINDER_METHOD_ENTRY(setSimulateDeviceConnections) \
BINDER_METHOD_ENTRY(setRequestedLatencyMode) \
BINDER_METHOD_ENTRY(getSupportedLatencyModes) \
BINDER_METHOD_ENTRY(setBluetoothVariableLatencyEnabled) \
@@ -502,6 +503,25 @@
return final_result;
}
+status_t AudioFlinger::setSimulateDeviceConnections(bool enabled) {
+ bool at_least_one_succeeded = false;
+ status_t last_error = INVALID_OPERATION;
+ Mutex::Autolock _l(mLock);
+ AutoMutex lock(mHardwareLock);
+ mHardwareStatus = AUDIO_HW_SET_SIMULATE_CONNECTIONS;
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ status_t result = dev->setSimulateDeviceConnections(enabled);
+ if (result == OK) {
+ at_least_one_succeeded = true;
+ } else {
+ last_error = result;
+ }
+ }
+ mHardwareStatus = AUDIO_HW_IDLE;
+ return at_least_one_succeeded ? OK : last_error;
+}
+
// getDefaultVibratorInfo_l must be called with AudioFlinger lock held.
std::optional<media::AudioVibratorInfo> AudioFlinger::getDefaultVibratorInfo_l() {
if (mAudioVibratorInfos.empty()) {
@@ -706,7 +726,7 @@
}
status_t AudioFlinger::addEffectToHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
AutoMutex lock(mHardwareLock);
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
if (audioHwDevice == nullptr) {
@@ -716,7 +736,7 @@
}
status_t AudioFlinger::removeEffectFromHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
AutoMutex lock(mHardwareLock);
AudioHwDevice *audioHwDevice = mAudioHwDevs.valueFor(hwModuleId);
if (audioHwDevice == nullptr) {
@@ -838,6 +858,7 @@
}
status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
if (!dumpAllowed()) {
dumpPermissionDenial(fd, args);
@@ -943,7 +964,6 @@
// to lookup the service if it's not running, as it will block for a second
if (sMediaLogServiceAsBinder != 0) {
dprintf(fd, "\nmedia.log:\n");
- Vector<String16> args;
sMediaLogServiceAsBinder->dump(fd, args);
}
@@ -1445,8 +1465,9 @@
if (NO_ERROR == ret) {
Mutex::Autolock _l(mLock);
mMode = mode;
- for (size_t i = 0; i < mPlaybackThreads.size(); i++)
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->setMode(mode);
+ }
}
mediametrics::LogItem(mMetricsId)
@@ -1794,7 +1815,7 @@
// forwardAudioHwSyncToDownstreamPatches_l() must be called with AudioFlinger::mLock held
void AudioFlinger::forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
- std::function<bool(const sp<PlaybackThread>&)> useThread)
+ const std::function<bool(const sp<PlaybackThread>&)>& useThread)
{
std::vector<PatchPanel::SoftwarePatch> swPatches;
if (mPatchPanel.getDownstreamSoftwarePatches(upStream, &swPatches) != OK) return;
@@ -1810,7 +1831,7 @@
// Update downstream patches for all playback threads attached to an MSD module
void AudioFlinger::updateDownStreamPatches_l(const struct audio_patch *patch,
- const std::set<audio_io_handle_t> streams)
+ const std::set<audio_io_handle_t>& streams)
{
for (const audio_io_handle_t stream : streams) {
PlaybackThread *playbackThread = checkPlaybackThread_l(stream);
@@ -2016,24 +2037,29 @@
mHardwareStatus = AUDIO_HW_GET_INPUT_BUFFER_SIZE;
sp<DeviceHalInterface> dev = mPrimaryHardwareDev->hwDevice();
+
std::vector<audio_channel_mask_t> channelMasks = {channelMask};
- if (channelMask != AUDIO_CHANNEL_IN_MONO)
+ if (channelMask != AUDIO_CHANNEL_IN_MONO) {
channelMasks.push_back(AUDIO_CHANNEL_IN_MONO);
- if (channelMask != AUDIO_CHANNEL_IN_STEREO)
+ }
+ if (channelMask != AUDIO_CHANNEL_IN_STEREO) {
channelMasks.push_back(AUDIO_CHANNEL_IN_STEREO);
+ }
std::vector<audio_format_t> formats = {format};
- if (format != AUDIO_FORMAT_PCM_16_BIT)
+ if (format != AUDIO_FORMAT_PCM_16_BIT) {
formats.push_back(AUDIO_FORMAT_PCM_16_BIT);
+ }
std::vector<uint32_t> sampleRates = {sampleRate};
static const uint32_t SR_44100 = 44100;
static const uint32_t SR_48000 = 48000;
-
- if (sampleRate != SR_48000)
+ if (sampleRate != SR_48000) {
sampleRates.push_back(SR_48000);
- if (sampleRate != SR_44100)
+ }
+ if (sampleRate != SR_44100) {
sampleRates.push_back(SR_44100);
+ }
mHardwareStatus = AUDIO_HW_IDLE;
@@ -2504,7 +2530,7 @@
// session and move it to this thread.
sp<EffectChain> chain = getOrphanEffectChain_l(sessionId);
if (chain != 0) {
- Mutex::Autolock _l(thread->mLock);
+ Mutex::Autolock _l2(thread->mLock);
thread->addEffectChain_l(chain);
}
break;
@@ -2906,7 +2932,7 @@
sp<AudioFlinger::ThreadBase> AudioFlinger::openOutput_l(audio_module_handle_t module,
audio_io_handle_t *output,
audio_config_t *halConfig,
- audio_config_base_t *mixerConfig __unused,
+ audio_config_base_t *mixerConfig,
audio_devices_t deviceType,
const String8& address,
audio_output_flags_t flags)
@@ -3032,7 +3058,6 @@
aidl2legacy_int32_t_audio_output_flags_t_mask(request.flags));
audio_io_handle_t output;
- uint32_t latencyMs;
ALOGI("openOutput() this %p, module %d Device %s, SamplingRate %d, Format %#08x, "
"Channels %#x, flags %#x",
@@ -3055,6 +3080,7 @@
sp<ThreadBase> thread = openOutput_l(module, &output, &halConfig,
&mixerConfig, deviceType, address, flags);
if (thread != 0) {
+ uint32_t latencyMs = 0;
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
latencyMs = playbackThread->latency();
@@ -3403,7 +3429,7 @@
continue;
}
if (t->hasAudioSession(chain->sessionId()) != 0) {
- Mutex::Autolock _l(t->mLock);
+ Mutex::Autolock _l2(t->mLock);
ALOGV("closeInput() found thread %d for effect session %d",
t->id(), chain->sessionId());
t->addEffectChain_l(chain);
@@ -3614,7 +3640,8 @@
}
for (size_t i = 0; i < chains.size(); i++) {
- sp<EffectChain> ec = chains[i];
+ // clang-tidy suggests const ref
+ sp<EffectChain> ec = chains[i]; // NOLINT(performance-unnecessary-copy-initialization)
int sessionid = ec->sessionId();
sp<ThreadBase> t = ec->thread().promote();
if (t == 0) {
@@ -3797,7 +3824,7 @@
PlaybackThread *thread = primaryPlaybackThread_l();
if (thread == NULL) {
- return DeviceTypeSet();
+ return {};
}
return thread->outDeviceTypes();
@@ -4309,7 +4336,7 @@
// session and used it instead of creating a new one.
sp<EffectChain> chain = getOrphanEffectChain_l(sessionId);
if (chain != 0) {
- Mutex::Autolock _l(thread->mLock);
+ Mutex::Autolock _l2(thread->mLock);
thread->addEffectChain_l(chain);
}
}
@@ -4427,6 +4454,7 @@
status_t AudioFlinger::moveEffectChain_l(audio_session_t sessionId,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread)
+NO_THREAD_SAFETY_ANALYSIS // requires srcThread and dstThread locks
{
ALOGV("moveEffectChain_l() session %d from thread %p to thread %p",
sessionId, srcThread, dstThread);
@@ -4456,11 +4484,12 @@
// transfer all effects one by one so that new effect chain is created on new thread with
// correct buffer sizes and audio parameters and effect engines reconfigured accordingly
sp<EffectChain> dstChain;
- sp<EffectModule> effect = chain->getEffectFromId_l(0);
Vector< sp<EffectModule> > removed;
status_t status = NO_ERROR;
std::string errorString;
- while (effect != nullptr) {
+ // process effects one by one.
+ for (sp<EffectModule> effect = chain->getEffectFromId_l(0); effect != nullptr;
+ effect = chain->getEffectFromId_l(0)) {
srcThread->removeEffect_l(effect);
removed.add(effect);
status = dstThread->addEffect_l(effect);
@@ -4481,7 +4510,6 @@
break;
}
}
- effect = chain->getEffectFromId_l(0);
}
size_t restored = 0;
@@ -4585,6 +4613,7 @@
}
bool AudioFlinger::isNonOffloadableGlobalEffectEnabled_l()
+NO_THREAD_SAFETY_ANALYSIS // thread lock for getEffectChain_l.
{
if (mGlobalEffectEnableTime != 0 &&
((systemTime() - mGlobalEffectEnableTime) < kMinGlobalEffectEnabletimeNs)) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 2204f8f..077fa26 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -124,7 +124,6 @@
class EffectsFactoryHalInterface;
class FastMixer;
class IAudioManager;
-class ISoundDoseCallback;
class PassthruBufferProvider;
class RecordBufferConverter;
class ServerProxy;
@@ -300,6 +299,8 @@
virtual status_t setDeviceConnectedState(const struct audio_port_v7 *port, bool connected);
+ virtual status_t setSimulateDeviceConnections(bool enabled);
+
virtual status_t setRequestedLatencyMode(
audio_io_handle_t output, audio_latency_mode_t mode);
@@ -341,12 +342,12 @@
static void onExternalVibrationStop(const sp<os::ExternalVibration>& externalVibration);
status_t addEffectToHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect);
status_t removeEffectFromHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect);
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect);
void updateDownStreamPatches_l(const struct audio_patch *patch,
- const std::set<audio_io_handle_t> streams);
+ const std::set<audio_io_handle_t>& streams);
std::optional<media::AudioVibratorInfo> getDefaultVibratorInfo_l();
@@ -389,7 +390,7 @@
audio_session_t triggerSession,
audio_session_t listenerSession,
sync_event_callback_t callBack,
- wp<RefBase> cookie)
+ const wp<RefBase>& cookie)
: mType(type), mTriggerSession(triggerSession), mListenerSession(listenerSession),
mCallback(callBack), mCookie(cookie)
{}
@@ -869,7 +870,7 @@
void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
- std::function<bool(const sp<PlaybackThread>&)> useThread = nullptr);
+ const std::function<bool(const sp<PlaybackThread>&)>& useThread = nullptr);
// AudioStreamIn is immutable, so their fields are const.
// For emphasis, we could also make all pointers to them be "const *",
@@ -882,7 +883,8 @@
sp<DeviceHalInterface> hwDev() const { return audioHwDev->hwDevice(); }
- AudioStreamIn(AudioHwDevice *dev, sp<StreamInHalInterface> in, audio_input_flags_t flags) :
+ AudioStreamIn(AudioHwDevice *dev, const sp<StreamInHalInterface>& in,
+ audio_input_flags_t flags) :
audioHwDev(dev), stream(in), flags(flags) {}
status_t read(void *buffer, size_t bytes, size_t *read) override {
return stream->read(buffer, bytes, read);
@@ -953,6 +955,7 @@
AUDIO_HW_GET_MASTER_MUTE, // get_master_mute
AUDIO_HW_GET_MICROPHONES, // getMicrophones
AUDIO_HW_SET_CONNECTED_STATE, // setConnectedState
+ AUDIO_HW_SET_SIMULATE_CONNECTIONS, // setSimulateDeviceConnections
};
mutable hardware_call_state mHardwareStatus; // for dump only
diff --git a/services/audioflinger/AudioHwDevice.h b/services/audioflinger/AudioHwDevice.h
index 1749f3f..d071922 100644
--- a/services/audioflinger/AudioHwDevice.h
+++ b/services/audioflinger/AudioHwDevice.h
@@ -46,7 +46,7 @@
AudioHwDevice(audio_module_handle_t handle,
const char *moduleName,
- sp<DeviceHalInterface> hwDevice,
+ const sp<DeviceHalInterface>& hwDevice,
Flags flags)
: mHandle(handle)
, mModuleName(strdup(moduleName))
diff --git a/services/audioflinger/AutoPark.h b/services/audioflinger/AutoPark.h
index 9ac7b65..83f6b7d 100644
--- a/services/audioflinger/AutoPark.h
+++ b/services/audioflinger/AutoPark.h
@@ -58,4 +58,4 @@
FastThreadState::Command mPreviousCommand;
}; // class AutoPark
-} // namespace
+} // namespace android
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index 9105500..2f61a01 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -145,7 +145,9 @@
return status;
}
-void AudioFlinger::DeviceEffectManager::dump(int fd) {
+void AudioFlinger::DeviceEffectManager::dump(int fd)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
+{
const bool locked = dumpTryLock(mLock);
if (!locked) {
String8 result("DeviceEffectManager may be deadlocked\n");
diff --git a/services/audioflinger/DeviceEffectManager.h b/services/audioflinger/DeviceEffectManager.h
index 7602f12..395781d 100644
--- a/services/audioflinger/DeviceEffectManager.h
+++ b/services/audioflinger/DeviceEffectManager.h
@@ -45,11 +45,11 @@
int32_t sessionId, int32_t deviceId,
sp<EffectHalInterface> *effect);
status_t addEffectToHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
return mAudioFlinger.addEffectToHal(deviceId, hwModuleId, effect);
};
status_t removeEffectFromHal(audio_port_handle_t deviceId, audio_module_handle_t hwModuleId,
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
return mAudioFlinger.removeEffectFromHal(deviceId, hwModuleId, effect);
};
@@ -74,7 +74,7 @@
class DeviceEffectManagerCallback : public EffectCallbackInterface {
public:
- DeviceEffectManagerCallback(DeviceEffectManager& manager)
+ explicit DeviceEffectManagerCallback(DeviceEffectManager& manager)
: mManager(manager) {}
status_t createEffectHal(const effect_uuid_t *pEffectUuid,
@@ -105,10 +105,10 @@
size_t frameCount() const override { return 0; }
uint32_t latency() const override { return 0; }
- status_t addEffectToHal(sp<EffectHalInterface> effect __unused) override {
+ status_t addEffectToHal(const sp<EffectHalInterface>& /* effect */) override {
return NO_ERROR;
}
- status_t removeEffectFromHal(sp<EffectHalInterface> effect __unused) override {
+ status_t removeEffectFromHal(const sp<EffectHalInterface>& /* effect */) override {
return NO_ERROR;
}
@@ -133,11 +133,11 @@
int newEffectId() { return mManager.audioFlinger().nextUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT); }
status_t addEffectToHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
return mManager.addEffectToHal(deviceId, hwModuleId, effect);
}
status_t removeEffectFromHal(audio_port_handle_t deviceId,
- audio_module_handle_t hwModuleId, sp<EffectHalInterface> effect) {
+ audio_module_handle_t hwModuleId, const sp<EffectHalInterface>& effect) {
return mManager.removeEffectFromHal(deviceId, hwModuleId, effect);
}
private:
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 84b9c40..19e4151 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -498,6 +498,7 @@
}
void AudioFlinger::EffectBase::dump(int fd, const Vector<String16>& args __unused)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
String8 result;
@@ -569,7 +570,6 @@
mMaxDisableWaitCnt(1), // set by configure(), should be >= 1
mDisableWaitCnt(0), // set by process() and updateState()
mOffloaded(false),
- mAddedToHal(false),
mIsOutput(false)
#ifdef FLOAT_EFFECT_CHAIN
, mSupportsFloat(false)
@@ -1103,12 +1103,12 @@
{
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
(mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
- if (mAddedToHal) {
+ if (mCurrentHalStream == getCallback()->io()) {
return;
}
(void)getCallback()->addEffectToHal(mEffectInterface);
- mAddedToHal = true;
+ mCurrentHalStream = getCallback()->io();
}
}
@@ -1204,12 +1204,11 @@
{
if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
(mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
- if (!mAddedToHal) {
- return NO_ERROR;
+ if (mCurrentHalStream != getCallback()->io()) {
+ return (mCurrentHalStream == AUDIO_IO_HANDLE_NONE) ? NO_ERROR : INVALID_OPERATION;
}
-
getCallback()->removeEffectFromHal(mEffectInterface);
- mAddedToHal = false;
+ mCurrentHalStream = AUDIO_IO_HANDLE_NONE;
}
return NO_ERROR;
}
@@ -1249,13 +1248,13 @@
return -EINVAL;
}
if (cmdCode == EFFECT_CMD_GET_PARAM &&
- (maxReplySize < sizeof(effect_param_t) ||
+ (maxReplySize < static_cast<signed>(sizeof(effect_param_t)) ||
param->psize > maxReplySize - sizeof(effect_param_t))) {
android_errorWriteLog(0x534e4554, "29251553");
return -EINVAL;
}
if (cmdCode == EFFECT_CMD_GET_PARAM &&
- (sizeof(effect_param_t) > maxReplySize
+ (static_cast<signed>(sizeof(effect_param_t)) > maxReplySize
|| param->psize > maxReplySize - sizeof(effect_param_t)
|| param->vsize > maxReplySize - sizeof(effect_param_t)
- param->psize
@@ -1685,6 +1684,7 @@
}
void AudioFlinger::EffectModule::dump(int fd, const Vector<String16>& args)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
EffectBase::dump(fd, args);
@@ -1946,7 +1946,7 @@
}
mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
// Client destructor must run with AudioFlinger client mutex locked
- Mutex::Autolock _l(mClient->audioFlinger()->mClientLock);
+ Mutex::Autolock _l2(mClient->audioFlinger()->mClientLock);
mClient.clear();
}
}
@@ -2010,14 +2010,14 @@
}
if (cmdCode == EFFECT_CMD_ENABLE) {
- if (maxResponseSize < sizeof(int)) {
+ if (maxResponseSize < static_cast<signed>(sizeof(int))) {
android_errorWriteLog(0x534e4554, "32095713");
RETURN(BAD_VALUE);
}
writeToBuffer(NO_ERROR, response);
return enable(_aidl_return);
} else if (cmdCode == EFFECT_CMD_DISABLE) {
- if (maxResponseSize < sizeof(int)) {
+ if (maxResponseSize < static_cast<signed>(sizeof(int))) {
android_errorWriteLog(0x534e4554, "32095713");
RETURN(BAD_VALUE);
}
@@ -2041,7 +2041,7 @@
RETURN(INVALID_OPERATION);
}
- if (maxResponseSize < sizeof(int)) {
+ if (maxResponseSize < (signed)sizeof(int)) {
android_errorWriteLog(0x534e4554, "32095713");
RETURN(BAD_VALUE);
}
@@ -2050,7 +2050,7 @@
// No need to trylock() here as this function is executed in the binder thread serving a
// particular client process: no risk to block the whole media server process or mixer
// threads if we are stuck here
- Mutex::Autolock _l(mCblk->lock);
+ Mutex::Autolock _l2(mCblk->lock);
// keep local copy of index in case of client corruption b/32220769
const uint32_t clientIndex = mCblk->clientIndex;
const uint32_t serverIndex = mCblk->serverIndex;
@@ -2153,6 +2153,7 @@
}
void AudioFlinger::EffectHandle::dumpToBuffer(char* buffer, size_t size)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
bool locked = mCblk != NULL && AudioFlinger::dumpTryLock(mCblk->lock);
@@ -2407,7 +2408,7 @@
}
} else {
effect->setInBuffer(mInBuffer);
- if (idx_insert == previousSize) {
+ if (idx_insert == static_cast<ssize_t>(previousSize)) {
if (idx_insert != 0) {
mEffects[idx_insert-1]->configure();
mEffects[idx_insert-1]->setOutBuffer(mInBuffer);
@@ -2467,7 +2468,7 @@
}
// remember position of first insert effect and by default
// select this as insert position for new effect
- if (idx_insert == size) {
+ if (idx_insert == static_cast<ssize_t>(size)) {
idx_insert = i;
}
// remember position of last insert effect claiming
@@ -2697,6 +2698,7 @@
}
void AudioFlinger::EffectChain::dump(int fd, const Vector<String16>& args)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
String8 result;
@@ -3049,7 +3051,7 @@
}
status_t AudioFlinger::EffectChain::EffectCallback::addEffectToHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
status_t result = NO_INIT;
sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
@@ -3065,7 +3067,7 @@
}
status_t AudioFlinger::EffectChain::EffectCallback::removeEffectFromHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
status_t result = NO_INIT;
sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
@@ -3207,15 +3209,20 @@
return t->frameCount();
}
-uint32_t AudioFlinger::EffectChain::EffectCallback::latency() const {
+uint32_t AudioFlinger::EffectChain::EffectCallback::latency() const
+NO_THREAD_SAFETY_ANALYSIS // latency_l() access
+{
sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return 0;
}
+ // TODO(b/275956781) - this requires the thread lock.
return t->latency_l();
}
-void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, float right) const {
+void AudioFlinger::EffectChain::EffectCallback::setVolumeForOutput(float left, float right) const
+NO_THREAD_SAFETY_ANALYSIS // setVolumeForOutput_l() access
+{
sp<ThreadBase> t = thread().promote();
if (t == nullptr) {
return;
@@ -3459,7 +3466,7 @@
}
status_t AudioFlinger::DeviceEffectProxy::addEffectToHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
if (mHalEffect == nullptr) {
return NO_INIT;
}
@@ -3468,7 +3475,7 @@
}
status_t AudioFlinger::DeviceEffectProxy::removeEffectFromHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
if (mHalEffect == nullptr) {
return NO_INIT;
}
@@ -3506,7 +3513,9 @@
return audio_channel_count_from_in_mask(channelMask());
}
-void AudioFlinger::DeviceEffectProxy::dump(int fd, int spaces) {
+void AudioFlinger::DeviceEffectProxy::dump(int fd, int spaces)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
+{
const Vector<String16> args;
EffectBase::dump(fd, args);
@@ -3585,7 +3594,7 @@
}
status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::addEffectToHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
sp<DeviceEffectProxy> proxy = mProxy.promote();
if (proxy == nullptr) {
return NO_INIT;
@@ -3594,7 +3603,7 @@
}
status_t AudioFlinger::DeviceEffectProxy::ProxyCallback::removeEffectFromHal(
- sp<EffectHalInterface> effect) {
+ const sp<EffectHalInterface>& effect) {
sp<DeviceEffectProxy> proxy = mProxy.promote();
if (proxy == nullptr) {
return NO_INIT;
diff --git a/services/audioflinger/Effects.h b/services/audioflinger/Effects.h
index 7b71a85..885d3e5 100644
--- a/services/audioflinger/Effects.h
+++ b/services/audioflinger/Effects.h
@@ -45,8 +45,8 @@
// Non trivial methods usually implemented with help from ThreadBase:
// pay attention to mutex locking order
virtual uint32_t latency() const { return 0; }
- virtual status_t addEffectToHal(sp<EffectHalInterface> effect) = 0;
- virtual status_t removeEffectFromHal(sp<EffectHalInterface> effect) = 0;
+ virtual status_t addEffectToHal(const sp<EffectHalInterface>& effect) = 0;
+ virtual status_t removeEffectFromHal(const sp<EffectHalInterface>& effect) = 0;
virtual void setVolumeForOutput(float left, float right) const = 0;
virtual bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) = 0;
virtual void checkSuspendOnEffectEnabled(const sp<EffectBase>& effect,
@@ -159,8 +159,8 @@
bool isPinned() const { return mPinned; }
void unPin() { mPinned = false; }
- void lock() { mLock.lock(); }
- void unlock() { mLock.unlock(); }
+ void lock() ACQUIRE(mLock) { mLock.lock(); }
+ void unlock() RELEASE(mLock) { mLock.unlock(); }
status_t updatePolicyState();
@@ -319,7 +319,8 @@
// sending disable command.
uint32_t mDisableWaitCnt; // current process() calls count during disable period.
bool mOffloaded; // effect is currently offloaded to the audio DSP
- bool mAddedToHal; // effect has been added to the audio HAL
+ // effect has been added to this HAL input stream
+ audio_io_handle_t mCurrentHalStream = AUDIO_IO_HANDLE_NONE;
bool mIsOutput; // direction of the AF thread
#ifdef FLOAT_EFFECT_CHAIN
@@ -459,10 +460,10 @@
void process_l();
- void lock() {
+ void lock() ACQUIRE(mLock) {
mLock.lock();
}
- void unlock() {
+ void unlock() RELEASE(mLock) {
mLock.unlock();
}
@@ -608,8 +609,8 @@
size_t frameCount() const override;
uint32_t latency() const override;
- status_t addEffectToHal(sp<EffectHalInterface> effect) override;
- status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+ status_t addEffectToHal(const sp<EffectHalInterface>& effect) override;
+ status_t removeEffectFromHal(const sp<EffectHalInterface>& effect) override;
bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
void setVolumeForOutput(float left, float right) const override;
@@ -724,8 +725,8 @@
size_t removeEffect(const sp<EffectModule>& effect);
- status_t addEffectToHal(sp<EffectHalInterface> effect);
- status_t removeEffectFromHal(sp<EffectHalInterface> effect);
+ status_t addEffectToHal(const sp<EffectHalInterface>& effect);
+ status_t removeEffectFromHal(const sp<EffectHalInterface>& effect);
const AudioDeviceTypeAddr& device() { return mDevice; };
bool isOutput() const;
@@ -769,8 +770,8 @@
size_t frameCount() const override { return 0; }
uint32_t latency() const override { return 0; }
- status_t addEffectToHal(sp<EffectHalInterface> effect) override;
- status_t removeEffectFromHal(sp<EffectHalInterface> effect) override;
+ status_t addEffectToHal(const sp<EffectHalInterface>& effect) override;
+ status_t removeEffectFromHal(const sp<EffectHalInterface>& effect) override;
bool disconnectEffectHandle(EffectHandle *handle, bool unpinIfLast) override;
void setVolumeForOutput(float left __unused, float right __unused) const override {}
diff --git a/services/audioflinger/FastCaptureDumpState.cpp b/services/audioflinger/FastCaptureDumpState.cpp
index b8b3866..243dfa5 100644
--- a/services/audioflinger/FastCaptureDumpState.cpp
+++ b/services/audioflinger/FastCaptureDumpState.cpp
@@ -51,4 +51,4 @@
periodSec * 1e3, mSilenced ? "true" : "false");
}
-} // android
+} // namespace android
diff --git a/services/audioflinger/FastCaptureDumpState.h b/services/audioflinger/FastCaptureDumpState.h
index a1b8706..34ce456 100644
--- a/services/audioflinger/FastCaptureDumpState.h
+++ b/services/audioflinger/FastCaptureDumpState.h
@@ -38,6 +38,6 @@
bool mSilenced = false; // capture is silenced
};
-} // android
+} // namespace android
#endif // ANDROID_AUDIO_FAST_CAPTURE_DUMP_STATE_H
diff --git a/services/audioflinger/FastCaptureState.cpp b/services/audioflinger/FastCaptureState.cpp
index c4d5e45..918ba9c 100644
--- a/services/audioflinger/FastCaptureState.cpp
+++ b/services/audioflinger/FastCaptureState.cpp
@@ -42,4 +42,4 @@
LOG_ALWAYS_FATAL("%s", __func__);
}
-} // android
+} // namespace android
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index 3f20282..d041882 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -203,4 +203,4 @@
}
}
-} // android
+} // namespace android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 9b91cbc..294ef78 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -81,6 +81,6 @@
TimestampVerifier<int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
};
-} // android
+} // namespace android
#endif // ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 3f6b206..2f0f73f 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -92,6 +92,6 @@
}; // class FastThread
-} // android
+} // namespace android
#endif // ANDROID_AUDIO_FAST_THREAD_H
diff --git a/services/audioflinger/FastThreadDumpState.cpp b/services/audioflinger/FastThreadDumpState.cpp
index 964a725..e91073f 100644
--- a/services/audioflinger/FastThreadDumpState.cpp
+++ b/services/audioflinger/FastThreadDumpState.cpp
@@ -56,4 +56,4 @@
}
#endif
-} // android
+} // namespace android
diff --git a/services/audioflinger/FastThreadDumpState.h b/services/audioflinger/FastThreadDumpState.h
index 1ce0914..0b20e55 100644
--- a/services/audioflinger/FastThreadDumpState.h
+++ b/services/audioflinger/FastThreadDumpState.h
@@ -67,6 +67,6 @@
}; // struct FastThreadDumpState
-} // android
+} // namespace android
#endif // ANDROID_AUDIO_FAST_THREAD_DUMP_STATE_H
diff --git a/services/audioflinger/FastThreadState.h b/services/audioflinger/FastThreadState.h
index 54c0dc6..9fb4e06 100644
--- a/services/audioflinger/FastThreadState.h
+++ b/services/audioflinger/FastThreadState.h
@@ -50,6 +50,6 @@
static const char *commandToString(Command command);
}; // struct FastThreadState
-} // android
+} // namespace android
#endif // ANDROID_AUDIO_FAST_THREAD_STATE_H
diff --git a/services/audioflinger/MelReporter.cpp b/services/audioflinger/MelReporter.cpp
index c5c9652..3d5aae2 100644
--- a/services/audioflinger/MelReporter.cpp
+++ b/services/audioflinger/MelReporter.cpp
@@ -163,7 +163,7 @@
audio_io_handle_t streamHandle = patch.mAudioPatch.sources[0].ext.mix.handle;
ActiveMelPatch newPatch;
newPatch.streamHandle = streamHandle;
- for (int i = 0; i < patch.mAudioPatch.num_sinks; ++ i) {
+ for (size_t i = 0; i < patch.mAudioPatch.num_sinks; ++i) {
if (patch.mAudioPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE
&& shouldComputeMelForDeviceType(patch.mAudioPatch.sinks[i].ext.device.type)) {
audio_port_handle_t deviceId = patch.mAudioPatch.sinks[i].id;
@@ -174,15 +174,19 @@
}
}
- std::lock_guard _afl(mAudioFlinger.mLock);
- std::lock_guard _l(mLock);
- ALOGV("%s add patch handle %d to active devices", __func__, handle);
- startMelComputationForActivePatch_l(newPatch);
- newPatch.csdActive = true;
- mActiveMelPatches[handle] = newPatch;
+ if (!newPatch.deviceHandles.empty()) {
+ std::lock_guard _afl(mAudioFlinger.mLock);
+ std::lock_guard _l(mLock);
+ ALOGV("%s add patch handle %d to active devices", __func__, handle);
+ startMelComputationForActivePatch_l(newPatch);
+ newPatch.csdActive = true;
+ mActiveMelPatches[handle] = newPatch;
+ }
}
-void AudioFlinger::MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch) {
+void AudioFlinger::MelReporter::startMelComputationForActivePatch_l(const ActiveMelPatch& patch)
+NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
+{
auto outputThread = mAudioFlinger.checkOutputThread_l(patch.streamHandle);
if (outputThread == nullptr) {
ALOGE("%s cannot find thread for stream handle %d", __func__, patch.streamHandle);
@@ -244,13 +248,15 @@
mUseHalSoundDoseInterface = true;
}
-void AudioFlinger::MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch) {
+void AudioFlinger::MelReporter::stopMelComputationForPatch_l(const ActiveMelPatch& patch)
+NO_THREAD_SAFETY_ANALYSIS // access of AudioFlinger::checkOutputThread_l
+{
if (!patch.csdActive) {
// no need to stop CSD inactive patches
return;
}
- auto outputThread = mAudioFlinger.checkOutputThread_l(patch.streamHandle);
+ auto outputThread = mAudioFlinger.checkOutputThread_l(patch.streamHandle);
ALOGV("%s: stop MEL for stream id: %d", __func__, patch.streamHandle);
for (const auto& deviceId : patch.deviceHandles) {
@@ -264,7 +270,6 @@
}
}
- mSoundDoseManager->removeStreamProcessor(patch.streamHandle);
if (outputThread != nullptr) {
outputThread->stopMelComputation_l();
}
diff --git a/services/audioflinger/MelReporter.h b/services/audioflinger/MelReporter.h
index c1b291f..81a307a 100644
--- a/services/audioflinger/MelReporter.h
+++ b/services/audioflinger/MelReporter.h
@@ -90,12 +90,13 @@
void stopInternalMelComputation();
/** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
- void stopMelComputationForPatch_l(const ActiveMelPatch& patch);
+ void stopMelComputationForPatch_l(const ActiveMelPatch& patch) REQUIRES(mLock);
/** Should be called with the following order of locks: mAudioFlinger.mLock -> mLock. */
- void startMelComputationForActivePatch_l(const ActiveMelPatch& patch);
+ void startMelComputationForActivePatch_l(const ActiveMelPatch& patch) REQUIRES(mLock);
- std::optional<audio_patch_handle_t> activePatchStreamHandle_l(audio_io_handle_t streamHandle);
+ std::optional<audio_patch_handle_t>
+ activePatchStreamHandle_l(audio_io_handle_t streamHandle) REQUIRES(mLock);
bool useHalSoundDoseInterface();
diff --git a/services/audioflinger/PatchCommandThread.cpp b/services/audioflinger/PatchCommandThread.cpp
index c3cb7e7..f4aab1f 100644
--- a/services/audioflinger/PatchCommandThread.cpp
+++ b/services/audioflinger/PatchCommandThread.cpp
@@ -56,7 +56,9 @@
releaseAudioPatchCommand(handle);
}
-bool AudioFlinger::PatchCommandThread::threadLoop() {
+bool AudioFlinger::PatchCommandThread::threadLoop()
+NO_THREAD_SAFETY_ANALYSIS // bug in clang compiler.
+{
std::unique_lock _l(mLock);
while (!exitPending()) {
diff --git a/services/audioflinger/PatchCommandThread.h b/services/audioflinger/PatchCommandThread.h
index b7853f0..b52e0a9 100644
--- a/services/audioflinger/PatchCommandThread.h
+++ b/services/audioflinger/PatchCommandThread.h
@@ -84,7 +84,7 @@
class ReleaseAudioPatchData : public CommandData {
public:
- ReleaseAudioPatchData(audio_patch_handle_t handle)
+ explicit ReleaseAudioPatchData(audio_patch_handle_t handle)
: mHandle(handle) {}
audio_patch_handle_t mHandle;
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 68a3800..5555766 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -199,7 +199,7 @@
return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
- void setThread(sp<ThreadBase> thread) { mThread = thread; }
+ void setThread(const sp<ThreadBase>& thread) { mThread = thread; }
wp<ThreadBase> thread() const { return mThread; }
// returns the latency of the patch (from record to playback).
diff --git a/services/audioflinger/StateQueue.cpp b/services/audioflinger/StateQueue.cpp
index 9d4188f..38ce2c2 100644
--- a/services/audioflinger/StateQueue.cpp
+++ b/services/audioflinger/StateQueue.cpp
@@ -187,7 +187,9 @@
} // namespace android
-// hack for gcc
+// Hack to avoid explicit template instantiation of
+// template class StateQueue<FastCaptureState>;
+// template class StateQueue<FastMixerState>;
#ifdef STATE_QUEUE_INSTANTIATIONS
-#include STATE_QUEUE_INSTANTIATIONS
+#include STATE_QUEUE_INSTANTIATIONS // NOLINT(bugprone-suspicious-include)
#endif
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index e113efb..76c9ad8 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -376,7 +376,7 @@
// try three times to get the clock offset, choose the one
// with the minimum gap in measurements.
const int tries = 3;
- nsecs_t bestGap, measured;
+ nsecs_t bestGap = 0, measured = 0; // not required, initialized for clang-tidy
for (int i = 0; i < tries; ++i) {
const nsecs_t tmono = systemTime(SYSTEM_TIME_MONOTONIC);
const nsecs_t tbase = systemTime(clockbase);
@@ -627,6 +627,7 @@
// sendConfigEvent_l() must be called with ThreadBase::mLock held
// Can temporarily release the lock if waiting for a reply from processConfigEvents_l().
status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)
+NO_THREAD_SAFETY_ANALYSIS // condition variable
{
status_t status = NO_ERROR;
@@ -942,6 +943,7 @@
}
void AudioFlinger::ThreadBase::dump(int fd, const Vector<String16>& args)
+NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
dprintf(fd, "\n%s thread %p, name %s, tid %d, type %d (%s):\n", isOutput() ? "Output" : "Input",
this, mThreadName, getTid(), type(), threadTypeToString(type()));
@@ -1310,7 +1312,9 @@
void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(bool enabled,
audio_session_t sessionId,
- bool threadLocked) {
+ bool threadLocked)
+NO_THREAD_SAFETY_ANALYSIS // manual locking
+{
if (!threadLocked) {
mLock.lock();
}
@@ -1794,6 +1798,7 @@
void AudioFlinger::ThreadBase::lockEffectChains_l(
Vector< sp<AudioFlinger::EffectChain> >& effectChains)
+NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::lock()
{
effectChains = mEffectChains;
for (size_t i = 0; i < mEffectChains.size(); i++) {
@@ -1803,6 +1808,7 @@
void AudioFlinger::ThreadBase::unlockEffectChains(
const Vector< sp<AudioFlinger::EffectChain> >& effectChains)
+NO_THREAD_SAFETY_ANALYSIS // calls EffectChain::unlock()
{
for (size_t i = 0; i < effectChains.size(); i++) {
effectChains[i]->unlock();
@@ -1910,7 +1916,7 @@
template <typename T>
void AudioFlinger::ThreadBase::ActiveTracks<T>::updatePowerState(
- sp<ThreadBase> thread, bool force) {
+ const sp<ThreadBase>& thread, bool force) {
// Updates ActiveTracks client uids to the thread wakelock.
if (mActiveTracksGeneration != mLastActiveTracksGeneration || force) {
thread->updateWakeLockUids_l(getWakeLockUids());
@@ -2788,6 +2794,7 @@
// addTrack_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::PlaybackThread::addTrack_l(const sp<Track>& track)
+NO_THREAD_SAFETY_ANALYSIS // release and re-acquire mLock
{
status_t status = ALREADY_EXISTS;
@@ -2901,6 +2908,9 @@
if (!trackActive) {
removeTrack_l(track);
} else if (track->isFastTrack() || track->isOffloaded() || track->isDirect()) {
+ if (track->isPausePending()) {
+ track->pauseAck();
+ }
track->mState = TrackBase::STOPPING_1;
}
@@ -2941,7 +2951,7 @@
if (initCheck() == NO_ERROR && mOutput->stream->getParameters(keys, &out_s8) == OK) {
return out_s8;
}
- return String8();
+ return {};
}
status_t AudioFlinger::DirectOutputThread::selectPresentation(int presentationId, int programId) {
@@ -3703,10 +3713,10 @@
size_t numSamples = mNormalFrameCount
* (audio_channel_count_from_out_mask(mMixerChannelMask)
+ mHapticChannelCount);
- status_t result = mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
+ const status_t allocateStatus = mAudioFlinger->mEffectsFactoryHal->allocateBuffer(
numSamples * sizeof(effect_buffer_t),
&halInBuffer);
- if (result != OK) return result;
+ if (allocateStatus != OK) return allocateStatus;
#ifdef FLOAT_EFFECT_CHAIN
buffer = halInBuffer ? halInBuffer->audioBuffer()->f32 : buffer;
#else
@@ -3792,8 +3802,8 @@
}
// detach all tracks with same session ID from this chain
- for (size_t i = 0; i < mTracks.size(); ++i) {
- sp<Track> track = mTracks[i];
+ for (size_t j = 0; j < mTracks.size(); ++j) {
+ sp<Track> track = mTracks[j];
if (session == track->sessionId()) {
track->setMainBuffer(reinterpret_cast<effect_buffer_t*>(mSinkBuffer));
chain->decTrackCnt();
@@ -3846,6 +3856,7 @@
}
bool AudioFlinger::PlaybackThread::threadLoop()
+NO_THREAD_SAFETY_ANALYSIS // manual locking of AudioFlinger
{
tlNBLogWriter = mNBLogWriter.get();
@@ -3914,7 +3925,7 @@
// is more informational.
if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
std::vector<PatchPanel::SoftwarePatch> swPatches;
- double latencyMs;
+ double latencyMs = 0.; // not required; initialized for clang-tidy
status_t status = INVALID_OPERATION;
audio_patch_handle_t downstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
if (mAudioFlinger->mPatchPanel.getDownstreamSoftwarePatches(id(), &swPatches) == OK
@@ -3934,8 +3945,7 @@
ALOGVV("new downstream latency %lf ms", latencyMs);
} else {
ALOGD("out of range downstream latency %lf ms", latencyMs);
- if (latencyMs < minLatency) latencyMs = minLatency;
- else if (latencyMs > maxLatency) latencyMs = maxLatency;
+ latencyMs = std::clamp(latencyMs, minLatency, maxLatency);
}
mDownstreamLatencyStatMs.add(latencyMs);
}
@@ -4624,6 +4634,7 @@
// removeTracks_l() must be called with ThreadBase::mLock held
void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
+NO_THREAD_SAFETY_ANALYSIS // release and re-acquire mLock
{
for (const auto& track : tracksToRemove) {
mActiveTracks.remove(track);
@@ -4746,8 +4757,8 @@
"as it does not support audio patches",
patch->sinks[i].ext.device.type);
type = static_cast<audio_devices_t>(type | patch->sinks[i].ext.device.type);
- deviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
- patch->sinks[i].ext.device.address));
+ deviceTypeAddrs.emplace_back(patch->sinks[i].ext.device.type,
+ patch->sinks[i].ext.device.address);
}
audio_port_handle_t sinkPortId = patch->sinks[0].id;
@@ -4962,14 +4973,15 @@
// When it wakes up after a maximum latency, it runs a few cycles quickly before
// finally blocking. Note the pipe implementation rounds up the request to a power of 2.
MonoPipe *monoPipe = new MonoPipe(mNormalFrameCount * 4, format, true /*writeCanBlock*/);
- const NBAIO_Format offers[1] = {format};
- size_t numCounterOffers = 0;
+ const NBAIO_Format offersFast[1] = {format};
+ size_t numCounterOffersFast = 0;
#if !LOG_NDEBUG
ssize_t index =
#else
(void)
#endif
- monoPipe->negotiate(offers, 1, NULL, numCounterOffers);
+ monoPipe->negotiate(offersFast, std::size(offersFast),
+ nullptr /* counterOffers */, numCounterOffersFast);
ALOG_ASSERT(index == 0);
monoPipe->setAvgFrames((mScreenState & 1) ?
(monoPipe->maxFrames() * 7) / 8 : mNormalFrameCount * 2);
@@ -5396,7 +5408,7 @@
// tallyUnderrunFrames() is called to update the track counters
// with the number of underrun frames for a particular mixer period.
// We defer tallying until we know the final mixer status.
- void tallyUnderrunFrames(sp<Track> track, size_t underrunFrames) {
+ void tallyUnderrunFrames(const sp<Track>& track, size_t underrunFrames) {
mUnderrunFrames.emplace_back(track, underrunFrames);
}
@@ -5656,7 +5668,7 @@
// during last round
size_t desiredFrames;
const uint32_t sampleRate = track->mAudioTrackServerProxy->getSampleRate();
- AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
+ const AudioPlaybackRate playbackRate = track->mAudioTrackServerProxy->getPlaybackRate();
desiredFrames = sourceFramesNeededWithTimestretch(
sampleRate, mNormalFrameCount, mSampleRate, playbackRate.mSpeed);
@@ -5849,12 +5861,12 @@
AudioMixer::SAMPLE_RATE,
(void *)(uintptr_t)reqSampleRate);
- AudioPlaybackRate playbackRate = proxy->getPlaybackRate();
mAudioMixer->setParameter(
trackId,
AudioMixer::TIMESTRETCH,
AudioMixer::PLAYBACK_RATE,
- &playbackRate);
+ // cast away constness for this generic API.
+ const_cast<void *>(reinterpret_cast<const void *>(&playbackRate)));
/*
* Select the appropriate output buffer for the track.
@@ -6238,12 +6250,12 @@
mAudioMixer = new AudioMixer(mNormalFrameCount, mSampleRate);
for (const auto &track : mTracks) {
const int trackId = track->id();
- status_t status = mAudioMixer->create(
+ const status_t createStatus = mAudioMixer->create(
trackId,
track->mChannelMask,
track->mFormat,
track->mSessionId);
- ALOGW_IF(status != NO_ERROR,
+ ALOGW_IF(createStatus != NO_ERROR,
"%s(): AudioMixer cannot create track(%d)"
" mask %#x, format %#x, sessionId %d",
__func__,
@@ -6483,9 +6495,13 @@
if (right > GAIN_FLOAT_UNITY) {
right = GAIN_FLOAT_UNITY;
}
-
- left *= v * mMasterBalanceLeft; // DirectOutputThread balance applied as track volume
- right *= v * mMasterBalanceRight;
+ left *= v;
+ right *= v;
+ if (mAudioFlinger->getMode() != AUDIO_MODE_IN_COMMUNICATION
+ || audio_channel_count_from_out_mask(mChannelMask) > 1) {
+ left *= mMasterBalanceLeft; // DirectOutputThread balance applied as track volume
+ right *= mMasterBalanceRight;
+ }
}
track->processMuteEvent_l(mAudioFlinger->getOrCreateAudioManager(),
@@ -7414,7 +7430,7 @@
void AudioFlinger::DuplicatingThread::threadLoop_mix()
{
// mix buffers...
- if (outputsReady(outputTracks)) {
+ if (outputsReady()) {
mAudioMixer->process();
} else {
if (mMixerBufferValid) {
@@ -7485,7 +7501,7 @@
}
}
-void AudioFlinger::DuplicatingThread::dumpInternals_l(int fd, const Vector<String16>& args __unused)
+void AudioFlinger::DuplicatingThread::dumpInternals_l(int fd, const Vector<String16>& args)
{
MixerThread::dumpInternals_l(fd, args);
@@ -7589,9 +7605,7 @@
}
}
-
-bool AudioFlinger::DuplicatingThread::outputsReady(
- const SortedVector< sp<OutputTrack> > &outputTracks)
+bool AudioFlinger::DuplicatingThread::outputsReady()
{
for (size_t i = 0; i < outputTracks.size(); i++) {
sp<ThreadBase> thread = outputTracks[i]->thread().promote();
@@ -7858,14 +7872,16 @@
// pipe will be shared directly with fast clients, so clear to avoid leaking old information
memset(pipeBuffer, 0, pipeSize);
Pipe *pipe = new Pipe(pipeFramesP2, format, pipeBuffer);
- const NBAIO_Format offers[1] = {format};
- size_t numCounterOffers = 0;
- [[maybe_unused]] ssize_t index = pipe->negotiate(offers, 1, NULL, numCounterOffers);
+ const NBAIO_Format offersFast[1] = {format};
+ size_t numCounterOffersFast = 0;
+ [[maybe_unused]] ssize_t index = pipe->negotiate(offersFast, std::size(offersFast),
+ nullptr /* counterOffers */, numCounterOffersFast);
ALOG_ASSERT(index == 0);
mPipeSink = pipe;
PipeReader *pipeReader = new PipeReader(*pipe);
- numCounterOffers = 0;
- index = pipeReader->negotiate(offers, 1, NULL, numCounterOffers);
+ numCounterOffersFast = 0;
+ index = pipeReader->negotiate(offersFast, std::size(offersFast),
+ nullptr /* counterOffers */, numCounterOffersFast);
ALOG_ASSERT(index == 0);
mPipeSource = pipeReader;
mPipeFramesP2 = pipeFramesP2;
@@ -8213,7 +8229,7 @@
// copy to the right place. Permitted because mRsmpInBuffer was over-allocated.
int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
- ssize_t framesRead;
+ ssize_t framesRead = 0; // not needed, remove clang-tidy warning.
const int64_t lastIoBeginNs = systemTime(); // start IO timing
// If an NBAIO source is present, use it to read the normal capture's data
@@ -8406,8 +8422,9 @@
// straight from RecordThread buffer to RecordTrack buffer.
AudioBufferProvider::Buffer buffer;
buffer.frameCount = framesOut;
- status_t status = activeTrack->mResamplerBufferProvider->getNextBuffer(&buffer);
- if (status == OK && buffer.frameCount != 0) {
+ const status_t getNextBufferStatus =
+ activeTrack->mResamplerBufferProvider->getNextBuffer(&buffer);
+ if (getNextBufferStatus == OK && buffer.frameCount != 0) {
ALOGV_IF(buffer.frameCount != framesOut,
"%s() read less than expected (%zu vs %zu)",
__func__, buffer.frameCount, framesOut);
@@ -8417,7 +8434,7 @@
} else {
framesOut = 0;
ALOGE("%s() cannot fill request, status: %d, frameCount: %zu",
- __func__, status, buffer.frameCount);
+ __func__, getNextBufferStatus, buffer.frameCount);
}
} else {
// process frames from the RecordThread buffer provider to the RecordTrack
@@ -8837,7 +8854,6 @@
// or using a separate command thread
recordTrack->mState = TrackBase::STARTING_1;
mActiveTracks.add(recordTrack);
- status_t status = NO_ERROR;
if (recordTrack->isExternalTrack()) {
mLock.unlock();
status = AudioSystem::startInput(recordTrack->portId());
@@ -9028,7 +9044,7 @@
// "best effort" behavior of the API.
if (sharedOffset < 0) {
sharedAudioStartFrames = mRsmpInRear;
- } else if (sharedOffset > mRsmpInFrames) {
+ } else if (sharedOffset > static_cast<signed>(mRsmpInFrames)) {
sharedAudioStartFrames =
audio_utils::safe_sub_overflow(mRsmpInRear, (int32_t)mRsmpInFrames);
}
@@ -9406,7 +9422,7 @@
return out_s8;
}
}
- return String8();
+ return {};
}
void AudioFlinger::RecordThread::ioConfigChanged(audio_io_config_event_t event, pid_t pid,
@@ -9647,7 +9663,7 @@
maxFilled = filled;
}
}
- if (maxFilled > mRsmpInFrames) {
+ if (maxFilled > static_cast<signed>(mRsmpInFrames)) {
(void)__builtin_sub_overflow(mRsmpInRear, mRsmpInFrames, &oldestFront);
}
return oldestFront;
@@ -9843,7 +9859,7 @@
AudioFlinger::MmapThread::MmapThread(
const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady, bool isOut)
+ AudioHwDevice *hwDev, const sp<StreamHalInterface>& stream, bool systemReady, bool isOut)
: ThreadBase(audioFlinger, id, (isOut ? MMAP_PLAYBACK : MMAP_CAPTURE), systemReady, isOut),
mSessionId(AUDIO_SESSION_NONE),
mPortId(AUDIO_PORT_HANDLE_NONE),
@@ -10049,8 +10065,10 @@
mHalVolFloat = -1.0f;
} else if (!track->isSilenced_l()) {
for (const sp<MmapTrack> &t : mActiveTracks) {
- if (t->isSilenced_l() && t->uid() != client.attributionSource.uid)
+ if (t->isSilenced_l()
+ && t->uid() != static_cast<uid_t>(client.attributionSource.uid)) {
t->invalidate();
+ }
}
}
@@ -10287,7 +10305,7 @@
if (initCheck() == NO_ERROR && mHalStream->getParameters(keys, &out_s8) == OK) {
return out_s8;
}
- return String8();
+ return {};
}
void AudioFlinger::MmapThread::ioConfigChanged(audio_io_config_event_t event, pid_t pid,
@@ -10317,6 +10335,7 @@
status_t AudioFlinger::MmapThread::createAudioPatch_l(const struct audio_patch *patch,
audio_patch_handle_t *handle)
+NO_THREAD_SAFETY_ANALYSIS // elease and re-acquire mLock
{
status_t status = NO_ERROR;
@@ -10334,8 +10353,8 @@
"as it does not support audio patches",
patch->sinks[i].ext.device.type);
type = static_cast<audio_devices_t>(type | patch->sinks[i].ext.device.type);
- sinkDeviceTypeAddrs.push_back(AudioDeviceTypeAddr(patch->sinks[i].ext.device.type,
- patch->sinks[i].ext.device.address));
+ sinkDeviceTypeAddrs.emplace_back(patch->sinks[i].ext.device.type,
+ patch->sinks[i].ext.device.address);
}
deviceId = patch->sinks[0].id;
numDevices = mPatch.num_sinks;
@@ -10544,6 +10563,7 @@
}
void AudioFlinger::MmapThread::checkInvalidTracks_l()
+NO_THREAD_SAFETY_ANALYSIS // release and re-acquire mLock
{
sp<MmapStreamCallback> callback;
for (const sp<MmapTrack> &track : mActiveTracks) {
@@ -10717,6 +10737,7 @@
}
void AudioFlinger::MmapPlaybackThread::processVolume_l()
+NO_THREAD_SAFETY_ANALYSIS // access of track->processMuteEvent_l
{
float volume;
@@ -10851,16 +10872,23 @@
const sp<audio_utils::MelProcessor>& processor)
{
ALOGV("%s: starting mel processor for thread %d", __func__, id());
- if (processor != nullptr) {
- mMelProcessor = processor;
+ mMelProcessor.store(processor);
+ if (processor) {
+ processor->resume();
}
+
+ // no need to update output format for MMapPlaybackThread since it is
+ // assigned constant for each thread
}
// stopMelComputation_l() must be called with AudioFlinger::mLock held
void AudioFlinger::MmapPlaybackThread::stopMelComputation_l()
{
- ALOGV("%s: stopping mel processor for thread %d", __func__, id());
- mMelProcessor = nullptr;
+ ALOGV("%s: pausing mel processor for thread %d", __func__, id());
+ auto melProcessor = mMelProcessor.load();
+ if (melProcessor != nullptr) {
+ melProcessor->pause();
+ }
}
void AudioFlinger::MmapPlaybackThread::dumpInternals_l(int fd, const Vector<String16>& args)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 03e4567..7b4c150 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -164,7 +164,7 @@
class SetParameterConfigEventData : public ConfigEventData {
public:
- explicit SetParameterConfigEventData(String8 keyValuePairs) :
+ explicit SetParameterConfigEventData(const String8& keyValuePairs) :
mKeyValuePairs(keyValuePairs) {}
virtual void dump(char *buffer, size_t size) {
@@ -176,7 +176,7 @@
class SetParameterConfigEvent : public ConfigEvent {
public:
- explicit SetParameterConfigEvent(String8 keyValuePairs) :
+ explicit SetParameterConfigEvent(const String8& keyValuePairs) :
ConfigEvent(CFG_EVENT_SET_PARAMETER) {
mData = new SetParameterConfigEventData(keyValuePairs);
mWaitStatus = true;
@@ -802,7 +802,7 @@
// ThreadBase thread.
void clear();
// periodically called in the threadLoop() to update power state uids.
- void updatePowerState(sp<ThreadBase> thread, bool force = false);
+ void updatePowerState(const sp<ThreadBase>& thread, bool force = false);
/** @return true if one or move active tracks was added or removed since the
* last time this function was called or the vector was created.
@@ -1291,7 +1291,7 @@
template <typename T>
class Tracks {
public:
- Tracks(bool saveDeletedTrackIds) :
+ explicit Tracks(bool saveDeletedTrackIds) :
mSaveDeletedTrackIds(saveDeletedTrackIds) { }
// SortedVector methods
@@ -1320,7 +1320,7 @@
return mTracks.end();
}
- size_t processDeletedTrackIds(std::function<void(int)> f) {
+ size_t processDeletedTrackIds(const std::function<void(int)>& f) {
for (const int trackId : mDeletedTrackIds) {
f(trackId);
}
@@ -1442,7 +1442,7 @@
class IsTimestampAdvancing {
public:
// The timestamp will not be checked any faster than the specified time.
- IsTimestampAdvancing(nsecs_t minimumTimeBetweenChecksNs)
+ explicit IsTimestampAdvancing(nsecs_t minimumTimeBetweenChecksNs)
: mMinimumTimeBetweenChecksNs(minimumTimeBetweenChecksNs)
{
clear();
@@ -1759,7 +1759,7 @@
void dumpInternals_l(int fd, const Vector<String16>& args) override;
private:
- bool outputsReady(const SortedVector< sp<OutputTrack> > &outputTracks);
+ bool outputsReady();
protected:
// threadLoop snippets
virtual void threadLoop_mix();
@@ -2108,7 +2108,7 @@
#include "MmapTracks.h"
MmapThread(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
- AudioHwDevice *hwDev, sp<StreamHalInterface> stream, bool systemReady,
+ AudioHwDevice *hwDev, const sp<StreamHalInterface>& stream, bool systemReady,
bool isOut);
virtual ~MmapThread();
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index f305aa8..254fb91 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -124,7 +124,7 @@
* This may be called without the thread lock.
*/
virtual double bufferLatencyMs() const {
- return mServerProxy->framesReadySafe() * 1000 / sampleRate();
+ return mServerProxy->framesReadySafe() * 1000. / sampleRate();
}
/** returns whether the track supports server latency computation.
@@ -432,7 +432,7 @@
{
public:
using Timeout = std::optional<std::chrono::nanoseconds>;
- PatchTrackBase(sp<ClientProxy> proxy, const ThreadBase& thread,
+ PatchTrackBase(const sp<ClientProxy>& proxy, const ThreadBase& thread,
const Timeout& timeout);
void setPeerTimeout(std::chrono::nanoseconds timeout);
template <typename T>
diff --git a/services/audioflinger/TrackMetrics.h b/services/audioflinger/TrackMetrics.h
index 6fc70d6..f3425df 100644
--- a/services/audioflinger/TrackMetrics.h
+++ b/services/audioflinger/TrackMetrics.h
@@ -17,6 +17,9 @@
#ifndef ANDROID_AUDIO_TRACKMETRICS_H
#define ANDROID_AUDIO_TRACKMETRICS_H
+#include <binder/IActivityManager.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
#include <mutex>
namespace android {
@@ -38,10 +41,13 @@
* We currently deliver metrics based on an AudioIntervalGroup.
*/
class TrackMetrics final {
+
+
public:
- TrackMetrics(std::string metricsId, bool isOut)
+ TrackMetrics(std::string metricsId, bool isOut, int clientUid)
: mMetricsId(std::move(metricsId))
, mIsOut(isOut)
+ , mUid(clientUid)
{} // we don't log a constructor item, we wait for more info in logConstructor().
~TrackMetrics() {
@@ -64,6 +70,18 @@
AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP, devices.c_str());
}
++mIntervalCount;
+ const auto& mActivityManager = getActivityManager();
+ if (mActivityManager) {
+ if (mIsOut) {
+ mActivityManager->logFgsApiBegin(AUDIO_API,
+ mUid,
+ IPCThreadState::self() -> getCallingPid());
+ } else {
+ mActivityManager->logFgsApiBegin(MICROPHONE_API,
+ mUid,
+ IPCThreadState::self() -> getCallingPid());
+ }
+ }
}
void logConstructor(pid_t creatorPid, uid_t creatorUid, int32_t internalTrackId,
@@ -93,6 +111,18 @@
logVolume_l(mVolume); // flush out the last volume.
mLastVolumeChangeTimeNs = 0;
}
+ const auto& mActivityManager = getActivityManager();
+ if (mActivityManager) {
+ if (mIsOut) {
+ mActivityManager->logFgsApiEnd(AUDIO_API,
+ mUid,
+ IPCThreadState::self() -> getCallingPid());
+ } else {
+ mActivityManager->logFgsApiEnd(MICROPHONE_API,
+ mUid,
+ IPCThreadState::self() -> getCallingPid());
+ }
+ }
}
void logInvalidate() const {
@@ -113,7 +143,8 @@
mDeviceStartupMs.add(startupMs);
}
- void updateMinMaxVolume(int64_t durationNs, double deviceVolume) {
+ void updateMinMaxVolume_l(int64_t durationNs, double deviceVolume)
+ REQUIRES(mLock) {
if (deviceVolume > mMaxVolume) {
mMaxVolume = deviceVolume;
mMaxVolumeDurationNs = durationNs;
@@ -165,7 +196,7 @@
mDeviceTimeNs += durationNs;
mCumulativeTimeNs += durationNs;
}
- updateMinMaxVolume(durationNs, mVolume); // always update.
+ updateMinMaxVolume_l(durationNs, mVolume); // always update.
mVolume = volume;
mLastVolumeChangeTimeNs = timeNs;
}
@@ -221,9 +252,25 @@
// do not reset mUnderrunCount - it keeps continuously running for tracks.
}
+ // Meyer's singleton is thread-safe.
+ static const sp<IActivityManager>& getActivityManager() {
+ static const auto activityManager = []() -> sp<IActivityManager> {
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ return interface_cast<IActivityManager>(sm->checkService(String16("activity")));
+ }
+ return nullptr;
+ }();
+ return activityManager;
+ }
+
const std::string mMetricsId;
const bool mIsOut; // if true, than a playback track, otherwise used for record.
+ static constexpr int AUDIO_API = 5;
+ static constexpr int MICROPHONE_API = 6;
+ const int mUid;
+
mutable std::mutex mLock;
// Devices in the interval group.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 1fbf720..8faaffe 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -118,7 +118,7 @@
mThreadIoHandle(thread ? thread->id() : AUDIO_IO_HANDLE_NONE),
mPortId(portId),
mIsInvalid(false),
- mTrackMetrics(std::move(metricsId), isOut),
+ mTrackMetrics(std::move(metricsId), isOut, clientUid),
mCreatorPid(creatorPid)
{
const uid_t callingUid = IPCThreadState::self()->getCallingUid();
@@ -304,7 +304,7 @@
return NO_ERROR;
}
-AudioFlinger::ThreadBase::PatchTrackBase::PatchTrackBase(sp<ClientProxy> proxy,
+AudioFlinger::ThreadBase::PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
const ThreadBase& thread,
const Timeout& timeout)
: mProxy(proxy)
@@ -1319,8 +1319,9 @@
// must be called with thread lock held
void AudioFlinger::PlaybackThread::Track::flushAck()
{
- if (!isOffloaded() && !isDirect())
+ if (!isOffloaded() && !isDirect()) {
return;
+ }
// Clear the client ring buffer so that the app can prime the buffer while paused.
// Otherwise it might not get cleared until playback is resumed and obtainBuffer() is called.
@@ -1851,23 +1852,23 @@
//To be called with thread lock held
bool AudioFlinger::PlaybackThread::Track::isResumePending() {
-
- if (mState == RESUMING)
+ if (mState == RESUMING) {
return true;
+ }
/* Resume is pending if track was stopping before pause was called */
if (mState == STOPPING_1 &&
- mResumeToStopping)
+ mResumeToStopping) {
return true;
+ }
return false;
}
//To be called with thread lock held
void AudioFlinger::PlaybackThread::Track::resumeAck() {
-
-
- if (mState == RESUMING)
+ if (mState == RESUMING) {
mState = ACTIVE;
+ }
// Other possibility of pending resume is stopping_1 state
// Do not update the state from stopping as this prevents
@@ -2135,7 +2136,10 @@
if (thread != 0 && !thread->standby()) {
if (mBufferQueue.size() < kMaxOverFlowBuffers) {
pInBuffer = new Buffer;
- pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize);
+ const size_t bufferSize = inBuffer.frameCount * mFrameSize;
+ pInBuffer->mBuffer = malloc(bufferSize);
+ LOG_ALWAYS_FATAL_IF(pInBuffer->mBuffer == nullptr,
+ "%s: Unable to malloc size %zu", __func__, bufferSize);
pInBuffer->frameCount = inBuffer.frameCount;
pInBuffer->raw = pInBuffer->mBuffer;
memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize);
@@ -2299,7 +2303,7 @@
buf.mFrameCount = buffer->frameCount;
buf.mRaw = buffer->raw;
mPeerProxy->releaseBuffer(&buf);
- TrackBase::releaseBuffer(buffer);
+ TrackBase::releaseBuffer(buffer); // Note: this is the base class.
}
status_t AudioFlinger::PlaybackThread::PatchTrack::obtainBuffer(Proxy::Buffer* buffer,
@@ -2913,7 +2917,7 @@
{
void *ptr = nullptr;
(void)posix_memalign(&ptr, alignment, size);
- return std::unique_ptr<void, decltype(free)*>(ptr, free);
+ return {ptr, free};
}
AudioFlinger::RecordThread::PassthruPatchRecord::PassthruPatchRecord(
diff --git a/services/audioflinger/sounddose/SoundDoseManager.cpp b/services/audioflinger/sounddose/SoundDoseManager.cpp
index 21252d6..827f7d4 100644
--- a/services/audioflinger/sounddose/SoundDoseManager.cpp
+++ b/services/audioflinger/sounddose/SoundDoseManager.cpp
@@ -51,33 +51,36 @@
std::lock_guard _l(mLock);
if (mHalSoundDose != nullptr && !mDisableCsd) {
- ALOGW("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
+ ALOGD("%s: using HAL MEL computation, no MelProcessor needed.", __func__);
return nullptr;
}
auto streamProcessor = mActiveProcessors.find(streamHandle);
- sp<audio_utils::MelProcessor> processor;
- if (streamProcessor != mActiveProcessors.end() &&
- (processor = streamProcessor->second.promote())) {
- ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
- const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
- if (activeTypeIt != mActiveDeviceTypes.end()) {
- processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
+ if (streamProcessor != mActiveProcessors.end()) {
+ auto processor = streamProcessor->second.promote();
+ // if processor is nullptr it means it was removed by the playback
+ // thread and can be replaced in the mActiveProcessors map
+ if (processor != nullptr) {
+ ALOGV("%s: found callback for stream id %d", __func__, streamHandle);
+ const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
+ if (activeTypeIt != mActiveDeviceTypes.end()) {
+ processor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
+ }
+ processor->setDeviceId(deviceId);
+ processor->setOutputRs2UpperBound(mRs2UpperBound);
+ return processor;
}
- processor->setDeviceId(deviceId);
- processor->setOutputRs2UpperBound(mRs2UpperBound);
- return processor;
- } else {
- ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
- sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
- sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
- const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
- if (activeTypeIt != mActiveDeviceTypes.end()) {
- melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
- }
- mActiveProcessors[streamHandle] = melProcessor;
- return melProcessor;
}
+
+ ALOGV("%s: creating new callback for stream id %d", __func__, streamHandle);
+ sp<audio_utils::MelProcessor> melProcessor = sp<audio_utils::MelProcessor>::make(
+ sampleRate, channelCount, format, this, deviceId, mRs2UpperBound);
+ const auto activeTypeIt = mActiveDeviceTypes.find(deviceId);
+ if (activeTypeIt != mActiveDeviceTypes.end()) {
+ melProcessor->setAttenuation(mMelAttenuationDB[activeTypeIt->second]);
+ }
+ mActiveProcessors[streamHandle] = melProcessor;
+ return melProcessor;
}
bool SoundDoseManager::setHalSoundDoseInterface(const std::shared_ptr<ISoundDose>& halSoundDose) {
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index 8f9c60b..3d1cf76 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -246,6 +246,8 @@
unsigned int *num_ports,
struct audio_port_v7 *ports,
unsigned int *generation) = 0;
+ virtual status_t listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* result) = 0;
virtual status_t getAudioPort(struct audio_port_v7 *port) = 0;
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 52a000f..876911d 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -301,6 +301,10 @@
return mActiveClients;
}
+ // Returns 0 if not all active clients have the same exclusive preferred device
+ // or the number of active clients with the same exclusive preferred device
+ size_t sameExclusivePreferredDevicesCount() const;
+
bool useHwGain() const
{
return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a46186b..7ee6566 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -238,6 +238,27 @@
return clients;
}
+size_t AudioOutputDescriptor::sameExclusivePreferredDevicesCount() const
+{
+ audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ size_t count = 0;
+ for (const auto &client : getClientIterable()) {
+ if (client->active()) {
+ if (!(client->hasPreferredDevice() &&
+ client->isPreferredDeviceForExclusiveUse())) {
+ return 0;
+ }
+ if (deviceId == AUDIO_PORT_HANDLE_NONE) {
+ deviceId = client->preferredDeviceId();
+ } else if (deviceId != client->preferredDeviceId()) {
+ return 0;
+ }
+ count++;
+ }
+ }
+ return count;
+}
+
bool AudioOutputDescriptor::isAnyActive(VolumeSource volumeSourceToIgnore) const
{
return std::find_if(begin(mActiveClients), end(mActiveClients),
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index ba5a6a7..4cfdaad 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -278,17 +278,6 @@
mixesDisallowsRequestedDevice = true;
}
- if (!primaryOutputMix && (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) {
- // AAudio does not support MMAP_NO_IRQ loopback render, and there is no way with
- // the current MmapStreamInterface::start to reject a specific client added to a shared
- // mmap stream.
- // As a result all MMAP_NOIRQ requests have to be rejected when an loopback render
- // policy is present. That ensures no shared mmap stream is used when an loopback
- // render policy is registered.
- ALOGD("%s: Rejecting MMAP_NOIRQ request due to LOOPBACK|RENDER mix present.", __func__);
- return INVALID_OPERATION;
- }
-
if (primaryOutputMix && primaryMix != nullptr) {
ALOGV("%s: Skiping %zu: Primary output already found", __func__, i);
continue; // Primary output already found
@@ -299,6 +288,13 @@
continue; // skip the mix
}
+ if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+ // AAudio MMAP_NOIRQ streams cannot be routed using dynamic audio policy.
+ ALOGD("%s: Rejecting MMAP_NOIRQ request matched to dynamic audio policy mix.",
+ __func__);
+ return INVALID_OPERATION;
+ }
+
if (mixDevice != nullptr && mixDevice->equals(requestedDevice)) {
ALOGV("%s: Mix %zu: requested device mathches", __func__, i);
mixesDisallowsRequestedDevice = false;
diff --git a/services/audiopolicy/fuzzer/Android.bp b/services/audiopolicy/fuzzer/Android.bp
index 9f6b703..621f643 100644
--- a/services/audiopolicy/fuzzer/Android.bp
+++ b/services/audiopolicy/fuzzer/Android.bp
@@ -63,6 +63,15 @@
],
data: [":audiopolicyfuzzer_configuration_files"],
fuzz_config: {
- cc: ["mnaganov@google.com"],
+ cc: ["mnaganov@google.com"],
+ componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libaudiopolicy",
+ vector: "local_no_privileges_required",
+ service_privilege: "privileged",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index f5c7a71..dd27ca4 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2228,8 +2228,7 @@
outputDesc->setClientActive(client, true);
if (client->hasPreferredDevice(true)) {
- if (outputDesc->clientsList(true /*activeOnly*/).size() == 1 &&
- client->isPreferredDeviceForExclusiveUse()) {
+ if (outputDesc->sameExclusivePreferredDevicesCount() > 0) {
// Preferred device may be exclusive, use only if no other active clients on this output
devices = DeviceVector(
mAvailableOutputDevices.getDeviceFromId(client->preferredDeviceId()));
@@ -2461,7 +2460,8 @@
}
}
bool forceDeviceUpdate = false;
- if (client->hasPreferredDevice(true)) {
+ if (client->hasPreferredDevice(true) &&
+ outputDesc->sameExclusivePreferredDevicesCount() < 2) {
checkStrategyRoute(client->strategy(), AUDIO_IO_HANDLE_NONE);
forceDeviceUpdate = true;
}
@@ -4602,6 +4602,28 @@
return NO_ERROR;
}
+status_t AudioPolicyManager::listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* _aidl_return) {
+ auto pushPort = [&](const sp<DeviceDescriptor>& dev) -> status_t {
+ audio_port_v7 port;
+ dev->toAudioPort(&port);
+ auto aidlPort = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
+ _aidl_return->push_back(std::move(aidlPort));
+ return OK;
+ };
+
+ for (const auto& module : mHwModulesAll) {
+ for (const auto& dev : module->getDeclaredDevices()) {
+ if (role == media::AudioPortRole::NONE ||
+ ((role == media::AudioPortRole::SOURCE)
+ == audio_is_input_device(dev->type()))) {
+ RETURN_STATUS_IF_ERROR(pushPort(dev));
+ }
+ }
+ }
+ return OK;
+}
+
status_t AudioPolicyManager::getAudioPort(struct audio_port_v7 *port)
{
if (port == nullptr || port->id == AUDIO_PORT_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index ed212c2..2924ee1 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -263,6 +263,8 @@
unsigned int *num_ports,
struct audio_port_v7 *ports,
unsigned int *generation);
+ status_t listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* result) override;
virtual status_t getAudioPort(struct audio_port_v7 *port);
virtual status_t createAudioPatch(const struct audio_patch *patch,
audio_patch_handle_t *handle,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 35411f9..af7be52 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -301,7 +301,8 @@
audio_stream_type_t stream = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioStreamType_audio_stream_type_t(streamAidl));
- if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT) {
+ if (uint32_t(stream) >= AUDIO_STREAM_PUBLIC_CNT
+ && stream != AUDIO_STREAM_ASSISTANT && stream != AUDIO_STREAM_CALL_ASSISTANT) {
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_io_handle_t_int32_t(AUDIO_IO_HANDLE_NONE));
return Status::ok();
@@ -1540,6 +1541,17 @@
return Status::ok();
}
+Status AudioPolicyService::listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* _aidl_return) {
+ Mutex::Autolock _l(mLock);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ AutoCallerClear acc;
+ return binderStatusFromStatusT(mAudioPolicyManager->listDeclaredDevicePorts(
+ role, _aidl_return));
+}
+
Status AudioPolicyService::getAudioPort(int portId,
media::AudioPortFw* _aidl_return) {
audio_port_v7 port{ .id = portId };
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 31d5249..59aabac 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -175,6 +175,8 @@
binder::Status listAudioPorts(media::AudioPortRole role, media::AudioPortType type,
Int* count, std::vector<media::AudioPortFw>* ports,
int32_t* _aidl_return) override;
+ binder::Status listDeclaredDevicePorts(media::AudioPortRole role,
+ std::vector<media::AudioPortFw>* _aidl_return) override;
binder::Status getAudioPort(int portId,
media::AudioPortFw* _aidl_return) override;
binder::Status createAudioPatch(const media::AudioPatchFw& patch, int32_t handle,
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index d325509..874bde4 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -108,8 +108,8 @@
.freshnessTimeout = Ticks(kFreshnessTimeout).count(),
.predictionDuration = []() -> float {
const int duration_ms =
- property_get_int32("audio.spatializer.prediction_duration_ms", 0);
- if (duration_ms > 0) {
+ property_get_int32("audio.spatializer.prediction_duration_ms", -1);
+ if (duration_ms >= 0) {
return duration_ms * 1'000'000LL;
} else {
return Ticks(kPredictionDuration).count();
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index ed77936..412ab19 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -82,6 +82,14 @@
return criterion;
}
+// TODO b/182392769: use attribution source util
+AttributionSourceState createAttributionSourceState(uid_t uid) {
+ AttributionSourceState attributionSourceState;
+ attributionSourceState.uid = uid;
+ attributionSourceState.token = sp<BBinder>::make();
+ return attributionSourceState;
+}
+
} // namespace
TEST(AudioPolicyManagerTestInit, EngineFailure) {
@@ -271,10 +279,7 @@
AudioPolicyInterface::output_type_t outputType;
bool isSpatialized;
bool isBitPerfectInternal;
- // TODO b/182392769: use attribution source util
- AttributionSourceState attributionSource = AttributionSourceState();
- attributionSource.uid = uid;
- attributionSource.token = sp<BBinder>::make();
+ AttributionSourceState attributionSource = createAttributionSourceState(uid);
ASSERT_EQ(OK, mManager->getOutputForAttr(
&attr, output, session, &stream, attributionSource, &config, &flags,
selectedDeviceId, portId, {}, &outputType, &isSpatialized,
@@ -302,10 +307,7 @@
if (!portId) portId = &localPortId;
*portId = AUDIO_PORT_HANDLE_NONE;
AudioPolicyInterface::input_type_t inputType;
- // TODO b/182392769: use attribution source util
- AttributionSourceState attributionSource = AttributionSourceState();
- attributionSource.uid = 0;
- attributionSource.token = sp<BBinder>::make();
+ AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
ASSERT_EQ(OK, mManager->getInputForAttr(
&attr, &input, riid, session, attributionSource, &config, flags,
selectedDeviceId, &inputType, portId));
@@ -1859,6 +1861,82 @@
/*expected_match=*/ false)
.withSessionId(TEST_SESSION_ID).withUsage(AUDIO_USAGE_MEDIA)));
+struct DPMmapTestParam {
+ DPMmapTestParam(int mixRouteFlags, audio_devices_t deviceType, const std::string& deviceAddress)
+ : mixRouteFlags(mixRouteFlags), deviceType(deviceType), deviceAddress(deviceAddress) {}
+
+ int mixRouteFlags;
+ audio_devices_t deviceType;
+ std::string deviceAddress;
+};
+
+class AudioPolicyManagerTestMMapPlaybackRerouting
+ : public AudioPolicyManagerTestDynamicPolicy,
+ public ::testing::WithParamInterface<DPMmapTestParam> {
+ protected:
+ void SetUp() override {
+ AudioPolicyManagerTestDynamicPolicy::SetUp();
+ audioConfig = AUDIO_CONFIG_INITIALIZER;
+ audioConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ audioConfig.format = AUDIO_FORMAT_PCM_16_BIT;
+ audioConfig.sample_rate = k48000SamplingRate;
+ }
+
+ audio_config_t audioConfig;
+ audio_io_handle_t mOutput;
+ audio_stream_type_t mStream = AUDIO_STREAM_DEFAULT;
+ audio_port_handle_t mSelectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_port_handle_t mPortId;
+ AudioPolicyInterface::output_type_t mOutputType;
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ bool mIsSpatialized;
+ bool mIsBitPerfect;
+};
+
+TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, MmapPlaybackStreamMatchingDapMixFails) {
+ // 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);
+
+ // Geting output for matching uid and mmap-ed stream should fail.
+ audio_output_flags_t outputFlags = AUDIO_OUTPUT_FLAG_MMAP_NOIRQ;
+ ASSERT_EQ(INVALID_OPERATION,
+ mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
+ createAttributionSourceState(testUid), &audioConfig,
+ &outputFlags, &mSelectedDeviceId, &mPortId, {},
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect));
+}
+
+TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, NonMmapPlaybackStreamMatchingDapMixSucceeds) {
+ // 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);
+
+ // Geting 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,
+ createAttributionSourceState(testUid), &audioConfig,
+ &outputFlags, &mSelectedDeviceId, &mPortId, {},
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect));
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ MmapPlaybackRerouting, AudioPolicyManagerTestMMapPlaybackRerouting,
+ testing::Values(DPMmapTestParam(MIX_ROUTE_FLAG_LOOP_BACK, AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ /*deviceAddress=*/"remote_submix_media"),
+ DPMmapTestParam(MIX_ROUTE_FLAG_LOOP_BACK_AND_RENDER,
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
+ /*deviceAddress=*/"remote_submix_media"),
+ DPMmapTestParam(MIX_ROUTE_FLAG_RENDER, AUDIO_DEVICE_OUT_SPEAKER,
+ /*deviceAddress=*/"")));
+
class AudioPolicyManagerTestDPMixRecordInjection : public AudioPolicyManagerTestDynamicPolicy,
public testing::WithParamInterface<DPTestParam> {
protected:
@@ -2018,19 +2096,19 @@
// Connecting a valid output device with valid parameters should trigger a routing update
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
- "a", "b", AUDIO_FORMAT_DEFAULT));
+ "00:11:22:33:44:55", "b", AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(1, mClient->getRoutingUpdatedCounter());
// Disconnecting a connected device should succeed and trigger a routing update
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- "a", "b", AUDIO_FORMAT_DEFAULT));
+ "00:11:22:33:44:55", "b", AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(2, mClient->getRoutingUpdatedCounter());
// Disconnecting a disconnected device should fail and not trigger a routing update
ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
AUDIO_DEVICE_OUT_BLUETOOTH_SCO, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
- "a", "b", AUDIO_FORMAT_DEFAULT));
+ "00:11:22:33:44:55", "b", AUDIO_FORMAT_DEFAULT));
ASSERT_EQ(2, mClient->getRoutingUpdatedCounter());
// Changing force use should trigger an update
@@ -2158,9 +2236,9 @@
DeviceConnectionTestParams({AUDIO_DEVICE_OUT_HDMI, "test_out_hdmi",
"audio_policy_test_out_hdmi"}),
DeviceConnectionTestParams({AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "bt_hfp_in",
- "hfp_client_in"}),
+ "00:11:22:33:44:55"}),
DeviceConnectionTestParams({AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "bt_hfp_out",
- "hfp_client_out"})
+ "00:11:22:33:44:55"})
)
);
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 1c922ce..e818759 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -120,6 +120,7 @@
],
shared_libs: [
+ "libactivitymanager_aidl",
"libbase",
"libdl",
"libexif",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 0115023..1564ff3 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -69,6 +69,8 @@
#include <private/android_filesystem_config.h>
#include <system/camera_vendor_tags.h>
#include <system/camera_metadata.h>
+#include <binder/IServiceManager.h>
+#include <binder/IActivityManager.h>
#include <system/camera.h>
@@ -137,6 +139,8 @@
"android.permission.CAMERA_OPEN_CLOSE_LISTENER");
static const String16
sCameraInjectExternalCameraPermission("android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
+// Constant integer for FGS Logging, used to denote the API type for logger
+static const int LOG_FGS_CAMERA_API = 1;
const char *sFileName = "lastOpenSessionDumpFile";
static constexpr int32_t kSystemNativeClientScore = resource_policy::PERCEPTIBLE_APP_ADJ;
static constexpr int32_t kSystemNativeClientState =
@@ -1024,7 +1028,7 @@
int api1CameraId, int facing, int sensorOrientation, int clientPid, uid_t clientUid,
int servicePid, std::pair<int, IPCTransport> deviceVersionAndTransport,
apiLevel effectiveApiLevel, bool overrideForPerfClass, bool overrideToPortrait,
- /*out*/sp<BasicClient>* client) {
+ bool forceSlowJpegMode, /*out*/sp<BasicClient>* client) {
// For HIDL devices
if (deviceVersionAndTransport.second == IPCTransport::HIDL) {
// Create CameraClient based on device version reported by the HAL.
@@ -1057,9 +1061,10 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
packageName, featureId, cameraId, api1CameraId, facing, sensorOrientation,
- clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait);
- ALOGI("%s: Camera1 API (legacy), override to portrait %d", __FUNCTION__,
- overrideToPortrait);
+ clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
+ forceSlowJpegMode);
+ ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
+ __FUNCTION__, overrideToPortrait, forceSlowJpegMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -1157,7 +1162,8 @@
sp<ICameraClient>{nullptr}, id, cameraId,
internalPackageName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
- /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true, /*out*/ tmp)
+ /*targetSdkVersion*/ __ANDROID_API_FUTURE__, /*overrideToPortrait*/ true,
+ /*forceSlowJpegMode*/false, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
}
@@ -1682,6 +1688,7 @@
int clientPid,
int targetSdkVersion,
bool overrideToPortrait,
+ bool forceSlowJpegMode,
/*out*/
sp<ICamera>* device) {
@@ -1693,7 +1700,7 @@
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
clientPackageName,/*systemNativeClient*/ false, {}, clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
- overrideToPortrait, /*out*/client);
+ overrideToPortrait, forceSlowJpegMode, /*out*/client);
if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
@@ -1702,6 +1709,15 @@
}
*device = client;
+
+ const sp<IServiceManager> sm(defaultServiceManager());
+ const auto& mActivityManager = getActivityManager();
+ if (mActivityManager) {
+ mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
+ CameraThreadState::getCallingUid(),
+ CameraThreadState::getCallingPid());
+ }
+
return ret;
}
@@ -1823,7 +1839,8 @@
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1, clientPackageNameAdj, systemNativeClient,clientFeatureId,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, oomScoreOffset,
- targetSdkVersion, overrideToPortrait, /*out*/client);
+ targetSdkVersion, overrideToPortrait, /*forceSlowJpegMode*/false,
+ /*out*/client);
if(!ret.isOk()) {
logRejected(id, callingPid, String8(clientPackageNameAdj), ret.toString8());
@@ -1847,6 +1864,13 @@
ALOGE("%s: Error while creating the file: %s", __FUNCTION__, sFileName);
}
}
+ const sp<IServiceManager> sm(defaultServiceManager());
+ const auto& mActivityManager = getActivityManager();
+ if (mActivityManager) {
+ mActivityManager->logFgsApiBegin(LOG_FGS_CAMERA_API,
+ CameraThreadState::getCallingUid(),
+ CameraThreadState::getCallingPid());
+ }
return ret;
}
@@ -1885,7 +1909,8 @@
int api1CameraId, const String16& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int oomScoreOffset, int targetSdkVersion,
- bool overrideToPortrait, /*out*/sp<CLIENT>& device) {
+ bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
bool isNonSystemNdk = false;
@@ -2001,7 +2026,8 @@
clientFeatureId, cameraId, api1CameraId, facing, orientation,
clientPid, clientUid, getpid(),
deviceVersionAndTransport, effectiveApiLevel, overrideForPerfClass,
- overrideToPortrait, /*out*/&tmp)).isOk()) {
+ overrideToPortrait, forceSlowJpegMode,
+ /*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
@@ -3511,6 +3537,13 @@
// client shouldn't be able to call into us anymore
mClientPid = 0;
+ const auto& mActivityManager = getActivityManager();
+ if (mActivityManager) {
+ mActivityManager->logFgsApiEnd(LOG_FGS_CAMERA_API,
+ CameraThreadState::getCallingUid(),
+ CameraThreadState::getCallingPid());
+ }
+
return res;
}
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 59c5534..d8b14d7 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -29,6 +29,8 @@
#include <binder/ActivityManager.h>
#include <binder/AppOpsManager.h>
#include <binder/BinderService.h>
+#include <binder/IServiceManager.h>
+#include <binder/IActivityManager.h>
#include <binder/IAppOpsCallback.h>
#include <binder/IUidObserver.h>
#include <hardware/camera.h>
@@ -152,7 +154,7 @@
virtual binder::Status connect(const sp<hardware::ICameraClient>& cameraClient,
int32_t cameraId, const String16& clientPackageName,
int32_t clientUid, int clientPid, int targetSdkVersion,
- bool overrideToPortrait,
+ bool overrideToPortrait, bool forceSlowJpegMode,
/*out*/
sp<hardware::ICamera>* device) override;
@@ -596,6 +598,20 @@
private:
+ // TODO: b/263304156 update this to make use of a death callback for more
+ // robust/fault tolerant logging
+ static const sp<IActivityManager>& getActivityManager() {
+ static const char* kActivityService = "activity";
+ static const auto activityManager = []() -> sp<IActivityManager> {
+ const sp<IServiceManager> sm(defaultServiceManager());
+ if (sm != nullptr) {
+ return interface_cast<IActivityManager>(sm->checkService(String16(kActivityService)));
+ }
+ return nullptr;
+ }();
+ return activityManager;
+ }
+
/**
* Typesafe version of device status, containing both the HAL-layer and the service interface-
* layer values.
@@ -887,7 +903,8 @@
int api1CameraId, const String16& clientPackageNameMaybe, bool systemNativeClient,
const std::optional<String16>& clientFeatureId, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool shimUpdateOnly, int scoreOffset, int targetSdkVersion,
- bool overrideToPortrait, /*out*/sp<CLIENT>& device);
+ bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<CLIENT>& device);
// Lock guarding camera service state
Mutex mServiceLock;
@@ -1340,7 +1357,8 @@
const String8& cameraId, int api1CameraId, int facing, int sensorOrientation,
int clientPid, uid_t clientUid, int servicePid,
std::pair<int, IPCTransport> deviceVersionAndIPCTransport, apiLevel effectiveApiLevel,
- bool overrideForPerfClass, bool overrideToPortrait, /*out*/sp<BasicClient>* client);
+ bool overrideForPerfClass, bool overrideToPortrait, bool forceSlowJpegMode,
+ /*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
index b9f1224..402f8a2 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.cpp
@@ -19,6 +19,7 @@
#include "AidlCameraDeviceUser.h"
#include <aidl/AidlUtils.h>
#include <aidl/android/frameworks/cameraservice/device/CaptureMetadataInfo.h>
+#include <android-base/properties.h>
namespace android::frameworks::cameraservice::device::implementation {
@@ -35,7 +36,7 @@
using ::android::hardware::cameraservice::utils::conversion::aidl::cloneToAidl;
using ::android::hardware::cameraservice::utils::conversion::aidl::convertFromAidl;
using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
-using ::android::hardware::cameraservice::utils::conversion::aidl::convertToAidl;
+using ::android::hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
using ::ndk::ScopedAStatus;
namespace {
@@ -55,6 +56,7 @@
AidlCameraDeviceUser::AidlCameraDeviceUser(const sp<UICameraDeviceUser>& deviceRemote):
mDeviceRemote(deviceRemote) {
mInitSuccess = initDevice();
+ mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
}
bool AidlCameraDeviceUser::initDevice() {
@@ -171,6 +173,13 @@
ALOGE("%s: Failed to create default request: %s", __FUNCTION__, ret.toString8().string());
return fromUStatus(ret);
}
+
+ if (filterVndkKeys(mVndkVersion, metadata, /*isStatic*/false) != OK) {
+ ALOGE("%s: Unable to filter vndk metadata keys for version %d",
+ __FUNCTION__, mVndkVersion);
+ return fromSStatus(SStatus::UNKNOWN_ERROR);
+ }
+
const camera_metadata_t* rawMetadata = metadata.getAndLock();
cloneToAidl(rawMetadata, _aidl_return);
metadata.unlock(rawMetadata);
diff --git a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
index afff197..8014951 100644
--- a/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
+++ b/services/camera/libcameraservice/aidl/AidlCameraDeviceUser.h
@@ -109,6 +109,7 @@
std::shared_ptr<CaptureResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
bool mInitSuccess = false;
int32_t mRequestId = REQUEST_ID_NONE;
+ int mVndkVersion = -1;
};
} // namespace android::frameworks::cameraservice::device::implementation
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index b33303e..d71462f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -63,7 +63,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait):
+ bool overrideToPortrait,
+ bool forceSlowJpegMode):
Camera2ClientBase(cameraService, cameraClient, cameraServiceProxyWrapper, clientPackageName,
false/*systemNativeClient - since no ndk for api1*/, clientFeatureId,
cameraDeviceId, api1CameraId, cameraFacing, sensorOrientation, clientPid,
@@ -79,6 +80,9 @@
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
+ if (forceSlowJpegMode) {
+ l.mParameters.isSlowJpegModeForced = true;
+ }
}
status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index f035fea..6d7651f 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -114,7 +114,8 @@
uid_t clientUid,
int servicePid,
bool overrideForPerfClass,
- bool overrideToPortrait);
+ bool overrideToPortrait,
+ bool forceSlowJpegMode);
virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index 8b2af90..23570c2 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -990,9 +990,8 @@
Size maxJpegSize = getMaxSize(getAvailableJpegSizes());
int64_t minFrameDurationNs = getJpegStreamMinFrameDurationNs(maxJpegSize);
- slowJpegMode = false;
- if (minFrameDurationNs > kSlowJpegModeThreshold) {
- slowJpegMode = true;
+ slowJpegMode = isSlowJpegModeForced || minFrameDurationNs > kSlowJpegModeThreshold;
+ if (slowJpegMode) {
// Slow jpeg devices does not support video snapshot without
// slowing down preview.
// TODO: support video size video snapshot only?
@@ -2089,7 +2088,7 @@
paramsFlattened = newParams.flatten();
params = newParams;
- slowJpegMode = false;
+ slowJpegMode = isSlowJpegModeForced;
Size pictureSize = { pictureWidth, pictureHeight };
bool zslFrameRateSupported = false;
int64_t jpegMinFrameDurationNs = getJpegStreamMinFrameDurationNs(pictureSize);
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index fd18a5d..2bd3d43 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -183,6 +183,8 @@
bool isDeviceZslSupported;
// Whether the device supports geometric distortion correction
bool isDistortionCorrectionSupported;
+ // Whether slowJpegMode is forced regardless of jpeg stream FPS
+ bool isSlowJpegModeForced;
// Overall camera state
enum State {
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index 3e348c6..55b0f03 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -1072,7 +1072,7 @@
outputConfiguration.getSensorPixelModesUsed();
if (SessionConfigurationUtils::checkAndOverrideSensorPixelModesUsed(
sensorPixelModesUsed, format, width, height, getStaticInfo(cameraIdUsed),
- /*allowRounding*/ false, &overriddenSensorPixelModesUsed) != OK) {
+ &overriddenSensorPixelModesUsed) != OK) {
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT,
"sensor pixel modes used not valid for deferred stream");
}
diff --git a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
index d798632..29d7e6f 100644
--- a/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraOfflineSessionClient.cpp
@@ -106,7 +106,6 @@
void CameraOfflineSessionClient::clearStreamUseCaseOverrides() {
}
-
status_t CameraOfflineSessionClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 442b122..836b1bb 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -100,6 +100,9 @@
mNeedFixupMonochromeTags(false),
mOverrideForPerfClass(overrideForPerfClass),
mOverrideToPortrait(overrideToPortrait),
+ mRotateAndCropOverride(ANDROID_SCALER_ROTATE_AND_CROP_NONE),
+ mComposerOutput(false),
+ mAutoframingOverride(ANDROID_CONTROL_AUTOFRAMING_OFF),
mActivePhysicalId("")
{
ATRACE_CALL();
@@ -1365,12 +1368,54 @@
set_camera_metadata_vendor_id(meta, mVendorTagId);
filteredParams.unlock(meta);
if (availableSessionKeys.count > 0) {
+ bool rotateAndCropSessionKey = false;
+ bool autoframingSessionKey = false;
for (size_t i = 0; i < availableSessionKeys.count; i++) {
camera_metadata_ro_entry entry = params.find(
availableSessionKeys.data.i32[i]);
if (entry.count > 0) {
filteredParams.update(entry);
}
+ if (ANDROID_SCALER_ROTATE_AND_CROP == availableSessionKeys.data.i32[i]) {
+ rotateAndCropSessionKey = true;
+ }
+ if (ANDROID_CONTROL_AUTOFRAMING == availableSessionKeys.data.i32[i]) {
+ autoframingSessionKey = true;
+ }
+ }
+
+ if (rotateAndCropSessionKey || autoframingSessionKey) {
+ sp<CaptureRequest> request = new CaptureRequest();
+ PhysicalCameraSettings settingsList;
+ settingsList.metadata = filteredParams;
+ request->mSettingsList.push_back(settingsList);
+
+ if (rotateAndCropSessionKey) {
+ sp<CaptureRequest> request = new CaptureRequest();
+ PhysicalCameraSettings settingsList;
+ settingsList.metadata = filteredParams;
+ request->mSettingsList.push_back(settingsList);
+
+ auto rotateAndCropEntry = filteredParams.find(ANDROID_SCALER_ROTATE_AND_CROP);
+ if (rotateAndCropEntry.count > 0 &&
+ rotateAndCropEntry.data.u8[0] == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ request->mRotateAndCropAuto = true;
+ } else {
+ request->mRotateAndCropAuto = false;
+ }
+
+ overrideAutoRotateAndCrop(request, mOverrideToPortrait, mRotateAndCropOverride);
+ }
+
+ if (autoframingSessionKey) {
+ auto autoframingEntry = filteredParams.find(ANDROID_CONTROL_AUTOFRAMING);
+ if (autoframingEntry.count > 0 &&
+ autoframingEntry.data.u8[0] == ANDROID_CONTROL_AUTOFRAMING_AUTO) {
+ overrideAutoframing(request, mAutoframingOverride);
+ }
+ }
+
+ filteredParams = request->mSettingsList.begin()->metadata;
}
}
@@ -2399,7 +2444,7 @@
}
mGroupIdPhysicalCameraMap.clear();
- bool composerSurfacePresent = false;
+ mComposerOutput = false;
for (size_t i = 0; i < mOutputStreams.size(); i++) {
// Don't configure bidi streams twice, nor add them twice to the list
@@ -2445,7 +2490,7 @@
}
if (outputStream->usage & GraphicBuffer::USAGE_HW_COMPOSER) {
- composerSurfacePresent = true;
+ mComposerOutput = true;
}
}
@@ -2515,7 +2560,7 @@
}
}
- mRequestThread->setComposerSurface(composerSurfacePresent);
+ mRequestThread->setComposerSurface(mComposerOutput);
// Request thread needs to know to avoid using repeat-last-settings protocol
// across configure_streams() calls
@@ -3470,6 +3515,17 @@
latestRequestId = NAME_NOT_FOUND;
}
+ for (size_t i = 0; i < mNextRequests.size(); i++) {
+ auto& nextRequest = mNextRequests.editItemAt(i);
+ sp<CaptureRequest> captureRequest = nextRequest.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);
+ }
+
// 'mNextRequests' will at this point contain either a set of HFR batched requests
// or a single request from streaming or burst. In either case the first element
// should contain the latest camera settings that we need to check for any session
@@ -3619,19 +3675,15 @@
bool triggersMixedIn = (triggerCount > 0 || mPrevTriggers > 0);
mPrevTriggers = triggerCount;
- // 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
- bool rotateAndCropChanged = (mComposerOutput && !mOverrideToPortrait) ? false :
- overrideAutoRotateAndCrop(captureRequest);
- bool autoframingChanged = overrideAutoframing(captureRequest);
bool testPatternChanged = overrideTestPattern(captureRequest);
// If the request is the same as last, or we had triggers now or last time or
// changing overrides this time
bool newRequest =
- (mPrevRequest != captureRequest || triggersMixedIn || rotateAndCropChanged ||
- autoframingChanged || testPatternChanged) &&
+ (mPrevRequest != captureRequest || triggersMixedIn ||
+ captureRequest->mRotateAndCropChanged ||
+ captureRequest->mAutoframingChanged ||
+ testPatternChanged) &&
// Request settings are all the same within one batch, so only treat the first
// request in a batch as new
!(batchedRequest && i > 0);
@@ -4106,9 +4158,6 @@
camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropValue) {
ATRACE_CALL();
Mutex::Autolock l(mTriggerMutex);
- if (rotateAndCropValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
- return BAD_VALUE;
- }
mRotateAndCropOverride = rotateAndCropValue;
return OK;
}
@@ -4117,9 +4166,6 @@
camera_metadata_enum_android_control_autoframing_t autoframingValue) {
ATRACE_CALL();
Mutex::Autolock l(mTriggerMutex);
- if (autoframingValue == ANDROID_CONTROL_AUTOFRAMING_AUTO) {
- return BAD_VALUE;
- }
mAutoframingOverride = autoframingValue;
return OK;
}
@@ -4707,13 +4753,20 @@
return OK;
}
-bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(
- const sp<CaptureRequest> &request) {
+bool Camera3Device::RequestThread::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mTriggerMutex);
+ return Camera3Device::overrideAutoRotateAndCrop(request, this->mOverrideToPortrait,
+ this->mRotateAndCropOverride);
+}
+
+bool Camera3Device::overrideAutoRotateAndCrop(const sp<CaptureRequest> &request,
+ bool overrideToPortrait,
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride) {
ATRACE_CALL();
- if (mOverrideToPortrait) {
- Mutex::Autolock l(mTriggerMutex);
- uint8_t rotateAndCrop_u8 = mRotateAndCropOverride;
+ if (overrideToPortrait) {
+ uint8_t rotateAndCrop_u8 = rotateAndCropOverride;
CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
&rotateAndCrop_u8, 1);
@@ -4721,24 +4774,44 @@
}
if (request->mRotateAndCropAuto) {
- Mutex::Autolock l(mTriggerMutex);
CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
auto rotateAndCropEntry = metadata.find(ANDROID_SCALER_ROTATE_AND_CROP);
if (rotateAndCropEntry.count > 0) {
- if (rotateAndCropEntry.data.u8[0] == mRotateAndCropOverride) {
+ if (rotateAndCropEntry.data.u8[0] == rotateAndCropOverride) {
return false;
} else {
- rotateAndCropEntry.data.u8[0] = mRotateAndCropOverride;
+ rotateAndCropEntry.data.u8[0] = rotateAndCropOverride;
return true;
}
} else {
- uint8_t rotateAndCrop_u8 = mRotateAndCropOverride;
- metadata.update(ANDROID_SCALER_ROTATE_AND_CROP,
- &rotateAndCrop_u8, 1);
+ uint8_t rotateAndCrop_u8 = rotateAndCropOverride;
+ metadata.update(ANDROID_SCALER_ROTATE_AND_CROP, &rotateAndCrop_u8, 1);
return true;
}
}
+
+ return false;
+}
+
+bool Camera3Device::overrideAutoframing(const sp<CaptureRequest> &request /*out*/,
+ camera_metadata_enum_android_control_autoframing_t autoframingOverride) {
+ CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
+ auto autoframingEntry = metadata.find(ANDROID_CONTROL_AUTOFRAMING);
+ if (autoframingEntry.count > 0) {
+ if (autoframingEntry.data.u8[0] == autoframingOverride) {
+ return false;
+ } else {
+ autoframingEntry.data.u8[0] = autoframingOverride;
+ return true;
+ }
+ } else {
+ uint8_t autoframing_u8 = autoframingOverride;
+ metadata.update(ANDROID_CONTROL_AUTOFRAMING,
+ &autoframing_u8, 1);
+ return true;
+ }
+
return false;
}
@@ -4747,23 +4820,9 @@
if (request->mAutoframingAuto) {
Mutex::Autolock l(mTriggerMutex);
- CameraMetadata &metadata = request->mSettingsList.begin()->metadata;
-
- auto autoframingEntry = metadata.find(ANDROID_CONTROL_AUTOFRAMING);
- if (autoframingEntry.count > 0) {
- if (autoframingEntry.data.u8[0] == mAutoframingOverride) {
- return false;
- } else {
- autoframingEntry.data.u8[0] = mAutoframingOverride;
- return true;
- }
- } else {
- uint8_t autoframing_u8 = mAutoframingOverride;
- metadata.update(ANDROID_CONTROL_AUTOFRAMING,
- &autoframing_u8, 1);
- return true;
- }
+ return Camera3Device::overrideAutoframing(request, mAutoframingOverride);
}
+
return false;
}
@@ -5251,6 +5310,10 @@
if (mRequestThread == nullptr) {
return INVALID_OPERATION;
}
+ if (rotateAndCropValue == ANDROID_SCALER_ROTATE_AND_CROP_AUTO) {
+ return BAD_VALUE;
+ }
+ mRotateAndCropOverride = rotateAndCropValue;
return mRequestThread->setRotateAndCropAutoBehavior(rotateAndCropValue);
}
@@ -5262,6 +5325,10 @@
if (mRequestThread == nullptr) {
return INVALID_OPERATION;
}
+ if (autoframingValue == ANDROID_CONTROL_AUTOFRAMING_AUTO) {
+ return BAD_VALUE;
+ }
+ mAutoframingOverride = autoframingValue;
return mRequestThread->setAutoframingAutoBehaviour(autoframingValue);
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2b5d4db..e045b98 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -627,9 +627,14 @@
// overriding of ROTATE_AND_CROP value and adjustment of coordinates
// in several other controls in both the request and the result
bool mRotateAndCropAuto;
+ // Indicates that the ROTATE_AND_CROP value within 'mSettingsList' was modified
+ // irrespective of the original value.
+ bool mRotateAndCropChanged = false;
// Whether this request has AUTOFRAMING_AUTO set, so need to override the AUTOFRAMING value
// in the capture request.
bool mAutoframingAuto;
+ // Indicates that the auto framing value within 'mSettingsList' was modified
+ bool mAutoframingChanged = false;
// Whether this capture request has its zoom ratio set to 1.0x before
// the framework overrides it for camera HAL consumption.
@@ -818,6 +823,15 @@
*/
static nsecs_t getMonoToBoottimeOffset();
+ // Override rotate_and_crop control if needed
+ static bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request /*out*/,
+ bool overrideToPortrait,
+ camera_metadata_enum_android_scaler_rotate_and_crop_t rotateAndCropOverride);
+
+ // Override auto framing control if needed
+ static bool overrideAutoframing(const sp<CaptureRequest> &request /*out*/,
+ camera_metadata_enum_android_control_autoframing_t autoframingOverride);
+
struct RequestTrigger {
// Metadata tag number, e.g. android.control.aePrecaptureTrigger
uint32_t metadataTag;
@@ -975,7 +989,7 @@
status_t addFakeTriggerIds(const sp<CaptureRequest> &request);
// Override rotate_and_crop control if needed; returns true if the current value was changed
- bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request);
+ bool overrideAutoRotateAndCrop(const sp<CaptureRequest> &request /*out*/);
// Override autoframing control if needed; returns true if the current value was changed
bool overrideAutoframing(const sp<CaptureRequest> &request);
@@ -1419,6 +1433,11 @@
// Whether the camera framework overrides the device characteristics for
// app compatibility reasons.
bool mOverrideToPortrait;
+ camera_metadata_enum_android_scaler_rotate_and_crop_t mRotateAndCropOverride;
+ bool mComposerOutput;
+
+ // Auto framing override value
+ camera_metadata_enum_android_control_autoframing mAutoframingOverride;
// Current active physical id of the logical multi-camera, if any
std::string mActivePhysicalId;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 738c314..f742a6d 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -639,9 +639,24 @@
if (deviceInfo != states.physicalDeviceInfoMap.end()) {
auto orientation = deviceInfo->second.find(ANDROID_SENSOR_ORIENTATION);
if (orientation.count > 0) {
+ int32_t transform;
ret = CameraUtils::getRotationTransform(deviceInfo->second,
- OutputConfiguration::MIRROR_MODE_AUTO, &request.transform);
- if (ret != OK) {
+ OutputConfiguration::MIRROR_MODE_AUTO, &transform);
+ if (ret == OK) {
+ // It is possible for camera providers to return the capture
+ // results after the processed frames. In such scenario, we will
+ // not be able to set the output transformation before the frames
+ // return back to the consumer for the current capture request
+ // but we could still try and configure it for any future requests
+ // that are still in flight. The assumption is that the physical
+ // device id remains the same for the duration of the pending queue.
+ for (size_t i = 0; i < states.inflightMap.size(); i++) {
+ auto &r = states.inflightMap.editValueAt(i);
+ if (r.requestTimeNs >= request.requestTimeNs) {
+ r.transform = transform;
+ }
+ }
+ } else {
ALOGE("%s: Failed to calculate current stream transformation: %s "
"(%d)", __FUNCTION__, strerror(-ret), ret);
}
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
index 26e813a..0f7f127 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.cpp
@@ -19,10 +19,12 @@
#include <gui/Surface.h>
#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <aidl/AidlUtils.h>
#include <hidl/AidlCameraDeviceCallbacks.h>
#include <hidl/HidlCameraDeviceUser.h>
#include <hidl/Utils.h>
#include <android/hardware/camera/device/3.2/types.h>
+#include <android-base/properties.h>
namespace android {
namespace frameworks {
@@ -31,6 +33,7 @@
namespace V2_1 {
namespace implementation {
+using hardware::cameraservice::utils::conversion::aidl::filterVndkKeys;
using hardware::cameraservice::utils::conversion::convertToHidl;
using hardware::cameraservice::utils::conversion::convertFromHidl;
using hardware::cameraservice::utils::conversion::B2HStatus;
@@ -55,6 +58,7 @@
const sp<hardware::camera2::ICameraDeviceUser> &deviceRemote)
: mDeviceRemote(deviceRemote) {
mInitSuccess = initDevice();
+ mVndkVersion = base::GetIntProperty("ro.vndk.version", __ANDROID_API_FUTURE__);
}
bool HidlCameraDeviceUser::initDevice() {
@@ -235,8 +239,16 @@
android::CameraMetadata cameraMetadata;
binder::Status ret = mDeviceRemote->createDefaultRequest(convertFromHidl(templateId),
&cameraMetadata);
- HStatus hStatus = B2HStatus(ret);
+
HCameraMetadata hidlMetadata;
+ if (filterVndkKeys(mVndkVersion, cameraMetadata, /*isStatic*/false) != OK) {
+ ALOGE("%s: Unable to filter vndk metadata keys for version %d",
+ __FUNCTION__, mVndkVersion);
+ _hidl_cb(HStatus::UNKNOWN_ERROR, hidlMetadata);
+ return Void();
+ }
+
+ HStatus hStatus = B2HStatus(ret);
const camera_metadata_t *rawMetadata = cameraMetadata.getAndLock();
convertToHidl(rawMetadata, &hidlMetadata);
_hidl_cb(hStatus, hidlMetadata);
diff --git a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
index 0e2ab3d..a653ca2 100644
--- a/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
+++ b/services/camera/libcameraservice/hidl/HidlCameraDeviceUser.h
@@ -127,6 +127,7 @@
std::shared_ptr<CaptureResultMetadataQueue> mCaptureResultMetadataQueue = nullptr;
bool mInitSuccess = false;
int32_t mRequestId = REQUEST_ID_NONE;
+ int mVndkVersion = -1;
};
} // implementation
diff --git a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
index 072fcfb..b397573 100644
--- a/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
+++ b/services/camera/libcameraservice/libcameraservice_fuzzer/camera_service_fuzzer.cpp
@@ -346,7 +346,8 @@
android::CameraService::USE_CALLING_UID,
android::CameraService::USE_CALLING_PID,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__,
- /*overrideToPortrait*/true, &cameraDevice);
+ /*overrideToPortrait*/true, /*forceSlowJpegMode*/false,
+ &cameraDevice);
if (!rc.isOk()) {
// camera not connected
return;
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
index 4e05b78..c1a4fa0 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.cpp
@@ -380,6 +380,23 @@
}
}
+bool dataSpaceFromColorSpace(android_dataspace *dataSpace, int32_t colorSpace) {
+ switch (colorSpace) {
+ case ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_SRGB:
+ *dataSpace = HAL_DATASPACE_V0_SRGB;
+ return true;
+ case ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_DISPLAY_P3:
+ *dataSpace = HAL_DATASPACE_DISPLAY_P3;
+ return true;
+ case ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_BT2020_HLG:
+ *(reinterpret_cast<int32_t*>(dataSpace)) = HAL_DATASPACE_BT2020_HLG;
+ return true;
+ default:
+ ALOGE("%s: Unsupported color space %d", __FUNCTION__, colorSpace);
+ return false;
+ }
+}
+
bool isStreamUseCaseSupported(int64_t streamUseCase,
const CameraMetadata &deviceInfo) {
camera_metadata_ro_entry_t availableStreamUseCases =
@@ -472,6 +489,16 @@
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
+ if (colorSpace != ANDROID_REQUEST_AVAILABLE_COLOR_SPACE_PROFILES_MAP_UNSPECIFIED &&
+ format != HAL_PIXEL_FORMAT_BLOB) {
+ if (!dataSpaceFromColorSpace(&dataSpace, colorSpace)) {
+ String8 msg = String8::format("Camera %s: color space %d not supported, failed to "
+ "convert to data space", logicalCameraId.string(), colorSpace);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+ }
+
// FIXME: remove this override since the default format should be
// IMPLEMENTATION_DEFINED. b/9487482 & b/35317944
if ((format >= HAL_PIXEL_FORMAT_RGBA_8888 && format <= HAL_PIXEL_FORMAT_BGRA_8888) &&
@@ -483,7 +510,7 @@
}
std::unordered_set<int32_t> overriddenSensorPixelModes;
if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed, format, width, height,
- physicalCameraMetadata, flexibleConsumer, &overriddenSensorPixelModes) != OK) {
+ physicalCameraMetadata, &overriddenSensorPixelModes) != OK) {
String8 msg = String8::format("Camera %s: sensor pixel modes for stream with "
"format %#x are not valid",logicalCameraId.string(), format);
ALOGE("%s: %s", __FUNCTION__, msg.string());
@@ -757,7 +784,7 @@
streamInfo.dynamicRangeProfile = it.getDynamicRangeProfile();
if (checkAndOverrideSensorPixelModesUsed(sensorPixelModesUsed,
streamInfo.format, streamInfo.width,
- streamInfo.height, metadataChosen, false /*flexibleConsumer*/,
+ streamInfo.height, metadataChosen,
&streamInfo.sensorPixelModesUsed) != OK) {
ALOGE("%s: Deferred surface sensor pixel modes not valid",
__FUNCTION__);
@@ -935,7 +962,7 @@
status_t checkAndOverrideSensorPixelModesUsed(
const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
- const CameraMetadata &staticInfo, bool flexibleConsumer,
+ const CameraMetadata &staticInfo,
std::unordered_set<int32_t> *overriddenSensorPixelModesUsed) {
const std::unordered_set<int32_t> &sensorPixelModesUsedSet =
@@ -944,6 +971,8 @@
if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
sensorPixelModesUsedSet.end()) {
// invalid value for non ultra high res sensors
+ ALOGE("%s ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION used on a device which doesn't "
+ "support ultra high resolution capture", __FUNCTION__);
return BAD_VALUE;
}
overriddenSensorPixelModesUsed->clear();
@@ -974,27 +1003,30 @@
overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
return OK;
}
- // We don't allow flexible consumer for max resolution mode.
if (isInMaximumResolutionStreamConfigurationMap) {
- overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
- return OK;
- }
- if (isInDefaultStreamConfigurationMap || (flexibleConsumer && width < ROUNDING_WIDTH_CAP)) {
+ overriddenSensorPixelModesUsed->insert(
+ ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION);
+ } else {
overriddenSensorPixelModesUsed->insert(ANDROID_SENSOR_PIXEL_MODE_DEFAULT);
- return OK;
}
- return BAD_VALUE;
+ return OK;
}
// Case2: The app has set sensorPixelModesUsed, we need to verify that they
// are valid / err out.
if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_DEFAULT) !=
sensorPixelModesUsedSet.end() && !isInDefaultStreamConfigurationMap) {
+ ALOGE("%s: ANDROID_SENSOR_PIXEL_MODE_DEFAULT set by client, but stream f: %d size %d x %d"
+ " isn't present in default stream configuration map", __FUNCTION__, format, width,
+ height);
return BAD_VALUE;
}
if (sensorPixelModesUsedSet.find(ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION) !=
sensorPixelModesUsedSet.end() && !isInMaximumResolutionStreamConfigurationMap) {
+ ALOGE("%s: ANDROID_SENSOR_PIXEL_MODE_MAXIMUM_RESOLUTION set by client, but stream f: "
+ "%d size %d x %d isn't present in default stream configuration map", __FUNCTION__,
+ format, width, height);
return BAD_VALUE;
}
*overriddenSensorPixelModesUsed = sensorPixelModesUsedSet;
diff --git a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
index 71b6c1d..d27144e 100644
--- a/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
+++ b/services/camera/libcameraservice/utils/SessionConfigurationUtils.h
@@ -115,6 +115,8 @@
bool isColorSpaceSupported(int32_t colorSpace, int32_t format, android_dataspace dataSpace,
int64_t dynamicRangeProfile, const CameraMetadata& staticMeta);
+bool dataSpaceFromColorSpace(android_dataspace *dataSpace, int32_t colorSpace);
+
bool isStreamUseCaseSupported(int64_t streamUseCase, const CameraMetadata &deviceInfo);
void mapStreamInfo(const OutputStreamInfo &streamInfo,
@@ -145,7 +147,7 @@
status_t checkAndOverrideSensorPixelModesUsed(
const std::vector<int32_t> &sensorPixelModesUsed, int format, int width, int height,
- const CameraMetadata &staticInfo, bool flexibleConsumer,
+ const CameraMetadata &staticInfo,
std::unordered_set<int32_t> *overriddenSensorPixelModesUsed);
bool targetPerfClassPrimaryCamera(
diff --git a/services/medialog/fuzzer/Android.bp b/services/medialog/fuzzer/Android.bp
index 9ff0ce4..c96c37b 100644
--- a/services/medialog/fuzzer/Android.bp
+++ b/services/medialog/fuzzer/Android.bp
@@ -38,5 +38,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmedialogservice library",
+ vector: "local_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "future_version",
},
}
diff --git a/services/mediametrics/fuzzer/Android.bp b/services/mediametrics/fuzzer/Android.bp
index 8b33f10..20a6378 100644
--- a/services/mediametrics/fuzzer/Android.bp
+++ b/services/mediametrics/fuzzer/Android.bp
@@ -68,5 +68,13 @@
"android-media-fuzzing-reports@google.com",
],
componentid: 155276,
+ hotlists: [
+ "4593311",
+ ],
+ description: "The fuzzer targets the APIs of libmediametricsservice",
+ vector: "local_no_privileges_required",
+ service_privilege: "constrained",
+ users: "multi_user",
+ fuzzed_code_usage: "shipped",
},
}
diff --git a/services/mediametrics/statsd_drm.cpp b/services/mediametrics/statsd_drm.cpp
index 9f08eca..e5f7190 100644
--- a/services/mediametrics/statsd_drm.cpp
+++ b/services/mediametrics/statsd_drm.cpp
@@ -281,9 +281,9 @@
const int32_t uid = IPCThreadState::self()->getCallingUid();
int32_t frontend = 0;
if (!item->getInt32("frontend", &frontend)) return false;
- int32_t requested_security_level = -1;
+ int32_t requested_security_level = 0;
if (!item->getInt32("requested_security_level", &requested_security_level)) return false;
- int32_t opened_security_level = -1;
+ int32_t opened_security_level = 0;
if (!item->getInt32("opened_security_level", &opened_security_level)) return false;
// Optional to be included
@@ -325,12 +325,10 @@
if (!item->getInt32("frontend", &frontend)) return false;
std::string object_nonce = "";
if (!item->getString("object_nonce", &object_nonce)) return false;
- int32_t security_level = -1;
- if (!item->getInt32("security_level", &security_level)) return false;
std::string api_str = "";
if (!item->getString("api", &api_str)) return false;
const int32_t api = MediaDrmStatsdHelper::findDrmApi(api_str);
- int32_t error_code = -1;
+ int32_t error_code = 0;
if (!item->getInt32("error_code", &error_code)) return false;
// Optional to be included
@@ -338,12 +336,14 @@
item->getString("version", &version);
std::string session_nonce = "";
item->getString("session_nonce", &session_nonce);
+ int32_t security_level = 0;
+ item->getInt32("security_level", &security_level);
int32_t cdm_err = 0;
item->getInt32("cdm_err", &cdm_err);
int32_t oem_err = 0;
item->getInt32("oem_err", &oem_err);
- int32_t error_context = -1;
+ int32_t error_context = 0;
item->getInt32("error_context", &error_context);
const int result = stats_write(stats::media_metrics::MEDIA_DRM_ERRORED, scheme, uuid_lsb,
diff --git a/services/mediaresourcemanager/OWNERS b/services/mediaresourcemanager/OWNERS
index 82abf8f..4fc3728 100644
--- a/services/mediaresourcemanager/OWNERS
+++ b/services/mediaresourcemanager/OWNERS
@@ -1 +1,3 @@
-dwkang@google.com
+girishshetty@google.com
+lajos@google.com
+wonsik@google.com
diff --git a/services/mediaresourcemanager/ResourceManagerMetrics.cpp b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
index b60e734..8d591df 100644
--- a/services/mediaresourcemanager/ResourceManagerMetrics.cpp
+++ b/services/mediaresourcemanager/ResourceManagerMetrics.cpp
@@ -146,18 +146,21 @@
void ResourceManagerMetrics::notifyClientReleased(const ClientInfoParcel& clientInfo) {
bool stopCalled = true;
- ClientConfigMap::iterator found;
+ ClientConfigParcel clientConfig;
{
std::scoped_lock lock(mLock);
- found = mClientConfigMap.find(clientInfo.id);
+ ClientConfigMap::iterator found = mClientConfigMap.find(clientInfo.id);
if (found != mClientConfigMap.end()) {
// Release is called without Stop!
stopCalled = false;
+ clientConfig = found->second;
+ // Update the timestamp for stopping the codec.
+ clientConfig.timeStamp = systemTime(SYSTEM_TIME_MONOTONIC) / 1000LL;
}
}
if (!stopCalled) {
// call Stop to update the metrics.
- notifyClientStopped(found->second);
+ notifyClientStopped(clientConfig);
}
{
std::scoped_lock lock(mLock);