Merge "audio policy: fix capture policy for assistant when running as top" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index e9b757b..34ff367 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -30,8 +30,10 @@
# Only turn on clang-format check for the following subfolders.
clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+ camera/
media/libaudioclient/tests/
media/libaudiohal/tests/
media/libmediatranscoding/
services/camera/virtualcamera/
services/mediatranscoding/
+ services/camera/libcameraservice/
diff --git a/camera/Android.bp b/camera/Android.bp
index d91fcb2..25b5e2c 100644
--- a/camera/Android.bp
+++ b/camera/Android.bp
@@ -54,7 +54,13 @@
cc_aconfig_library {
name: "camera_platform_flags_c_lib",
aconfig_declarations: "camera_platform_flags",
+}
+
+cc_aconfig_library {
+ name: "camera_platform_flags_c_lib_for_test",
+ aconfig_declarations: "camera_platform_flags",
host_supported: true,
+ mode: "test",
}
java_aconfig_library {
diff --git a/camera/camera2/SessionConfiguration.cpp b/camera/camera2/SessionConfiguration.cpp
index 2f1f22d..065d283 100644
--- a/camera/camera2/SessionConfiguration.cpp
+++ b/camera/camera2/SessionConfiguration.cpp
@@ -72,17 +72,15 @@
bool hasSessionParameters = false;
CameraMetadata settings;
- if (flags::feature_combination_query()) {
- if ((err = parcel->readBool(&hasSessionParameters)) != OK) {
- ALOGE("%s: Failed to read hasSessionParameters flag from parcel", __FUNCTION__);
- return err;
- }
+ if ((err = parcel->readBool(&hasSessionParameters)) != OK) {
+ ALOGE("%s: Failed to read hasSessionParameters flag from parcel", __FUNCTION__);
+ return err;
+ }
- if (hasSessionParameters) {
- if ((err = settings.readFromParcel(parcel)) != OK) {
- ALOGE("%s: Failed to read metadata flag from parcel", __FUNCTION__);
- return err;
- }
+ if (hasSessionParameters) {
+ if ((err = settings.readFromParcel(parcel)) != OK) {
+ ALOGE("%s: Failed to read metadata flag from parcel", __FUNCTION__);
+ return err;
}
}
@@ -94,10 +92,8 @@
for (auto& stream : outputStreams) {
mOutputStreams.push_back(stream);
}
- if (flags::feature_combination_query()) {
- mHasSessionParameters = hasSessionParameters;
- mSessionParameters = std::move(settings);
- }
+ mHasSessionParameters = hasSessionParameters;
+ mSessionParameters = std::move(settings);
return err;
}
@@ -125,14 +121,12 @@
err = parcel->writeParcelableVector(mOutputStreams);
if (err != OK) return err;
- if (flags::feature_combination_query()) {
- err = parcel->writeBool(mHasSessionParameters);
- if (err != OK) return err;
+ err = parcel->writeBool(mHasSessionParameters);
+ if (err != OK) return err;
- if (mHasSessionParameters) {
- err = mSessionParameters.writeToParcel(parcel);
- if (err != OK) return err;
- }
+ if (mHasSessionParameters) {
+ err = mSessionParameters.writeToParcel(parcel);
+ if (err != OK) return err;
}
return OK;
diff --git a/camera/camera_platform.aconfig b/camera/camera_platform.aconfig
index e916985..db33dd7 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -27,20 +27,6 @@
flag {
namespace: "camera_platform"
- name: "watch_foreground_changes"
- description: "Request AppOps to notify changes in the foreground status of the client"
- bug: "290086710"
-}
-
-flag {
- namespace: "camera_platform"
- name: "log_ultrawide_usage"
- description: "Enable measuring how much usage there is for ultrawide-angle cameras"
- bug: "300515796"
-}
-
-flag {
- namespace: "camera_platform"
name: "camera_manual_flash_strength_control"
is_exported: true
description: "Flash brightness level control in manual flash mode"
@@ -49,27 +35,6 @@
flag {
namespace: "camera_platform"
- name: "lazy_aidl_wait_for_service"
- description: "Use waitForService instead of getService with lazy AIDL HALs"
- bug: "285546208"
-}
-
-flag {
- namespace: "camera_platform"
- name: "log_zoom_override_usage"
- description: "Enable measuring how much usage there is for zoom settings overrde"
- bug: "307409002"
-}
-
-flag {
- namespace: "camera_platform"
- name: "session_hal_buf_manager"
- description: "Enable or disable HAL buffer manager as requested by the camera HAL"
- bug: "311263114"
-}
-
-flag {
- namespace: "camera_platform"
name: "inject_session_params"
description: "Enable session parameter injection via reconfiguration"
bug: "308984721"
@@ -92,13 +57,6 @@
flag {
namespace: "camera_platform"
- name: "use_ro_board_api_level_for_vndk_version"
- description: "Enable using ro.board.api_level instead of ro.vndk.version to get VNDK version"
- bug: "312315580"
-}
-
-flag {
- namespace: "camera_platform"
name: "camera_extensions_characteristics_get"
is_exported: true
description: "Enable get extension specific camera characteristics API"
@@ -107,13 +65,6 @@
flag {
namespace: "camera_platform"
- name: "delay_lazy_hal_instantiation"
- description: "Only trigger lazy HAL instantiation when the HAL is needed for an operation."
- bug: "319735068"
-}
-
-flag {
- namespace: "camera_platform"
name: "return_buffers_outside_locks"
description: "Enable returning graphics buffers to buffer queues without holding the in-flight mutex"
bug: "315526878"
@@ -137,16 +88,6 @@
flag {
namespace: "camera_platform"
- name: "surface_ipc"
- description: "Optimize Surface binder IPC"
- bug: "323292530"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "extension_10_bit"
is_exported: true
description: "Enables 10-bit support in the camera extensions."
@@ -155,57 +96,9 @@
flag {
namespace: "camera_platform"
- name: "single_thread_executor"
- description: "Ensure device logic is run within one thread."
- bug: "305857746"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
- name: "surface_leak_fix"
- description: "Address Surface release leaks in CaptureRequest"
- bug: "324071855"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
- name: "concert_mode_api"
- description: "Covers the eyes free videography public facing API"
- bug: "297083874"
-}
-
-
-flag {
- namespace: "camera_platform"
- name: "cache_permission_services"
- description: "Cache IPermissionController and IPermissionChecker in CameraService to reduce query latency."
- bug: "326139956"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
- name: "check_session_support_before_session_char"
- description: "Validate that a SessionConfiguration is supported before fetching SessionCharacteristics."
- bug: "327008530"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
- name: "calculate_perf_override_during_session_support"
- description: "Dynamically calulate whether perf class override should be set in isSessionConfigurationWithParametersSupported."
- bug: "332975108"
+ name: "single_thread_executor_naming"
+ description: "Set the device executor thread name."
+ bug: "359709863"
metadata {
purpose: PURPOSE_BUGFIX
}
@@ -220,26 +113,6 @@
flag {
namespace: "camera_platform"
- name: "realtime_priority_bump"
- description: "Bump the scheduling priority of performance critical code paths"
- bug: "336628522"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
- name: "use_system_api_for_vndk_version"
- description: "ro.board.api_level isn't reliable. Use system api to replace ro.vndk.version"
- bug: "312315580"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "multi_res_raw_reprocessing"
description: "Allow multi-resolution raw reprocessing without reprocessing capability"
bug: "336922859"
@@ -276,4 +149,25 @@
metadata {
purpose: PURPOSE_BUGFIX
}
-}
\ No newline at end of file
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "enable_hal_abort_from_cameraservicewatchdog"
+ description: "Enable CameraServiceWatchdog to abort camera HAL to generate HAL tombstones"
+ bug: "349652177"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "enable_stream_reconfiguration_for_unchanged_streams"
+ description: "Enable stream reconfiguration for unchanged streams"
+ bug: "341740105"
+}
+
+flag {
+ namespace: "camera_platform"
+ name: "use_context_attribution_source"
+ description: "Use the context-provided AttributionSource when checking for client permissions"
+ bug: "190657833"
+}
diff --git a/camera/cameraserver/Android.bp b/camera/cameraserver/Android.bp
index 6862cb1..d0df90b 100644
--- a/camera/cameraserver/Android.bp
+++ b/camera/cameraserver/Android.bp
@@ -22,6 +22,11 @@
default_applicable_licenses: ["frameworks_av_camera_license"],
}
+vintf_fragment {
+ name: "manifest_android.frameworks.cameraservice.service.xml",
+ src: "manifest_android.frameworks.cameraservice.service.xml",
+}
+
cc_binary {
name: "cameraserver",
@@ -61,7 +66,7 @@
init_rc: ["cameraserver.rc"],
- vintf_fragments: [
+ vintf_fragment_modules: [
"manifest_android.frameworks.cameraservice.service.xml",
],
}
diff --git a/camera/ndk/impl/ACameraManager.cpp b/camera/ndk/impl/ACameraManager.cpp
index 6d29ef5..53c4489 100644
--- a/camera/ndk/impl/ACameraManager.cpp
+++ b/camera/ndk/impl/ACameraManager.cpp
@@ -170,97 +170,78 @@
}
sp<hardware::ICameraService> CameraManagerGlobal::getCameraServiceLocked() {
- if (mCameraService.get() == nullptr) {
- if (CameraUtils::isCameraServiceDisabled()) {
- return mCameraService;
- }
+ if (mCameraService.get() != nullptr) {
+ return mCameraService;
+ }
+ if (CameraUtils::isCameraServiceDisabled()) {
+ return mCameraService;
+ }
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder;
- binder = sm->checkService(String16(kCameraServiceName));
- if (binder == nullptr) {
- ALOGE("%s: Could not get CameraService instance.", __FUNCTION__);
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder;
+ binder = sm->checkService(String16(kCameraServiceName));
+ if (binder == nullptr) {
+ ALOGE("%s: Could not get CameraService instance.", __FUNCTION__);
+ return nullptr;
+ }
+ sp<hardware::ICameraService> cameraService = interface_cast<hardware::ICameraService>(binder);
+ if (mDeathNotifier == nullptr) {
+ mDeathNotifier = new DeathNotifier(this);
+ binder->linkToDeath(mDeathNotifier);
+ }
+
+ // Setup looper thread to perform availability callbacks
+ if (mCbLooper == nullptr) {
+ mCbLooper = new ALooper;
+ mCbLooper->setName("C2N-mgr-looper");
+ status_t err = mCbLooper->start(
+ /*runOnCallingThread*/false,
+ /*canCallJava*/ true,
+ PRIORITY_DEFAULT);
+ if (err != OK) {
+ ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ mCbLooper.clear();
return nullptr;
}
- if (mDeathNotifier == nullptr) {
- mDeathNotifier = new DeathNotifier(this);
+ if (mHandler == nullptr) {
+ mHandler = new CallbackHandler(this);
}
- binder->linkToDeath(mDeathNotifier);
- mCameraService = interface_cast<hardware::ICameraService>(binder);
+ mCbLooper->registerHandler(mHandler);
+ }
- // Setup looper thread to perfrom availiability callbacks
- if (mCbLooper == nullptr) {
- mCbLooper = new ALooper;
- mCbLooper->setName("C2N-mgr-looper");
- status_t err = mCbLooper->start(
- /*runOnCallingThread*/false,
- /*canCallJava*/ true,
- PRIORITY_DEFAULT);
- if (err != OK) {
- ALOGE("%s: Unable to start camera service listener looper: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- mCbLooper.clear();
- return nullptr;
- }
- if (mHandler == nullptr) {
- mHandler = new CallbackHandler(this);
- }
- mCbLooper->registerHandler(mHandler);
+ // register ICameraServiceListener
+ std::vector<hardware::CameraStatus> cameraStatuses{};
+ if (mCameraServiceListener == nullptr) {
+ mCameraServiceListener = new CameraServiceListener(this);
+ cameraService->addListener(mCameraServiceListener, &cameraStatuses);
+ }
+
+ for (auto& c : cameraStatuses) {
+ onStatusChangedLocked(c.status, c.deviceId, c.cameraId);
+
+ for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
+ onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
+ c.deviceId, c.cameraId, unavailablePhysicalId);
}
+ }
+ // setup vendor tags
+ if (!setupVendorTags(cameraService)) {
+ ALOGE("%s: Vendor tag descriptor cache couldn't be set up", __FUNCTION__);
+ return nullptr;
+ }
- // register ICameraServiceListener
- if (mCameraServiceListener == nullptr) {
- mCameraServiceListener = new CameraServiceListener(this);
- }
- std::vector<hardware::CameraStatus> cameraStatuses{};
- mCameraService->addListener(mCameraServiceListener, &cameraStatuses);
- for (auto& c : cameraStatuses) {
- onStatusChangedLocked(c.status, c.deviceId, c.cameraId);
+ mCameraService = cameraService;
+ ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
+ return mCameraService;
+}
- for (auto& unavailablePhysicalId : c.unavailablePhysicalIds) {
- onStatusChangedLocked(hardware::ICameraServiceListener::STATUS_NOT_PRESENT,
- c.deviceId, c.cameraId, unavailablePhysicalId);
- }
- }
-
- // setup vendor tags
- sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
- binder::Status ret = mCameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
-
- if (ret.isOk()) {
- if (0 < desc->getTagCount()) {
- status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
- if (err != OK) {
- ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
- __FUNCTION__, strerror(-err), err);
- }
- } else {
- sp<VendorTagDescriptorCache> cache =
- new VendorTagDescriptorCache();
- binder::Status res =
- mCameraService->getCameraVendorTagCache(
- /*out*/cache.get());
- if (res.serviceSpecificErrorCode() ==
- hardware::ICameraService::ERROR_DISCONNECTED) {
- // No camera module available, not an error on devices with no cameras
- VendorTagDescriptorCache::clearGlobalVendorTagCache();
- } else if (res.isOk()) {
- status_t err =
- VendorTagDescriptorCache::setAsGlobalVendorTagCache(
- cache);
- if (err != OK) {
- ALOGE("%s: Failed to set vendor tag cache,"
- "received error %s (%d)", __FUNCTION__,
- strerror(-err), err);
- }
- } else {
- VendorTagDescriptorCache::clearGlobalVendorTagCache();
- ALOGE("%s: Failed to setup vendor tag cache: %s",
- __FUNCTION__, res.toString8().c_str());
- }
- }
- } else if (ret.serviceSpecificErrorCode() ==
- hardware::ICameraService::ERROR_DEPRECATED_HAL) {
+bool CameraManagerGlobal::setupVendorTags(sp<hardware::ICameraService> &cameraService) {
+ sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+ binder::Status ret = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
+ if (!ret.isOk()) {
+ if (ret.serviceSpecificErrorCode() ==
+ hardware::ICameraService::ERROR_DEPRECATED_HAL) {
ALOGW("%s: Camera HAL too old; does not support vendor tags",
__FUNCTION__);
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
@@ -268,9 +249,45 @@
ALOGE("%s: Failed to get vendor tag descriptors: %s",
__FUNCTION__, ret.toString8().c_str());
}
+ return false;
}
- ALOGE_IF(mCameraService == nullptr, "no CameraService!?");
- return mCameraService;
+
+ if (0 < desc->getTagCount()) {
+ status_t err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
+ if (err != OK) {
+ ALOGE("%s: Failed to set vendor tag descriptors, received error %s (%d)",
+ __FUNCTION__, strerror(-err), err);
+ return false;
+ }
+ } else {
+ sp<VendorTagDescriptorCache> cache =
+ new VendorTagDescriptorCache();
+ binder::Status res =
+ cameraService->getCameraVendorTagCache(
+ /*out*/cache.get());
+ if (res.serviceSpecificErrorCode() ==
+ hardware::ICameraService::ERROR_DISCONNECTED) {
+ // No camera module available, not an error on devices with no cameras
+ VendorTagDescriptorCache::clearGlobalVendorTagCache();
+ } else if (res.isOk()) {
+ status_t err =
+ VendorTagDescriptorCache::setAsGlobalVendorTagCache(
+ cache);
+ if (err != OK) {
+ ALOGE("%s: Failed to set vendor tag cache,"
+ "received error %s (%d)", __FUNCTION__,
+ strerror(-err), err);
+ return false;
+ }
+ } else {
+ VendorTagDescriptorCache::clearGlobalVendorTagCache();
+ ALOGE("%s: Failed to setup vendor tag cache: %s",
+ __FUNCTION__, res.toString8().c_str());
+ return false;
+ }
+ }
+
+ return true;
}
void CameraManagerGlobal::DeathNotifier::binderDied(const wp<IBinder>&)
@@ -290,6 +307,8 @@
key.cameraId);
}
cm->mCameraService.clear();
+ cm->mCameraServiceListener.clear();
+ cm->mDeathNotifier.clear();
// TODO: consider adding re-connect call here?
}
}
@@ -398,6 +417,9 @@
bool CameraManagerGlobal::supportsCamera2ApiLocked(const std::string &cameraId) {
bool camera2Support = false;
auto cs = getCameraServiceLocked();
+ if (cs == nullptr) {
+ return false;
+ }
binder::Status serviceRet =
cs->supportsCameraApi(cameraId,
hardware::ICameraService::API_VERSION_2, &camera2Support);
diff --git a/camera/ndk/impl/ACameraManager.h b/camera/ndk/impl/ACameraManager.h
index f4124ef..cb7a4ff 100644
--- a/camera/ndk/impl/ACameraManager.h
+++ b/camera/ndk/impl/ACameraManager.h
@@ -105,6 +105,8 @@
template <class T>
void registerAvailCallback(const DeviceContext& deviceContext, const T* callback);
+ bool setupVendorTags(sp<hardware::ICameraService> &cameraService);
+
class DeathNotifier : public IBinder::DeathRecipient {
public:
explicit DeathNotifier(CameraManagerGlobal* cm) : mCameraManager(cm) {}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 7d234bb..7fb2d05 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -91,7 +91,6 @@
ACAMERA_AUTOMOTIVE_LENS,
ACAMERA_EXTENSION,
ACAMERA_JPEGR,
- ACAMERA_EFV,
ACAMERA_SECTION_COUNT,
ACAMERA_VENDOR = 0x8000
@@ -139,7 +138,6 @@
ACAMERA_AUTOMOTIVE_LENS_START = ACAMERA_AUTOMOTIVE_LENS << 16,
ACAMERA_EXTENSION_START = ACAMERA_EXTENSION << 16,
ACAMERA_JPEGR_START = ACAMERA_JPEGR << 16,
- ACAMERA_EFV_START = ACAMERA_EFV << 16,
ACAMERA_VENDOR_START = ACAMERA_VENDOR << 16
} acamera_metadata_section_start_t;
@@ -482,10 +480,21 @@
* camera device auto-exposure routine for the overridden
* fields for a given capture will be available in its
* CaptureResult.</p>
+ * <p>When ACAMERA_CONTROL_AE_MODE is AE_MODE_ON and if the device
+ * supports manual flash strength control, i.e.,
+ * if ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1, then
+ * the auto-exposure (AE) precapture metering sequence should be
+ * triggered to avoid the image being incorrectly exposed at
+ * different ACAMERA_FLASH_STRENGTH_LEVEL.</p>
*
+ * @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_CONTROL_MODE
* @see ACAMERA_FLASH_INFO_AVAILABLE
* @see ACAMERA_FLASH_MODE
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+ * @see ACAMERA_FLASH_STRENGTH_LEVEL
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
* @see ACAMERA_SENSOR_EXPOSURE_TIME
* @see ACAMERA_SENSOR_FRAME_DURATION
* @see ACAMERA_SENSOR_SENSITIVITY
@@ -646,9 +655,14 @@
* be made, and for firing pre-capture flash pulses to estimate
* scene brightness and required final capture flash power, when
* the flash is enabled.</p>
- * <p>Normally, this entry should be set to START for only a
- * single request, and the application should wait until the
- * sequence completes before starting a new one.</p>
+ * <p>Flash is enabled during precapture sequence when:</p>
+ * <ul>
+ * <li>AE mode is ON_ALWAYS_FLASH</li>
+ * <li>AE mode is ON_AUTO_FLASH and the scene is deemed too dark without flash, or</li>
+ * <li>AE mode is ON and flash mode is TORCH or SINGLE</li>
+ * </ul>
+ * <p>Normally, this entry should be set to START for only single request, and the
+ * application should wait until the sequence completes before starting a new one.</p>
* <p>When a precapture metering sequence is finished, the camera device
* may lock the auto-exposure routine internally to be able to accurately expose the
* subsequent still capture image (<code>ACAMERA_CONTROL_CAPTURE_INTENT == STILL_CAPTURE</code>).
@@ -2289,8 +2303,6 @@
* boost when the light level threshold is exceeded.</p>
* <p>This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
* indicate when it is not being applied by returning 'INACTIVE'.</p>
- * <p>This key will be absent from the CaptureResult if AE mode is not set to
- * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.</p>
* <p>The default value will always be 'INACTIVE'.</p>
*/
ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE = // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
@@ -2448,6 +2460,13 @@
* in ACAMERA_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL.
* If ACAMERA_CONTROL_AE_MODE is set to any of <code>ON_AUTO_FLASH</code>, <code>ON_ALWAYS_FLASH</code>,
* <code>ON_AUTO_FLASH_REDEYE</code>, <code>ON_EXTERNAL_FLASH</code> values, then the strengthLevel will be ignored.</p>
+ * <p>When AE mode is ON and flash mode is TORCH or SINGLE, the application should make sure
+ * the AE mode, flash mode, and flash strength level remain the same between precapture
+ * trigger request and final capture request. The flash strength level being set during
+ * precapture sequence is used by the camera device as a reference. The actual strength
+ * may be less, and the auto-exposure routine makes sure proper conversions of sensor
+ * exposure time and sensitivities between precapture and final capture for the specified
+ * strength level.</p>
*
* @see ACAMERA_CONTROL_AE_MODE
* @see ACAMERA_FLASH_MODE
@@ -8225,7 +8244,17 @@
* ACAMERA_SENSOR_FRAME_DURATION are ignored. The
* application has control over the various
* ACAMERA_FLASH_* fields.</p>
+ * <p>If the device supports manual flash strength control, i.e.,
+ * if ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL and
+ * ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL are greater than 1, then
+ * the auto-exposure (AE) precapture metering sequence should be
+ * triggered for the configured flash mode and strength to avoid
+ * the image being incorrectly exposed at different
+ * ACAMERA_FLASH_STRENGTH_LEVEL.</p>
*
+ * @see ACAMERA_FLASH_SINGLE_STRENGTH_MAX_LEVEL
+ * @see ACAMERA_FLASH_STRENGTH_LEVEL
+ * @see ACAMERA_FLASH_TORCH_STRENGTH_MAX_LEVEL
* @see ACAMERA_SENSOR_EXPOSURE_TIME
* @see ACAMERA_SENSOR_FRAME_DURATION
* @see ACAMERA_SENSOR_SENSITIVITY
@@ -11563,7 +11592,6 @@
-
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_TAGS_H */
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
index cdba8ff..5b69f5c 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.cpp
@@ -194,11 +194,11 @@
return (strncmp(value, "0", 2) != 0 && strncasecmp(value, "false", 6) != 0);
}
-bool CameraManagerGlobal::setupVendorTags() {
+bool CameraManagerGlobal::setupVendorTags(std::shared_ptr<ICameraService> &cameraService) {
sp<VendorTagDescriptorCache> tagCache = new VendorTagDescriptorCache();
Status status = Status::NO_ERROR;
std::vector<ProviderIdAndVendorTagSections> providerIdsAndVts;
- ScopedAStatus remoteRet = mCameraService->getCameraVendorTagSections(&providerIdsAndVts);
+ ScopedAStatus remoteRet = cameraService->getCameraVendorTagSections(&providerIdsAndVts);
if (!remoteRet.isOk()) {
if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
@@ -261,15 +261,12 @@
ALOGE("%s: Could not get ICameraService instance.", __FUNCTION__);
return nullptr;
}
-
if (mDeathRecipient.get() == nullptr) {
mDeathRecipient = ndk::ScopedAIBinder_DeathRecipient(
AIBinder_DeathRecipient_new(CameraManagerGlobal::binderDeathCallback));
+ AIBinder_linkToDeath(cameraService->asBinder().get(),
+ mDeathRecipient.get(), /*cookie=*/ this);
}
- AIBinder_linkToDeath(cameraService->asBinder().get(),
- mDeathRecipient.get(), /*cookie=*/ this);
-
- mCameraService = cameraService;
// Setup looper thread to perform availability callbacks
if (mCbLooper == nullptr) {
@@ -291,33 +288,25 @@
mCbLooper->registerHandler(mHandler);
}
+ std::vector<CameraStatusAndId> cameraStatuses;
// register ICameraServiceListener
if (mCameraServiceListener == nullptr) {
mCameraServiceListener = ndk::SharedRefBase::make<CameraServiceListener>(weak_from_this());
- }
-
- std::vector<CameraStatusAndId> cameraStatuses;
- Status status = Status::NO_ERROR;
- ScopedAStatus remoteRet = mCameraService->addListener(mCameraServiceListener,
- &cameraStatuses);
-
- if (!remoteRet.isOk()) {
- if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
- Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
- ALOGE("%s: Failed to add listener to camera service: %s", __FUNCTION__,
- toString(errStatus).c_str());
- } else {
- ALOGE("%s: Transaction failed when adding listener to camera service: %d",
- __FUNCTION__, remoteRet.getExceptionCode());
+ ScopedAStatus remoteRet = cameraService->addListener(mCameraServiceListener,
+ &cameraStatuses);
+ if (!remoteRet.isOk()) {
+ if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+ ALOGE("%s: Failed to add listener to camera service: %s", __FUNCTION__,
+ toString(errStatus).c_str());
+ } else {
+ ALOGE("%s: Transaction failed when adding listener to camera service: %d",
+ __FUNCTION__, remoteRet.getExceptionCode());
+ }
+ return nullptr;
}
}
- // Setup vendor tags
- if (!setupVendorTags()) {
- ALOGE("Unable to set up vendor tags");
- return nullptr;
- }
-
for (auto& csi: cameraStatuses){
onStatusChangedLocked(csi.deviceStatus, csi.cameraId);
@@ -326,6 +315,13 @@
csi.cameraId, unavailablePhysicalId);
}
}
+
+ // Setup vendor tags
+ if (!setupVendorTags(cameraService)) {
+ ALOGE("Unable to set up vendor tags");
+ return nullptr;
+ }
+ mCameraService = cameraService;
return mCameraService;
}
@@ -346,6 +342,8 @@
instance->onStatusChangedLocked(deviceStatus, cameraId);
}
instance->mCameraService.reset();
+ instance->mDeathRecipient.release();
+ instance->mCameraServiceListener.reset();
// TODO: consider adding re-connect call here?
}
diff --git a/camera/ndk/ndk_vendor/impl/ACameraManager.h b/camera/ndk/ndk_vendor/impl/ACameraManager.h
index 2d8eefa..5688e76 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraManager.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraManager.h
@@ -188,7 +188,7 @@
const std::string &physicalCameraId);
void onStatusChangedLocked(const CameraDeviceStatus &status, const std::string &cameraId,
const std::string &physicalCameraId);
- bool setupVendorTags();
+ bool setupVendorTags(std::shared_ptr<ICameraService> &cameraService);
// Utils for status
static bool validStatus(CameraDeviceStatus status);
diff --git a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
index f046785..97a8cc4 100644
--- a/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
+++ b/drm/libmediadrmrkp/include/DrmRemotelyProvisionedComponent.h
@@ -35,7 +35,8 @@
class DrmRemotelyProvisionedComponent : public BnRemotelyProvisionedComponent {
public:
DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm, std::string drmVendor,
- std::string drmDesc, std::vector<uint8_t> bcc);
+ std::string drmDesc, std::vector<uint8_t> bcc,
+ std::vector<uint8_t> bcc_signature);
ScopedAStatus getHardwareInfo(RpcHardwareInfo* info) override;
ScopedAStatus generateEcdsaP256KeyPair(bool testMode, MacedPublicKey* macedPublicKey,
@@ -60,6 +61,7 @@
std::string mDrmVendor;
std::string mDrmDesc;
std::vector<uint8_t> mBcc;
+ std::vector<uint8_t> mBccSignature;
};
} // namespace android::mediadrm
diff --git a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
index 440be79..65054b0 100644
--- a/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
+++ b/drm/libmediadrmrkp/src/DrmRemotelyProvisionedComponent.cpp
@@ -28,11 +28,13 @@
DrmRemotelyProvisionedComponent::DrmRemotelyProvisionedComponent(std::shared_ptr<IDrmPlugin> drm,
std::string drmVendor,
std::string drmDesc,
- std::vector<uint8_t> bcc)
+ std::vector<uint8_t> bcc,
+ std::vector<uint8_t> bcc_signature)
: mDrm(std::move(drm)),
mDrmVendor(std::move(drmVendor)),
mDrmDesc(std::move(drmDesc)),
- mBcc(std::move(bcc)) {}
+ mBcc(std::move(bcc)),
+ mBccSignature(std::move(bcc_signature)) {}
ScopedAStatus DrmRemotelyProvisionedComponent::getHardwareInfo(RpcHardwareInfo* info) {
info->versionNumber = 3;
@@ -107,7 +109,7 @@
for (auto i : keyToProp) {
auto key = i.first;
auto prop = i.second;
- const auto& val= deviceInfoMap.get(key);
+ const auto& val = deviceInfoMap.get(key);
if (val == nullptr || val->asTstr()->value().empty()) {
std::string propValue = android::base::GetProperty(prop, "");
if (propValue.empty()) {
@@ -161,12 +163,16 @@
}
// assemble AuthenticatedRequest (definition in IRemotelyProvisionedComponent.aidl)
- *out = cppbor::Array()
- .add(1 /* version */)
- .add(cppbor::Map() /* UdsCerts */)
- .add(cppbor::EncodedItem(mBcc))
- .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)))
- .encode();
+ cppbor::Array request_array = cppbor::Array().add(1 /* version */);
+ if (!mBccSignature.empty()) {
+ request_array.add(cppbor::EncodedItem(mBccSignature) /* UdsCerts */);
+ } else {
+ request_array.add(cppbor::Map() /* empty UdsCerts */);
+ }
+ request_array.add(cppbor::EncodedItem(mBcc))
+ .add(cppbor::EncodedItem(std::move(deviceSignedCsrPayload)));
+ *out = request_array.encode();
+
return ScopedAStatus::ok();
}
} // namespace android::mediadrm
\ No newline at end of file
diff --git a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
index 515d157..750b51e 100644
--- a/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
+++ b/drm/libmediadrmrkp/src/DrmRkpAdapter.cpp
@@ -87,13 +87,21 @@
status.getDescription().c_str());
return;
}
-
+ std::vector<uint8_t> bcc_signature;
+ status =
+ mDrm->getPropertyByteArray("bootCertificateChainSignature", &bcc_signature);
+ if (!status.isOk()) {
+ ALOGW("mDrm->getPropertyByteArray(\"bootCertificateChainSignature\") failed."
+ "Detail: [%s].",
+ status.getDescription().c_str());
+ // bcc signature is optional, no need to return when it is unavailable.
+ }
std::string compName(instance);
auto comps = static_cast<
std::map<std::string, std::shared_ptr<IRemotelyProvisionedComponent>>*>(
context);
(*comps)[compName] = ::ndk::SharedRefBase::make<DrmRemotelyProvisionedComponent>(
- mDrm, drmVendor, drmDesc, bcc);
+ mDrm, drmVendor, drmDesc, bcc, bcc_signature);
});
return comps;
}
diff --git a/drm/mediadrm/plugins/clearkey/aidl/Android.bp b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
index 1bb3da6..079e075 100644
--- a/drm/mediadrm/plugins/clearkey/aidl/Android.bp
+++ b/drm/mediadrm/plugins/clearkey/aidl/Android.bp
@@ -86,7 +86,7 @@
],
srcs: ["Service.cpp"],
init_rc: ["android.hardware.drm-service.clearkey.rc"],
- vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+ vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
}
cc_binary {
@@ -98,7 +98,13 @@
overrides: ["android.hardware.drm-service.clearkey"],
srcs: ["ServiceLazy.cpp"],
init_rc: ["android.hardware.drm-service-lazy.clearkey.rc"],
- vintf_fragments: ["android.hardware.drm-service.clearkey.xml"],
+ vintf_fragment_modules: ["android.hardware.drm-service.clearkey.xml_vintf"],
+}
+
+vintf_fragment {
+ name: "android.hardware.drm-service.clearkey.xml_vintf",
+ src: "android.hardware.drm-service.clearkey.xml",
+ vendor: true,
}
cc_binary {
diff --git a/media/TEST_MAPPING b/media/TEST_MAPPING
index 1a637ac..695cad6 100644
--- a/media/TEST_MAPPING
+++ b/media/TEST_MAPPING
@@ -45,6 +45,32 @@
"file_patterns": ["(?i)drm|crypto"]
}
],
+ "postsubmit": [
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.EncodeDecodeTest"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.DecodeEditEncodeTest"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-filter": "android.media.codec.cts.ExtractDecodeEditEncodeMuxTest"
+ }
+ ]
+ }
+ ],
// Postsubmit tests for TV devices
"tv-postsubmit": [
{
diff --git a/media/aconfig/codec_fwk.aconfig b/media/aconfig/codec_fwk.aconfig
index 362e98e..ed1522b 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -13,6 +13,26 @@
}
flag {
+ name: "codec_buffer_state_cleanup"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for more buffer state cleanup in MediaCodec"
+ bug: "343502509"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "dataspace_v0_partial"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for using V0 dataspace in some cases"
+ bug: "313827126"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "dynamic_color_aspects"
is_exported: true
namespace: "codec_fwk"
@@ -98,6 +118,16 @@
}
flag {
+ name: "secure_codecs_require_crypto"
+ namespace: "codec_fwk"
+ description: "Bugfix flag for requiring setting crypto for secure codecs"
+ bug: "365162324"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
name: "set_callback_stall"
namespace: "codec_fwk"
description: "Bugfix flag for setCallback stall"
diff --git a/media/audio/aconfig/Android.bp b/media/audio/aconfig/Android.bp
index de8aca7..a5aeff2 100644
--- a/media/audio/aconfig/Android.bp
+++ b/media/audio/aconfig/Android.bp
@@ -50,6 +50,23 @@
}
cc_aconfig_library {
+ name: "com.android.media.audioserver-aconfig-cc-ro",
+ aconfig_declarations: "com.android.media.audioserver-aconfig",
+ defaults: ["audio-aconfig-cc-defaults"],
+ double_loadable: true,
+ host_supported: true,
+ product_available: true,
+ vendor_available: true,
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ "com.android.media.swcodec",
+ ],
+ min_sdk_version: "29",
+ mode: "force-read-only",
+}
+
+cc_aconfig_library {
name: "com.android.media.audio-aconfig-cc",
aconfig_declarations: "com.android.media.audio-aconfig",
defaults: ["audio-aconfig-cc-defaults"],
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index 9221c04..c732708 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -60,6 +60,15 @@
}
flag {
+ name: "equal_sco_lea_vc_index_range"
+ namespace: "media_audio"
+ description:
+ "Introduce the same index range for voice calls over SCO and "
+ "LE audio"
+ bug: "364364777"
+}
+
+flag {
name: "music_fx_edge_to_edge"
namespace: "media_audio"
description: "Enable Edge-to-edge feature for MusicFx and handle insets"
diff --git a/media/audio/aconfig/audio_framework.aconfig b/media/audio/aconfig/audio_framework.aconfig
index 0209e28..411996e 100644
--- a/media/audio/aconfig/audio_framework.aconfig
+++ b/media/audio/aconfig/audio_framework.aconfig
@@ -22,6 +22,13 @@
bug: "302323921"
}
+flag{
+ name: "enable_ringtone_haptics_customization"
+ namespace: "media_audio"
+ description: "Enables haptic customization for playing ringtone."
+ bug: "351974934"
+}
+
flag {
name: "feature_spatial_audio_headtracking_low_latency"
is_exported: true
@@ -40,6 +47,14 @@
bug: "316414750"
}
+flag {
+ name: "dolby_ac4_level4_encoding_api"
+ namespace: "media_audio"
+ description: "Feature flag for Dolby AC-4 level 4 AudioFormat encoding."
+ is_fixed_read_only: true
+ bug: "266537650"
+}
+
# TODO remove
flag {
name: "foreground_audio_control"
@@ -86,6 +101,13 @@
}
flag {
+ name: "muted_by_port_volume_api"
+ namespace: "media_audio"
+ description: "Playback monitoring flag used when player muted by port volume"
+ bug: "319515324"
+}
+
+flag {
name: "sco_managed_by_audio"
is_exported: true
namespace: "media_audio"
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index d1c6239..1ce4d00 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -22,6 +22,13 @@
}
flag {
+ name: "enable_audio_input_device_routing"
+ namespace: "media_audio"
+ description: "Allow audio input devices routing control."
+ bug: "364923030"
+}
+
+flag {
name: "fdtostring_timeout_fix"
namespace: "media_audio"
description: "Improve fdtostring implementation to properly handle timing out."
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 9eaddce..cdcce08 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -76,6 +76,8 @@
using media::audio::common::AudioOffloadInfo;
using media::audio::common::AudioOutputFlags;
using media::audio::common::AudioPlaybackRate;
+using media::audio::common::AudioPolicyForcedConfig;
+using media::audio::common::AudioPolicyForceUse;
using media::audio::common::AudioPort;
using media::audio::common::AudioPortConfig;
using media::audio::common::AudioPortDeviceExt;
@@ -739,6 +741,8 @@
{// Note: not in the IANA registry.
AUDIO_FORMAT_APTX_HD, make_AudioFormatDescription("audio/vnd.qcom.aptx.hd")},
{AUDIO_FORMAT_AC4, make_AudioFormatDescription(::android::MEDIA_MIMETYPE_AUDIO_AC4)},
+ {AUDIO_FORMAT_AC4_L4, make_AudioFormatDescription(
+ std::string(::android::MEDIA_MIMETYPE_AUDIO_AC4) + ";version=02.01.04")},
{// Note: not in the IANA registry.
AUDIO_FORMAT_LDAC, make_AudioFormatDescription("audio/vnd.sony.ldac")},
{AUDIO_FORMAT_MAT,
@@ -1053,6 +1057,14 @@
return OK;
}
+namespace {
+ // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast
+ // and universaly administered
+ constexpr std::array<uint8_t, 4> BTANON_PREFIX {0xFD, 0xFF, 0xFF, 0xFF};
+ // Keep sync with ServiceUtilities.cpp mustAnonymizeBluetoothAddress
+ constexpr const char * BTANON_PREFIX_STR = "XX:XX:XX:XX:";
+}
+
::android::status_t aidl2legacy_AudioDevice_audio_device(
const AudioDevice& aidl,
audio_devices_t* legacyType, std::string* legacyAddress) {
@@ -1067,8 +1079,16 @@
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]);
+ if (std::equal(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin())) {
+ // special case for anonymized mac address:
+ // change anonymized bytes back from FD:FF:FF:FF: to XX:XX:XX:XX:
+ snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN,
+ "%s%02X:%02X", BTANON_PREFIX_STR, mac[4], mac[5]);
+ } else {
+ 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>();
@@ -1130,8 +1150,20 @@
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]);
+ int status;
+ // special case for anonymized mac address:
+ // change anonymized bytes so that they can be scanned as HEX bytes
+ if (legacyAddress.starts_with(BTANON_PREFIX_STR)) {
+ std::copy(BTANON_PREFIX.begin(), BTANON_PREFIX.end(), mac.begin());
+ LOG_ALWAYS_FATAL_IF(legacyAddress.length() <= strlen(BTANON_PREFIX_STR));
+ status = sscanf(legacyAddress.c_str() + strlen(BTANON_PREFIX_STR),
+ "%hhX:%hhX",
+ &mac[4], &mac[5]);
+ status += 4;
+ } else {
+ 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);
@@ -3301,6 +3333,138 @@
return OK;
}
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(AudioPolicyForceUse aidl) {
+ switch (aidl) {
+ case AudioPolicyForceUse::COMMUNICATION:
+ return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
+ case AudioPolicyForceUse::MEDIA:
+ return AUDIO_POLICY_FORCE_FOR_MEDIA;
+ case AudioPolicyForceUse::RECORD:
+ return AUDIO_POLICY_FORCE_FOR_RECORD;
+ case AudioPolicyForceUse::DOCK:
+ return AUDIO_POLICY_FORCE_FOR_DOCK;
+ case AudioPolicyForceUse::SYSTEM:
+ return AUDIO_POLICY_FORCE_FOR_SYSTEM;
+ case AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
+ return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
+ case AudioPolicyForceUse::ENCODED_SURROUND:
+ return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
+ case AudioPolicyForceUse::VIBRATE_RINGING:
+ return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
+ switch (legacy) {
+ case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
+ return AudioPolicyForceUse::COMMUNICATION;
+ case AUDIO_POLICY_FORCE_FOR_MEDIA:
+ return AudioPolicyForceUse::MEDIA;
+ case AUDIO_POLICY_FORCE_FOR_RECORD:
+ return AudioPolicyForceUse::RECORD;
+ case AUDIO_POLICY_FORCE_FOR_DOCK:
+ return AudioPolicyForceUse::DOCK;
+ case AUDIO_POLICY_FORCE_FOR_SYSTEM:
+ return AudioPolicyForceUse::SYSTEM;
+ case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
+ return AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
+ case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
+ return AudioPolicyForceUse::ENCODED_SURROUND;
+ case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
+ return AudioPolicyForceUse::VIBRATE_RINGING;
+ case AUDIO_POLICY_FORCE_USE_CNT:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(AudioPolicyForcedConfig aidl) {
+ switch (aidl) {
+ case AudioPolicyForcedConfig::NONE:
+ return AUDIO_POLICY_FORCE_NONE;
+ case AudioPolicyForcedConfig::SPEAKER:
+ return AUDIO_POLICY_FORCE_SPEAKER;
+ case AudioPolicyForcedConfig::HEADPHONES:
+ return AUDIO_POLICY_FORCE_HEADPHONES;
+ case AudioPolicyForcedConfig::BT_SCO:
+ return AUDIO_POLICY_FORCE_BT_SCO;
+ case AudioPolicyForcedConfig::BT_A2DP:
+ return AUDIO_POLICY_FORCE_BT_A2DP;
+ case AudioPolicyForcedConfig::WIRED_ACCESSORY:
+ return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
+ case AudioPolicyForcedConfig::BT_CAR_DOCK:
+ return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
+ case AudioPolicyForcedConfig::BT_DESK_DOCK:
+ return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
+ case AudioPolicyForcedConfig::ANALOG_DOCK:
+ return AUDIO_POLICY_FORCE_ANALOG_DOCK;
+ case AudioPolicyForcedConfig::DIGITAL_DOCK:
+ return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
+ case AudioPolicyForcedConfig::NO_BT_A2DP:
+ return AUDIO_POLICY_FORCE_NO_BT_A2DP;
+ case AudioPolicyForcedConfig::SYSTEM_ENFORCED:
+ return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
+ case AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
+ return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
+ case AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
+ case AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
+ case AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
+ return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
+ case AudioPolicyForcedConfig::BT_BLE:
+ return AUDIO_POLICY_FORCE_BT_BLE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
+ switch (legacy) {
+ case AUDIO_POLICY_FORCE_NONE:
+ return AudioPolicyForcedConfig::NONE;
+ case AUDIO_POLICY_FORCE_SPEAKER:
+ return AudioPolicyForcedConfig::SPEAKER;
+ case AUDIO_POLICY_FORCE_HEADPHONES:
+ return AudioPolicyForcedConfig::HEADPHONES;
+ case AUDIO_POLICY_FORCE_BT_SCO:
+ return AudioPolicyForcedConfig::BT_SCO;
+ case AUDIO_POLICY_FORCE_BT_A2DP:
+ return AudioPolicyForcedConfig::BT_A2DP;
+ case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
+ return AudioPolicyForcedConfig::WIRED_ACCESSORY;
+ case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
+ return AudioPolicyForcedConfig::BT_CAR_DOCK;
+ case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
+ return AudioPolicyForcedConfig::BT_DESK_DOCK;
+ case AUDIO_POLICY_FORCE_ANALOG_DOCK:
+ return AudioPolicyForcedConfig::ANALOG_DOCK;
+ case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
+ return AudioPolicyForcedConfig::DIGITAL_DOCK;
+ case AUDIO_POLICY_FORCE_NO_BT_A2DP:
+ return AudioPolicyForcedConfig::NO_BT_A2DP;
+ case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
+ return AudioPolicyForcedConfig::SYSTEM_ENFORCED;
+ case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
+ return AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
+ return AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
+ return AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
+ case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
+ return AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
+ case AUDIO_POLICY_FORCE_BT_BLE:
+ return AudioPolicyForcedConfig::BT_BLE;
+ case AUDIO_POLICY_FORCE_CFG_CNT:
+ break;
+ }
+ return unexpected(BAD_VALUE);
+}
+
} // namespace android
#undef GET_DEVICE_DESC_CONNECTION
diff --git a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
index 7268464..9dfb7e7 100644
--- a/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
+++ b/media/audioaidlconversion/include/media/AidlConversionCppNdk-impl.h
@@ -58,6 +58,8 @@
#include PREFIX(android/media/audio/common/AudioMode.h)
#include PREFIX(android/media/audio/common/AudioOffloadInfo.h)
#include PREFIX(android/media/audio/common/AudioOutputFlags.h)
+#include PREFIX(android/media/audio/common/AudioPolicyForceUse.h)
+#include PREFIX(android/media/audio/common/AudioPolicyForcedConfig.h)
#include PREFIX(android/media/audio/common/AudioPort.h)
#include PREFIX(android/media/audio/common/AudioPortConfig.h)
#include PREFIX(android/media/audio/common/AudioPortExt.h)
@@ -76,6 +78,7 @@
#include <system/audio.h>
#include <system/audio_effect.h>
+#include <system/audio_policy.h>
#if defined(BACKEND_NDK_IMPL)
namespace aidl {
@@ -454,6 +457,18 @@
media::audio::common::MicrophoneInfo* aidlInfo,
media::audio::common::MicrophoneDynamicInfo* aidlDynamic);
+ConversionResult<audio_policy_forced_cfg_t>
+aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(
+ media::audio::common::AudioPolicyForcedConfig aidl);
+ConversionResult<media::audio::common::AudioPolicyForcedConfig>
+legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
+
+ConversionResult<audio_policy_force_use_t>
+aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+ media::audio::common::AudioPolicyForceUse aidl);
+ConversionResult<media::audio::common::AudioPolicyForceUse>
+legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
+
} // namespace android
#if defined(BACKEND_NDK_IMPL)
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
index 5d7daa4..d55932d 100644
--- a/media/audioserver/main_audioserver.cpp
+++ b/media/audioserver/main_audioserver.cpp
@@ -205,6 +205,7 @@
__func__, status, policyInfos.size());
}
const auto endTime = std::chrono::steady_clock::now();
+ af->startupFinished();
using FloatMillis = std::chrono::duration<float, std::milli>;
const float timeTaken = std::chrono::duration_cast<FloatMillis>(
endTime - startTime).count();
diff --git a/media/codec2/components/mp3/C2SoftMp3Dec.cpp b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
index 149c6ee..aed5e68 100644
--- a/media/codec2/components/mp3/C2SoftMp3Dec.cpp
+++ b/media/codec2/components/mp3/C2SoftMp3Dec.cpp
@@ -114,7 +114,9 @@
c2_status_t C2SoftMP3::onStop() {
// Make sure that the next buffer output does not still
// depend on fragments from the last one decoded.
- pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ if (mDecoderBuf) {
+ pvmp3_InitDecoder(mConfig, mDecoderBuf);
+ }
mSignalledError = false;
mIsFirst = true;
mSignalledOutputEos = false;
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index ea4d045..de9332b 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -153,6 +153,13 @@
mParamReflectors.push_back(paramReflector);
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -212,12 +219,20 @@
if (c2interface == nullptr) {
return nullptr;
}
+ // Framework support for Large audio frame feature depends on:
+ // 1. All feature flags enabled on platform
+ // 2. The capability of the implementation to use the same input buffer
+ // for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+ // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
c2_status_t err = C2_OK;
C2ComponentDomainSetting domain;
std::vector<std::unique_ptr<C2Param>> heapParams;
- err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
- if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+ err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK
+ && (domain.value == C2Component::DOMAIN_AUDIO)
+ && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
std::vector<std::shared_ptr<C2ParamDescriptor>> params;
bool isComponentSupportsLargeAudioFrame = false;
c2interface->querySupportedParams_nb(¶ms);
@@ -234,7 +249,7 @@
// thus we pass the component's param reflector, which is mParamReflectors[0].
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index b2158a6..bb4c596 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -52,6 +52,13 @@
using ::aidl::android::hardware::media::bufferpool2::IClientManager;
struct ComponentStore : public BnComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -120,6 +127,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 1ba1889..108ba06 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
if (c2interface == nullptr) {
return nullptr;
}
+ // Framework support for Large audio frame feature depends on:
+ // 1. All feature flags enabled on platform
+ // 2. The capability of the implementation to use the same input buffer
+ // for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+ // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
c2_status_t err = C2_OK;
C2ComponentDomainSetting domain;
std::vector<std::unique_ptr<C2Param>> heapParams;
- err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
- if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+ err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK
+ && (domain.value == C2Component::DOMAIN_AUDIO)
+ && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
std::vector<std::shared_ptr<C2ParamDescriptor>> params;
bool isComponentSupportsLargeAudioFrame = false;
c2interface->querySupportedParams_nb(¶ms);
@@ -225,7 +241,7 @@
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
index 44b8ec1..028238b 100644
--- a/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.0/utils/include/codec2/hidl/1.0/ComponentStore.h
@@ -55,6 +55,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -124,6 +131,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index 1b86958..84f5d26 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
if (c2interface == nullptr) {
return nullptr;
}
+ // Framework support for Large audio frame feature depends on:
+ // 1. All feature flags enabled on platform
+ // 2. The capability of the implementation to use the same input buffer
+ // for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+ // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
c2_status_t err = C2_OK;
C2ComponentDomainSetting domain;
std::vector<std::unique_ptr<C2Param>> heapParams;
- err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
- if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+ err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK
+ && (domain.value == C2Component::DOMAIN_AUDIO)
+ && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
std::vector<std::shared_ptr<C2ParamDescriptor>> params;
bool isComponentSupportsLargeAudioFrame = false;
c2interface->querySupportedParams_nb(¶ms);
@@ -222,11 +238,10 @@
break;
}
}
-
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
index 52d2945..b023115 100644
--- a/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.1/utils/include/codec2/hidl/1.1/ComponentStore.h
@@ -56,6 +56,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -132,6 +139,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index 2e0386f..5585be8 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -149,6 +149,14 @@
}
#endif
+ // MultiAccessUnit reflector helper is allocated once per store.
+ // All components in this store can reuse this reflector helper.
+ if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
+ std::shared_ptr<C2ReflectorHelper> helper = std::make_shared<C2ReflectorHelper>();
+ mParamReflectors.push_back(helper);
+ mMultiAccessUnitReflector = helper;
+ }
+
// Retrieve supported parameters from store
using namespace std::placeholders;
mInit = mConfigurable->init(mParameterCache);
@@ -207,12 +215,20 @@
if (c2interface == nullptr) {
return nullptr;
}
+ // Framework support for Large audio frame feature depends on:
+ // 1. All feature flags enabled on platform
+ // 2. The capability of the implementation to use the same input buffer
+ // for different C2Work (C2Config::api_feature_t::API_SAME_INPUT_BUFFER)
+ // 3. Implementation does not inherently support C2LargeFrame::output::PARAM_TYPE param.
if (MultiAccessUnitHelper::isEnabledOnPlatform()) {
c2_status_t err = C2_OK;
C2ComponentDomainSetting domain;
std::vector<std::unique_ptr<C2Param>> heapParams;
- err = c2interface->query_vb({&domain}, {}, C2_MAY_BLOCK, &heapParams);
- if (err == C2_OK && (domain.value == C2Component::DOMAIN_AUDIO)) {
+ C2ApiFeaturesSetting features = (C2Config::api_feature_t)0;
+ err = c2interface->query_vb({&domain, &features}, {}, C2_MAY_BLOCK, &heapParams);
+ if (err == C2_OK
+ && (domain.value == C2Component::DOMAIN_AUDIO)
+ && ((features.value & C2Config::api_feature_t::API_SAME_INPUT_BUFFER) != 0)) {
std::vector<std::shared_ptr<C2ParamDescriptor>> params;
bool isComponentSupportsLargeAudioFrame = false;
c2interface->querySupportedParams_nb(¶ms);
@@ -225,7 +241,7 @@
if (!isComponentSupportsLargeAudioFrame) {
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- std::static_pointer_cast<C2ReflectorHelper>(mParamReflectors[0]));
+ mMultiAccessUnitReflector);
}
}
}
diff --git a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
index 1b209e2..a7e043b 100644
--- a/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
+++ b/media/codec2/hal/hidl/1.2/utils/include/codec2/hidl/1.2/ComponentStore.h
@@ -56,6 +56,13 @@
using ::android::sp;
struct ComponentStore : public IComponentStore {
+ /**
+ * Constructor for ComponentStore.
+ *
+ * IMPORTANT: SetPreferredCodec2ComponentStore() is called in the constructor.
+ * Be careful about the order of SetPreferredCodec2ComponentStore() and
+ * ComponentStore() in the code.
+ */
ComponentStore(const std::shared_ptr<C2ComponentStore>& store);
virtual ~ComponentStore();
@@ -139,6 +146,9 @@
std::shared_ptr<C2ComponentStore> mStore;
std::vector<std::shared_ptr<C2ParamReflector>> mParamReflectors;
+ // Reflector helper for MultiAccessUnitHelper
+ std::shared_ptr<C2ReflectorHelper> mMultiAccessUnitReflector;
+
std::map<C2Param::CoreIndex, std::shared_ptr<C2StructDescriptor>> mStructDescriptors;
std::set<C2Param::CoreIndex> mUnsupportedStructDescriptors;
std::set<C2String> mLoadedInterfaces;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index 47412b7..34872f0 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -856,21 +856,31 @@
C2String getName() const override { return "android.sample.filter-plugin-store"; }
c2_status_t createComponent(
C2String name, std::shared_ptr<C2Component>* const component) override {
- if (mFactories.count(name) == 0) {
+ auto it = std::find_if(
+ mFactories.begin(), mFactories.end(),
+ [&name](const std::unique_ptr<ComponentFactory> &factory) {
+ return name == factory->getTraits()->name;
+ });
+ if (it == mFactories.end()) {
return C2_BAD_VALUE;
}
- return mFactories.at(name)->createComponent(++mNodeId, component);
+ return (*it)->createComponent(++mNodeId, component);
}
c2_status_t createInterface(
C2String name, std::shared_ptr<C2ComponentInterface>* const interface) override {
- if (mFactories.count(name) == 0) {
+ auto it = std::find_if(
+ mFactories.begin(), mFactories.end(),
+ [&name](const std::unique_ptr<ComponentFactory> &factory) {
+ return name == factory->getTraits()->name;
+ });
+ if (it == mFactories.end()) {
return C2_BAD_VALUE;
}
- return mFactories.at(name)->createInterface(++mNodeId, interface);
+ return (*it)->createInterface(++mNodeId, interface);
}
std::vector<std::shared_ptr<const C2Component::Traits>> listComponents() override {
std::vector<std::shared_ptr<const C2Component::Traits>> ret;
- for (const auto &[name, factory] : mFactories) {
+ for (const auto &factory : mFactories) {
ret.push_back(factory->getTraits());
}
return ret;
@@ -951,20 +961,18 @@
template <class T>
static void AddFactory(
- std::map<C2String, std::unique_ptr<ComponentFactory>> *factories,
+ std::vector<std::unique_ptr<ComponentFactory>> *factories,
const std::shared_ptr<C2ReflectorHelper> &reflector) {
std::shared_ptr<C2ComponentInterface> intf{new typename T::Interface(0, reflector)};
std::shared_ptr<C2Component::Traits> traits(new (std::nothrow) C2Component::Traits);
CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
<< "Failed to fill traits from interface";
- factories->emplace(
- traits->name,
- new ComponentFactoryImpl<T>(traits, reflector));
+ factories->emplace_back(new ComponentFactoryImpl<T>(traits, reflector));
}
- static std::map<C2String, std::unique_ptr<ComponentFactory>> CreateFactories(
+ static std::vector<std::unique_ptr<ComponentFactory>> CreateFactories(
const std::shared_ptr<C2ReflectorHelper> &reflector) {
- std::map<C2String, std::unique_ptr<ComponentFactory>> factories;
+ std::vector<std::unique_ptr<ComponentFactory>> factories;
AddFactory<SampleToneMappingFilter>(&factories, reflector);
return factories;
}
@@ -977,7 +985,7 @@
}
} mIntf;
- const std::map<C2String, std::unique_ptr<ComponentFactory>> mFactories;
+ const std::vector<std::unique_ptr<ComponentFactory>> mFactories;
std::atomic_int32_t mNodeId{0};
};
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 68f1dda..632eaed 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -512,9 +512,14 @@
uint64_t usage = mConfig.mUsage;
(void)(*node)->setConsumerUsage((int64_t)usage);
+ // AIDL does not define legacy dataspace.
+ android_dataspace_t dataspace = mDataSpace;
+ if (android::media::codec::provider_->dataspace_v0_partial()) {
+ ColorUtils::convertDataSpaceToV0(dataspace);
+ }
return fromAidlStatus(mSource->configure(
(*node), static_cast<::aidl::android::hardware::graphics::common::Dataspace>(
- mDataSpace)));
+ dataspace)));
}
void disconnect() override {
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index d829523..3ef2f84 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -228,17 +228,23 @@
status_t CCodecBufferChannel::setInputSurface(
const std::shared_ptr<InputSurfaceWrapper> &surface) {
ALOGV("[%s] setInputSurface", mName);
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- *inputSurface = surface;
- return (*inputSurface)->connect(mComponent);
+ if (!surface) {
+ ALOGE("[%s] setInputSurface: surface must not be null", mName);
+ return BAD_VALUE;
+ }
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ inputSurface->numProcessingBuffersBalance = 0;
+ inputSurface->surface = surface;
+ mHasInputSurface = true;
+ return inputSurface->surface->connect(mComponent);
}
status_t CCodecBufferChannel::signalEndOfInputStream() {
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- if ((*inputSurface) == nullptr) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ if (inputSurface->surface == nullptr) {
return INVALID_OPERATION;
}
- return (*inputSurface)->signalEndOfInputStream();
+ return inputSurface->surface->signalEndOfInputStream();
}
status_t CCodecBufferChannel::queueInputBufferInternal(
@@ -1063,19 +1069,36 @@
if (mInputMetEos) {
return;
}
- {
+ int64_t numOutputSlots = 0;
+ bool outputFull = [this, &numOutputSlots]() {
Mutexed<Output>::Locked output(mOutput);
- if (!output->buffers ||
- output->buffers->hasPending() ||
+ if (!output->buffers) {
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+ "return because output buffers are null", mName);
+ return true;
+ }
+ numOutputSlots = int64_t(output->numSlots);
+ if (output->buffers->hasPending() ||
(!output->bounded && output->buffers->numActiveSlots() >= output->numSlots)) {
- return;
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: "
+ "return because there are no room for more output buffers", mName);
+ return true;
+ }
+ return false;
+ }();
+ if (android::media::codec::provider_->input_surface_throttle()) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ if (inputSurface->surface) {
+ if (inputSurface->numProcessingBuffersBalance <= numOutputSlots) {
+ ++inputSurface->numProcessingBuffersBalance;
+ ALOGV("[%s] feedInputBufferIfAvailableInternal: numProcessingBuffersBalance = %lld",
+ mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+ inputSurface->surface->onInputBufferEmptied();
+ }
}
}
- if (android::media::codec::provider_->input_surface_throttle()) {
- Mutexed<std::shared_ptr<InputSurfaceWrapper>>::Locked inputSurface(mInputSurface);
- if ((*inputSurface) != nullptr) {
- (*inputSurface)->onInputBufferEmptied();
- }
+ if (outputFull) {
+ return;
}
size_t numActiveSlots = 0;
while (!mPipelineWatcher.lock()->pipelineFull()) {
@@ -1704,7 +1727,7 @@
&& (hasCryptoOrDescrambler() || conforming)) {
input->buffers.reset(new SlotInputBuffers(mName));
} else if (graphic) {
- if (mInputSurface.lock()->get()) {
+ if (mHasInputSurface) {
input->buffers.reset(new DummyInputBuffers(mName));
} else if (mMetaMode == MODE_ANW) {
input->buffers.reset(new GraphicMetadataInputBuffers(mName));
@@ -1987,7 +2010,7 @@
status_t CCodecBufferChannel::prepareInitialInputBuffers(
std::map<size_t, sp<MediaCodecBuffer>> *clientInputBuffers, bool retry) {
- if (mInputSurface.lock()->get()) {
+ if (mHasInputSurface) {
return OK;
}
@@ -2113,9 +2136,13 @@
void CCodecBufferChannel::reset() {
stop();
- mInputSurface.lock()->reset();
mPipelineWatcher.lock()->flush();
{
+ mHasInputSurface = false;
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ inputSurface->surface.reset();
+ }
+ {
Mutexed<Input>::Locked input(mInput);
input->buffers.reset(new DummyInputBuffers(""));
input->extraBuffers.flush();
@@ -2208,9 +2235,6 @@
void CCodecBufferChannel::onInputBufferDone(
uint64_t frameIndex, size_t arrayIndex) {
- if (mInputSurface.lock()->get()) {
- return;
- }
std::shared_ptr<C2Buffer> buffer =
mPipelineWatcher.lock()->onInputBufferReleased(frameIndex, arrayIndex);
bool newInputSlotAvailable = false;
@@ -2265,8 +2289,7 @@
notifyClient = false;
}
- bool hasInputSurface = (mInputSurface.lock()->get() != nullptr);
- if (!hasInputSurface && (work->worklets.size() != 1u
+ if (!mHasInputSurface && (work->worklets.size() != 1u
|| !work->worklets.front()
|| !(work->worklets.front()->output.flags &
C2FrameData::FLAG_INCOMPLETE))) {
@@ -2475,7 +2498,7 @@
c2_cntr64_t timestamp =
worklet->output.ordinal.timestamp + work->input.ordinal.customOrdinal
- work->input.ordinal.timestamp;
- if (hasInputSurface) {
+ if (mHasInputSurface) {
// When using input surface we need to restore the original input timestamp.
timestamp = work->input.ordinal.customOrdinal;
}
@@ -2605,8 +2628,6 @@
switch (action) {
case OutputBuffers::SKIP:
return;
- case OutputBuffers::DISCARD:
- break;
case OutputBuffers::NOTIFY_CLIENT:
{
// TRICKY: we want popped buffers reported in order, so sending
@@ -2625,8 +2646,8 @@
bufferMetadata->m.values[nMeta];
flag = convertFlags(bufferMetadataStruct.flags, false);
accessUnitInfos.emplace_back(flag,
- static_cast<size_t>(bufferMetadataStruct.size),
- static_cast<size_t>(bufferMetadataStruct.timestamp));
+ bufferMetadataStruct.size,
+ bufferMetadataStruct.timestamp);
}
sp<WrapperObject<std::vector<AccessUnitInfo>>> obj{
new WrapperObject<std::vector<AccessUnitInfo>>{accessUnitInfos}};
@@ -2634,6 +2655,15 @@
}
}
mCallback->onOutputBufferAvailable(index, outBuffer);
+ [[fallthrough]];
+ }
+ case OutputBuffers::DISCARD: {
+ if (mHasInputSurface && android::media::codec::provider_->input_surface_throttle()) {
+ Mutexed<InputSurface>::Locked inputSurface(mInputSurface);
+ --inputSurface->numProcessingBuffersBalance;
+ ALOGV("[%s] onWorkDone: numProcessingBuffersBalance = %lld",
+ mName, static_cast<long long>(inputSurface->numProcessingBuffersBalance));
+ }
break;
}
case OutputBuffers::REALLOCATE:
@@ -2802,7 +2832,7 @@
}
void CCodecBufferChannel::setInfoBuffer(const std::shared_ptr<C2InfoBuffer> &buffer) {
- if (mInputSurface.lock()->get() == nullptr) {
+ if (!mHasInputSurface) {
mInfoBuffers.push_back(buffer);
} else {
std::list<std::unique_ptr<C2Work>> items;
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.h b/media/codec2/sfplugin/CCodecBufferChannel.h
index f5e268a..4d296fd 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.h
+++ b/media/codec2/sfplugin/CCodecBufferChannel.h
@@ -391,7 +391,21 @@
};
Mutexed<BlockPools> mBlockPools;
- Mutexed<std::shared_ptr<InputSurfaceWrapper>> mInputSurface;
+ std::atomic_bool mHasInputSurface;
+ struct InputSurface {
+ std::shared_ptr<InputSurfaceWrapper> surface;
+ // This variable tracks the number of buffers processing
+ // in the input surface and codec by counting the # of buffers to
+ // be filled in and queued from the input surface and the # of
+ // buffers generated from the codec.
+ //
+ // Note that this variable can go below 0, because it does not take
+ // account the number of buffers initially in the buffer queue at
+ // start. This is okay, as we only track how many more we allow
+ // from the initial state.
+ int64_t numProcessingBuffersBalance;
+ };
+ Mutexed<InputSurface> mInputSurface;
MetaMode mMetaMode;
diff --git a/media/codec2/sfplugin/Codec2Buffer.cpp b/media/codec2/sfplugin/Codec2Buffer.cpp
index 164a1e0..7d4e8ab 100644
--- a/media/codec2/sfplugin/Codec2Buffer.cpp
+++ b/media/codec2/sfplugin/Codec2Buffer.cpp
@@ -20,6 +20,8 @@
#include <utils/Log.h>
#include <utils/Trace.h>
+#include <android_media_codec.h>
+
#include <aidl/android/hardware/graphics/common/Cta861_3.h>
#include <aidl/android/hardware/graphics/common/Smpte2086.h>
#include <android-base/no_destructor.h>
@@ -33,6 +35,7 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/foundation/ColorUtils.h>
#include <mediadrm/ICrypto.h>
#include <nativebase/nativebase.h>
#include <ui/GraphicBufferMapper.h>
@@ -735,6 +738,10 @@
// Gralloc4 not supported; nothing to do
return err;
}
+ // Use V0 dataspaces for Gralloc4+
+ if (android::media::codec::provider_->dataspace_v0_partial()) {
+ ColorUtils::convertDataSpaceToV0(dataSpace);
+ }
status_t status = mapper.setDataspace(buffer.get(), static_cast<ui::Dataspace>(dataSpace));
if (status != OK) {
err = C2_CORRUPTED;
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 4b417a7..add28e0 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -36,9 +36,6 @@
symbol_file: "src/libaaudio.map.txt",
first_version: "26",
unversioned_until: "current",
- export_header_libs: [
- "libAAudio_headers",
- ],
}
cc_library_headers {
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 1e27a81..1e8ac8d 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -602,6 +602,7 @@
}
AAUDIO_API aaudio_result_t AAudio_setMMapPolicy(aaudio_policy_t policy) {
+ ALOGD("%s(%d)", __func__, policy);
return AudioGlobal_setMMapPolicy(policy);
}
diff --git a/media/libaaudio/src/core/AudioStreamBuilder.cpp b/media/libaaudio/src/core/AudioStreamBuilder.cpp
index c9d8b35..01f0038 100644
--- a/media/libaaudio/src/core/AudioStreamBuilder.cpp
+++ b/media/libaaudio/src/core/AudioStreamBuilder.cpp
@@ -109,10 +109,12 @@
std::vector<AudioMMapPolicyInfo> policyInfos;
aaudio_policy_t mmapPolicy = AudioGlobal_getMMapPolicy();
- if (android::AudioSystem::getMmapPolicyInfo(
- AudioMMapPolicyType::DEFAULT, &policyInfos) == NO_ERROR) {
+ ALOGD("%s, global mmap policy is %d", __func__, mmapPolicy);
+ if (status_t status = android::AudioSystem::getMmapPolicyInfo(
+ AudioMMapPolicyType::DEFAULT, &policyInfos); status == NO_ERROR) {
aaudio_policy_t systemMmapPolicy = AAudio_getAAudioPolicy(
policyInfos, AAUDIO_MMAP_POLICY_DEFAULT_AIDL);
+ ALOGD("%s, system mmap policy is %d", __func__, systemMmapPolicy);
if (mmapPolicy == AAUDIO_POLICY_ALWAYS && systemMmapPolicy == AAUDIO_POLICY_NEVER) {
// No need to try as AAudioService is not created and the client only wants MMAP path.
return AAUDIO_ERROR_NO_SERVICE;
@@ -125,6 +127,7 @@
mmapPolicy = systemMmapPolicy;
}
} else {
+ ALOGD("%s, failed to query system mmap policy, error=%d", __func__, status);
// If it fails querying mmap policy info, it is highly possible that the AAudioService is
// not created. In this case, we don't try mmap path.
if (mmapPolicy == AAUDIO_POLICY_ALWAYS) {
@@ -136,17 +139,22 @@
if (mmapPolicy == AAUDIO_UNSPECIFIED) {
mmapPolicy = AAUDIO_MMAP_POLICY_DEFAULT;
}
+ ALOGD("%s, final mmap policy is %d", __func__, mmapPolicy);
policyInfos.clear();
aaudio_policy_t mmapExclusivePolicy = AAUDIO_UNSPECIFIED;
- if (android::AudioSystem::getMmapPolicyInfo(
- AudioMMapPolicyType::EXCLUSIVE, &policyInfos) == NO_ERROR) {
+ if (status_t status = android::AudioSystem::getMmapPolicyInfo(
+ AudioMMapPolicyType::EXCLUSIVE, &policyInfos); status == NO_ERROR) {
mmapExclusivePolicy = AAudio_getAAudioPolicy(
policyInfos, AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT_AIDL);
+ ALOGD("%s, system mmap exclusive policy is %d", __func__, mmapExclusivePolicy);
+ } else {
+ ALOGD("%s, failed to query mmap exclusive policy, error=%d", __func__, status);
}
if (mmapExclusivePolicy == AAUDIO_UNSPECIFIED) {
mmapExclusivePolicy = AAUDIO_MMAP_EXCLUSIVE_POLICY_DEFAULT;
}
+ ALOGD("%s, final mmap exclusive policy is %d", __func__, mmapExclusivePolicy);
aaudio_sharing_mode_t sharingMode = getSharingMode();
if ((sharingMode == AAUDIO_SHARING_MODE_EXCLUSIVE)
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 5785537..61204ae 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -158,6 +158,7 @@
"framework-permission-aidl-cpp",
"libbinder",
"libmediametrics",
+ "libmediautils",
"spatializer-aidl-cpp",
],
@@ -358,8 +359,6 @@
"aidl/android/media/AudioMixerBehavior.aidl",
"aidl/android/media/AudioOffloadMode.aidl",
"aidl/android/media/AudioPolicyDeviceState.aidl",
- "aidl/android/media/AudioPolicyForceUse.aidl",
- "aidl/android/media/AudioPolicyForcedConfig.aidl",
"aidl/android/media/AudioProductStrategy.aidl",
"aidl/android/media/AudioVolumeGroup.aidl",
"aidl/android/media/DeviceRole.aidl",
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 7f5a165..5b954f7 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -79,6 +79,17 @@
return NO_ERROR;
}
+status_t AudioRecord::logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage,
+ const std::string& func) {
+ if (status != NO_ERROR) {
+ if (!func.empty()) mMediaMetrics.markError(status, func.c_str());
+ ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+ reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
+ }
+ mStatus = status;
+ return mStatus;
+}
+
// ---------------------------------------------------------------------------
void AudioRecord::MediaMetrics::gather(const AudioRecord *record)
@@ -246,13 +257,28 @@
if (pid == -1 || (callingPid != myPid)) {
adjPid = callingPid;
}
- mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(adjPid));
-
+ auto clientAttributionSourcePid = legacy2aidl_pid_t_int32_t(adjPid);
+ if (!clientAttributionSourcePid.ok()) {
+ return logIfErrorAndReturnStatus(BAD_VALUE,
+ StringPrintf("%s: received invalid client attribution "
+ "source pid, pid: %d, sessionId: %d",
+ __func__, pid, sessionId),
+ __func__);
+ }
+ mClientAttributionSource.pid = clientAttributionSourcePid.value();
uid_t adjUid = uid;
if (uid == -1 || (callingPid != myPid)) {
adjUid = IPCThreadState::self()->getCallingUid();
}
- mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(adjUid));
+ auto clientAttributionSourceUid = legacy2aidl_uid_t_int32_t(adjUid);
+ if (!clientAttributionSourceUid.ok()) {
+ return logIfErrorAndReturnStatus(BAD_VALUE,
+ StringPrintf("%s: received invalid client attribution "
+ "source uid, pid: %d, session id: %d",
+ __func__, pid, sessionId),
+ __func__);
+ }
+ mClientAttributionSource.uid = clientAttributionSourceUid.value();
mTracker.reset(new RecordingActivityTracker());
@@ -268,7 +294,6 @@
mSelectedMicFieldDimension = microphoneFieldDimension;
mMaxSharedAudioHistoryMs = maxSharedAudioHistoryMs;
- std::string errorMessage;
// Copy the state variables early so they are available for error reporting.
if (pAttributes == nullptr) {
mAttributes = AUDIO_ATTRIBUTES_INITIALIZER;
@@ -311,38 +336,48 @@
break;
case TRANSFER_CALLBACK:
if (callback == nullptr) {
- errorMessage = StringPrintf(
- "%s: Transfer type TRANSFER_CALLBACK but callback == nullptr", __func__);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Transfer type TRANSFER_CALLBACK but callback == nullptr, "
+ "pid: %d, session id: %d",
+ __func__, pid, sessionId),
+ __func__);
}
break;
case TRANSFER_OBTAIN:
case TRANSFER_SYNC:
break;
default:
- errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, mTransfer);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Invalid transfer type %d, pid: %d, session id: %d", __func__,
+ mTransfer, pid, sessionId),
+ __func__);
}
// invariant that mAudioRecord != 0 is true only after set() returns successfully
if (mAudioRecord != 0) {
- errorMessage = StringPrintf("%s: Track already in use", __func__);
- status = INVALID_OPERATION;
- goto error;
+ return logIfErrorAndReturnStatus(
+ INVALID_OPERATION,
+ StringPrintf("%s: Track already in use, pid: %d, session id: %d", __func__, pid,
+ sessionId),
+ __func__);
}
if (!audio_is_valid_format(mFormat)) {
- errorMessage = StringPrintf("%s: Format %#x is not valid", __func__, mFormat);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Format %#x is not valid, pid: %d, session id: %d", __func__,
+ mFormat, pid, sessionId),
+ __func__);
}
if (!audio_is_input_channel(mChannelMask)) {
- errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, mChannelMask);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Invalid channel mask %#x, pid: %d, session id: %d", __func__,
+ mChannelMask, pid, sessionId),
+ __func__);
}
mChannelCount = audio_channel_count_from_in_mask(mChannelMask);
@@ -376,7 +411,8 @@
mAudioRecordThread.clear();
}
// bypass error message to avoid logging twice (createRecord_l logs the error).
- goto exit;
+ mStatus = status;
+ return mStatus;
}
// TODO: add audio hardware input latency here
@@ -392,15 +428,7 @@
mFramesRead = 0;
mFramesReadServerOffset = 0;
-error:
- if (status != NO_ERROR) {
- mMediaMetrics.markError(status, __FUNCTION__);
- ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
- reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
- }
-exit:
- mStatus = status;
- return status;
+ return logIfErrorAndReturnStatus(status, "", __func__);
}
// -------------------------------------------------------------------------
@@ -801,12 +829,10 @@
status_t status;
static const int32_t kMaxCreateAttempts = 3;
int32_t remainingAttempts = kMaxCreateAttempts;
- std::string errorMessage;
if (audioFlinger == 0) {
- errorMessage = StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId);
- status = NO_INIT;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ NO_INIT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId), "");
}
// mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -864,16 +890,34 @@
do {
media::CreateRecordResponse response;
- status = audioFlinger->createRecord(VALUE_OR_FATAL(input.toAidl()), response);
- output = VALUE_OR_FATAL(IAudioFlinger::CreateRecordOutput::fromAidl(response));
+ auto aidlInput = input.toAidl();
+ if (!aidlInput.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s(%d): Could not create record due to invalid input", __func__,
+ mPortId),
+ "");
+ }
+ status = audioFlinger->createRecord(aidlInput.value(), response);
+
+ auto recordOutput = IAudioFlinger::CreateRecordOutput::fromAidl(response);
+ if (!recordOutput.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s(%d): Could not create record output due to invalid response",
+ __func__, mPortId),
+ "");
+ }
+ output = recordOutput.value();
if (status == NO_ERROR) {
break;
}
if (status != FAILED_TRANSACTION || --remainingAttempts <= 0) {
- errorMessage = StringPrintf(
- "%s(%d): AudioFlinger could not create record track, status: %d",
- __func__, mPortId, status);
- goto exit;
+ return logIfErrorAndReturnStatus(
+ status,
+ StringPrintf("%s(%d): AudioFlinger could not create record track, status: %d",
+ __func__, mPortId, status),
+ "");
}
// FAILED_TRANSACTION happens under very specific conditions causing a state mismatch
// between audio policy manager and audio flinger during the input stream open sequence
@@ -908,9 +952,9 @@
mHalFormat = output.halConfig.format;
if (output.cblk == 0) {
- errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
- status = NO_INIT;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ NO_INIT, StringPrintf("%s(%d): Could not get control block", __func__, mPortId),
+ "");
}
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
@@ -918,10 +962,9 @@
// issue (e.g. by copying).
iMemPointer = output.cblk ->unsecurePointer();
if (iMemPointer == NULL) {
- errorMessage = StringPrintf(
- "%s(%d): Could not get control block pointer", __func__, mPortId);
- status = NO_INIT;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ NO_INIT,
+ StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId), "");
}
cblk = static_cast<audio_track_cblk_t*>(iMemPointer);
@@ -938,10 +981,9 @@
// issue (e.g. by copying).
buffers = output.buffers->unsecurePointer();
if (buffers == NULL) {
- errorMessage = StringPrintf(
- "%s(%d): Could not get buffer pointer", __func__, mPortId);
- status = NO_INIT;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ NO_INIT,
+ StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId), "");
}
}
@@ -1033,15 +1075,8 @@
.set(AMEDIAMETRICS_PROP_SELECTEDMICFIELDDIRECTION, (double)mSelectedMicFieldDimension)
.record();
-exit:
- if (status != NO_ERROR) {
- ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
- reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
- }
-
- mStatus = status;
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
- return status;
+ return logIfErrorAndReturnStatus(status, "", "");
}
// Report error associated with the event and some configuration details.
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 55f74e1..769475c 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -60,6 +60,8 @@
using media::audio::common::AudioMMapPolicyInfo;
using media::audio::common::AudioMMapPolicyType;
using media::audio::common::AudioOffloadInfo;
+using media::audio::common::AudioPolicyForceUse;
+using media::audio::common::AudioPolicyForcedConfig;
using media::audio::common::AudioSource;
using media::audio::common::AudioStreamType;
using media::audio::common::AudioUsage;
@@ -306,11 +308,11 @@
}
status_t AudioSystem::setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output) {
+ bool muted, audio_io_handle_t output) {
if (uint32_t(stream) >= AUDIO_STREAM_CNT) return BAD_VALUE;
const sp<IAudioFlinger> af = get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- af->setStreamVolume(stream, value, output);
+ af->setStreamVolume(stream, value, muted, output);
return NO_ERROR;
}
@@ -323,14 +325,15 @@
}
status_t AudioSystem::setPortsVolume(
- const std::vector<audio_port_handle_t>& portIds, float volume, audio_io_handle_t output) {
+ const std::vector<audio_port_handle_t>& portIds, float volume, bool muted,
+ audio_io_handle_t output) {
const sp<IAudioFlinger> af = get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(
portIds, legacy2aidl_audio_port_handle_t_int32_t));
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
- af->setPortsVolume(portIdsAidl, volume, outputAidl);
+ af->setPortsVolume(portIdsAidl, volume, muted, outputAidl);
return NO_ERROR;
}
@@ -1054,9 +1057,9 @@
if (aps == 0) return AUDIO_POLICY_FORCE_NONE;
auto result = [&]() -> ConversionResult<audio_policy_forced_cfg_t> {
- media::AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
+ AudioPolicyForceUse usageAidl = VALUE_OR_RETURN(
legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(usage));
- media::AudioPolicyForcedConfig configAidl;
+ AudioPolicyForcedConfig configAidl;
RETURN_IF_ERROR(statusTFromBinderStatus(
aps->getForceUse(usageAidl, &configAidl)));
return aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(configAidl);
@@ -1094,7 +1097,8 @@
std::vector<audio_io_handle_t>* secondaryOutputs,
bool *isSpatialized,
bool *isBitPerfect,
- float *volume) {
+ float *volume,
+ bool *muted) {
if (attr == nullptr) {
ALOGE("%s NULL audio attributes", __func__);
return BAD_VALUE;
@@ -1161,6 +1165,7 @@
*attr = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioAttributes_audio_attributes_t(responseAidl.attr));
*volume = responseAidl.volume;
+ *muted = responseAidl.muted;
return OK;
}
@@ -1324,6 +1329,7 @@
status_t AudioSystem::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
+ bool muted,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
@@ -1334,7 +1340,7 @@
AudioDeviceDescription deviceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_devices_t_AudioDeviceDescription(device));
return statusTFromBinderStatus(
- aps->setStreamVolumeIndex(streamAidl, deviceAidl, indexAidl));
+ aps->setStreamVolumeIndex(streamAidl, deviceAidl, indexAidl, muted));
}
status_t AudioSystem::getStreamVolumeIndex(audio_stream_type_t stream,
@@ -1358,6 +1364,7 @@
status_t AudioSystem::setVolumeIndexForAttributes(const audio_attributes_t& attr,
int index,
+ bool muted,
audio_devices_t device) {
const sp<IAudioPolicyService> aps = get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
@@ -1368,7 +1375,7 @@
AudioDeviceDescription deviceAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_devices_t_AudioDeviceDescription(device));
return statusTFromBinderStatus(
- aps->setVolumeIndexForAttributes(attrAidl, deviceAidl, indexAidl));
+ aps->setVolumeIndexForAttributes(attrAidl, deviceAidl, indexAidl, muted));
}
status_t AudioSystem::getVolumeIndexForAttributes(const audio_attributes_t& attr,
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 336af36..d7c0b5b 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -188,6 +188,14 @@
return result.value_or(false);
}
+status_t AudioTrack::logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage) {
+ if (status != NO_ERROR) {
+ ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
+ reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
+ }
+ mStatus = status;
+ return mStatus;
+}
// ---------------------------------------------------------------------------
void AudioTrack::MediaMetrics::gather(const AudioTrack *track)
@@ -365,6 +373,10 @@
mSessionId, IPCThreadState::self()->getCallingPid(), clientPid);
AudioSystem::releaseAudioSessionId(mSessionId, clientPid);
}
+
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
+ }
}
void AudioTrack::stopAndJoinCallbacks() {
@@ -413,9 +425,16 @@
uint32_t channelCount;
pid_t callingPid;
pid_t myPid;
- uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
- pid_t pid = VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(attributionSource.pid));
- std::string errorMessage;
+ auto uid = aidl2legacy_int32_t_uid_t(attributionSource.uid);
+ auto pid = aidl2legacy_int32_t_pid_t(attributionSource.pid);
+ if (!uid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: received invalid attribution source uid", __func__));
+ }
+ if (!pid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: received invalid attribution source pid", __func__));
+ }
// Note mPortId is not valid until the track is created, so omit mPortId in ALOG for set.
ALOGV("%s(): streamType %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
"flags %#x, notificationFrames %d, sessionId %d, transferType %d, uid %d, pid %d",
@@ -486,34 +505,33 @@
case TRANSFER_CALLBACK:
case TRANSFER_SYNC_NOTIF_CALLBACK:
if (callback == nullptr || sharedBuffer != 0) {
- errorMessage = StringPrintf(
- "%s: Transfer type %s but callback == nullptr || sharedBuffer != 0",
- convertTransferToText(transferType), __func__);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf(
+ "%s: Transfer type %s but callback == nullptr || sharedBuffer != 0",
+ convertTransferToText(transferType), __func__));
}
break;
case TRANSFER_OBTAIN:
case TRANSFER_SYNC:
if (sharedBuffer != 0) {
- errorMessage = StringPrintf(
- "%s: Transfer type TRANSFER_OBTAIN but sharedBuffer != 0", __func__);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Transfer type TRANSFER_OBTAIN but sharedBuffer != 0",
+ __func__));
}
break;
case TRANSFER_SHARED:
if (sharedBuffer == 0) {
- errorMessage = StringPrintf(
- "%s: Transfer type TRANSFER_SHARED but sharedBuffer == 0", __func__);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: Transfer type TRANSFER_SHARED but sharedBuffer == 0",
+ __func__));
}
break;
default:
- errorMessage = StringPrintf("%s: Invalid transfer type %d", __func__, transferType);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: Invalid transfer type %d", __func__, transferType));
}
mSharedBuffer = sharedBuffer;
mTransfer = transferType;
@@ -524,9 +542,8 @@
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
- errorMessage = StringPrintf("%s: Track already in use", __func__);
- status = INVALID_OPERATION;
- goto error;
+ return logIfErrorAndReturnStatus(INVALID_OPERATION,
+ StringPrintf("%s: Track already in use", __func__));
}
// handle default values first.
@@ -535,9 +552,8 @@
}
if (pAttributes == NULL) {
if (uint32_t(streamType) >= AUDIO_STREAM_PUBLIC_CNT) {
- errorMessage = StringPrintf("%s: Invalid stream type %d", __func__, streamType);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: Invalid stream type %d", __func__, streamType));
}
mOriginalStreamType = streamType;
} else {
@@ -546,15 +562,13 @@
// validate parameters
if (!audio_is_valid_format(format)) {
- errorMessage = StringPrintf("%s: Invalid format %#x", __func__, format);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(BAD_VALUE,
+ StringPrintf("%s: Invalid format %#x", __func__, format));
}
if (!audio_is_output_channel(channelMask)) {
- errorMessage = StringPrintf("%s: Invalid channel mask %#x", __func__, channelMask);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: Invalid channel mask %#x", __func__, channelMask));
}
channelCount = audio_channel_count_from_out_mask(channelMask);
mChannelCount = channelCount;
@@ -569,10 +583,9 @@
// sampling rate must be specified for direct outputs
if (sampleRate == 0 && (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
- errorMessage = StringPrintf(
- "%s: sample rate must be specified for direct outputs", __func__);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: sample rate must be specified for direct outputs", __func__));
}
// 1.0 <= mMaxRequiredSpeed <= AUDIO_TIMESTRETCH_SPEED_MAX
mMaxRequiredSpeed = min(max(maxRequiredSpeed, 1.0f), AUDIO_TIMESTRETCH_SPEED_MAX);
@@ -600,17 +613,16 @@
mNotificationsPerBufferReq = 0;
} else {
if (!(mFlags & AUDIO_OUTPUT_FLAG_FAST)) {
- errorMessage = StringPrintf(
- "%s: notificationFrames=%d not permitted for non-fast track",
- __func__, notificationFrames);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: notificationFrames=%d not permitted for non-fast track",
+ __func__, notificationFrames));
}
if (frameCount > 0) {
- ALOGE("%s(): notificationFrames=%d not permitted with non-zero frameCount=%zu",
- __func__, notificationFrames, frameCount);
- status = BAD_VALUE;
- goto error;
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s(): notificationFrames=%d not permitted "
+ "with non-zero frameCount=%zu",
+ __func__, notificationFrames, frameCount));
}
mNotificationFramesReq = 0;
const uint32_t minNotificationsPerBuffer = 1;
@@ -627,12 +639,24 @@
mClientAttributionSource = AttributionSourceState(attributionSource);
callingPid = IPCThreadState::self()->getCallingPid();
myPid = getpid();
- if (uid == -1 || (callingPid != myPid)) {
- mClientAttributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(
- IPCThreadState::self()->getCallingUid()));
+ if (uid.value() == -1 || (callingPid != myPid)) {
+ auto clientAttributionSourceUid =
+ legacy2aidl_uid_t_int32_t(IPCThreadState::self()->getCallingUid());
+ if (!clientAttributionSourceUid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: received invalid client attribution source uid", __func__));
+ }
+ mClientAttributionSource.uid = clientAttributionSourceUid.value();
}
- if (pid == (pid_t)-1 || (callingPid != myPid)) {
- mClientAttributionSource.pid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(callingPid));
+ if (pid.value() == (pid_t)-1 || (callingPid != myPid)) {
+ auto clientAttributionSourcePid = legacy2aidl_uid_t_int32_t(callingPid);
+ if (!clientAttributionSourcePid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: received invalid client attribution source pid", __func__));
+ }
+ mClientAttributionSource.pid = clientAttributionSourcePid.value();
}
mAuxEffectId = 0;
mCallback = callback;
@@ -655,7 +679,8 @@
mAudioTrackThread.clear();
}
// We do not goto error to prevent double-logging errors.
- goto exit;
+ mStatus = status;
+ return mStatus;
}
mLoopCount = 0;
@@ -670,7 +695,7 @@
mReleased = 0;
mStartNs = 0;
mStartFromZeroUs = 0;
- AudioSystem::acquireAudioSessionId(mSessionId, pid, uid);
+ AudioSystem::acquireAudioSessionId(mSessionId, pid.value(), uid.value());
mSequence = 1;
mObservedSequence = mSequence;
mInUnderrun = false;
@@ -688,15 +713,7 @@
mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
mVolumeHandler = new media::VolumeHandler();
-error:
- if (status != NO_ERROR) {
- ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
- reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
- }
- // fall through
-exit:
- mStatus = status;
- return status;
+ return logIfErrorAndReturnStatus(status, "");
}
@@ -723,8 +740,22 @@
audio_port_handle_t selectedDeviceId)
{
AttributionSourceState attributionSource;
- attributionSource.uid = VALUE_OR_FATAL(legacy2aidl_uid_t_int32_t(uid));
- attributionSource.pid = VALUE_OR_FATAL(legacy2aidl_pid_t_int32_t(pid));
+ auto attributionSourceUid = legacy2aidl_uid_t_int32_t(uid);
+ if (!attributionSourceUid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: received invalid attribution source uid, uid: %d, session id: %d",
+ __func__, uid, sessionId));
+ }
+ attributionSource.uid = attributionSourceUid.value();
+ auto attributionSourcePid = legacy2aidl_pid_t_int32_t(pid);
+ if (!attributionSourcePid.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s: received invalid attribution source pid, pid: %d, sessionId: %d",
+ __func__, pid, sessionId));
+ }
+ attributionSource.pid = attributionSourcePid.value();
attributionSource.token = sp<BBinder>::make();
if (callback) {
mLegacyCallbackWrapper = sp<LegacyCallbackWrapper>::make(callback, user);
@@ -1804,15 +1835,11 @@
status_t AudioTrack::createTrack_l()
{
status_t status;
- bool callbackAdded = false;
- std::string errorMessage;
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
- errorMessage = StringPrintf("%s(%d): Could not get audioflinger",
- __func__, mPortId);
- status = DEAD_OBJECT;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ DEAD_OBJECT, StringPrintf("%s(%d): Could not get audioflinger", __func__, mPortId));
}
{
@@ -1880,21 +1907,31 @@
input.audioTrackCallback = mAudioTrackCallback;
media::CreateTrackResponse response;
- status = audioFlinger->createTrack(VALUE_OR_FATAL(input.toAidl()), response);
+ auto aidlInput = input.toAidl();
+ if (!aidlInput.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s(%d): Could not create track due to invalid input",
+ __func__, mPortId));
+ }
+ status = audioFlinger->createTrack(aidlInput.value(), response);
IAudioFlinger::CreateTrackOutput output{};
if (status == NO_ERROR) {
- output = VALUE_OR_FATAL(IAudioFlinger::CreateTrackOutput::fromAidl(response));
+ auto trackOutput = IAudioFlinger::CreateTrackOutput::fromAidl(response);
+ if (!trackOutput.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE,
+ StringPrintf("%s(%d): Could not create track output due to invalid response",
+ __func__, mPortId));
+ }
+ output = trackOutput.value();
}
if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
- errorMessage = StringPrintf(
- "%s(%d): AudioFlinger could not create track, status: %d output %d",
- __func__, mPortId, status, output.outputId);
- if (status == NO_ERROR) {
- status = INVALID_OPERATION; // device not ready
- }
- goto exit;
+ return logIfErrorAndReturnStatus(
+ status == NO_ERROR ? INVALID_OPERATION : status, // device not ready
+ StringPrintf("%s(%d): AudioFlinger could not create track, status: %d output %d",
+ __func__, mPortId, status, output.outputId));
}
ALOG_ASSERT(output.audioTrack != 0);
@@ -1924,22 +1961,22 @@
// FIXME compare to AudioRecord
std::optional<media::SharedFileRegion> sfr;
output.audioTrack->getCblk(&sfr);
- sp<IMemory> iMem = VALUE_OR_FATAL(aidl2legacy_NullableSharedFileRegion_IMemory(sfr));
- if (iMem == 0) {
- errorMessage = StringPrintf("%s(%d): Could not get control block", __func__, mPortId);
- status = FAILED_TRANSACTION;
- goto exit;
+ auto iMemory = aidl2legacy_NullableSharedFileRegion_IMemory(sfr);
+ if (!iMemory.ok() || iMemory.value() == 0) {
+ return logIfErrorAndReturnStatus(
+ FAILED_TRANSACTION,
+ StringPrintf("%s(%d): Could not get control block", __func__, mPortId));
}
+ sp<IMemory> iMem = iMemory.value();
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
// Either document why it is safe in this case or address the
// issue (e.g. by copying).
void *iMemPointer = iMem->unsecurePointer();
if (iMemPointer == NULL) {
- errorMessage = StringPrintf(
- "%s(%d): Could not get control block pointer", __func__, mPortId);
- status = FAILED_TRANSACTION;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ FAILED_TRANSACTION,
+ StringPrintf("%s(%d): Could not get control block pointer", __func__, mPortId));
}
// invariant that mAudioTrack != 0 is true only after set() returns successfully
if (mAudioTrack != 0) {
@@ -1974,7 +2011,6 @@
AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
}
AudioSystem::addAudioDeviceCallback(this, output.outputId, output.portId);
- callbackAdded = true;
}
mPortId = output.portId;
@@ -1999,11 +2035,9 @@
// issue (e.g. by copying).
buffers = mSharedBuffer->unsecurePointer();
if (buffers == NULL) {
- errorMessage = StringPrintf(
- "%s(%d): Could not get buffer pointer", __func__, mPortId);
- ALOGE("%s", errorMessage.c_str());
- status = FAILED_TRANSACTION;
- goto exit;
+ return logIfErrorAndReturnStatus(
+ FAILED_TRANSACTION,
+ StringPrintf("%s(%d): Could not get buffer pointer", __func__, mPortId));
}
}
@@ -2100,19 +2134,8 @@
}
-exit:
- if (status != NO_ERROR) {
- if (callbackAdded) {
- // note: mOutput is always valid is callbackAdded is true
- AudioSystem::removeAudioDeviceCallback(this, mOutput, mPortId);
- }
- ALOGE_IF(!errorMessage.empty(), "%s", errorMessage.c_str());
- reportError(status, AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE, errorMessage.c_str());
- }
- mStatus = status;
-
// sp<IAudioTrack> track destructor will cause releaseOutput() to be called by AudioFlinger
- return status;
+ return logIfErrorAndReturnStatus(status, "");
}
void AudioTrack::reportError(status_t status, const char *event, const char *message) const
@@ -3203,7 +3226,12 @@
media::AudioTimestampInternal ts;
mAudioTrack->getTimestamp(&ts, &status);
if (status == OK) {
- timestamp = VALUE_OR_FATAL(aidl2legacy_AudioTimestampInternal_AudioTimestamp(ts));
+ auto legacyTs = aidl2legacy_AudioTimestampInternal_AudioTimestamp(ts);
+ if (!legacyTs.ok()) {
+ return logIfErrorAndReturnStatus(
+ BAD_VALUE, StringPrintf("%s: received invalid audio timestamp", __func__));
+ }
+ timestamp = legacyTs.value();
}
} else {
// read timestamp from shared memory
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 9241973..168b47e 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -337,11 +337,12 @@
}
status_t AudioFlingerClientAdapter::setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output) {
+ bool muted, audio_io_handle_t output) {
AudioStreamType streamAidl = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_stream_type_t_AudioStreamType(stream));
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
- return statusTFromBinderStatus(mDelegate->setStreamVolume(streamAidl, value, outputAidl));
+ return statusTFromBinderStatus(
+ mDelegate->setStreamVolume(streamAidl, value, muted, outputAidl));
}
status_t AudioFlingerClientAdapter::setStreamMute(audio_stream_type_t stream, bool muted) {
@@ -351,12 +352,14 @@
}
status_t AudioFlingerClientAdapter::setPortsVolume(
- const std::vector<audio_port_handle_t>& portIds, float volume, audio_io_handle_t output) {
+ const std::vector<audio_port_handle_t> &portIds, float volume, bool muted,
+ audio_io_handle_t output) {
std::vector<int32_t> portIdsAidl = VALUE_OR_RETURN_STATUS(
convertContainer<std::vector<int32_t>>(
portIds, legacy2aidl_audio_port_handle_t_int32_t));
int32_t outputAidl = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_io_handle_t_int32_t(output));
- return statusTFromBinderStatus(mDelegate->setPortsVolume(portIdsAidl, volume, outputAidl));
+ return statusTFromBinderStatus(
+ mDelegate->setPortsVolume(portIdsAidl, volume, muted, outputAidl));
}
status_t AudioFlingerClientAdapter::setMode(audio_mode_t mode) {
@@ -1007,12 +1010,13 @@
}
Status AudioFlingerServerAdapter::setStreamVolume(AudioStreamType stream, float value,
- int32_t output) {
+ bool muted, int32_t output) {
audio_stream_type_t streamLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_AudioStreamType_audio_stream_type_t(stream));
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_int32_t_audio_io_handle_t(output));
- return Status::fromStatusT(mDelegate->setStreamVolume(streamLegacy, value, outputLegacy));
+ return Status::fromStatusT(
+ mDelegate->setStreamVolume(streamLegacy, value, muted, outputLegacy));
}
Status AudioFlingerServerAdapter::setStreamMute(AudioStreamType stream, bool muted) {
@@ -1022,13 +1026,14 @@
}
Status AudioFlingerServerAdapter::setPortsVolume(
- const std::vector<int32_t>& portIds, float volume, int32_t output) {
+ const std::vector<int32_t>& portIds, float volume, bool muted, int32_t output) {
std::vector<audio_port_handle_t> portIdsLegacy = VALUE_OR_RETURN_BINDER(
convertContainer<std::vector<audio_port_handle_t>>(
portIds, aidl2legacy_int32_t_audio_port_handle_t));
audio_io_handle_t outputLegacy = VALUE_OR_RETURN_BINDER(
aidl2legacy_int32_t_audio_io_handle_t(output));
- return Status::fromStatusT(mDelegate->setPortsVolume(portIdsLegacy, volume, outputLegacy));
+ return Status::fromStatusT(
+ mDelegate->setPortsVolume(portIdsLegacy, volume, muted, outputLegacy));
}
Status AudioFlingerServerAdapter::setMode(AudioMode mode) {
diff --git a/media/libaudioclient/PolicyAidlConversion.cpp b/media/libaudioclient/PolicyAidlConversion.cpp
index 163a359..a414cb7 100644
--- a/media/libaudioclient/PolicyAidlConversion.cpp
+++ b/media/libaudioclient/PolicyAidlConversion.cpp
@@ -296,138 +296,6 @@
return unexpected(BAD_VALUE);
}
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl) {
- switch (aidl) {
- case media::AudioPolicyForceUse::COMMUNICATION:
- return AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
- case media::AudioPolicyForceUse::MEDIA:
- return AUDIO_POLICY_FORCE_FOR_MEDIA;
- case media::AudioPolicyForceUse::RECORD:
- return AUDIO_POLICY_FORCE_FOR_RECORD;
- case media::AudioPolicyForceUse::DOCK:
- return AUDIO_POLICY_FORCE_FOR_DOCK;
- case media::AudioPolicyForceUse::SYSTEM:
- return AUDIO_POLICY_FORCE_FOR_SYSTEM;
- case media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO:
- return AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO;
- case media::AudioPolicyForceUse::ENCODED_SURROUND:
- return AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND;
- case media::AudioPolicyForceUse::VIBRATE_RINGING:
- return AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy) {
- switch (legacy) {
- case AUDIO_POLICY_FORCE_FOR_COMMUNICATION:
- return media::AudioPolicyForceUse::COMMUNICATION;
- case AUDIO_POLICY_FORCE_FOR_MEDIA:
- return media::AudioPolicyForceUse::MEDIA;
- case AUDIO_POLICY_FORCE_FOR_RECORD:
- return media::AudioPolicyForceUse::RECORD;
- case AUDIO_POLICY_FORCE_FOR_DOCK:
- return media::AudioPolicyForceUse::DOCK;
- case AUDIO_POLICY_FORCE_FOR_SYSTEM:
- return media::AudioPolicyForceUse::SYSTEM;
- case AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO:
- return media::AudioPolicyForceUse::HDMI_SYSTEM_AUDIO;
- case AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND:
- return media::AudioPolicyForceUse::ENCODED_SURROUND;
- case AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING:
- return media::AudioPolicyForceUse::VIBRATE_RINGING;
- case AUDIO_POLICY_FORCE_USE_CNT:
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl) {
- switch (aidl) {
- case media::AudioPolicyForcedConfig::NONE:
- return AUDIO_POLICY_FORCE_NONE;
- case media::AudioPolicyForcedConfig::SPEAKER:
- return AUDIO_POLICY_FORCE_SPEAKER;
- case media::AudioPolicyForcedConfig::HEADPHONES:
- return AUDIO_POLICY_FORCE_HEADPHONES;
- case media::AudioPolicyForcedConfig::BT_SCO:
- return AUDIO_POLICY_FORCE_BT_SCO;
- case media::AudioPolicyForcedConfig::BT_A2DP:
- return AUDIO_POLICY_FORCE_BT_A2DP;
- case media::AudioPolicyForcedConfig::WIRED_ACCESSORY:
- return AUDIO_POLICY_FORCE_WIRED_ACCESSORY;
- case media::AudioPolicyForcedConfig::BT_CAR_DOCK:
- return AUDIO_POLICY_FORCE_BT_CAR_DOCK;
- case media::AudioPolicyForcedConfig::BT_DESK_DOCK:
- return AUDIO_POLICY_FORCE_BT_DESK_DOCK;
- case media::AudioPolicyForcedConfig::ANALOG_DOCK:
- return AUDIO_POLICY_FORCE_ANALOG_DOCK;
- case media::AudioPolicyForcedConfig::DIGITAL_DOCK:
- return AUDIO_POLICY_FORCE_DIGITAL_DOCK;
- case media::AudioPolicyForcedConfig::NO_BT_A2DP:
- return AUDIO_POLICY_FORCE_NO_BT_A2DP;
- case media::AudioPolicyForcedConfig::SYSTEM_ENFORCED:
- return AUDIO_POLICY_FORCE_SYSTEM_ENFORCED;
- case media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED:
- return AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED;
- case media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER;
- case media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS;
- case media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL:
- return AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL;
- case media::AudioPolicyForcedConfig::BT_BLE:
- return AUDIO_POLICY_FORCE_BT_BLE;
- }
- return unexpected(BAD_VALUE);
-}
-
-ConversionResult<media::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy) {
- switch (legacy) {
- case AUDIO_POLICY_FORCE_NONE:
- return media::AudioPolicyForcedConfig::NONE;
- case AUDIO_POLICY_FORCE_SPEAKER:
- return media::AudioPolicyForcedConfig::SPEAKER;
- case AUDIO_POLICY_FORCE_HEADPHONES:
- return media::AudioPolicyForcedConfig::HEADPHONES;
- case AUDIO_POLICY_FORCE_BT_SCO:
- return media::AudioPolicyForcedConfig::BT_SCO;
- case AUDIO_POLICY_FORCE_BT_A2DP:
- return media::AudioPolicyForcedConfig::BT_A2DP;
- case AUDIO_POLICY_FORCE_WIRED_ACCESSORY:
- return media::AudioPolicyForcedConfig::WIRED_ACCESSORY;
- case AUDIO_POLICY_FORCE_BT_CAR_DOCK:
- return media::AudioPolicyForcedConfig::BT_CAR_DOCK;
- case AUDIO_POLICY_FORCE_BT_DESK_DOCK:
- return media::AudioPolicyForcedConfig::BT_DESK_DOCK;
- case AUDIO_POLICY_FORCE_ANALOG_DOCK:
- return media::AudioPolicyForcedConfig::ANALOG_DOCK;
- case AUDIO_POLICY_FORCE_DIGITAL_DOCK:
- return media::AudioPolicyForcedConfig::DIGITAL_DOCK;
- case AUDIO_POLICY_FORCE_NO_BT_A2DP:
- return media::AudioPolicyForcedConfig::NO_BT_A2DP;
- case AUDIO_POLICY_FORCE_SYSTEM_ENFORCED:
- return media::AudioPolicyForcedConfig::SYSTEM_ENFORCED;
- case AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED:
- return media::AudioPolicyForcedConfig::HDMI_SYSTEM_AUDIO_ENFORCED;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_NEVER:
- return media::AudioPolicyForcedConfig::ENCODED_SURROUND_NEVER;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS:
- return media::AudioPolicyForcedConfig::ENCODED_SURROUND_ALWAYS;
- case AUDIO_POLICY_FORCE_ENCODED_SURROUND_MANUAL:
- return media::AudioPolicyForcedConfig::ENCODED_SURROUND_MANUAL;
- case AUDIO_POLICY_FORCE_BT_BLE:
- return media::AudioPolicyForcedConfig::BT_BLE;
- case AUDIO_POLICY_FORCE_CFG_CNT:
- break;
- }
- return unexpected(BAD_VALUE);
-}
-
ConversionResult<device_role_t>
aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl) {
switch (aidl) {
diff --git a/media/libaudioclient/TEST_MAPPING b/media/libaudioclient/TEST_MAPPING
index 68dba34..29b876c 100644
--- a/media/libaudioclient/TEST_MAPPING
+++ b/media/libaudioclient/TEST_MAPPING
@@ -47,12 +47,7 @@
"name": "audioeffect_analysis"
},
{
- "name": "CtsVirtualDevicesTestCases",
- "options" : [
- {
- "include-filter": "android.virtualdevice.cts.VirtualAudioTest"
- }
- ]
+ "name": "CtsVirtualDevicesAudioTestCases"
}
]
}
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index 79fcea8..d325d0a 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -1033,17 +1033,11 @@
mState = TONE_IDLE;
- if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
- ALOGE("Unable to marshal AudioFlinger");
- return;
- }
mThreadCanCallJava = threadCanCallJava;
mStreamType = streamType;
mVolume = volume;
mpToneDesc = NULL;
mpNewToneDesc = NULL;
- // Generate tone by chunks of 20 ms to keep cadencing precision
- mProcessSize = (mSamplingRate * 20) / 1000;
char value[PROPERTY_VALUE_MAX];
if (property_get("gsm.operator.iso-country", value, "") == 0) {
@@ -1321,21 +1315,21 @@
mpAudioTrack = new AudioTrack(attributionSource);
ALOGV("AudioTrack(%p) created", mpAudioTrack.get());
+
audio_attributes_t attr;
audio_stream_type_t streamType = mStreamType;
- if (mStreamType == AUDIO_STREAM_VOICE_CALL) {
+ if (mStreamType == AUDIO_STREAM_VOICE_CALL || mStreamType == AUDIO_STREAM_BLUETOOTH_SCO) {
streamType = AUDIO_STREAM_DTMF;
}
attr = AudioSystem::streamTypeToAttributes(streamType);
attr.flags = static_cast<audio_flags_mask_t>(attr.flags | AUDIO_FLAG_LOW_LATENCY);
- const size_t frameCount = mProcessSize;
status_t status = mpAudioTrack->set(
AUDIO_STREAM_DEFAULT,
0, // sampleRate
AUDIO_FORMAT_PCM_16_BIT,
AUDIO_CHANNEL_OUT_MONO,
- frameCount,
+ 0, // frameCount
AUDIO_OUTPUT_FLAG_NONE,
wp<AudioTrack::IAudioTrackCallback>::fromExisting(this),
0, // notificationFrames
@@ -1355,6 +1349,10 @@
return false;
}
+ mSamplingRate = mpAudioTrack->getSampleRate();
+ // Generate tone by chunks of 20 ms to keep cadencing precision
+ mProcessSize = (mSamplingRate * 20) / 1000;
+
mpAudioTrack->setVolume(mVolume);
mState = TONE_INIT;
return true;
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 4fc1c44..bc38251 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -38,12 +38,12 @@
player_type_t playerType, audio_usage_t usage,
audio_session_t sessionId) {
PlayerBase::init(playerType, usage, sessionId);
- mAudioTrack = pat;
- if (mAudioTrack != 0) {
+ mAudioTrack.store(pat);
+ if (pat != 0) {
mCallbackHandle = callback;
mSelfAudioDeviceCallback = new SelfAudioDeviceCallback(*this);
- mAudioTrack->addAudioDeviceCallback(mSelfAudioDeviceCallback);
- mAudioTrack->setPlayerIId(mPIId); // set in PlayerBase::init().
+ pat->addAudioDeviceCallback(mSelfAudioDeviceCallback);
+ pat->setPlayerIId(mPIId); // set in PlayerBase::init().
}
}
@@ -65,12 +65,15 @@
}
void TrackPlayerBase::doDestroy() {
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
- mAudioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
+ sp<AudioTrack> audioTrack = getAudioTrack();
+
+ // Note that there may still be another reference in post-unlock phase of SetPlayState
+ clearAudioTrack();
+
+ if (audioTrack != 0) {
+ audioTrack->stop();
+ audioTrack->removeAudioDeviceCallback(mSelfAudioDeviceCallback);
mSelfAudioDeviceCallback.clear();
- // Note that there may still be another reference in post-unlock phase of SetPlayState
- mAudioTrack.clear();
}
}
@@ -87,16 +90,16 @@
// Implementation of IPlayer
status_t TrackPlayerBase::playerStart() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- status = mAudioTrack->start();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ status = audioTrack->start();
}
return status;
}
status_t TrackPlayerBase::playerPause() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- mAudioTrack->pause();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ audioTrack->pause();
status = NO_ERROR;
}
return status;
@@ -105,8 +108,8 @@
status_t TrackPlayerBase::playerStop() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
- mAudioTrack->stop();
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
+ audioTrack->stop();
status = NO_ERROR;
}
return status;
@@ -118,10 +121,10 @@
status_t TrackPlayerBase::doSetVolume() {
status_t status = NO_INIT;
- if (mAudioTrack != 0) {
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
float tl = mPlayerVolumeL * mPanMultiplierL * mVolumeMultiplierL;
float tr = mPlayerVolumeR * mPanMultiplierR * mVolumeMultiplierR;
- mAudioTrack->setVolume(tl, tr);
+ audioTrack->setVolume(tl, tr);
status = NO_ERROR;
}
return status;
@@ -140,10 +143,9 @@
if (s != OK) {
return binderStatusFromStatusT(s);
}
-
- if (mAudioTrack != 0) {
+ if (sp<AudioTrack> audioTrack = getAudioTrack(); audioTrack != 0) {
ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
- VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
+ VolumeShaper::Status status = audioTrack->applyVolumeShaper(spConfiguration, spOperation);
if (status < 0) { // a non-negative value is the volume shaper id.
ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
deleted file mode 100644
index 9bb0605..0000000
--- a/media/libaudioclient/aidl/android/media/AudioPolicyForceUse.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-/**
- * {@hide}
- */
-@Backing(type="int")
-enum AudioPolicyForceUse {
- COMMUNICATION = 0,
- MEDIA = 1,
- RECORD = 2,
- DOCK = 3,
- SYSTEM = 4,
- HDMI_SYSTEM_AUDIO = 5,
- ENCODED_SURROUND = 6,
- VIBRATE_RINGING = 7,
-}
diff --git a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl b/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
deleted file mode 100644
index 111bb2f..0000000
--- a/media/libaudioclient/aidl/android/media/AudioPolicyForcedConfig.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.media;
-
-/**
- * {@hide}
- */
-@Backing(type="int")
-enum AudioPolicyForcedConfig {
- NONE = 0,
- SPEAKER = 1,
- HEADPHONES = 2,
- BT_SCO = 3,
- BT_A2DP = 4,
- WIRED_ACCESSORY = 5,
- BT_CAR_DOCK = 6,
- BT_DESK_DOCK = 7,
- ANALOG_DOCK = 8,
- DIGITAL_DOCK = 9,
- NO_BT_A2DP = 10, /* A2DP sink is not preferred to speaker or wired HS */
- SYSTEM_ENFORCED = 11,
- HDMI_SYSTEM_AUDIO_ENFORCED = 12,
- ENCODED_SURROUND_NEVER = 13,
- ENCODED_SURROUND_ALWAYS = 14,
- ENCODED_SURROUND_MANUAL = 15,
- BT_BLE = 16,
-}
diff --git a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
index 4b26d5b..d3975c0 100644
--- a/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
+++ b/media/libaudioclient/aidl/android/media/GetOutputForAttrResponse.aidl
@@ -41,4 +41,6 @@
AudioAttributes attr;
/** initial port volume for the new audio track */
float volume;
+ /** initial port muted state for the new audio track */
+ boolean muted;
}
diff --git a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
index 1c825bc..474ab11 100644
--- a/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioFlingerService.aidl
@@ -96,15 +96,17 @@
/*
* Set stream type state. This will probably be used by
* the preference panel, mostly.
+ * This method is deprecated. Please use the setPortsVolume method instead.
*/
- void setStreamVolume(AudioStreamType stream, float value, int /* audio_io_handle_t */ output);
+ void setStreamVolume(AudioStreamType stream, float value, boolean muted,
+ int /* audio_io_handle_t */ output);
void setStreamMute(AudioStreamType stream, boolean muted);
/*
* Set AudioTrack port ids volume attribute. This is the new way of controlling volume from
* AudioPolicyManager to AudioFlinger.
*/
- void setPortsVolume(in int[] /* audio_port_handle_t[] */ portIds, float volume,
+ void setPortsVolume(in int[] /* audio_port_handle_t[] */ portIds, float volume, boolean muted,
int /* audio_io_handle_t */ output);
// set audio mode.
diff --git a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index ac42ea9..40ab938 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -25,8 +25,6 @@
import android.media.AudioOffloadMode;
import android.media.AudioPatchFw;
import android.media.AudioPolicyDeviceState;
-import android.media.AudioPolicyForcedConfig;
-import android.media.AudioPolicyForceUse;
import android.media.AudioPortFw;
import android.media.AudioPortConfigFw;
import android.media.AudioPortRole;
@@ -49,6 +47,8 @@
import android.media.audio.common.AudioDeviceDescription;
import android.media.audio.common.AudioFormatDescription;
import android.media.audio.common.AudioMode;
+import android.media.audio.common.AudioPolicyForcedConfig;
+import android.media.audio.common.AudioPolicyForceUse;
import android.media.audio.common.AudioProfile;
import android.media.audio.common.AudioOffloadInfo;
import android.media.audio.common.AudioPort;
@@ -116,9 +116,9 @@
void releaseInput(int /* audio_port_handle_t */ portId);
- oneway void setDeviceAbsoluteVolumeEnabled(in AudioDevice device,
- boolean enabled,
- AudioStreamType streamToDriveAbs);
+ void setDeviceAbsoluteVolumeEnabled(in AudioDevice device,
+ boolean enabled,
+ AudioStreamType streamToDriveAbs);
void initStreamVolume(AudioStreamType stream,
int indexMin,
@@ -126,14 +126,14 @@
void setStreamVolumeIndex(AudioStreamType stream,
in AudioDeviceDescription device,
- int index);
+ int index, boolean muted);
int getStreamVolumeIndex(AudioStreamType stream,
in AudioDeviceDescription device);
void setVolumeIndexForAttributes(in AudioAttributes attr,
in AudioDeviceDescription device,
- int index);
+ int index, boolean muted);
int getVolumeIndexForAttributes(in AudioAttributes attr,
in AudioDeviceDescription device);
diff --git a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
index 710a656..b0b7e03 100644
--- a/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
+++ b/media/libaudioclient/fuzzer/audioflinger_fuzzer.cpp
@@ -511,11 +511,11 @@
stream = getValue(&mFdp, kStreamtypes);
AudioSystem::setStreamVolume(stream, mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeIntegral<int32_t>());
+ mFdp.ConsumeBool(), mFdp.ConsumeIntegral<int32_t>());
} else {
std::vector <audio_port_handle_t> portsForVolumeChange{};
AudioSystem::setPortsVolume(portsForVolumeChange, mFdp.ConsumeFloatingPoint<float>(),
- mFdp.ConsumeIntegral<int32_t>());
+ mFdp.ConsumeBool(), mFdp.ConsumeIntegral<int32_t>());
}
audio_mode_t mode = getValue(&mFdp, kModes);
AudioSystem::setMode(mode);
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index d4479ef..25d91d3 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -138,6 +138,12 @@
audio_format_t format,
audio_channel_mask_t channelMask);
+ /* Checks for erroneous status, marks error in MediaMetrics, logs the error message.
+ * Updates and returns mStatus.
+ */
+ status_t logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage,
+ const std::string& func);
+
/* How data is transferred from AudioRecord
*/
enum transfer_type {
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 40e5673..31e4f05 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -126,7 +126,7 @@
// set stream volume on specified output
static status_t setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output);
+ bool muted, audio_io_handle_t output);
// mute/unmute stream
static status_t setStreamMute(audio_stream_type_t stream, bool mute);
@@ -135,11 +135,12 @@
* Set volume for given AudioTrack port ids on specified output
* @param portIds to consider
* @param volume to set
+ * @param muted to set
* @param output to consider
* @return NO_ERROR if successful
*/
static status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds,
- float volume, audio_io_handle_t output);
+ float volume, bool muted, audio_io_handle_t output);
// set audio mode in audio hardware
static status_t setMode(audio_mode_t mode);
@@ -345,7 +346,8 @@
std::vector<audio_io_handle_t> *secondaryOutputs,
bool *isSpatialized,
bool *isBitPerfect,
- float *volume);
+ float *volume,
+ bool *muted);
static status_t startOutput(audio_port_handle_t portId);
static status_t stopOutput(audio_port_handle_t portId);
static void releaseOutput(audio_port_handle_t portId);
@@ -391,6 +393,7 @@
int indexMax);
static status_t setStreamVolumeIndex(audio_stream_type_t stream,
int index,
+ bool muted,
audio_devices_t device);
static status_t getStreamVolumeIndex(audio_stream_type_t stream,
int *index,
@@ -398,6 +401,7 @@
static status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
int index,
+ bool muted,
audio_devices_t device);
static status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
int &index,
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 3a001a4..de97863 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -233,8 +233,7 @@
* FIXME This API assumes a route, and so should be deprecated.
*/
- static status_t getMinFrameCount(size_t* frameCount,
- audio_stream_type_t streamType,
+ static status_t getMinFrameCount(size_t* frameCount, audio_stream_type_t streamType,
uint32_t sampleRate);
/* Check if direct playback is possible for the given audio configuration and attributes.
@@ -243,6 +242,11 @@
static bool isDirectOutputSupported(const audio_config_base_t& config,
const audio_attributes_t& attributes);
+ /* Checks for erroneous status, logs the error message.
+ * Updates and returns mStatus.
+ */
+ status_t logIfErrorAndReturnStatus(status_t status, const std::string& errorMessage);
+
/* How data is transferred to AudioTrack
*/
enum transfer_type {
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index a5f3217..21ecb09 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -226,18 +226,19 @@
* the preference panel, mostly.
*/
virtual status_t setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output) = 0;
+ bool muted, audio_io_handle_t output) = 0;
virtual status_t setStreamMute(audio_stream_type_t stream, bool muted) = 0;
/**
* Set volume for given AudioTrack port ids on specified output
* @param portIds to consider
* @param volume to set
+ * @param muted to set
* @param output to consider
* @return NO_ERROR if successful
*/
virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
- audio_io_handle_t output) = 0;
+ bool muted, audio_io_handle_t output) = 0;
// set audio mode
virtual status_t setMode(audio_mode_t mode) = 0;
@@ -428,10 +429,10 @@
status_t setMasterBalance(float balance) override;
status_t getMasterBalance(float* balance) const override;
status_t setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output) override;
+ bool muted, audio_io_handle_t output) override;
status_t setStreamMute(audio_stream_type_t stream, bool muted) override;
status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
- audio_io_handle_t output) override;
+ bool muted, audio_io_handle_t output) override;
status_t setMode(audio_mode_t mode) override;
status_t setMicMute(bool state) override;
bool getMicMute() const override;
@@ -675,10 +676,10 @@
Status setMasterBalance(float balance) override;
Status getMasterBalance(float* _aidl_return) override;
Status setStreamVolume(media::audio::common::AudioStreamType stream,
- float value, int32_t output) override;
+ float value, bool muted, int32_t output) override;
Status setStreamMute(media::audio::common::AudioStreamType stream, bool muted) override;
- Status setPortsVolume(const std::vector<int32_t>& portIds, float volume, int32_t output)
- override;
+ Status setPortsVolume(const std::vector<int32_t>& portIds, float volume, bool muted,
+ int32_t output) override;
Status setMode(media::audio::common::AudioMode mode) override;
Status setMicMute(bool state) override;
Status getMicMute(bool* _aidl_return) override;
diff --git a/media/libaudioclient/include/media/PolicyAidlConversion.h b/media/libaudioclient/include/media/PolicyAidlConversion.h
index ed9ddd6..1b90d6b 100644
--- a/media/libaudioclient/include/media/PolicyAidlConversion.h
+++ b/media/libaudioclient/include/media/PolicyAidlConversion.h
@@ -28,8 +28,6 @@
#include <android/media/AudioMixRouteFlag.h>
#include <android/media/AudioMixType.h>
#include <android/media/AudioOffloadMode.h>
-#include <android/media/AudioPolicyForceUse.h>
-#include <android/media/AudioPolicyForcedConfig.h>
#include <android/media/DeviceRole.h>
#include <media/AidlConversionUtil.h>
@@ -84,16 +82,6 @@
ConversionResult<media::AudioPolicyDeviceState>
legacy2aidl_audio_policy_dev_state_t_AudioPolicyDeviceState(audio_policy_dev_state_t legacy);
-ConversionResult<audio_policy_force_use_t>
-aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(media::AudioPolicyForceUse aidl);
-ConversionResult<media::AudioPolicyForceUse>
-legacy2aidl_audio_policy_force_use_t_AudioPolicyForceUse(audio_policy_force_use_t legacy);
-
-ConversionResult<audio_policy_forced_cfg_t>
-aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(media::AudioPolicyForcedConfig aidl);
-ConversionResult<media::AudioPolicyForcedConfig>
-legacy2aidl_audio_policy_forced_cfg_t_AudioPolicyForcedConfig(audio_policy_forced_cfg_t legacy);
-
ConversionResult<device_role_t>
aidl2legacy_DeviceRole_device_role_t(media::DeviceRole aidl);
ConversionResult<media::DeviceRole>
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index fe88116..8df9ff8 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -19,6 +19,7 @@
#include <media/AudioTrack.h>
#include <media/PlayerBase.h>
+#include <mediautils/Synchronization.h>
namespace android {
@@ -37,10 +38,11 @@
const media::VolumeShaperConfiguration& configuration,
const media::VolumeShaperOperation& operation);
- //FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
- sp<AudioTrack> mAudioTrack;
+ sp<AudioTrack> getAudioTrack() { return mAudioTrack.load(); }
- void setPlayerVolume(float vl, float vr);
+ void clearAudioTrack() { mAudioTrack.store(nullptr); }
+
+ void setPlayerVolume(float vl, float vr);
protected:
@@ -68,6 +70,7 @@
float mPlayerVolumeL, mPlayerVolumeR;
sp<AudioTrack::IAudioTrackCallback> mCallbackHandle;
sp<SelfAudioDeviceCallback> mSelfAudioDeviceCallback;
+ mediautils::atomic_sp<AudioTrack> mAudioTrack;
};
} // namespace android
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 7f55e48..2076045 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -483,8 +483,27 @@
AudioDeviceAddress::make<AudioDeviceAddress::Tag::alsa>(
std::vector<int32_t>{1, 2}))));
+TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) {
+ const std::vector<uint8_t> sAnonymizedAidlAddress {0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD};
+ const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD");
+ auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
+ sAnonymizedLegacyAddress);
+ ASSERT_TRUE(device.ok());
+ ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag());
+ ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get<AudioDeviceAddress::mac>());
+
+ audio_devices_t legacyType;
+ std::string legacyAddress;
+ status_t status =
+ aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress);
+ ASSERT_EQ(OK, status);
+ EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
+ EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress);
+}
+
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam<AudioFormatDescription> {
};
+
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial);
diff --git a/media/libaudioclient/tests/audiorouting_tests.cpp b/media/libaudioclient/tests/audiorouting_tests.cpp
index 8151d39..a3ab9d2 100644
--- a/media/libaudioclient/tests/audiorouting_tests.cpp
+++ b/media/libaudioclient/tests/audiorouting_tests.cpp
@@ -86,7 +86,18 @@
}
}
-TEST(AudioTrackTest, DefaultRoutingTest) {
+class AudioTrackTest
+ : public ::testing::TestWithParam<int> {
+
+public:
+ AudioTrackTest()
+ : mSampleRate(GetParam()){};
+
+ const uint32_t mSampleRate;
+
+};
+
+TEST_P(AudioTrackTest, DefaultRoutingTest) {
audio_port_v7 port;
if (OK != getPortByAttributes(AUDIO_PORT_ROLE_SOURCE, AUDIO_PORT_TYPE_DEVICE,
AUDIO_DEVICE_IN_REMOTE_SUBMIX, "0", port)) {
@@ -95,7 +106,8 @@
// create record instance
sp<AudioCapture> capture = sp<AudioCapture>::make(
- AUDIO_SOURCE_REMOTE_SUBMIX, 48000, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO);
+ AUDIO_SOURCE_REMOTE_SUBMIX, mSampleRate, AUDIO_FORMAT_PCM_16_BIT,
+ AUDIO_CHANNEL_IN_STEREO);
ASSERT_NE(nullptr, capture);
ASSERT_EQ(OK, capture->create()) << "record creation failed";
sp<OnAudioDeviceUpdateNotifier> cbCapture = sp<OnAudioDeviceUpdateNotifier>::make();
@@ -103,7 +115,7 @@
// create playback instance
sp<AudioPlayback> playback = sp<AudioPlayback>::make(
- 48000 /* sampleRate */, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
+ mSampleRate, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
AUDIO_OUTPUT_FLAG_NONE, AUDIO_SESSION_NONE);
ASSERT_NE(nullptr, playback);
ASSERT_EQ(OK, playback->loadResource("/data/local/tmp/bbb_2ch_24kHz_s16le.raw"))
@@ -133,6 +145,12 @@
playback->stop();
}
+INSTANTIATE_TEST_SUITE_P(
+ AudioTrackParameterizedTest,
+ AudioTrackTest,
+ ::testing::Values(44100, 48000)
+);
+
class AudioRoutingTest : public ::testing::Test {
public:
void SetUp() override {
diff --git a/media/libaudioclient/tests/trackplayerbase_tests.cpp b/media/libaudioclient/tests/trackplayerbase_tests.cpp
index 7317bf0..a4dba9b 100644
--- a/media/libaudioclient/tests/trackplayerbase_tests.cpp
+++ b/media/libaudioclient/tests/trackplayerbase_tests.cpp
@@ -54,7 +54,7 @@
mPlayer = new TrackPlayer();
mPlayer->init(track.get(), mPlayer, PLAYER_TYPE_AAUDIO, AUDIO_USAGE_MEDIA,
AUDIO_SESSION_NONE);
- sp<AudioTrack> playerTrack = mPlayer->mAudioTrack;
+ sp<AudioTrack> playerTrack = mPlayer->getAudioTrack();
ASSERT_EQ(playerTrack->initCheck(), NO_ERROR);
mBufferSize = mFrameCount * playerTrack->frameSize();
@@ -74,7 +74,7 @@
void playBuffer() {
bool blocking = true;
- ssize_t nbytes = mPlayer->mAudioTrack->write(mBuffer.data(), mBufferSize, blocking);
+ ssize_t nbytes = mPlayer->getAudioTrack()->write(mBuffer.data(), mBufferSize, blocking);
EXPECT_EQ(nbytes, mBufferSize) << "Did not write all data in blocking mode";
}
diff --git a/media/libaudiohal/impl/DeviceHalAidl.cpp b/media/libaudiohal/impl/DeviceHalAidl.cpp
index 3cc923d..629cd7c 100644
--- a/media/libaudiohal/impl/DeviceHalAidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalAidl.cpp
@@ -22,6 +22,7 @@
#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_ibinder_platform.h>
#include <error/expected_utils.h>
#include <media/AidlConversionCppNdk.h>
#include <media/AidlConversionNdk.h>
@@ -29,6 +30,8 @@
#include <media/AidlConversionUtil.h>
#include <mediautils/TimeCheck.h>
#include <system/audio.h>
+#include <system/thread_defs.h>
+
#include <Utils.h>
#include <utils/Log.h>
@@ -504,8 +507,15 @@
std::shared_ptr<OutputStreamCallbackAidl> streamCb;
if (isOffload) {
streamCb = ndk::SharedRefBase::make<OutputStreamCallbackAidl>(this);
+ ndk::SpAIBinder binder = streamCb->asBinder();
+ AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ AIBinder_setInheritRt(binder.get(), true);
}
auto eventCb = ndk::SharedRefBase::make<OutputStreamEventCallbackAidl>(this);
+ ndk::SpAIBinder binder = eventCb->asBinder();
+ AIBinder_setMinSchedulerPolicy(binder.get(), SCHED_NORMAL, ANDROID_PRIORITY_AUDIO);
+ AIBinder_setInheritRt(binder.get(), true);
+
if (isOffload || isHwAvSync) {
args.offloadInfo = aidlConfig.offloadInfo;
}
diff --git a/media/libaudiohal/impl/DeviceHalHidl.cpp b/media/libaudiohal/impl/DeviceHalHidl.cpp
index 0a262e4..263ef96 100644
--- a/media/libaudiohal/impl/DeviceHalHidl.cpp
+++ b/media/libaudiohal/impl/DeviceHalHidl.cpp
@@ -619,7 +619,14 @@
result != NO_ERROR) {
return result;
}
- return processReturn("setConnectedState", mDevice->setConnectedState(hidlAddress, connected));
+ Return<Result> ret = mDevice->setConnectedState(hidlAddress, connected);
+ if (ret.isOk() || ret == Result::NOT_SUPPORTED) {
+ // The framework is only interested in errors occurring due to connection state handling,
+ // so it can decide whether retrying is needed. If the HAL does not support this operation,
+ // it's not an error.
+ return NO_ERROR;
+ }
+ return processReturn("setConnectedState", ret);
}
error::Result<audio_hw_sync_t> DeviceHalHidl::getHwAvSync() {
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
index a13903b..f719d97 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.cpp
@@ -532,5 +532,13 @@
AudioChannelLayout::LAYOUT_HAPTIC_AB /* mask */);
}
+size_t EffectConversionHelperAidl::getInputChannelCount() const {
+ return getChannelCount(mCommon.input.base.channelMask);
+}
+
+size_t EffectConversionHelperAidl::getOutputChannelCount() const {
+ return getChannelCount(mCommon.output.base.channelMask);
+}
+
} // namespace effect
} // namespace android
diff --git a/media/libaudiohal/impl/EffectConversionHelperAidl.h b/media/libaudiohal/impl/EffectConversionHelperAidl.h
index 50b47a9..e9e9fc2 100644
--- a/media/libaudiohal/impl/EffectConversionHelperAidl.h
+++ b/media/libaudiohal/impl/EffectConversionHelperAidl.h
@@ -51,6 +51,8 @@
size_t getAudioChannelCount() const;
size_t getHapticChannelCount() const;
+ size_t getInputChannelCount() const;
+ size_t getOutputChannelCount() const;
uint8_t mOutputAccessMode = EFFECT_BUFFER_ACCESS_WRITE;
diff --git a/media/libaudiohal/impl/EffectHalAidl.cpp b/media/libaudiohal/impl/EffectHalAidl.cpp
index ea4dbf6..9fdde49 100644
--- a/media/libaudiohal/impl/EffectHalAidl.cpp
+++ b/media/libaudiohal/impl/EffectHalAidl.cpp
@@ -75,7 +75,14 @@
mEffect(effect),
mSessionId(sessionId),
mIoId(ioId),
- mIsProxyEffect(isProxyEffect) {
+ mIsProxyEffect(isProxyEffect),
+ mHalVersion([factory]() {
+ int version = 0;
+ // use factory HAL version because effect can be an EffectProxy instance
+ return factory->getInterfaceVersion(&version).isOk() ? version : 0;
+ }()),
+ mEventFlagDataMqNotEmpty(mHalVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
+ : kEventFlagNotEmpty) {
assert(mFactory != nullptr);
assert(mEffect != nullptr);
createAidlConversion(effect, sessionId, ioId, desc);
@@ -159,6 +166,7 @@
mConversion = std::make_unique<android::effect::AidlConversionVendorExtension>(
effect, sessionId, ioId, desc, mIsProxyEffect);
}
+ mEffectName = mConversion->getDescriptor().common.name;
return OK;
}
@@ -174,100 +182,153 @@
// write to input FMQ here, wait for statusMQ STATUS_OK, and read from output FMQ
status_t EffectHalAidl::process() {
- const std::string effectName = mConversion->getDescriptor().common.name;
State state = State::INIT;
if (mConversion->isBypassing() || !mEffect->getState(&state).isOk() ||
state != State::PROCESSING) {
- ALOGI("%s skipping %s process because it's %s", __func__, effectName.c_str(),
+ ALOGI("%s skipping process because it's %s", mEffectName.c_str(),
mConversion->isBypassing()
? "bypassing"
: aidl::android::hardware::audio::effect::toString(state).c_str());
return -ENODATA;
}
- // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
- auto efGroup = mConversion->getEventFlagGroup();
+ const std::shared_ptr<android::hardware::EventFlag> efGroup = mConversion->getEventFlagGroup();
if (!efGroup) {
- ALOGE("%s invalid efGroup", __func__);
+ ALOGE("%s invalid efGroup", mEffectName.c_str());
return INVALID_OPERATION;
}
- // use IFactory HAL version because IEffect can be an EffectProxy instance
- static const int halVersion = [&]() {
- int version = 0;
- return mFactory->getInterfaceVersion(&version).isOk() ? version : 0;
- }();
+ // reopen if halVersion >= kReopenSupportedVersion and receive kEventFlagDataMqUpdate
+ RETURN_STATUS_IF_ERROR(maybeReopen(efGroup));
+ const size_t samplesWritten = writeToHalInputFmqAndSignal(efGroup);
+ if (0 == samplesWritten) {
+ return INVALID_OPERATION;
+ }
- if (uint32_t efState = 0; halVersion >= kReopenSupportedVersion &&
- ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
+ RETURN_STATUS_IF_ERROR(waitHalStatusFmq(samplesWritten));
+ RETURN_STATUS_IF_ERROR(readFromHalOutputFmq(samplesWritten));
+ return OK;
+}
+
+status_t EffectHalAidl::maybeReopen(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+ if (mHalVersion < kReopenSupportedVersion) {
+ return OK;
+ }
+
+ // check if the DataMq needs any update, timeout at 1ns to avoid being blocked
+ if (uint32_t efState = 0; ::android::OK == efGroup->wait(kEventFlagDataMqUpdate, &efState,
1 /* ns */, true /* retry */) &&
efState & kEventFlagDataMqUpdate) {
- ALOGD("%s %s V%d receive dataMQUpdate eventFlag from HAL", __func__, effectName.c_str(),
- halVersion);
-
- mConversion->reopen();
+ ALOGD("%s V%d receive dataMQUpdate eventFlag from HAL", mEffectName.c_str(), mHalVersion);
+ return mConversion->reopen();
}
- 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;
+ return OK;
+}
+
+size_t EffectHalAidl::writeToHalInputFmqAndSignal(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const {
+ const auto inputQ = mConversion->getInputMQ();
+ if (!inputQ || !inputQ->isValid()) {
+ ALOGE("%s invalid input FMQ", mEffectName.c_str());
+ return 0;
}
- size_t available = inputQ->availableToWrite();
- const size_t floatsToWrite = std::min(available, mInBuffer->getSize() / sizeof(float));
- if (floatsToWrite == 0) {
- ALOGE("%s not able to write, floats in buffer %zu, space in FMQ %zu", __func__,
- mInBuffer->getSize() / sizeof(float), available);
- return INVALID_OPERATION;
- }
- 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;
+ const size_t fmqSpaceSamples = inputQ->availableToWrite();
+ const size_t samplesInBuffer =
+ mInBuffer->audioBuffer()->frameCount * mConversion->getInputChannelCount();
+ const size_t samplesToWrite = std::min(fmqSpaceSamples, samplesInBuffer);
+ if (samplesToWrite == 0) {
+ ALOGE("%s not able to write, samplesInBuffer %zu, fmqSpaceSamples %zu", mEffectName.c_str(),
+ samplesInBuffer, fmqSpaceSamples);
+ return 0;
}
- // for V2 audio effect HAL, expect different EventFlag to avoid bit conflict with FMQ_NOT_EMPTY
- efGroup->wake(halVersion >= kReopenSupportedVersion ? kEventFlagDataMqNotEmpty
- : kEventFlagNotEmpty);
+ const float* const inputRawBuffer = static_cast<const float*>(mInBuffer->audioBuffer()->f32);
+ if (!inputQ->write(inputRawBuffer, samplesToWrite)) {
+ ALOGE("%s failed to write %zu samples to inputQ [avail %zu]", mEffectName.c_str(),
+ samplesToWrite, inputQ->availableToWrite());
+ return 0;
+ }
+
+ efGroup->wake(mEventFlagDataMqNotEmpty);
+ return samplesToWrite;
+}
+
+void EffectHalAidl::writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+ float* const fmqOutputBuffer) const {
+ const auto audioChNum = mConversion->getAudioChannelCount();
+ const auto audioSamples =
+ totalSamples * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
+
+ static constexpr float kHalFloatSampleLimit = 2.0f;
+ // for HapticGenerator, the input data buffer will be updated
+ float* const inputRawBuffer = static_cast<float*>(mInBuffer->audioBuffer()->f32);
+ // accumulate or copy input to output, haptic samples remains all zero
+ if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ accumulate_float(outputRawBuffer, inputRawBuffer, audioSamples);
+ } else {
+ memcpy_to_float_from_float_with_clamping(outputRawBuffer, inputRawBuffer, audioSamples,
+ kHalFloatSampleLimit);
+ }
+ // append the haptic sample at the end of input audio samples
+ memcpy_to_float_from_float_with_clamping(inputRawBuffer + audioSamples,
+ fmqOutputBuffer + audioSamples,
+ totalSamples - audioSamples, kHalFloatSampleLimit);
+}
+
+status_t EffectHalAidl::waitHalStatusFmq(size_t samplesWritten) const {
+ const auto statusQ = mConversion->getStatusMQ();
+ if (const bool statusValid = statusQ && statusQ->isValid(); !statusValid) {
+ ALOGE("%s statusFMQ %s", mEffectName.c_str(), statusValid ? "valid" : "invalid");
+ return INVALID_OPERATION;
+ }
IEffect::Status retStatus{};
if (!statusQ->readBlocking(&retStatus, 1)) {
- ALOGE("%s %s V%d read status from status FMQ failed", __func__, effectName.c_str(),
- halVersion);
+ ALOGE("%s V%d read status from status FMQ failed", mEffectName.c_str(), mHalVersion);
return INVALID_OPERATION;
}
- if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != floatsToWrite ||
+ if (retStatus.status != OK || (size_t)retStatus.fmqConsumed != samplesWritten ||
retStatus.fmqProduced == 0) {
- ALOGE("%s read status failed: %s, consumed %d (of %zu) produced %d", __func__,
- retStatus.toString().c_str(), retStatus.fmqConsumed, floatsToWrite,
- retStatus.fmqProduced);
+ ALOGE("%s read status failed: %s, FMQ consumed %d (of %zu) produced %d",
+ mEffectName.c_str(), retStatus.toString().c_str(), retStatus.fmqConsumed,
+ samplesWritten, retStatus.fmqProduced);
return INVALID_OPERATION;
}
- available = outputQ->availableToRead();
- const size_t floatsToRead = std::min(available, mOutBuffer->getSize() / sizeof(float));
- if (floatsToRead == 0) {
- ALOGE("%s not able to read, buffer space %zu, floats in FMQ %zu", __func__,
- mOutBuffer->getSize() / sizeof(float), available);
+ return OK;
+}
+
+status_t EffectHalAidl::readFromHalOutputFmq(size_t samplesWritten) const {
+ const auto outputQ = mConversion->getOutputMQ();
+ if (const bool outputValid = outputQ && outputQ->isValid(); !outputValid) {
+ ALOGE("%s outputFMQ %s", mEffectName.c_str(), outputValid ? "valid" : "invalid");
return INVALID_OPERATION;
}
- float *outputRawBuffer = mOutBuffer->audioBuffer()->f32;
+ const size_t fmqProducedSamples = outputQ->availableToRead();
+ const size_t bufferSpaceSamples =
+ mOutBuffer->audioBuffer()->frameCount * mConversion->getOutputChannelCount();
+ const size_t samplesToRead = std::min(fmqProducedSamples, bufferSpaceSamples);
+ if (samplesToRead == 0) {
+ ALOGE("%s unable to read, bufferSpace %zu, fmqProduced %zu samplesWritten %zu",
+ mEffectName.c_str(), bufferSpaceSamples, fmqProducedSamples, samplesWritten);
+ return INVALID_OPERATION;
+ }
+
+ float* const outputRawBuffer = static_cast<float*>(mOutBuffer->audioBuffer()->f32);
+ float* fmqOutputBuffer = outputRawBuffer;
std::vector<float> tempBuffer;
// keep original data in the output buffer for accumulate mode or HapticGenerator effect
if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE || mIsHapticGenerator) {
- tempBuffer.resize(floatsToRead);
- outputRawBuffer = tempBuffer.data();
+ tempBuffer.resize(samplesToRead, 0);
+ fmqOutputBuffer = tempBuffer.data();
}
// always read floating point data for AIDL
- if (!outputQ->read(outputRawBuffer, floatsToRead)) {
- ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", __func__, floatsToRead,
- mOutBuffer->audioBuffer());
+ if (!outputQ->read(fmqOutputBuffer, samplesToRead)) {
+ ALOGE("%s failed to read %zu from outputQ to audioBuffer %p", mEffectName.c_str(),
+ samplesToRead, fmqOutputBuffer);
return INVALID_OPERATION;
}
@@ -276,26 +337,10 @@
// offset as input buffer, here we skip the audio samples in output FMQ and append haptic
// samples to the end of input buffer
if (mIsHapticGenerator) {
- static constexpr float kHalFloatSampleLimit = 2.0f;
- assert(floatsToRead == floatsToWrite);
- const auto audioChNum = mConversion->getAudioChannelCount();
- const auto audioSamples =
- floatsToWrite * audioChNum / (audioChNum + mConversion->getHapticChannelCount());
- // accumulate or copy input to output, haptic samples remains all zero
- if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- accumulate_float(mOutBuffer->audioBuffer()->f32, mInBuffer->audioBuffer()->f32,
- audioSamples);
- } else {
- memcpy_to_float_from_float_with_clamping(mOutBuffer->audioBuffer()->f32,
- mInBuffer->audioBuffer()->f32, audioSamples,
- kHalFloatSampleLimit);
- }
- // append the haptic sample at the end of input audio samples
- memcpy_to_float_from_float_with_clamping(mInBuffer->audioBuffer()->f32 + audioSamples,
- outputRawBuffer + audioSamples,
- floatsToRead - audioSamples, kHalFloatSampleLimit);
+ assert(samplesRead == samplesWritten);
+ writeHapticGeneratorData(samplesToRead, outputRawBuffer, fmqOutputBuffer);
} else if (mConversion->mOutputAccessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
- accumulate_float(mOutBuffer->audioBuffer()->f32, outputRawBuffer, floatsToRead);
+ accumulate_float(outputRawBuffer, fmqOutputBuffer, samplesToRead);
}
return OK;
diff --git a/media/libaudiohal/impl/EffectHalAidl.h b/media/libaudiohal/impl/EffectHalAidl.h
index 4f7de7c..a775337 100644
--- a/media/libaudiohal/impl/EffectHalAidl.h
+++ b/media/libaudiohal/impl/EffectHalAidl.h
@@ -73,7 +73,12 @@
const int32_t mSessionId;
const int32_t mIoId;
const bool mIsProxyEffect;
+ const int32_t mHalVersion;
+ // Audio effect HAL v2+ changes flag to kEventFlagDataMqNotEmpty to avoid conflict from using
+ // kEventFlagNotEmpty
+ const uint32_t mEventFlagDataMqNotEmpty;
bool mIsHapticGenerator = false;
+ std::string mEffectName;
std::unique_ptr<EffectConversionHelperAidl> mConversion;
@@ -93,6 +98,14 @@
bool setEffectReverse(bool reverse);
bool needUpdateReturnParam(uint32_t cmdCode);
+ status_t maybeReopen(const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+ void writeHapticGeneratorData(size_t totalSamples, float* const outputRawBuffer,
+ float* const fmqOutputBuffer) const;
+ size_t writeToHalInputFmqAndSignal(
+ const std::shared_ptr<android::hardware::EventFlag>& efGroup) const;
+ status_t waitHalStatusFmq(size_t samplesWritten) const;
+ status_t readFromHalOutputFmq(size_t samplesWritten) const;
+
// The destructor automatically releases the effect.
virtual ~EffectHalAidl();
};
diff --git a/media/libaudiohal/impl/Hal2AidlMapper.cpp b/media/libaudiohal/impl/Hal2AidlMapper.cpp
index f352849..0cdf0f2 100644
--- a/media/libaudiohal/impl/Hal2AidlMapper.cpp
+++ b/media/libaudiohal/impl/Hal2AidlMapper.cpp
@@ -368,16 +368,21 @@
const AudioConfig& config, const std::optional<AudioIoFlags>& flags, int32_t ioHandle,
AudioSource source, const std::set<int32_t>& destinationPortIds,
AudioPortConfig* portConfig, bool* created) {
- // These flags get removed one by one in this order when retrying port finding.
- static const std::vector<AudioInputFlags> kOptionalInputFlags{
- AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
if (auto portConfigIt = findPortConfig(config, flags, ioHandle);
portConfigIt == mPortConfigs.end() && flags.has_value()) {
- auto optionalInputFlagsIt = kOptionalInputFlags.begin();
+ // These input flags get removed one by one in this order when retrying port finding.
+ std::vector<AudioInputFlags> optionalInputFlags {
+ AudioInputFlags::FAST, AudioInputFlags::RAW, AudioInputFlags::VOIP_TX };
+ // For remote submix input, retry with direct input flag removed as the remote submix
+ // input is not expected to manipulate the contents of the audio stream.
+ if (mRemoteSubmixIn.has_value()) {
+ optionalInputFlags.push_back(AudioInputFlags::DIRECT);
+ }
+ auto optionalInputFlagsIt = optionalInputFlags.begin();
AudioIoFlags matchFlags = flags.value();
auto portsIt = findPort(config, matchFlags, destinationPortIds);
while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::input
- && optionalInputFlagsIt != kOptionalInputFlags.end()) {
+ && optionalInputFlagsIt != optionalInputFlags.end()) {
if (!isBitPositionFlagSet(
matchFlags.get<AudioIoFlags::Tag::input>(), *optionalInputFlagsIt)) {
++optionalInputFlagsIt;
@@ -392,6 +397,36 @@
config.toString().c_str(), flags.value().toString().c_str(),
matchFlags.toString().c_str());
}
+ // These output flags get removed one by one in this order when retrying port finding.
+ std::vector<AudioOutputFlags> optionalOutputFlags { };
+ // For remote submix output, retry with these output flags removed one by one:
+ // 1. DIRECT: remote submix outputs are expected not to manipulate the contents of the
+ // audio stream.
+ // 2. IEC958_NONAUDIO: remote submix outputs are not connected to ALSA and do not require
+ // non audio signalling.
+ if (mRemoteSubmixOut.has_value()) {
+ optionalOutputFlags.push_back(AudioOutputFlags::DIRECT);
+ optionalOutputFlags.push_back(AudioOutputFlags::IEC958_NONAUDIO);
+ }
+ auto optionalOutputFlagsIt = optionalOutputFlags.begin();
+ matchFlags = flags.value();
+ while (portsIt == mPorts.end() && matchFlags.getTag() == AudioIoFlags::Tag::output
+ && optionalOutputFlagsIt != optionalOutputFlags.end()) {
+ if (!isBitPositionFlagSet(
+ matchFlags.get<AudioIoFlags::Tag::output>(),*optionalOutputFlagsIt)) {
+ ++optionalOutputFlagsIt;
+ continue;
+ }
+ matchFlags.set<AudioIoFlags::Tag::output>(matchFlags.get<AudioIoFlags::Tag::output>() &
+ ~makeBitPositionFlagMask(*optionalOutputFlagsIt++));
+ portsIt = findPort(config, matchFlags, destinationPortIds);
+ AUGMENT_LOG(I,
+ "mix port for config %s, flags %s was not found"
+ "retried with flags %s",
+ config.toString().c_str(), flags.value().toString().c_str(),
+ matchFlags.toString().c_str());
+ }
+
if (portsIt == mPorts.end()) {
AUGMENT_LOG(E, "mix port for config %s, flags %s is not found",
config.toString().c_str(), matchFlags.toString().c_str());
@@ -792,7 +827,8 @@
status_t status = prepareToOpenStreamHelper(ioHandle, devicePortConfig.portId,
devicePortConfig.id, flags, source, initialConfig, cleanups, config,
mixPortConfig, patch);
- if (status != OK) {
+ if (status != OK && !(mRemoteSubmixOut.has_value() &&
+ initialConfig.base.format.type != AudioFormatType::PCM)) {
// If using the client-provided config did not work out for establishing a mix port config
// or patching, try with the device port config. Note that in general device port config and
// mix port config are not required to be the same, however they must match if the HAL
diff --git a/media/libaudiohal/impl/StreamHalAidl.cpp b/media/libaudiohal/impl/StreamHalAidl.cpp
index 63be1bc..9863fec 100644
--- a/media/libaudiohal/impl/StreamHalAidl.cpp
+++ b/media/libaudiohal/impl/StreamHalAidl.cpp
@@ -59,6 +59,16 @@
template<HalCommand::Tag cmd, typename T> HalCommand makeHalCommand(T data) {
return HalCommand::make<cmd>(data);
}
+
+template <typename MQTypeError>
+auto fmqErrorHandler(const char* mqName) {
+ return [m = std::string(mqName)](MQTypeError fmqError, std::string&& errorMessage) {
+ mediautils::TimeCheck::signalAudioHals();
+ LOG_ALWAYS_FATAL_IF(fmqError != MQTypeError::NONE, "%s: %s",
+ m.c_str(), errorMessage.c_str());
+ };
+}
+
} // namespace
// static
@@ -103,6 +113,17 @@
StreamHalAidl::getAudioProperties(&config) == NO_ERROR) {
mStreamPowerLog.init(config.sample_rate, config.channel_mask, config.format);
}
+
+ if (mStream != nullptr) {
+ mContext.getCommandMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::CommandMQ::Error>("CommandMQ"));
+ mContext.getReplyMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::ReplyMQ::Error>("ReplyMQ"));
+ if (mContext.getDataMQ() != nullptr) {
+ mContext.getDataMQ()->setErrorHandler(
+ fmqErrorHandler<StreamContextAidl::DataMQ::Error>("DataMQ"));
+ }
+ }
}
StreamHalAidl::~StreamHalAidl() {
@@ -388,11 +409,8 @@
return INVALID_OPERATION;
}
}
- StreamContextAidl::DataMQ::Error fmqError = StreamContextAidl::DataMQ::Error::NONE;
- std::string fmqErrorMsg;
if (!mIsInput) {
- bytes = std::min(bytes,
- mContext.getDataMQ()->availableToWrite(&fmqError, &fmqErrorMsg));
+ bytes = std::min(bytes, mContext.getDataMQ()->availableToWrite());
}
StreamDescriptor::Command burst =
StreamDescriptor::Command::make<StreamDescriptor::Command::Tag::burst>(bytes);
@@ -409,14 +427,12 @@
LOG_ALWAYS_FATAL_IF(*transferred > bytes,
"%s: HAL module read %zu bytes, which exceeds requested count %zu",
__func__, *transferred, bytes);
- if (auto toRead = mContext.getDataMQ()->availableToRead(&fmqError, &fmqErrorMsg);
+ if (auto toRead = mContext.getDataMQ()->availableToRead();
toRead != 0 && !mContext.getDataMQ()->read(static_cast<int8_t*>(buffer), toRead)) {
AUGMENT_LOG(E, "failed to read %zu bytes to data MQ", toRead);
return NOT_ENOUGH_DATA;
}
}
- LOG_ALWAYS_FATAL_IF(fmqError != StreamContextAidl::DataMQ::Error::NONE,
- "%s", fmqErrorMsg.c_str());
mStreamPowerLog.log(buffer, *transferred);
return OK;
}
@@ -427,9 +443,29 @@
if (!mStream) return NO_INIT;
if (const auto state = getState(); isInPlayOrRecordState(state)) {
- return sendCommand(
- makeHalCommand<HalCommand::Tag::pause>(), reply,
+ StreamDescriptor::Reply localReply{};
+ StreamDescriptor::Reply* innerReply = reply ?: &localReply;
+ auto status = sendCommand(
+ makeHalCommand<HalCommand::Tag::pause>(), innerReply,
true /*safeFromNonWorkerThread*/); // The workers stops its I/O activity first.
+ if (status == STATUS_INVALID_OPERATION &&
+ !isInPlayOrRecordState(innerReply->state)) {
+ /**
+ * In case of transient states like DRAINING, the HAL may change its
+ * StreamDescriptor::State on its own and may not be in synchronization with client.
+ * Thus, client can send the unexpected command and HAL returns failure. such failure is
+ * natural. The client handles it gracefully.
+ * Example where HAL change its state,
+ * 1) DRAINING -> IDLE (on empty buffer)
+ * 2) DRAINING -> IDLE (on IStreamCallback::onDrainReady)
+ **/
+ AUGMENT_LOG(D,
+ "HAL failed to handle the 'pause' command, but stream state is in one of"
+ " the PAUSED kind of states, current state: %s",
+ toString(state).c_str());
+ return OK;
+ }
+ return status;
} else {
AUGMENT_LOG(D, "already stream in one of the PAUSED kind of states, current state: %s",
toString(state).c_str());
@@ -457,13 +493,9 @@
return INVALID_OPERATION;
}
return OK;
- } else if (state == StreamDescriptor::State::PAUSED ||
- state == StreamDescriptor::State::TRANSFER_PAUSED ||
- state == StreamDescriptor::State::DRAIN_PAUSED) {
+ } else if (isInPausedState(state)) {
return sendCommand(makeHalCommand<HalCommand::Tag::start>(), reply);
- } else if (state == StreamDescriptor::State::ACTIVE ||
- state == StreamDescriptor::State::TRANSFERRING ||
- state == StreamDescriptor::State::DRAINING) {
+ } else if (isInPlayOrRecordState(state)) {
AUGMENT_LOG(D, "already in stream state: %s", toString(state).c_str());
return OK;
} else {
diff --git a/media/libaudioprocessing/AudioMixerOps.h b/media/libaudioprocessing/AudioMixerOps.h
index ab6a8b6..8f60d29 100644
--- a/media/libaudioprocessing/AudioMixerOps.h
+++ b/media/libaudioprocessing/AudioMixerOps.h
@@ -347,6 +347,7 @@
[6] = AUDIO_CHANNEL_OUT_5POINT1,
[7] = AUDIO_CHANNEL_OUT_6POINT1,
[8] = AUDIO_CHANNEL_OUT_7POINT1,
+ [10] = AUDIO_CHANNEL_OUT_5POINT1POINT4,
[12] = AUDIO_CHANNEL_OUT_7POINT1POINT4,
[14] = AUDIO_CHANNEL_OUT_9POINT1POINT4,
[16] = AUDIO_CHANNEL_OUT_9POINT1POINT6,
diff --git a/media/libaudioprocessing/tests/mixerops_tests.cpp b/media/libaudioprocessing/tests/mixerops_tests.cpp
index 2500ba9..235129f 100644
--- a/media/libaudioprocessing/tests/mixerops_tests.cpp
+++ b/media/libaudioprocessing/tests/mixerops_tests.cpp
@@ -154,6 +154,9 @@
TEST(mixerops, stereovolume_8) {
MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 8>::testStereoVolume();
}
+TEST(mixerops, stereovolume_10) {
+ MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 10>::testStereoVolume();
+}
TEST(mixerops, stereovolume_12) {
if constexpr (FCC_LIMIT >= 12) { // NOTE: FCC_LIMIT is an enum, so can't #if
MixerOpsBasicTest<MIXTYPE_MULTI_STEREOVOL, 12>::testStereoVolume();
diff --git a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
index 55e07fb..dd29e86 100644
--- a/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
+++ b/media/libeffects/hapticgenerator/aidl/EffectHapticGenerator.cpp
@@ -55,6 +55,17 @@
namespace aidl::android::hardware::audio::effect {
+const std::vector<Range::HapticGeneratorRange> kHapticRange = {
+ MAKE_RANGE(HapticGenerator, vibratorInfo,
+ HapticGenerator::VibratorInformation(
+ {.resonantFrequencyHz = 1, .qFactor = 1, .maxAmplitude = -1}),
+ HapticGenerator::VibratorInformation(
+ {.resonantFrequencyHz = std::numeric_limits<float>::max(),
+ .qFactor = std::numeric_limits<float>::max(),
+ .maxAmplitude = 1}))};
+
+static const Capability kHapticCap = {.range = kHapticRange};
+
const std::string HapticGeneratorImpl::kEffectName = "Haptic Generator";
const Descriptor HapticGeneratorImpl::kDescriptor = {
.common = {.id = {.type = getEffectTypeUuidHapticGenerator(),
@@ -62,7 +73,8 @@
.proxy = std::nullopt},
.flags = {.type = Flags::Type::INSERT, .insert = Flags::Insert::FIRST},
.name = HapticGeneratorImpl::kEffectName,
- .implementor = "The Android Open Source Project"}};
+ .implementor = "The Android Open Source Project"},
+ .capability = kHapticCap};
ndk::ScopedAStatus HapticGeneratorImpl::getDescriptor(Descriptor* _aidl_return) {
RETURN_IF(!_aidl_return, EX_ILLEGAL_ARGUMENT, "Parameter:nullptr");
@@ -76,6 +88,8 @@
RETURN_IF(!mContext, EX_NULL_POINTER, "nullContext");
auto& hgParam = specific.get<Parameter::Specific::hapticGenerator>();
+ RETURN_IF(!inRange(hgParam, kHapticRange), EX_ILLEGAL_ARGUMENT, "outOfRange");
+
auto tag = hgParam.getTag();
switch (tag) {
diff --git a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
index 535b886..d8f9093 100644
--- a/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
+++ b/media/libeffects/hapticgenerator/aidl/HapticGeneratorContext.cpp
@@ -353,7 +353,7 @@
std::string HapticGeneratorContext::paramToString(const struct HapticGeneratorParam& param) const {
std::stringstream ss;
- ss << "\t\ttHapticGenerator Parameters:\n";
+ ss << "\t\tHapticGenerator Parameters:\n";
ss << "\t\t- mHapticChannelCount: " << param.mHapticChannelCount << '\n';
ss << "\t\t- mAudioChannelCount: " << param.mAudioChannelCount << '\n';
ss << "\t\t- mHapticChannelSource: " << param.mHapticChannelSource[0] << ", "
@@ -378,7 +378,7 @@
ss << "\t\t- distortion input gain: " << DEFAULT_DISTORTION_INPUT_GAIN << '\n';
ss << "\t\t- distortion cube threshold: " << DEFAULT_DISTORTION_CUBE_THRESHOLD << '\n';
ss << "\t\t- distortion output gain: " << getDistortionOutputGain() << '\n';
- ss << "\t\tHapticGenerator Parameters:\n" << paramToString(mParams) << "\n";
+ ss << paramToString(mParams) << "\n";
return ss.str();
}
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
index d5e3cf7..53d4311 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.cpp
@@ -90,6 +90,12 @@
}
}
+RetCode BundleContext::setCommon(const Parameter::Common& common) {
+ RetCode ret = EffectContext::setCommon(common);
+ RETURN_VALUE_IF(ret != RetCode::SUCCESS, ret, " setCommonFailed");
+ return init();
+}
+
RetCode BundleContext::enable() {
if (mEnabled) return RetCode::ERROR_ILLEGAL_PARAMETER;
// Bass boost or Virtualizer can be temporarily disabled if playing over device speaker due to
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
index e5ab40d..d5de5bd 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleContext.h
@@ -35,6 +35,8 @@
void deInit();
lvm::BundleEffectType getBundleType() const { return mType; }
+ RetCode setCommon(const Parameter::Common& common) override;
+
RetCode enable() override;
RetCode enableOperatingMode();
RetCode disable() override;
diff --git a/media/libmedia/include/media/mediametadataretriever.h b/media/libmedia/include/media/mediametadataretriever.h
index 116ed9a..d76ed25 100644
--- a/media/libmedia/include/media/mediametadataretriever.h
+++ b/media/libmedia/include/media/mediametadataretriever.h
@@ -122,6 +122,10 @@
static sp<IMediaPlayerService> sService;
Mutex mLock;
+ // Static lock was added to the client in order to consume at most
+ // one service thread from image extraction requests of the same
+ // client process(See also b/21277449).
+ static Mutex sLock;
sp<IMediaMetadataRetriever> mRetriever;
};
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index 40fd022..9196f9f 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -35,6 +35,8 @@
sp<IMediaPlayerService> MediaMetadataRetriever::sService;
sp<MediaMetadataRetriever::DeathNotifier> MediaMetadataRetriever::sDeathNotifier;
+Mutex MediaMetadataRetriever::sLock;
+
const sp<IMediaPlayerService> MediaMetadataRetriever::getService()
{
Mutex::Autolock lock(sServiceLock);
@@ -143,6 +145,7 @@
ALOGV("getFrameAtTime: time(%" PRId64 " us) option(%d) colorFormat(%d) metaOnly(%d)",
timeUs, option, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -155,6 +158,7 @@
ALOGV("getImageAtIndex: index(%d) colorFormat(%d) metaOnly(%d) thumbnail(%d)",
index, colorFormat, metaOnly, thumbnail);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -167,6 +171,7 @@
ALOGV("getImageRectAtIndex: index(%d) colorFormat(%d) rect {%d, %d, %d, %d}",
index, colorFormat, left, top, right, bottom);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
@@ -180,6 +185,7 @@
ALOGV("getFrameAtIndex: index(%d), colorFormat(%d) metaOnly(%d)",
index, colorFormat, metaOnly);
Mutex::Autolock _l(mLock);
+ Mutex::Autolock _gLock(sLock);
if (mRetriever == 0) {
ALOGE("retriever is not initialized");
return NULL;
diff --git a/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
index cc60933..f0db018 100644
--- a/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
+++ b/media/libmedia/tests/mediaplayer/IMediaPlayerTest.cpp
@@ -50,7 +50,7 @@
// We write a length greater than the following session id array. Should be discarded.
data.writeUint32(2);
- data.writeUnpadded(kMockByteArray, 1);
+ data.write(kMockByteArray, 1);
status_t result = IMediaPlayer::asBinder(iMediaPlayer_)
->transact(PREPARE_DRM, data, &reply);
diff --git a/media/libmediametrics/MediaMetricsItem.cpp b/media/libmediametrics/MediaMetricsItem.cpp
index ecb248d..2c58461 100644
--- a/media/libmediametrics/MediaMetricsItem.cpp
+++ b/media/libmediametrics/MediaMetricsItem.cpp
@@ -334,21 +334,21 @@
// This is checked only once in the lifetime of the process.
const uid_t uid = getuid();
- switch (uid) {
- case AID_RADIO: // telephony subsystem, RIL
+ const uid_t appid = multiuser_get_app_id(uid);
+
+ if (appid == AID_RADIO) {
+ // telephony subsystem, RIL
return false;
- default:
+ }
+
+ if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
// Some isolated processes can access the audio system; see
// AudioSystem::setAudioFlingerBinder (currently only the HotwordDetectionService). Instead
// of also allowing access to the MediaMetrics service, it's simpler to just disable it for
// now.
// TODO(b/190151205): Either allow the HotwordDetectionService to access MediaMetrics or
// make this disabling specific to that process.
- uid_t appid = multiuser_get_app_id(uid);
- if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
- return false;
- }
- break;
+ return false;
}
int enabled = property_get_int32(Item::EnabledProperty, -1);
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 718f782..a10c509 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -45,6 +45,7 @@
"android.hardware.media.omx@1.0",
"av-types-aidl-cpp",
"framework-permission-aidl-cpp",
+ "libaconfig_storage_read_api_cc",
"libaudioclient_aidl_conversion",
"libbase",
"libbinder_ndk",
@@ -76,6 +77,7 @@
"libstagefright_httplive",
"libutils",
"packagemanager_aidl-cpp",
+ "server_configurable_flags",
],
header_libs: [
@@ -86,6 +88,7 @@
],
static_libs: [
+ "com.android.media.flags.editing-aconfig-cc",
"libplayerservice_datasource",
"libstagefright_nuplayer",
"libstagefright_rtsp",
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index dce6ba8..086baa3 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -68,6 +68,7 @@
#include <system/audio.h>
#include <media/stagefright/rtsp/ARTPWriter.h>
+#include <com_android_media_editing_flags.h>
namespace android {
@@ -2121,7 +2122,8 @@
uint32_t bLayers = std::min(2u, tsLayers - 1); // use up-to 2 B-layers
// TODO(b/341121900): Remove this once B frames are handled correctly in screen recorder
// use case in case of mic only
- if (mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
+ if (!com::android::media::editing::flags::stagefrightrecorder_enable_b_frames()
+ && mAudioSource == AUDIO_SOURCE_MIC && mVideoSource == VIDEO_SOURCE_SURFACE) {
bLayers = 0;
}
uint32_t pLayers = tsLayers - bLayers;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index f4143da..3987a67 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -43,6 +43,12 @@
#include <mpeg2ts/ATSParser.h>
#include <gui/Surface.h>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
namespace android {
static float kDisplayRefreshingRate = 60.f; // TODO: get this from the display
@@ -157,7 +163,10 @@
int32_t index;
CHECK(msg->findInt32("index", &index));
+ ATRACE_BEGIN(StringPrintf("Nuplayer::handleAnInputBuffer [%s]",
+ mIsAudio ? "audio" : "video").c_str());
handleAnInputBuffer(index);
+ ATRACE_END();
break;
}
@@ -175,7 +184,10 @@
CHECK(msg->findInt64("timeUs", &timeUs));
CHECK(msg->findInt32("flags", &flags));
+ ATRACE_BEGIN(StringPrintf("Nuplayer::handleAnOutputBuffer [%s]",
+ mIsAudio ? "audio" : "video").c_str());
handleAnOutputBuffer(index, offset, size, timeUs, flags);
+ ATRACE_END();
break;
}
@@ -184,7 +196,10 @@
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
+ ATRACE_BEGIN(StringPrintf("Nuplayer::handleOutputFormatChange [%s]",
+ mIsAudio ? "audio" : "video").c_str());
handleOutputFormatChange(format);
+ ATRACE_END();
break;
}
@@ -205,15 +220,16 @@
break;
}
}
-
break;
}
case kWhatRenderBuffer:
{
+ ATRACE_BEGIN("Nuplayer::onRenderBuffer");
if (!isStaleReply(msg)) {
onRenderBuffer(msg);
}
+ ATRACE_END();
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 3e96d27..0cb5062 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -27,6 +27,12 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
namespace android {
NuPlayer::DecoderBase::DecoderBase(const sp<AMessage> ¬ify)
@@ -129,9 +135,11 @@
switch (msg->what()) {
case kWhatConfigure:
{
+ ATRACE_BEGIN("NuPlayer::DecoderBase::onConfigure");
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
onConfigure(format);
+ ATRACE_END();
break;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index c6595ba..851d252 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -36,6 +36,11 @@
#include <media/stagefright/Utils.h>
#include <media/stagefright/FoundationUtils.h>
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
static const int kDumpLockRetries = 50;
static const int kDumpLockSleepUs = 20000;
@@ -146,9 +151,11 @@
const char *url,
const KeyedVector<String8, String8> *headers) {
ALOGV("setDataSource(%p) url(%s)", this, uriDebugString(url, false).c_str());
+ ATRACE_BEGIN(StringPrintf("setDataSource(%p)", this).c_str());
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
+ ATRACE_END();
return INVALID_OPERATION;
}
@@ -159,15 +166,18 @@
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
+ ATRACE_END();
return mAsyncResult;
}
status_t NuPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) {
ALOGV("setDataSource(%p) file(%d)", this, fd);
+ ATRACE_BEGIN(StringPrintf("setDataSource(%p) file(%d)", this, fd).c_str());
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
+ ATRACE_END();
return INVALID_OPERATION;
}
@@ -178,15 +188,18 @@
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
+ ATRACE_END();
return mAsyncResult;
}
status_t NuPlayerDriver::setDataSource(const sp<IStreamSource> &source) {
ALOGV("setDataSource(%p) stream source", this);
+ ATRACE_BEGIN(StringPrintf("setDataSource(%p) stream source", this).c_str());
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
+ ATRACE_END();
return INVALID_OPERATION;
}
@@ -197,15 +210,18 @@
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
+ ATRACE_END();
return mAsyncResult;
}
status_t NuPlayerDriver::setDataSource(const sp<DataSource> &source) {
ALOGV("setDataSource(%p) callback source", this);
+ ATRACE_BEGIN(StringPrintf("setDataSource(%p) callback source", this).c_str());
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
+ ATRACE_END();
return INVALID_OPERATION;
}
@@ -216,15 +232,18 @@
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
+ ATRACE_END();
return mAsyncResult;
}
status_t NuPlayerDriver::setDataSource(const String8& rtpParams) {
ALOGV("setDataSource(%p) rtp source", this);
+ ATRACE_BEGIN(StringPrintf("setDataSource(%p) rtp source", this).c_str());
Mutex::Autolock autoLock(mLock);
if (mState != STATE_IDLE) {
+ ATRACE_END();
return INVALID_OPERATION;
}
@@ -235,6 +254,7 @@
while (mState == STATE_SET_DATASOURCE_PENDING) {
mCondition.wait(mLock);
}
+ ATRACE_END();
return mAsyncResult;
}
@@ -295,8 +315,11 @@
status_t NuPlayerDriver::prepare() {
ALOGV("prepare(%p)", this);
+ ATRACE_BEGIN(StringPrintf("prepare(%p)", this).c_str());
Mutex::Autolock autoLock(mLock);
- return prepare_l();
+ status_t ret = prepare_l();
+ ATRACE_END();
+ return ret;
}
status_t NuPlayerDriver::prepare_l() {
@@ -354,8 +377,11 @@
status_t NuPlayerDriver::start() {
ALOGV("start(%p), state is %d, eos is %d", this, mState, mAtEOS);
+ ATRACE_BEGIN(StringPrintf("start(%p), state is %d, eos is %d", this, mState, mAtEOS).c_str());
Mutex::Autolock autoLock(mLock);
- return start_l();
+ status_t ret = start_l();
+ ATRACE_END();
+ return ret;
}
status_t NuPlayerDriver::start_l() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 3c8b809..899d50e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -15,6 +15,7 @@
*/
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
#define LOG_TAG "NuPlayerRenderer"
#include <utils/Log.h>
@@ -37,6 +38,9 @@
#include <inttypes.h>
+#include <android-base/stringprintf.h>
+using ::android::base::StringPrintf;
+
namespace android {
/*
@@ -2000,6 +2004,8 @@
bool isStreaming) {
ALOGV("openAudioSink: offloadOnly(%d) offloadingAudio(%d)",
offloadOnly, offloadingAudio());
+ ATRACE_BEGIN(StringPrintf("NuPlayer::Renderer::onOpenAudioSink: offloadOnly(%d) "
+ "offloadingAudio(%d)", offloadOnly, offloadingAudio()).c_str());
bool audioSinkChanged = false;
int32_t numChannels;
@@ -2071,6 +2077,7 @@
if (memcmp(&mCurrentOffloadInfo, &offloadInfo, sizeof(offloadInfo)) == 0) {
ALOGV("openAudioSink: no change in offload mode");
// no change from previous configuration, everything ok.
+ ATRACE_END();
return OK;
}
mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
@@ -2140,6 +2147,7 @@
if (memcmp(&mCurrentPcmInfo, &info, sizeof(info)) == 0) {
ALOGV("openAudioSink: no change in pcm mode");
// no change from previous configuration, everything ok.
+ ATRACE_END();
return OK;
}
@@ -2184,6 +2192,7 @@
ALOGW("openAudioSink: non offloaded open failed status: %d", err);
mAudioSink->close();
mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
+ ATRACE_END();
return err;
}
mCurrentPcmInfo = info;
@@ -2195,13 +2204,16 @@
onAudioSinkChanged();
}
mAudioTornDown = false;
+ ATRACE_END();
return OK;
}
void NuPlayer::Renderer::onCloseAudioSink() {
+ ATRACE_BEGIN("NuPlyer::Renderer::onCloseAudioSink");
mAudioSink->close();
mCurrentOffloadInfo = AUDIO_INFO_INITIALIZER;
mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER;
+ ATRACE_END();
}
void NuPlayer::Renderer::onChangeAudioFormat(
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index ac178aa..d084f10 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -321,6 +321,7 @@
static_libs: [
"android.media.codec-aconfig-cc",
+ "com.android.media.flags.editing-aconfig-cc",
"libstagefright_esds",
"libstagefright_color_conversion",
"libyuv",
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 893b442..cc78510 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -654,7 +654,9 @@
mReadOptions.clearSeekTo();
if (err != OK) {
ALOGW("Input Error: err=%d", err);
- mediaBuffer->release();
+ if (mediaBuffer) {
+ mediaBuffer->release();
+ }
return err;
}
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 76b6aa6..3aa0107 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -53,6 +53,8 @@
#include <media/esds/ESDS.h>
#include "include/HevcUtils.h"
+#include <com_android_media_editing_flags.h>
+
#ifndef __predict_false
#define __predict_false(exp) __builtin_expect((exp) != 0, 0)
#endif
@@ -4944,6 +4946,8 @@
// Track with start offset.
ALOGV("Tracks starting > 0");
int32_t editDurationTicks = 0;
+ int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
+ ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
if (mMinCttsOffsetTicks == mMaxCttsOffsetTicks) {
// Video with no B frame or non-video track.
editDurationTicks =
@@ -4952,8 +4956,6 @@
ALOGV("editDuration:%" PRId64 "us", (trackStartOffsetUs + movieStartOffsetBFramesUs));
} else {
// Track with B frame.
- int32_t trackStartOffsetBFramesUs = getMinCttsOffsetTimeUs() - kMaxCttsOffsetTimeUs;
- ALOGV("trackStartOffsetBFramesUs:%" PRId32, trackStartOffsetBFramesUs);
editDurationTicks =
((trackStartOffsetUs + movieStartOffsetBFramesUs +
trackStartOffsetBFramesUs) * mvhdTimeScale + 5E5) / 1E6;
@@ -4967,7 +4969,15 @@
} else if (editDurationTicks < 0) {
// Only video tracks with B Frames would hit this case.
ALOGV("Edit list entry to negate start offset by B frames in other tracks");
- addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+ if (com::android::media::editing::flags::
+ stagefrightrecorder_enable_b_frames()) {
+ int32_t mediaTimeTicks =
+ ((trackStartOffsetUs + movieStartOffsetBFramesUs +
+ trackStartOffsetBFramesUs) * mTimeScale - 5E5) / 1E6;
+ addOneElstTableEntry(tkhdDurationTicks, std::abs(mediaTimeTicks), 1, 0);
+ } else {
+ addOneElstTableEntry(tkhdDurationTicks, std::abs(editDurationTicks), 1, 0);
+ }
} else {
ALOGV("No edit list entry needed for this track");
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1422868..9abe037 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2018,6 +2018,7 @@
int32_t flags;
CHECK(buffer->meta()->findInt32("flags", &flags));
if (flags & BUFFER_FLAG_DECODE_ONLY) {
+ ALOGV("discardDecodeOnlyOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
info->mData.clear();
mBufferChannel->discardBuffer(buffer);
@@ -2462,7 +2463,12 @@
mediametrics_setInt32(nextMetricsHandle, kCodecCrypto, 1);
}
} else if (mFlags & kFlagIsSecure) {
- ALOGW("Crypto or descrambler should be given for secure codec");
+ if (android::media::codec::provider_->secure_codecs_require_crypto()) {
+ mErrorLog.log(LOG_TAG, "Crypto or descrambler must be given for secure codec");
+ return INVALID_OPERATION;
+ } else {
+ ALOGW("Crypto or descrambler should be given for secure codec");
+ }
}
if (mConfigureMsg != nullptr) {
@@ -4492,9 +4498,16 @@
{
/* size_t index = */updateBuffers(kPortIndexInput, msg);
- if (mState == FLUSHING
- || mState == STOPPING
- || mState == RELEASING) {
+ bool inStateToReturnBuffers =
+ mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ // Late callbacks from the codec could arrive here
+ // after the codec is already stopped or released.
+ inStateToReturnBuffers = mState == FLUSHING ||
+ mState == STOPPING || mState == INITIALIZED ||
+ mState == RELEASING || mState == UNINITIALIZED;
+ }
+ if (inStateToReturnBuffers) {
returnBuffersToCodecOnPort(kPortIndexInput);
break;
}
@@ -4573,9 +4586,16 @@
/* size_t index = */updateBuffers(kPortIndexOutput, msg);
- if (mState == FLUSHING
- || mState == STOPPING
- || mState == RELEASING) {
+ bool inStateToReturnBuffers =
+ mState == FLUSHING || mState == STOPPING || mState == RELEASING;
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ // Late callbacks from the codec could arrive here
+ // after the codec is already stopped or released.
+ inStateToReturnBuffers = mState == FLUSHING ||
+ mState == STOPPING || mState == INITIALIZED ||
+ mState == RELEASING || mState == UNINITIALIZED;
+ }
+ if (inStateToReturnBuffers) {
returnBuffersToCodecOnPort(kPortIndexOutput);
break;
}
@@ -5941,7 +5961,7 @@
}
updateHdrMetrics(false /* isConfig */);
- }
+}
void MediaCodec::extractCSD(const sp<AMessage> &format) {
mCSD.clear();
@@ -6020,7 +6040,6 @@
return -EINVAL;
}
if (codecInputData->data() == NULL) {
- ALOGV("Input buffer %zu is not properly allocated", bufferIndex);
mErrorLog.log(LOG_TAG, base::StringPrintf(
"Fatal error: input buffer %zu is not properly allocated", bufferIndex));
return -EINVAL;
@@ -6066,6 +6085,10 @@
mInputFormat.clear();
mOutputFormat.clear();
+ if (android::media::codec::provider_->codec_buffer_state_cleanup()) {
+ mCSD.clear();
+ mLeftover.clear();
+ }
mFlags &= ~kFlagOutputFormatChanged;
mFlags &= ~kFlagOutputBuffersChanged;
mFlags &= ~kFlagStickyError;
@@ -6124,6 +6147,8 @@
ALOGD("port %d buffer %zu still owned by client when codec is reclaimed",
portIndex, i);
} else {
+ ALOGV("returnBuffersToCodecOnPort: mPortBuffers[%s][%zu] NOT owned by client",
+ portIndex == kPortIndexInput ? "in" : "out", i);
info->mOwnedByClient = false;
info->mData.clear();
}
@@ -6476,6 +6501,7 @@
// synchronization boundary for getBufferAndFormat
Mutex::Autolock al(mBufferLock);
+ ALOGV("onQueueInputBuffer: mPortBuffers[in][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
info->mData.clear();
@@ -6492,6 +6518,7 @@
sp<AMessage> msg = mLeftover.front();
mLeftover.pop_front();
msg->setSize("index", index);
+ ALOGV("handleLeftover(%zu)", index);
return onQueueInputBuffer(msg);
}
@@ -6560,6 +6587,7 @@
sp<MediaCodecBuffer> buffer;
{
Mutex::Autolock al(mBufferLock);
+ ALOGV("onReleaseOutputBuffer: mPortBuffers[out][%zu] NOT owned by client", index);
info->mOwnedByClient = false;
buffer = info->mData;
info->mData.clear();
@@ -6672,6 +6700,8 @@
{
Mutex::Autolock al(mBufferLock);
+ ALOGV("dequeuePortBuffer: mPortBuffers[%s][%zu] checking if not owned by client",
+ portIndex == kPortIndexInput ? "in" : "out", index);
CHECK(!info->mOwnedByClient);
info->mOwnedByClient = true;
diff --git a/media/libstagefright/TEST_MAPPING b/media/libstagefright/TEST_MAPPING
index b7efbce..354fab0 100644
--- a/media/libstagefright/TEST_MAPPING
+++ b/media/libstagefright/TEST_MAPPING
@@ -85,13 +85,37 @@
// writerTest fails about 5 out of 66
// { "name": "writerTest" },
{
- "name": "BatteryChecker_test"
+ "name": "BatteryChecker_test"
},
{
"name": "ExtractorFactoryTest"
},
{
"name": "HEVCUtilsUnitTest"
+ },
+ {
+ "name": "MctsMediaDecoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaEncoderTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
+ },
+ {
+ "name": "MctsMediaCodecTestCases",
+ "options": [
+ {
+ "include-annotation": "android.platform.test.annotations.Presubmit"
+ }
+ ]
}
]
}
diff --git a/media/libstagefright/writer_fuzzers/Android.bp b/media/libstagefright/writer_fuzzers/Android.bp
index 58aa7cd..840c6b3c 100644
--- a/media/libstagefright/writer_fuzzers/Android.bp
+++ b/media/libstagefright/writer_fuzzers/Android.bp
@@ -24,6 +24,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_av_media_libstagefright_license"],
+ default_team: "trendy_team_android_media_solutions_editing",
}
cc_defaults {
@@ -35,14 +36,17 @@
"include",
],
static_libs: [
+ "com.android.media.flags.editing-aconfig-cc",
"liblog",
- "libstagefright_foundation",
"libstagefright",
+ "libstagefright_foundation",
],
shared_libs: [
+ "libaconfig_storage_read_api_cc",
"libbinder",
"libcutils",
"libutils",
+ "server_configurable_flags",
],
}
@@ -96,9 +100,9 @@
}
cc_fuzz {
- name : "mpeg4_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "mpeg4_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"mpeg4_writer_fuzzer.cpp",
],
static_libs: [
@@ -107,9 +111,9 @@
}
cc_fuzz {
- name : "ogg_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "ogg_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"ogg_writer_fuzzer.cpp",
],
static_libs: [
@@ -118,9 +122,9 @@
}
cc_fuzz {
- name : "webm_writer_fuzzer",
- defaults : ["writer-fuzzer-defaults"],
- srcs : [
+ name: "webm_writer_fuzzer",
+ defaults: ["writer-fuzzer-defaults"],
+ srcs: [
"webm_writer_fuzzer.cpp",
],
static_libs: [
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 8c1ef3b..bd11326 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -1069,7 +1069,7 @@
codec.rank = rank;
}
- codec.variantSet = variants;
+ codec.variantSet.insert(variants.begin(), variants.end());
// we allow sets of domains...
for (const std::string &domain : domains) {
diff --git a/media/mediaserver/Android.bp b/media/mediaserver/Android.bp
index 6ea40e3..b5124d0 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -51,9 +51,16 @@
],
}
+vintf_fragment {
+ name: "manifest_media_c2_software.xml",
+ src: "manifest_media_c2_software.xml",
+}
+
mediaserver_cc_binary {
name: "mediaserver",
+ defaults: ["libcodec2_hal_selection"],
+
srcs: ["main_mediaserver.cpp"],
shared_libs: [
@@ -61,6 +68,7 @@
"libicu",
"libfmq",
"libbinder",
+ "libbinder_ndk",
"libhidlbase",
"liblog",
"libmediaplayerservice",
@@ -85,7 +93,7 @@
"-Wall",
],
- vintf_fragments: ["manifest_media_c2_software.xml"],
+ vintf_fragment_modules: ["manifest_media_c2_software.xml"],
soong_config_variables: {
TARGET_DYNAMIC_64_32_MEDIASERVER: {
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 026847a..8a62f30 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -17,11 +17,12 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-
+#include <android/binder_process.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <hidl/HidlTransportSupport.h>
+#include <codec2/common/HalSelection.h>
#include <utils/Log.h>
#include "RegisterExtensions.h"
@@ -30,6 +31,14 @@
using namespace android;
+namespace {
+ constexpr int kCodecThreadPoolCount = 16;
+
+ // This is the default thread count for binder thread pool
+ // if the thread count is not configured.
+ constexpr int kDefaultBinderThreadPoolCount = 15;
+}; // anonymous
+
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
@@ -40,8 +49,14 @@
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
registerExtensions();
- ::android::hardware::configureRpcThreadpool(16, false);
+
+ bool aidl = ::android::IsCodec2AidlHalSelected();
+ if (!aidl) {
+ ::android::hardware::configureRpcThreadpool(kCodecThreadPoolCount, false);
+ } else {
+ ABinderProcess_setThreadPoolMaxThreadCount(
+ kCodecThreadPoolCount + kDefaultBinderThreadPoolCount);
+ }
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
- ::android::hardware::joinRpcThreadpool();
}
diff --git a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
index 8817621..64fdfb9 100644
--- a/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
+++ b/media/module/codecs/amrnb/common/include/basic_op_c_equivalent.h
@@ -115,7 +115,6 @@
Returns:
L_sum = 32-bit sum of L_var1 and L_var2 (Word32)
*/
- __attribute__((no_sanitize("integer")))
static inline Word32 L_add(Word32 L_var1, Word32 L_var2, Flag *pOverflow)
{
Word32 L_sum;
@@ -454,7 +453,8 @@
{
Word32 result;
- result = L_var3 + L_var1 * L_var2;
+ __builtin_mul_overflow(L_var1, L_var2, &result);
+ __builtin_add_overflow(L_var3, result, &result);
return result;
}
@@ -463,7 +463,8 @@
{
Word32 result;
- result = L_var3 - L_var1 * L_var2;
+ __builtin_mul_overflow(L_var1, L_var2, &result);
+ __builtin_sub_overflow(L_var3, result, &result);
return result;
}
diff --git a/media/module/codecs/amrnb/common/src/az_lsp.cpp b/media/module/codecs/amrnb/common/src/az_lsp.cpp
index f3098f5..a19ddbf 100644
--- a/media/module/codecs/amrnb/common/src/az_lsp.cpp
+++ b/media/module/codecs/amrnb/common/src/az_lsp.cpp
@@ -237,9 +237,6 @@
------------------------------------------------------------------------------
*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
static Word16 Chebps(Word16 x,
Word16 f[], /* (n) */
Word16 n,
diff --git a/media/module/codecs/amrnb/common/src/l_abs.cpp b/media/module/codecs/amrnb/common/src/l_abs.cpp
index 7e0ae99..b13a40a 100644
--- a/media/module/codecs/amrnb/common/src/l_abs.cpp
+++ b/media/module/codecs/amrnb/common/src/l_abs.cpp
@@ -186,8 +186,12 @@
; Function body here
----------------------------------------------------------------------------*/
- Word32 y = L_var1 - (L_var1 < 0);
- y = y ^(y >> 31);
- return (y);
+ if (L_var1 >= 0) return L_var1;
+ if (L_var1 != 0x80000000) return -L_var1;
+ // abs(0x80000000) can not be represented in Word32.
+ // we choose to return the closest value we can -- 0x7fffffff
+ // This is acceptable because it keeps the result within the valid 32-bit signed integer range,
+ // consistent with other overflow handling in the code. such as amrnb/enc/src/l_negate.cpp.
+ return 0x7FFFFFFF;
}
diff --git a/media/module/codecs/amrnb/common/src/lsp_az.cpp b/media/module/codecs/amrnb/common/src/lsp_az.cpp
index 495359f..bb8a34d 100644
--- a/media/module/codecs/amrnb/common/src/lsp_az.cpp
+++ b/media/module/codecs/amrnb/common/src/lsp_az.cpp
@@ -281,8 +281,8 @@
t0 += ((Word32)lo * *lsp) >> 15;
*(f) += *(f - 2); /* *f += f[-2] */
- *(f--) -= t0 << 2; /* *f -= t0 */
-
+ __builtin_sub_overflow(*(f), (t0 << 2), f); /* *f -= t0 */
+ f--;
}
*f -= (Word32)(*lsp++) << 10;
diff --git a/media/module/codecs/amrnb/common/src/norm_l.cpp b/media/module/codecs/amrnb/common/src/norm_l.cpp
index d8d1259..b24ebda 100644
--- a/media/module/codecs/amrnb/common/src/norm_l.cpp
+++ b/media/module/codecs/amrnb/common/src/norm_l.cpp
@@ -211,8 +211,7 @@
if (L_var1)
{
- Word32 y = L_var1 - (L_var1 < 0);
- L_var1 = y ^(y >> 31);
+ L_var1 = L_abs(L_var1);
while (!(0x40000000L & L_var1))
diff --git a/media/module/codecs/amrnb/common/src/residu.cpp b/media/module/codecs/amrnb/common/src/residu.cpp
index 2ad132f..9b077e2 100644
--- a/media/module/codecs/amrnb/common/src/residu.cpp
+++ b/media/module/codecs/amrnb/common/src/residu.cpp
@@ -227,22 +227,35 @@
p_input3 = p_input_ptr--;
p_input4 = p_input_ptr--;
+ Word32 tmp;
for (j = M >> 1; j != 0; j--)
{
- s1 += ((Word32) * (p_coef) * *(p_input1++));
- s2 += ((Word32) * (p_coef) * *(p_input2++));
- s3 += ((Word32) * (p_coef) * *(p_input3++));
- s4 += ((Word32) * (p_coef--) * *(p_input4++));
- s1 += ((Word32) * (p_coef) * *(p_input1++));
- s2 += ((Word32) * (p_coef) * *(p_input2++));
- s3 += ((Word32) * (p_coef) * *(p_input3++));
- s4 += ((Word32) * (p_coef--) * *(p_input4++));
+ __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
+ __builtin_mul_overflow(*p_coef, *(p_input1++), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2++), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3++), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*(p_coef--), *(p_input4++), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
}
- s1 += (((Word32) * (p_coef)) * *(p_input1));
- s2 += (((Word32) * (p_coef)) * *(p_input2));
- s3 += (((Word32) * (p_coef)) * *(p_input3));
- s4 += (((Word32) * (p_coef)) * *(p_input4));
+ __builtin_mul_overflow(*p_coef, *(p_input1), &tmp);
+ __builtin_add_overflow(s1, tmp, &s1);
+ __builtin_mul_overflow(*p_coef, *(p_input2), &tmp);
+ __builtin_add_overflow(s2, tmp, &s2);
+ __builtin_mul_overflow(*p_coef, *(p_input3), &tmp);
+ __builtin_add_overflow(s3, tmp, &s3);
+ __builtin_mul_overflow(*p_coef, *(p_input4), &tmp);
+ __builtin_add_overflow(s4, tmp, &s4);
*(p_residual_ptr--) = (Word16)(s1 >> 12);
*(p_residual_ptr--) = (Word16)(s2 >> 12);
diff --git a/media/module/codecs/amrnb/common/src/sub.cpp b/media/module/codecs/amrnb/common/src/sub.cpp
index b956912..d936128 100644
--- a/media/module/codecs/amrnb/common/src/sub.cpp
+++ b/media/module/codecs/amrnb/common/src/sub.cpp
@@ -187,9 +187,6 @@
; FUNCTION CODE
----------------------------------------------------------------------------*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
Word16 sub(Word16 var1, Word16 var2, Flag *pOverflow)
{
diff --git a/media/module/codecs/amrnb/common/src/syn_filt.cpp b/media/module/codecs/amrnb/common/src/syn_filt.cpp
index 36c1d84..82770f1 100644
--- a/media/module/codecs/amrnb/common/src/syn_filt.cpp
+++ b/media/module/codecs/amrnb/common/src/syn_filt.cpp
@@ -245,9 +245,6 @@
------------------------------------------------------------------------------
*/
-#ifdef __clang__
-__attribute__((no_sanitize("integer")))
-#endif
void Syn_filt(
Word16 a[], /* (i) : a[M+1] prediction coefficients (M=10) */
Word16 x[], /* (i) : input signal */
diff --git a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
index af62074..984baf8 100644
--- a/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
+++ b/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest.cpp
@@ -22,6 +22,7 @@
#include <audio_utils/sndfile.h>
#include <stdio.h>
+#include <fstream>
#include "gsmamr_dec.h"
@@ -40,7 +41,7 @@
static AmrnbDecTestEnvironment *gEnv = nullptr;
-class AmrnbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrnbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
public:
AmrnbDecoderTest() : mFpInput(nullptr) {}
@@ -54,6 +55,7 @@
FILE *mFpInput;
SNDFILE *openOutputFile(SF_INFO *sfInfo);
int32_t DecodeFrames(void *amrHandle, SNDFILE *outFileHandle, int32_t frameCount = INT32_MAX);
+ bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
};
SNDFILE *AmrnbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -97,6 +99,42 @@
return 0;
}
+bool AmrnbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ " but output file size = %td bytes.", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrnbDecoderTest, CreateAmrnbDecoderTest) {
void *amrHandle;
int32_t status = GSMInitDecode(&amrHandle, (Word8 *)"AMRNBDecoder");
@@ -106,7 +144,7 @@
}
TEST_P(AmrnbDecoderTest, DecodeTest) {
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -126,10 +164,15 @@
sf_close(outFileHandle);
GSMDecodeFrameExit(&amrHandle);
ASSERT_EQ(amrHandle, nullptr) << "Error deleting AMR-NB decoder";
+
+ string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+ << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrnbDecoderTest, ResetDecodeTest) {
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -159,8 +202,24 @@
}
INSTANTIATE_TEST_SUITE_P(AmrnbDecoderTestAll, AmrnbDecoderTest,
- ::testing::Values(("bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb"),
- ("sine_amrnb_1ch_12kbps_8000hz.amrnb")));
+ ::testing::Values(std::make_tuple(
+ "bbb_8000hz_1ch_8kbps_amrnb_30sec.amrnb",
+ "bbb_8000hz_1ch_8kbps_amrnb_30sec_ref.pcm"),
+ std::make_tuple(
+ "sine_amrnb_1ch_12kbps_8000hz.amrnb",
+ "sine_amrnb_1ch_12kbps_8000hz_ref.pcm"),
+ std::make_tuple(
+ "trim_8000hz_1ch_12kpbs_amrnb_200ms.amrnb",
+ "trim_8000hz_1ch_12kpbs_amrnb_200ms_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_4.75kbps_amrnb_3sec.amrnb",
+ "bbb_8kHz_1ch_4.75kbps_amrnb_3sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_10kbps_amrnb_1sec.amrnb",
+ "bbb_8kHz_1ch_10kbps_amrnb_1sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_8kHz_1ch_12.2kbps_amrnb_3sec.amrnb",
+ "bbb_8kHz_1ch_12.2kbps_amrnb_3sec_ref.pcm")));
int main(int argc, char **argv) {
gEnv = new AmrnbDecTestEnvironment();
diff --git a/media/module/codecs/amrnb/dec/test/AndroidTest.xml b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
index 539fa5c..7b2ba15 100644
--- a/media/module/codecs/amrnb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrnbDecoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrnbDecoderTest-1.0" />
+ <option name="media-folder-name" value="AmrnbDecoderTest-2.0" />
<option name="dynamic-config-module" value="AmrnbDecoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrnbDecoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrnbDecoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
index 701a752..02b869a 100644
--- a/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrnb/dec/test/README.md b/media/module/codecs/amrnb/dec/test/README.md
index 41fb80a..ea54975 100644
--- a/media/module/codecs/amrnb/dec/test/README.md
+++ b/media/module/codecs/amrnb/dec/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrnbDecoderTest/AmrnbDecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/dec/test/AmrnbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrnbDecoderTest-1.0 /data/local/tmp/
+adb push AmrnbDecoderTest-2.0 /data/local/tmp/
```
usage: AmrnbDecoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrnbDecoderTest -P /data/local/tmp/AmrnbDecoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrnb/enc/src/autocorr.cpp b/media/module/codecs/amrnb/enc/src/autocorr.cpp
index c71811d..a078f5a 100644
--- a/media/module/codecs/amrnb/enc/src/autocorr.cpp
+++ b/media/module/codecs/amrnb/enc/src/autocorr.cpp
@@ -312,6 +312,7 @@
Word16 y[L_WINDOW];
Word32 sum;
+ Word32 mul;
Word16 overfl_shft;
@@ -343,7 +344,8 @@
temp = (amrnb_fxp_mac_16_by_16bb((Word32) * (p_x++), (Word32) * (p_wind++), 0x04000)) >> 15;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
if (sum < 0)
{
/*
@@ -395,10 +397,12 @@
{
temp = *p_y >> 2;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
temp = *p_y >> 2;
*(p_y++) = temp;
- sum += ((Word32)temp * temp) << 1;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(sum, mul << 1, &sum);
}
if (sum > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
index b211032..56b4fb8 100644
--- a/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c2_9pf.cpp
@@ -610,6 +610,7 @@
Word32 alp1;
Word16 i;
Word32 L_temp;
+ Word32 mul;
Word16 *p_codvec = &codvec[0];
OSCL_UNUSED_ARG(pOverflow);
@@ -693,7 +694,8 @@
L_temp = ((Word32) alp * sq1) << 1;
/* s = L_msu(L_temp, sq, alp_16, pOverflow); */
- s = L_temp - (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(L_temp, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
index 58ab2fa..bb4fe36 100644
--- a/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c3_14pf.cpp
@@ -403,6 +403,7 @@
Word16 *p_codvec = &codvec[0];
Word32 s;
+ Word32 mul;
Word32 alp0;
Word32 alp1;
@@ -487,7 +488,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
index d52b43b..062ee5a 100644
--- a/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/c4_17pf.cpp
@@ -416,6 +416,7 @@
Word16 *p_codvec = &codvec[0];
Word32 s;
+ Word32 mul;
Word32 alp0;
Word32 alp1;
@@ -497,7 +498,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
@@ -610,7 +612,8 @@
s = ((Word32) alp * sq1) << 1;
/* s = L_msu(s, sq, alp_16, pOverflow); */
- s -= (((Word32) sq * alp_16) << 1);
+ __builtin_mul_overflow(sq, alp_16, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
@@ -630,7 +633,8 @@
s = ((Word32) alpk * sq) << 1;
/* s = L_msu(s, psk, alp, pOverflow); */
- s -= (((Word32) psk * alp) << 1);
+ __builtin_mul_overflow(psk, alp, &mul);
+ __builtin_sub_overflow(s, (mul << 1), &s);
if (s > 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
index c25c026..398c71f 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x.cpp
@@ -254,6 +254,7 @@
Word16 k;
Word32 s;
+ Word32 mul;
Word32 y32[L_CODE];
Word32 max;
Word32 tot;
@@ -275,15 +276,19 @@
for (j = (L_CODE - i - 1) >> 1; j != 0; j--)
{
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
}
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
if (!((L_CODE - i) & 1)) /* if even number of iterations */
{
- s += ((Word32) * (p_x++) * *(p_ptr++)) << 1;
+ __builtin_mul_overflow(*(p_x++), *(p_ptr++), &mul);
+ __builtin_add_overflow(s, mul << 1, &s);
}
y32[i] = s;
@@ -299,7 +304,7 @@
}
}
- tot += (max >> 1);
+ __builtin_add_overflow(tot, (max >> 1), &tot);
}
@@ -310,10 +315,13 @@
for (i = L_CODE >> 1; i != 0; i--)
{
+ Word32 result;
s = L_shl(*(p_y32++), j, pOverflow);
- *(p_ptr++) = (s + 0x00008000) >> 16;
+ __builtin_add_overflow(s, 0x00008000, &result);
+ *(p_ptr++) = result >> 16;
s = L_shl(*(p_y32++), j, pOverflow);
- *(p_ptr++) = (s + 0x00008000) >> 16;
+ __builtin_add_overflow(s, 0x00008000, &result);
+ *(p_ptr++) = result >> 16;
}
return;
diff --git a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
index e32eb4a..80ebb73 100644
--- a/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
+++ b/media/module/codecs/amrnb/enc/src/cor_h_x2.cpp
@@ -268,7 +268,7 @@
max = s;
}
}
- tot = (tot + (max >> 1));
+ __builtin_add_overflow(tot, (max >> 1), &tot);
}
j = sub(norm_l(tot), sf, pOverflow);
diff --git a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
index 2ccb777..0d56c9b 100644
--- a/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
+++ b/media/module/codecs/amrnb/enc/src/dtx_enc.cpp
@@ -945,6 +945,7 @@
Word16 i;
Word32 L_frame_en;
+ Word32 mul;
Word32 L_temp;
Word16 log_en_e;
Word16 log_en_m;
@@ -967,7 +968,8 @@
for (i = L_FRAME; i != 0; i--)
{
- L_frame_en += (((Word32) * p_speech) * *(p_speech)) << 1;
+ __builtin_mul_overflow(*p_speech, *p_speech, &mul);
+ __builtin_add_overflow(L_frame_en, mul << 1, &L_frame_en);
p_speech++;
if (L_frame_en < 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/levinson.cpp b/media/module/codecs/amrnb/enc/src/levinson.cpp
index 29cdac6..83dd81e 100644
--- a/media/module/codecs/amrnb/enc/src/levinson.cpp
+++ b/media/module/codecs/amrnb/enc/src/levinson.cpp
@@ -731,7 +731,7 @@
t0 = t0 << 5;
t1 = ((Word32) * (Rh + i) << 16) + ((Word32)(*(Rl + i)) << 1);
- t0 += t1;
+ __builtin_add_overflow(t0, t1, &t0);
/* K = -t0 / Alpha */
diff --git a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
index 584f79b..ab0a221 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_fr.cpp
@@ -326,6 +326,7 @@
Word16 norm_h;
Word16 norm_l;
Word32 s;
+ Word32 mul;
Word32 s2;
Word16 excf[L_SUBFR];
Word16 scaling;
@@ -353,10 +354,12 @@
{
temp = *(p_excf++);
*(p_s_excf++) = temp >> 2;
- s += (Word32) temp * temp;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(s, mul, &s);
temp = *(p_excf++);
*(p_s_excf++) = temp >> 2;
- s += (Word32) temp * temp;
+ __builtin_mul_overflow(temp, temp, &mul);
+ __builtin_add_overflow(s, mul, &s);
}
@@ -387,20 +390,24 @@
while (j--)
{
- s += (Word32) * (p_x++) * *(p_s_excf);
- s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+ __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+ __builtin_add_overflow(s, mul, &s);
+ __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+ __builtin_add_overflow(s2, mul, &s2);
p_s_excf++;
- s += (Word32) * (p_x++) * *(p_s_excf);
- s2 += ((Word32)(*(p_s_excf)) * (*(p_s_excf)));
+ __builtin_mul_overflow(*(p_x++), *p_s_excf, &mul);
+ __builtin_add_overflow(s, mul, &s);
+ __builtin_mul_overflow(*p_s_excf, *p_s_excf, &mul);
+ __builtin_add_overflow(s2, mul, &s2);
p_s_excf++;
}
s2 = s2 << 1;
s2 = Inv_sqrt(s2, pOverflow);
norm_h = (Word16)(s2 >> 16);
- norm_l = (Word16)((s2 >> 1) - (norm_h << 15));
+ __builtin_sub_overflow((s2 >> 1), (norm_h << 15), &norm_l);
corr_h = (Word16)(s >> 15);
- corr_l = (Word16)((s) - (corr_h << 15));
+ __builtin_sub_overflow(s, (corr_h << 15), &corr_l);
/* Normalize correlation = correlation * (1/sqrt(energy)) */
diff --git a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
index c039bb0..0e4b74b 100644
--- a/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
+++ b/media/module/codecs/amrnb/enc/src/pitch_ol.cpp
@@ -959,6 +959,7 @@
Word16 p_max3;
Word16 scal_flag = 0;
Word32 t0;
+ Word32 mul;
#ifdef VAD2
Word32 r01;
@@ -1002,7 +1003,8 @@
for (i = -pit_max; i < L_frame; i++)
{
- t0 += (((Word32) * (p_signal)) * *(p_signal)) << 1;
+ __builtin_mul_overflow(*p_signal, *p_signal, &mul);
+ __builtin_add_overflow(t0, mul << 1, &t0);
p_signal++;
if (t0 < 0)
{
diff --git a/media/module/codecs/amrnb/enc/src/pre_proc.cpp b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
index 042920e..0e2be41 100644
--- a/media/module/codecs/amrnb/enc/src/pre_proc.cpp
+++ b/media/module/codecs/amrnb/enc/src/pre_proc.cpp
@@ -576,7 +576,7 @@
*(p_signal++) = (Word16)((L_tmp + 0x0000800L) >> 12);
st->y1_hi = (Word16)(L_tmp >> 12);
- st->y1_lo = (Word16)((L_tmp << 3) - ((Word32)(st->y1_hi) << 15));
+ __builtin_sub_overflow((Word16)(L_tmp << 3), (st->y1_hi) << 15, &st->y1_lo);
}
diff --git a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
index 352b611..97d0318 100644
--- a/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
+++ b/media/module/codecs/amrnb/enc/src/s10_8pf.cpp
@@ -746,11 +746,13 @@
for (i5 = ipos[5]; i5 < L_CODE; i5 += step)
{
- ps2 = ps1 + *(p_temp1++);
+ __builtin_add_overflow(ps1, *(p_temp1++), &ps2);
- alp2 = alp1 + ((Word32) * (p_temp2 + i5) << 12);
+ __builtin_add_overflow(alp1, *(p_temp2 + i5) << 12, &alp2);
- alp_16 = (Word16)((alp2 + ((Word32) * (p_temp1++) << 14)) >> 16);
+ Word32 result;
+ __builtin_add_overflow(alp2, *(p_temp1++) << 14, &result);
+ alp_16 = (Word16)(result >> 16);
sq2 = (Word16)(((Word32) ps2 * ps2) >> 15);
if (((Word32) sq2 * alp) > ((Word32) sq * alp_16))
diff --git a/media/module/codecs/amrnb/enc/src/set_sign.cpp b/media/module/codecs/amrnb/enc/src/set_sign.cpp
index fa43f78..55658a4 100644
--- a/media/module/codecs/amrnb/enc/src/set_sign.cpp
+++ b/media/module/codecs/amrnb/enc/src/set_sign.cpp
@@ -505,6 +505,7 @@
Word16 en[L_CODE]; /* correlation vector */
Word32 s;
Word32 t;
+ Word32 mul;
Word32 L_temp;
Word16 *p_cn;
Word16 *p_dn;
@@ -525,7 +526,8 @@
val = *(p_cn++);
s = L_mac(s, val, val, pOverflow);
val = *(p_dn++);
- t += ((Word32) val * val) << 1;
+ __builtin_mul_overflow(val, val, &mul);
+ __builtin_add_overflow(t, mul << 1, &t);
}
s = Inv_sqrt(s, pOverflow);
k_cn = (Word16)((L_shl(s, 5, pOverflow)) >> 16);
diff --git a/media/module/codecs/amrnb/enc/src/spstproc.cpp b/media/module/codecs/amrnb/enc/src/spstproc.cpp
index b9574aa..5210a39 100644
--- a/media/module/codecs/amrnb/enc/src/spstproc.cpp
+++ b/media/module/codecs/amrnb/enc/src/spstproc.cpp
@@ -192,6 +192,7 @@
Word16 i;
Word16 j;
Word16 temp;
+ Word32 mul;
Word32 L_temp;
Word32 L_temp2;
Word16 tempShift;
@@ -262,8 +263,10 @@
*/
L_temp = ((Word32) * (p_exc++) * pitch_fac) << 1;
L_temp2 = ((Word32) * (p_exc--) * pitch_fac) << 1;
- L_temp += ((Word32) * (p_code++) * gain_code) << 1;
- L_temp2 += ((Word32) * (p_code++) * gain_code) << 1;
+ __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+ __builtin_add_overflow(L_temp, mul << 1, &L_temp);
+ __builtin_mul_overflow(*(p_code++), gain_code, &mul);
+ __builtin_add_overflow(L_temp2, mul << 1, &L_temp2);
L_temp <<= tempShift;
L_temp2 <<= tempShift;
*(p_exc++) = (Word16)((L_temp + 0x08000L) >> 16);
diff --git a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
index fb72998..e3bd0e0 100644
--- a/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
+++ b/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest.cpp
@@ -21,6 +21,7 @@
#include <audio_utils/sndfile.h>
#include <stdio.h>
+#include <fstream>
#include "gsmamr_enc.h"
@@ -39,7 +40,7 @@
static AmrnbEncTestEnvironment *gEnv = nullptr;
-class AmrnbEncoderTest : public ::testing::TestWithParam<pair<string, int32_t>> {
+class AmrnbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, string>> {
public:
AmrnbEncoderTest() : mAmrEncHandle(nullptr) {}
@@ -53,6 +54,7 @@
AmrNbEncState *mAmrEncHandle;
int32_t EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
int32_t frameCount = INT32_MAX);
+ bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
};
int32_t AmrnbEncoderTest::EncodeFrames(int32_t mode, FILE *fpInput, FILE *mFpOutput,
@@ -87,6 +89,42 @@
return 0;
}
+bool AmrnbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ " but output file size = %td bytes.", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrnbEncoderTest, CreateAmrnbEncoderTest) {
mAmrEncHandle = (AmrNbEncState *)malloc(sizeof(AmrNbEncState));
ASSERT_NE(mAmrEncHandle, nullptr) << "Error in allocating memory to Codec handle";
@@ -111,7 +149,7 @@
int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
- string inputFile = gEnv->getRes() + GetParam().first;
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
FILE *fpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
@@ -121,7 +159,7 @@
// Write file header.
fwrite("#!AMR\n", 1, 6, fpOutput);
- int32_t mode = GetParam().second;
+ int32_t mode = std::get<1>(GetParam());
int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput);
ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
@@ -134,6 +172,11 @@
free(mAmrEncHandle);
mAmrEncHandle = nullptr;
ALOGV("Successfully deleted encoder");
+
+ string refFilePath = gEnv->getRes() + std::get<2>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file " << OUTPUT_FILE
+ << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrnbEncoderTest, ResetEncoderTest) {
@@ -142,7 +185,7 @@
int32_t status = AMREncodeInit(&mAmrEncHandle->encCtx, &mAmrEncHandle->pidSyncCtx, 0);
ASSERT_EQ(status, 0) << "Error creating AMR-NB encoder";
- string inputFile = gEnv->getRes() + GetParam().first;
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
FILE *fpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(fpInput, nullptr) << "Error opening input file " << inputFile;
@@ -152,7 +195,7 @@
// Write file header.
fwrite("#!AMR\n", 1, 6, fpOutput);
- int32_t mode = GetParam().second;
+ int32_t mode = std::get<1>(GetParam());
// Encode kNumFrameReset first
int32_t encodeErr = EncodeFrames(mode, fpInput, fpOutput, kNumFrameReset);
ASSERT_EQ(encodeErr, 0) << "EncodeFrames returned error for Codec mode: " << mode;
@@ -177,22 +220,23 @@
// TODO: Add more test vectors
INSTANTIATE_TEST_SUITE_P(AmrnbEncoderTestAll, AmrnbEncoderTest,
- ::testing::Values(make_pair("bbb_raw_1ch_8khz_s16le.raw", MR475),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR515),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR59),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR67),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR74),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR795),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR102),
- make_pair("bbb_raw_1ch_8khz_s16le.raw", MR122),
- make_pair("sinesweepraw.raw", MR475),
- make_pair("sinesweepraw.raw", MR515),
- make_pair("sinesweepraw.raw", MR59),
- make_pair("sinesweepraw.raw", MR67),
- make_pair("sinesweepraw.raw", MR74),
- make_pair("sinesweepraw.raw", MR795),
- make_pair("sinesweepraw.raw", MR102),
- make_pair("sinesweepraw.raw", MR122)));
+ ::testing::Values(
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR475, "bbb_raw_1ch_8khz_s16le_MR475_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR515, "bbb_raw_1ch_8khz_s16le_MR515_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR59, "bbb_raw_1ch_8khz_s16le_MR59_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR67, "bbb_raw_1ch_8khz_s16le_MR67_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR74, "bbb_raw_1ch_8khz_s16le_MR74_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR795, "bbb_raw_1ch_8khz_s16le_MR795_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR102, "bbb_raw_1ch_8khz_s16le_MR102_ref.amrnb"),
+ make_tuple("bbb_raw_1ch_8khz_s16le.raw", MR122, "bbb_raw_1ch_8khz_s16le_MR122_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR475, "sinesweepraw_MR475_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR515, "sinesweepraw_MR515_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR59, "sinesweepraw_MR59_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR67, "sinesweepraw_MR67_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR74, "sinesweepraw_MR74_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR795, "sinesweepraw_MR795_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR102, "sinesweepraw_MR102_ref.amrnb"),
+ make_tuple("sinesweepraw.raw", MR122, "sinesweepraw_MR122_ref.amrnb")));
int main(int argc, char **argv) {
gEnv = new AmrnbEncTestEnvironment();
diff --git a/media/module/codecs/amrnb/enc/test/AndroidTest.xml b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
index 1509728..a325ee8 100644
--- a/media/module/codecs/amrnb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrnb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrnbEncoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrnbEncoderTest-1.0" />
+ <option name="media-folder-name" value="AmrnbEncoderTest-2.0" />
<option name="dynamic-config-module" value="AmrnbEncoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrnbEncoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrnbEncoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
index 713667a..fdc0daa 100644
--- a/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrnb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrnb/enc/test/README.md b/media/module/codecs/amrnb/enc/test/README.md
index f896bd1..c7b9964 100644
--- a/media/module/codecs/amrnb/enc/test/README.md
+++ b/media/module/codecs/amrnb/enc/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrnbEncoderTest/AmrnbEncoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrnb/enc/test/AmrnbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrnbEncoderTest-1.0 /data/local/tmp/
+adb push AmrnbEncoderTest-2.0 /data/local/tmp/
```
usage: AmrnbEncoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrnbEncoderTest -P /data/local/tmp/AmrnbEncoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
index 2cc88ce..c0e032f 100644
--- a/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
+++ b/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest.cpp
@@ -23,6 +23,7 @@
#include <audio_utils/sndfile.h>
#include <memory>
#include <stdio.h>
+#include <fstream>
#include "pvamrwbdecoder.h"
#include "pvamrwbdecoder_api.h"
@@ -44,7 +45,7 @@
static AmrwbDecTestEnvironment *gEnv = nullptr;
-class AmrwbDecoderTest : public ::testing::TestWithParam<string> {
+class AmrwbDecoderTest : public ::testing::TestWithParam<std::tuple<string, string>> {
public:
AmrwbDecoderTest() : mFpInput(nullptr) {}
@@ -59,6 +60,7 @@
int32_t DecodeFrames(int16_t *decoderCookie, void *decoderBuf, SNDFILE *outFileHandle,
int32_t frameCount = INT32_MAX);
SNDFILE *openOutputFile(SF_INFO *sfInfo);
+ bool compareBinaryFiles(const std::string& refFilePath, const std::string& outFilePath);
};
SNDFILE *AmrwbDecoderTest::openOutputFile(SF_INFO *sfInfo) {
@@ -120,6 +122,42 @@
return 0;
}
+bool AmrwbDecoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ "but output file size = %td bytes", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_F(AmrwbDecoderTest, MultiCreateAmrwbDecoderTest) {
uint32_t memRequirements = pvDecoder_AmrWbMemRequirements();
std::unique_ptr<char[]> decoderBuf(new char[memRequirements]);
@@ -147,7 +185,7 @@
pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -160,6 +198,10 @@
ASSERT_EQ(decoderErr, 0) << "DecodeFrames returned error";
sf_close(outFileHandle);
+ string refFilePath = gEnv->getRes() + std::get<1>(GetParam());
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file "
+ << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
}
TEST_P(AmrwbDecoderTest, ResetDecoderTest) {
@@ -173,7 +215,7 @@
pvDecoder_AmrWb_Init(&amrHandle, decoderBuf.get(), &decoderCookie);
ASSERT_NE(amrHandle, nullptr) << "Failed to initialize decoder";
- string inputFile = gEnv->getRes() + GetParam();
+ string inputFile = gEnv->getRes() + std::get<0>(GetParam());
mFpInput = fopen(inputFile.c_str(), "rb");
ASSERT_NE(mFpInput, nullptr) << "Error opening input file " << inputFile;
@@ -198,8 +240,21 @@
}
INSTANTIATE_TEST_SUITE_P(AmrwbDecoderTestAll, AmrwbDecoderTest,
- ::testing::Values(("bbb_amrwb_1ch_14kbps_16000hz.amrwb"),
- ("bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb")));
+ ::testing::Values(std::make_tuple(
+ "bbb_amrwb_1ch_14kbps_16000hz.amrwb",
+ "bbb_amrwb_1ch_14kbps_16000hz_ref.pcm"),
+ std::make_tuple(
+ "bbb_16000hz_1ch_9kbps_amrwb_30sec.amrwb",
+ "bbb_16000hz_1ch_9kbps_amrwb_30sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_16bps_1sec.amrwb",
+ "bbb_16kHz_1ch_16bps_1sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_6.6bps_3sec.amrwb",
+ "bbb_16kHz_1ch_6.6bps_3sec_ref.pcm"),
+ std::make_tuple(
+ "bbb_16kHz_1ch_23.85bps_3sec.amrwb",
+ "bbb_16kHz_1ch_23.85bps_3sec_ref.pcm")));
int main(int argc, char **argv) {
gEnv = new AmrwbDecTestEnvironment();
diff --git a/media/module/codecs/amrwb/dec/test/AndroidTest.xml b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
index 392df03..dbd1407 100644
--- a/media/module/codecs/amrwb/dec/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/dec/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrwbDecoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrwbDecoderTest-1.0" />
+ <option name="media-folder-name" value="AmrwbDecoderTest-2.0" />
<option name="dynamic-config-module" value="AmrwbDecoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrwbDecoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrwbDecoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
index 506cc3d..52453ee 100644
--- a/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/dec/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrwb/dec/test/README.md b/media/module/codecs/amrwb/dec/test/README.md
index 8e77456..ed76051 100644
--- a/media/module/codecs/amrwb/dec/test/README.md
+++ b/media/module/codecs/amrwb/dec/test/README.md
@@ -22,15 +22,15 @@
adb push ${OUT}/data/nativetest/AmrwbDecoderTest/AmrwbDecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/dec/test/AmrwbDecoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
-adb push AmrwbDecoderTest-1.0 /data/local/tmp/
+adb push AmrwbDecoderTest-2.0 /data/local/tmp/
```
usage: AmrwbDecoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-1.0/
+adb shell /data/local/tmp/AmrwbDecoderTest -P /data/local/tmp/AmrwbDecoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecs/amrwb/enc/src/az_isp.c b/media/module/codecs/amrwb/enc/src/az_isp.c
index d7074f0..22a5c25 100644
--- a/media/module/codecs/amrwb/enc/src/az_isp.c
+++ b/media/module/codecs/amrwb/enc/src/az_isp.c
@@ -248,10 +248,10 @@
b1_h = b0_h;
}
- t0 = ((b1_h * x)<<1) + (((b1_l * x)>>15)<<1);
- t0 += (b2_h * (-32768))<<1; /* t0 = x*b1 - b2 */
- t0 -= (b2_l << 1);
- t0 += (f[n] << 12); /* t0 = x*b1 - b2 + f[i]/2 */
+ __builtin_add_overflow(((b1_h * x)<<1), (((b1_l * x)>>15)<<1), &t0);
+ __builtin_add_overflow(t0, (b2_h * (-32768))<<1, &t0); /* t0 = x*b1 - b2 */
+ __builtin_sub_overflow(t0, (b2_l << 1), &t0);
+ __builtin_add_overflow(t0, (f[n] << 12), &t0); /* t0 = x*b1 - b2 + f[i]/2 */
t0 = L_shl2(t0, 6); /* Q24 to Q30 with saturation */
diff --git a/media/module/codecs/amrwb/enc/src/syn_filt.c b/media/module/codecs/amrwb/enc/src/syn_filt.c
index 7eba12f..40398f5 100644
--- a/media/module/codecs/amrwb/enc/src/syn_filt.c
+++ b/media/module/codecs/amrwb/enc/src/syn_filt.c
@@ -109,38 +109,38 @@
p2 = &sig_lo[i - 1];
p3 = &sig_hi[i - 1];
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
- L_tmp -= vo_mult32((*p2--), (*p1));
- L_tmp1 -= vo_mult32((*p3--), (*p1++));
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
+ __builtin_sub_overflow(L_tmp, vo_mult32((*p2--), (*p1)), &L_tmp);
+ __builtin_sub_overflow(L_tmp1, vo_mult32((*p3--), (*p1++)), &L_tmp1);
L_tmp = L_tmp >> 11;
L_tmp += vo_L_mult(exc[i], a0);
diff --git a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
index 1a6ee27..dc9c1b1 100644
--- a/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
+++ b/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest.cpp
@@ -20,6 +20,7 @@
#include <utils/Log.h>
#include <stdio.h>
+#include <fstream>
#include "cmnMemory.h"
#include "voAMRWB.h"
@@ -34,13 +35,15 @@
static AmrwbEncTestEnvironment *gEnv = nullptr;
-class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t, VOAMRWBFRAMETYPE>> {
+class AmrwbEncoderTest : public ::testing::TestWithParam<tuple<string, int32_t,
+ VOAMRWBFRAMETYPE, string>> {
public:
AmrwbEncoderTest() : mEncoderHandle(nullptr) {
- tuple<string, int32_t, VOAMRWBFRAMETYPE> params = GetParam();
+ tuple<string, int32_t, VOAMRWBFRAMETYPE, string> params = GetParam();
mInputFile = gEnv->getRes() + get<0>(params);
mMode = get<1>(params);
mFrameType = get<2>(params);
+ refFilePath = gEnv->getRes() + get<3>(params);
mMemOperator.Alloc = cmnMemAlloc;
mMemOperator.Copy = cmnMemCopy;
mMemOperator.Free = cmnMemFree;
@@ -66,8 +69,47 @@
VO_CODEC_INIT_USERDATA mUserData;
VO_HANDLE mEncoderHandle;
int32_t mMode;
+ string refFilePath;
+
+ bool compareBinaryFiles(const string& refFilePath, const string& outFilePath);
};
+bool AmrwbEncoderTest::compareBinaryFiles(const std::string &refFilePath,
+ const std::string &outFilePath) {
+ std::ifstream refFile(refFilePath, std::ios::binary | std::ios::ate);
+ std::ifstream outFile(outFilePath, std::ios::binary | std::ios::ate);
+ assert(refFile.is_open() && "Error opening reference file " + refFilePath);
+ assert(outFile.is_open() && "Error opening output file " + outFilePath);
+
+ std::streamsize refFileSize = refFile.tellg();
+ std::streamsize outFileSize = outFile.tellg();
+ if (refFileSize != outFileSize) {
+ ALOGE("Error, File size mismatch: Reference file size = %td bytes,"
+ "but output file size = %td bytes", refFileSize, outFileSize);
+ return false;
+ }
+
+ refFile.seekg(0, std::ios::beg);
+ outFile.seekg(0, std::ios::beg);
+ constexpr std::streamsize kBufferSize = 16 * 1024;
+ char refBuffer[kBufferSize];
+ char outBuffer[kBufferSize];
+
+ while (refFile && outFile) {
+ refFile.read(refBuffer, kBufferSize);
+ outFile.read(outBuffer, kBufferSize);
+
+ std::streamsize refBytesRead = refFile.gcount();
+ std::streamsize outBytesRead = outFile.gcount();
+
+ if (refBytesRead != outBytesRead || memcmp(refBuffer, outBuffer, refBytesRead) != 0) {
+ ALOGE("Error, File content mismatch.");
+ return false;
+ }
+ }
+ return true;
+}
+
TEST_P(AmrwbEncoderTest, CreateAmrwbEncoderTest) {
int32_t status = voGetAMRWBEncAPI(&mApiHandle);
ASSERT_EQ(status, VO_ERR_NONE) << "Failed to get api handle";
@@ -152,38 +194,69 @@
if (fpOutput) {
fclose(fpOutput);
}
+
+ ASSERT_TRUE(compareBinaryFiles(refFilePath, OUTPUT_FILE))
+ << "Error, Binary file comparison failed: Output file "
+ << OUTPUT_FILE << " does not match the reference file " << refFilePath << ".";
}
INSTANTIATE_TEST_SUITE_P(
- AmrwbEncoderTestAll, AmrwbEncoderTest,
- ::testing::Values(
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267),
- make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267)));
+ AmrwbEncoderTestAll, AmrwbEncoderTest,
+ ::testing::Values(
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_DEFAULT,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_DEFAULT_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_ITU,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_ITU_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD66, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD66_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD885, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD885_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1265, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1265_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1425, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1425_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1585, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1585_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1825, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1825_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD1985, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD1985_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2305, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2305_VOAMRWB_RFC3267_ref.amrwb"),
+ make_tuple("bbb_raw_1ch_16khz_s16le.raw", VOAMRWB_MD2385, VOAMRWB_RFC3267,
+ "bbb_raw_1ch_16khz_s16le_VOAMRWB_MD2385_VOAMRWB_RFC3267_ref.amrwb")));
int main(int argc, char **argv) {
gEnv = new AmrwbEncTestEnvironment();
diff --git a/media/module/codecs/amrwb/enc/test/AndroidTest.xml b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
index 8822cb2..1f4121f 100644
--- a/media/module/codecs/amrwb/enc/test/AndroidTest.xml
+++ b/media/module/codecs/amrwb/enc/test/AndroidTest.xml
@@ -23,17 +23,17 @@
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
<option name="target" value="host" />
<option name="config-filename" value="AmrwbEncoderTest" />
- <option name="version" value="1.0"/>
+ <option name="version" value="2.0"/>
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="AmrwbEncoderTest-1.0" />
+ <option name="media-folder-name" value="AmrwbEncoderTest-2.0" />
<option name="dynamic-config-module" value="AmrwbEncoderTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="AmrwbEncoderTest" />
- <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-1.0/" />
+ <option name="native-test-flag" value="-P /sdcard/test/AmrwbEncoderTest-2.0/" />
</test>
</configuration>
diff --git a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
index a0b6218..59701ea 100644
--- a/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
+++ b/media/module/codecs/amrwb/enc/test/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip</value>
+ <value>https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/media/module/codecs/amrwb/enc/test/README.md b/media/module/codecs/amrwb/enc/test/README.md
index 3b9cc39..ea2c31e 100644
--- a/media/module/codecs/amrwb/enc/test/README.md
+++ b/media/module/codecs/amrwb/enc/test/README.md
@@ -22,7 +22,7 @@
adb push ${OUT}/data/nativetest/AmrwbEncoderTest/AmrwbEncoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-1.0.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://dl.google.com/android-unittest/media/frameworks/av/media/module/codecs/amrwb/enc/test/AmrwbEncoderTest-2.0.zip). Download, unzip and push these files into device for testing.
```
adb push AmrwbEncoderTest-1.0 /data/local/tmp/
@@ -30,7 +30,7 @@
usage: AmrwbEncoderTest -P \<path_to_folder\>
```
-adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-1.0/
+adb shell /data/local/tmp/AmrwbEncoderTest -P /data/local/tmp/AmrwbEncoderTest-2.0/
```
Alternatively, the test can also be run using atest command.
diff --git a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
index 42fd94e..433b5e9 100644
--- a/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
+++ b/media/module/codecserviceregistrant/CodecServiceRegistrant.cpp
@@ -790,47 +790,6 @@
}
using namespace ::android::hardware::media::c2;
-
- if (!ionPropertiesDefined()) {
- using IComponentStore =
- ::android::hardware::media::c2::V1_0::IComponentStore;
- std::string const preferredStoreName = "default";
- if (aidlSelected) {
- std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
- if (__builtin_available(android __ANDROID_API_S__, *)) {
- std::string instanceName = ::android::base::StringPrintf(
- "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
- if (AServiceManager_isDeclared(instanceName.c_str())) {
- preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
- AServiceManager_waitForService(instanceName.c_str())));
- }
- }
- if (preferredStore) {
- ::android::SetPreferredCodec2ComponentStore(
- std::make_shared<H2C2ComponentStore>(preferredStore));
- LOG(INFO) <<
- "Preferred Codec2 AIDL store is set to \"" <<
- preferredStoreName << "\".";
- } else {
- LOG(INFO) <<
- "Preferred Codec2 AIDL store is defaulted to \"software\".";
- }
- } else {
- sp<IComponentStore> preferredStore =
- IComponentStore::getService(preferredStoreName.c_str());
- if (preferredStore) {
- ::android::SetPreferredCodec2ComponentStore(
- std::make_shared<H2C2ComponentStore>(preferredStore));
- LOG(INFO) <<
- "Preferred Codec2 HIDL store is set to \"" <<
- preferredStoreName << "\".";
- } else {
- LOG(INFO) <<
- "Preferred Codec2 HIDL store is defaulted to \"software\".";
- }
- }
- }
-
bool registered = false;
const std::string aidlServiceName =
std::string(c2_aidl::IComponentStore::descriptor) + "/software";
@@ -876,6 +835,48 @@
" so it is not being registered with hwservicemanager.";
}
+ // Preferred store must be set after the store is registered to ensure that
+ // the correct preferred store is set.
+ if (!ionPropertiesDefined()) {
+ using IComponentStore =
+ ::android::hardware::media::c2::V1_0::IComponentStore;
+ std::string const preferredStoreName = "default";
+ if (aidlSelected) {
+ std::shared_ptr<c2_aidl::IComponentStore> preferredStore;
+ if (__builtin_available(android __ANDROID_API_S__, *)) {
+ std::string instanceName = ::android::base::StringPrintf(
+ "%s/%s", c2_aidl::IComponentStore::descriptor, preferredStoreName.c_str());
+ if (AServiceManager_isDeclared(instanceName.c_str())) {
+ preferredStore = c2_aidl::IComponentStore::fromBinder(::ndk::SpAIBinder(
+ AServiceManager_waitForService(instanceName.c_str())));
+ }
+ }
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 AIDL store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 AIDL store is defaulted to \"software\".";
+ }
+ } else {
+ sp<IComponentStore> preferredStore =
+ IComponentStore::getService(preferredStoreName.c_str());
+ if (preferredStore) {
+ ::android::SetPreferredCodec2ComponentStore(
+ std::make_shared<H2C2ComponentStore>(preferredStore));
+ LOG(INFO) <<
+ "Preferred Codec2 HIDL store is set to \"" <<
+ preferredStoreName << "\".";
+ } else {
+ LOG(INFO) <<
+ "Preferred Codec2 HIDL store is defaulted to \"software\".";
+ }
+ }
+ }
+
if (registered) {
LOG(INFO) << "Software Codec2 service created and registered.";
}
diff --git a/media/module/extractors/Android.bp b/media/module/extractors/Android.bp
index f654ecd..e29d3e6 100644
--- a/media/module/extractors/Android.bp
+++ b/media/module/extractors/Android.bp
@@ -28,6 +28,10 @@
"liblog",
],
+ static_libs: [
+ "libstagefright_metadatautils",
+ ],
+
// extractors are expected to run on Q(29)
min_sdk_version: "29",
apex_available: [
@@ -56,6 +60,7 @@
"libutils",
"libmediandk_format",
"libmedia_ndkformatpriv",
+ "libstagefright_metadatautils",
],
},
},
@@ -68,3 +73,21 @@
],
},
}
+
+aconfig_declarations {
+ name: "android.media.extractor.flags-aconfig",
+ package: "com.android.media.extractor.flags",
+ container: "com.android.media",
+ srcs: ["extractor.aconfig"],
+}
+
+cc_aconfig_library {
+ name: "android.media.extractor.flags-aconfig-cc",
+ aconfig_declarations: "android.media.extractor.flags-aconfig",
+ host_supported: true,
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+}
diff --git a/media/module/extractors/extractor.aconfig b/media/module/extractors/extractor.aconfig
new file mode 100644
index 0000000..c61efa4
--- /dev/null
+++ b/media/module/extractors/extractor.aconfig
@@ -0,0 +1,13 @@
+# Media Extractor flags.
+#
+# !!! Please add flags in alphabetical order. !!!
+package: "com.android.media.extractor.flags"
+container: "com.android.media"
+
+flag {
+ name: "extractor_sniff_midi_optimizations"
+ is_exported: true
+ namespace: "media_extractor"
+ description: "Enable SniffMidi optimizations."
+ bug: "359920208"
+}
diff --git a/media/module/extractors/fuzzers/Android.bp b/media/module/extractors/fuzzers/Android.bp
index 7a49d8e..3da1589 100644
--- a/media/module/extractors/fuzzers/Android.bp
+++ b/media/module/extractors/fuzzers/Android.bp
@@ -24,6 +24,7 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
default_applicable_licenses: ["frameworks_av_license"],
+ default_team: "trendy_team_android_media_solutions_playback",
}
cc_defaults {
@@ -131,6 +132,7 @@
"libstagefright_id3",
"libstagefright_esds",
"libmp4extractor",
+ "libstagefright_metadatautils",
],
dictionary: "mp4_extractor_fuzzer.dict",
@@ -301,12 +303,18 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libsonivox",
"libmedia_midiiowrapper",
"libmidiextractor",
"libwatchdog",
],
+ shared_libs: [
+ "server_configurable_flags",
+ ],
+
dictionary: "midi_extractor_fuzzer.dict",
host_supported: true,
diff --git a/media/module/extractors/midi/Android.bp b/media/module/extractors/midi/Android.bp
index feabf9e..0eb34fc 100644
--- a/media/module/extractors/midi/Android.bp
+++ b/media/module/extractors/midi/Android.bp
@@ -32,6 +32,8 @@
],
static_libs: [
+ "android.media.extractor.flags-aconfig-cc",
+ "libaconfig_storage_read_api_cc",
"libmedia_midiiowrapper",
"libsonivoxwithoutjet",
"libstagefright_foundation",
@@ -40,6 +42,7 @@
shared_libs: [
"libbase",
+ "server_configurable_flags",
],
host_supported: true,
diff --git a/media/module/extractors/midi/MidiExtractor.cpp b/media/module/extractors/midi/MidiExtractor.cpp
index 167cc40..98d7716 100644
--- a/media/module/extractors/midi/MidiExtractor.cpp
+++ b/media/module/extractors/midi/MidiExtractor.cpp
@@ -20,6 +20,7 @@
#include "MidiExtractor.h"
+#include <com_android_media_extractor_flags.h>
#include <media/MidiIoWrapper.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
@@ -323,10 +324,97 @@
return AMediaFormat_copy(meta, mFileMetadata);
}
-// Sniffer
+static bool startsWith(const uint8_t *buf, size_t size, const char *pattern, size_t patternSize) {
+ if (size < patternSize) {
+ return false;
+ }
+ return (memcmp(buf, pattern, patternSize) == 0);
+}
-bool SniffMidi(CDataSource *source, float *confidence)
-{
+static bool isValidMThd(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "MThd", 4);
+}
+
+static bool isValidXmf(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "XMF_", 4);
+}
+
+static bool isValidImelody(const uint8_t *buf, size_t size) {
+ return startsWith(buf, size, "BEGIN:IMELODY", 13);
+}
+
+static bool isValidRtttl(const uint8_t *buf, size_t size) {
+ #define RTTTL_MAX_TITLE_LEN 32
+ // rtttl starts with the following:
+ // <title>:<type>=<value>
+ //
+ // Where:
+ // - <title>: Up to 32 characters
+ // - <type>: Single character indicating:
+ // 'd' for duration
+ // 'o' for octave
+ // 'b' for beats per minute
+ // - <value>: Corresponding value for the type
+ if (size < 4) {
+ return false;
+ }
+ for (size_t i = 0; i < RTTTL_MAX_TITLE_LEN && i < size; i++) {
+ if (buf[i] == ':') {
+ if (i < (size - 3) && buf[i + 2] == '=') {
+ return true;
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+static bool isValidOta(const uint8_t *buf, size_t size) {
+ #define OTA_RINGTONE 0x25
+ #define OTA_SOUND 0x1d
+ #define OTA_UNICODE 0x22
+
+ // ota starts with the following:
+ // <cmdLen><cmd1><cmd2>..<cmdN>
+ //
+ // Where:
+ // - <cmdLen>: Single character command length
+ // - <cmd1>: Single character (OTA_RINGTONE << 1)
+ // - <cmd2>: Single character (OTA_SOUND << 1) or (OTA_UNICODE << 1)
+ // and so on with last cmd being (0x1d << 1)
+
+ if (size < 3) {
+ return false;
+ }
+
+ uint8_t cmdLen = buf[0];
+ if (cmdLen < 2) {
+ return false;
+ }
+
+ if ((buf[1] >> 1) != OTA_RINGTONE) {
+ return false;
+ }
+ cmdLen--;
+
+ size_t i = 2;
+ while(cmdLen && i < size) {
+ switch(buf[i] >> 1) {
+ case OTA_SOUND:
+ return true;
+ case OTA_UNICODE:
+ break;
+ default:
+ return false;
+ }
+ cmdLen--;
+ i++;
+ }
+
+ return false;
+}
+
+bool SniffMidiLegacy(CDataSource *source, float *confidence) {
MidiEngine p(source, NULL, NULL);
if (p.initCheck() == OK) {
*confidence = 0.8;
@@ -335,7 +423,47 @@
}
ALOGV("SniffMidi: no");
return false;
+}
+bool SniffMidiEfficiently(CDataSource *source, float *confidence) {
+ uint8_t header[128];
+ int filled = source->readAt(source->handle, 0, header, sizeof(header));
+
+ if (isValidMThd(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, MThd");
+ return true;
+ }
+ if (isValidXmf(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, XMF_");
+ return true;
+ }
+ if (isValidImelody(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, imelody");
+ return true;
+ }
+ if (isValidRtttl(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, rtttl");
+ return true;
+ }
+ if (isValidOta(header, filled)) {
+ *confidence = 0.80;
+ ALOGV("SniffMidi: yes, ota");
+ return true;
+ }
+ ALOGV("SniffMidi: no");
+ return false;
+}
+
+// Sniffer
+bool SniffMidi(CDataSource *source, float *confidence) {
+ if(com::android::media::extractor::flags::extractor_sniff_midi_optimizations()) {
+ return SniffMidiEfficiently(source, confidence);
+ }
+ return SniffMidiLegacy(source, confidence);
}
static const char *extensions[] = {
diff --git a/media/module/extractors/mkv/MatroskaExtractor.cpp b/media/module/extractors/mkv/MatroskaExtractor.cpp
index f326db1..10ae07a 100644
--- a/media/module/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/module/extractors/mkv/MatroskaExtractor.cpp
@@ -1787,7 +1787,7 @@
return ERROR_MALFORMED;
}
- if (!MakeVP9CodecSpecificData(trackInfo->mMeta, tmpData.get(), frame.len)) {
+ if (!MakeVP9CodecSpecificDataFromFirstFrame(trackInfo->mMeta, tmpData.get(), frame.len)) {
return ERROR_MALFORMED;
}
diff --git a/media/module/extractors/mp4/MPEG4Extractor.cpp b/media/module/extractors/mp4/MPEG4Extractor.cpp
index f247f8c..12c0aaf 100644
--- a/media/module/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/module/extractors/mp4/MPEG4Extractor.cpp
@@ -51,6 +51,7 @@
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataBase.h>
+#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
#include <byteswap.h>
@@ -2596,8 +2597,32 @@
*offset += chunk_size;
break;
}
-
case FOURCC("vpcC"):
+ {
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ auto buffer = heapbuffer<uint8_t>(chunk_data_size);
+
+ if (buffer.get() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (mDataSource->readAt(data_offset, buffer.get(), chunk_data_size) < chunk_data_size) {
+ return ERROR_IO;
+ }
+
+ if (!MakeVP9CodecPrivateFromVpcC(mLastTrack->meta, buffer.get(), chunk_data_size)) {
+ ALOGE("Failed to create VP9 CodecPrivate from vpcC.");
+ return ERROR_MALFORMED;
+ }
+
+ *offset += chunk_size;
+ break;
+ }
+
case FOURCC("av1C"):
{
auto buffer = heapbuffer<uint8_t>(chunk_data_size);
diff --git a/media/module/metadatautils/MetaDataUtils.cpp b/media/module/metadatautils/MetaDataUtils.cpp
index 0895bb5..177438a 100644
--- a/media/module/metadatautils/MetaDataUtils.cpp
+++ b/media/module/metadatautils/MetaDataUtils.cpp
@@ -134,10 +134,54 @@
}
return true;
}
+
+/**
+ * Build VP9 Codec Feature Metadata (CodecPrivate) to set CSD for VP9 codec.
+ * For reference:
+ * https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate.
+ *
+ * @param meta A pointer to AMediaFormat object.
+ * @param profile The profile value of the VP9 stream.
+ * @param level The VP9 codec level. If the level is unknown, pass -1 to this parameter.
+ * @param bitDepth The bit depth of the luma and color components of the VP9 stream.
+ * @param chromaSubsampling The chroma subsampling of the VP9 stream. If chromaSubsampling is
+ * unknown, pass -1 to this parameter.
+ * @return true if CodecPrivate is set as CSD of AMediaFormat object.
+ *
+ */
+static bool MakeVP9CodecPrivate(AMediaFormat* meta, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling) {
+ if (meta == nullptr) {
+ return false;
+ }
+
+ std::vector<uint8_t> codecPrivate;
+ // Construct CodecPrivate in WebM format (ID | Length | Data).
+ // Helper lambda to add a field to the codec private data
+ auto addField = [&codecPrivate](uint8_t id, uint8_t value) {
+ codecPrivate.push_back(id);
+ codecPrivate.push_back(0x01); // Length is always 1
+ codecPrivate.push_back(value);
+ };
+
+ // Add fields
+ addField(0x01, static_cast<uint8_t>(profile));
+ if (level >= 0) {
+ addField(0x02, static_cast<uint8_t>(level));
+ }
+ addField(0x03, static_cast<uint8_t>(bitDepth));
+ if (chromaSubsampling >= 0) {
+ addField(0x04, static_cast<uint8_t>(chromaSubsampling));
+ }
+ // Set CSD in the meta format
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, codecPrivate.data(), codecPrivate.size());
+ return true;
+}
+
// The param data contains the first frame data, starting with the uncompressed frame
// header. This uncompressed header (refer section 6.2 of the VP9 bitstream spec) is
// used to parse profile, bitdepth and subsampling.
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size) {
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size) {
if (meta == nullptr || data == nullptr || size == 0) {
return false;
}
@@ -227,29 +271,29 @@
if (chromaSubsampling != -1) {
csdSize += 3;
}
+ // As level is not present in first frame build CodecPrivate without it.
+ return MakeVP9CodecPrivate(meta, profile, -1, bitDepth, chromaSubsampling);
+}
- // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed
- // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
- sp<ABuffer> csd = sp<ABuffer>::make(csdSize);
- uint8_t* csdData = csd->data();
-
- *csdData++ = 0x01 /* FEATURE PROFILE */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = profile;
-
- *csdData++ = 0x03 /* FEATURE BITDEPTH */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = bitDepth;
-
- // csdSize more than 6 means chroma subsampling data was found.
- if (csdSize > 6) {
- *csdData++ = 0x04 /* FEATURE SUBSAMPLING */;
- *csdData++ = 0x01 /* length */;
- *csdData++ = chromaSubsampling;
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* csdData, size_t size) {
+ if (meta == nullptr || csdData == nullptr || size < 12) {
+ return false;
}
- AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd->data(), csd->size());
- return true;
+ // Check the first 4 bytes (VersionAndFlags) if they match the required value.
+ if (csdData[0] != 0x01 || csdData[1] != 0x00 || csdData[2] != 0x00 || csdData[3] != 0x00) {
+ return false;
+ }
+
+ // Create VP9 Codec Feature Metadata (CodecPrivate) that can be parsed.
+ // https://www.webmproject.org/docs/container/#vp9-codec-feature-metadata-codecprivate
+ const uint8_t* vpcCData = csdData + 4; // Skip the first 4 bytes (VersionAndFlags)
+
+ int32_t profile = vpcCData[0];
+ int32_t level = vpcCData[1];
+ int32_t bitDepth = (vpcCData[2] >> 4) & 0x0F; // Bit Depth (4 bits).
+ int32_t chromaSubsampling = (vpcCData[2] >> 1) & 0x07; // Chroma Subsampling (3 bits).
+ return MakeVP9CodecPrivate(meta, profile, level, bitDepth, chromaSubsampling);
}
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
diff --git a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
index 69cf21a..9988544 100644
--- a/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
+++ b/media/module/metadatautils/include/media/stagefright/MetaDataUtils.h
@@ -38,7 +38,10 @@
void parseVorbisComment(
AMediaFormat *fileMeta, const char *comment, size_t commentLength);
-bool MakeVP9CodecSpecificData(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecSpecificData(AMediaFormat* meta, int32_t csdSize, int32_t profile, int32_t level,
+ int32_t bitDepth, int32_t chromaSubsampling);
+bool MakeVP9CodecSpecificDataFromFirstFrame(AMediaFormat* meta, const uint8_t* data, size_t size);
+bool MakeVP9CodecPrivateFromVpcC(AMediaFormat* meta, const uint8_t* data, size_t size);
} // namespace android
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 979edab..26e5ddf 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,7 +20,6 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -298,9 +297,11 @@
void MtpFfsHandle::close() {
// Join all child threads before destruction
- for (auto& thread : mChildThreads) {
- thread.join();
+ int count = mChildThreads.size();
+ for (int i = 0; i < count; i++) {
+ mChildThreads[i].join();
}
+ mChildThreads.clear();
io_destroy(mCtx);
closeEndpoints();
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 3d873df..b250a03 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -52,9 +52,6 @@
symbol_file: "libmediandk.map.txt",
first_version: "21",
unversioned_until: "current",
- export_header_libs: [
- "libmediandk_headers",
- ],
}
ndk_headers {
diff --git a/media/psh_utils/Android.bp b/media/psh_utils/Android.bp
index 4662db8..dafa63b 100644
--- a/media/psh_utils/Android.bp
+++ b/media/psh_utils/Android.bp
@@ -19,18 +19,23 @@
local_include_dirs: ["include"],
export_include_dirs: ["include"],
srcs: [
+ "AudioPowerManager.cpp",
+ "AudioToken.cpp",
"HealthStats.cpp",
"HealthStatsProvider.cpp",
+ "PowerClientStats.cpp",
"PowerStats.cpp",
"PowerStatsCollector.cpp",
"PowerStatsProvider.cpp",
],
shared_libs: [
+ "com.android.media.audio-aconfig-cc",
"libaudioutils",
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
+ "libmediautils",
"libutils",
],
cflags: [
diff --git a/media/psh_utils/AudioPowerManager.cpp b/media/psh_utils/AudioPowerManager.cpp
new file mode 100644
index 0000000..3ae681a
--- /dev/null
+++ b/media/psh_utils/AudioPowerManager.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "AudioToken.h"
+#define LOG_TAG "AudioPowerManager"
+#include <com_android_media_audioserver.h>
+#include <cutils/properties.h>
+#include <utils/Log.h>
+#include <psh_utils/AudioPowerManager.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+AudioPowerManager& AudioPowerManager::getAudioPowerManager() {
+ [[clang::no_destroy]] static AudioPowerManager apm;
+ return apm;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startClient(pid_t pid, uid_t uid,
+ const std::string& additional) {
+ std::shared_ptr<PowerClientStats> powerClientStats;
+ std::lock_guard l(mMutex);
+ if (mPowerClientStats.count(uid) == 0) {
+ const auto it = mHistoricalClients.find(uid);
+ if (it == mHistoricalClients.end()) {
+ powerClientStats = std::make_shared<PowerClientStats>(uid, additional);
+ } else {
+ powerClientStats = it->second;
+ mHistoricalClients.erase(it);
+ }
+ mPowerClientStats[uid] = powerClientStats;
+ } else {
+ powerClientStats = mPowerClientStats[uid];
+ }
+ powerClientStats->addPid(pid);
+ mPidToUid[pid] = uid;
+ std::unique_ptr<Token> token =
+ std::make_unique<AudioClientToken>(powerClientStats, pid, uid, additional);
+ mOutstandingTokens.emplace(token.get());
+ return token;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startTrack(uid_t uid, const std::string& additional) {
+ std::lock_guard l(mMutex);
+ if (mPowerClientStats.count(uid) == 0) {
+ ALOGW("%s: Cannot find uid: %d", __func__, uid);
+ return {};
+ }
+ auto powerClientStats = mPowerClientStats[uid];
+ std::unique_ptr<Token> token =
+ std::make_unique<AudioTrackToken>(powerClientStats, additional);
+ mOutstandingTokens.emplace(token.get());
+ return token;
+}
+
+std::unique_ptr<Token> AudioPowerManager::startThread(
+ pid_t pid, const std::string& wakeLockName,
+ WakeFlag wakeFlag, const std::string& additional) {
+ std::lock_guard l(mMutex);
+ std::unique_ptr<Token> token =
+ std::make_unique<AudioThreadToken>(pid, wakeLockName, wakeFlag, additional);
+ mOutstandingTokens.emplace(token.get());
+ return token;
+}
+
+std::string AudioPowerManager::toString() const {
+ const std::string prefix(" ");
+ std::string result;
+ std::lock_guard l(mMutex);
+ result.append("Power Tokens:\n");
+ std::vector<std::string> tokenInfo;
+ for (const auto& token: mOutstandingTokens) {
+ tokenInfo.emplace_back(token->toString());
+ }
+ std::sort(tokenInfo.begin(), tokenInfo.end());
+ for (const auto& info: tokenInfo) {
+ result.append(prefix).append(info).append("\n");
+ }
+ result.append("Power Clients:\n");
+ for (const auto& [uid, powerClientStats]: mPowerClientStats) {
+ result.append(powerClientStats->toString(true, prefix));
+ }
+ result.append("Power Client History:\n");
+ for (const auto& [power, powerClientStats]: mHistoricalClients) {
+ result.append(powerClientStats->toString(true, prefix));
+ }
+ return result;
+}
+
+void AudioPowerManager::stopClient(pid_t pid) {
+ std::lock_guard l(mMutex);
+ const auto pidit = mPidToUid.find(pid);
+ if (pidit == mPidToUid.end()) return;
+ const uid_t uid = pidit->second;
+ const auto it = mPowerClientStats.find(uid);
+ if (it == mPowerClientStats.end()) return;
+
+ auto powerClientStats = it->second;
+ size_t count = powerClientStats->removePid(pid);
+ if (count == 0) {
+ mHistoricalClients[uid] = powerClientStats;
+ mPowerClientStats.erase(it);
+ if (mHistoricalClients.size() > kHistory) {
+ mHistoricalClients.erase(mHistoricalClients.begin()); // remove oldest.
+ }
+ }
+ mPidToUid.erase(pid);
+}
+
+void AudioPowerManager::clear_token_ptr(Token* token) {
+ if (token != nullptr) {
+ std::lock_guard l(mMutex);
+ (void)mOutstandingTokens.erase(token);
+ }
+}
+
+/* static */
+bool AudioPowerManager::enabled() {
+ static const bool enabled = com::android::media::audioserver::power_stats()
+ && property_get_bool("persist.audio.power_stats.enabled", false);
+ return enabled;
+}
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/AudioToken.cpp b/media/psh_utils/AudioToken.cpp
new file mode 100644
index 0000000..f7bf382
--- /dev/null
+++ b/media/psh_utils/AudioToken.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "AudioToken"
+#include <android-base/logging.h>
+#include <utils/Log.h>
+#include "AudioToken.h"
+#include <psh_utils/AudioPowerManager.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+constinit std::atomic<size_t> AudioClientToken::sIdCounter{};
+
+AudioClientToken::AudioClientToken(
+ std::shared_ptr<PowerClientStats> powerClientStats, pid_t pid, uid_t uid,
+ const std::string& additional)
+ : mPowerClientStats(std::move(powerClientStats))
+ , mPid(pid)
+ , mAdditional(additional)
+ , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+ (void)uid;
+}
+
+AudioClientToken::~AudioClientToken() {
+ auto& apm = AudioPowerManager::getAudioPowerManager();
+
+ // APM has a back pointer to AudioToken, which is accessible on toString().
+ // We first remove ourselves to prevent use after free.
+ apm.clear_token_ptr(this);
+
+ // The client token is released when it is no longer registered with AudioFlinger.
+ // However, it is possible that AudioTrackTokens are still active when the client is released
+ // after crashing and some of its tracks are draining. Those track tokens also
+ // maintain a pointer to the PowerClientStats keeping that consistent.
+
+ // Stopping the client moves its PowerClientStats from active to historical
+ // if it is the last pid associated with the client uid.
+ apm.stopClient(mPid);
+}
+
+std::string AudioClientToken::toString() const {
+ std::string result("Client-");
+ result.append(std::to_string(mId)).append(": ")
+ .append(" pid: ").append(std::to_string(mPid));
+ if (!mAdditional.empty()) {
+ result.append(" ").append(mAdditional);
+ }
+ return result;
+}
+
+std::unique_ptr<Token> createAudioClientToken(pid_t pid, uid_t uid,
+ const std::string& additional) {
+ return AudioPowerManager::getAudioPowerManager().startClient(pid, uid, additional);
+}
+
+/* static */
+constinit std::atomic<size_t> AudioThreadToken::sIdCounter{};
+
+AudioThreadToken::AudioThreadToken(
+ pid_t tid, const std::string& wakeLockName,
+ WakeFlag wakeFlag, const std::string& additional)
+ : mTid(tid)
+ , mWakeLockName(wakeLockName)
+ , mWakeFlag(wakeFlag)
+ , mAdditional(additional)
+ , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+}
+
+AudioThreadToken::~AudioThreadToken() {
+ auto& apm = AudioPowerManager::getAudioPowerManager();
+
+ // APM has a back pointer to AudioToken, which is accessible on toString().
+ // We first remove ourselves to prevent use after free.
+ apm.clear_token_ptr(this);
+}
+
+std::string AudioThreadToken::toString() const {
+ std::string result("Thread-");
+ result.append(std::to_string(mId)).append(": ")
+ .append(" ThreadBase-tid: ").append(std::to_string(mTid))
+ .append(" wakeLockName: ").append(mWakeLockName)
+ .append(" wakeFlag: ").append(::android::media::psh_utils::toString(mWakeFlag));
+ if (!mAdditional.empty()) {
+ result.append(" ").append(mAdditional);
+ }
+ return result;
+}
+
+std::unique_ptr<Token> createAudioThreadToken(
+ pid_t pid, const std::string& wakeLockName,
+ WakeFlag wakeFlag, const std::string& additional) {
+ return AudioPowerManager::getAudioPowerManager().startThread(
+ pid, wakeLockName, wakeFlag, additional);
+}
+
+/* static */
+constinit std::atomic<size_t> AudioTrackToken::sIdCounter{};
+
+AudioTrackToken::AudioTrackToken(
+ std::shared_ptr<PowerClientStats> powerClientStats, const std::string& additional)
+ : mPowerClientStats(std::move(powerClientStats))
+ , mAdditional(additional)
+ , mId(sIdCounter.fetch_add(1, std::memory_order_relaxed)) {
+ if (mPowerClientStats){
+ mPowerClientStats->getCommandThread().add(
+ "start",
+ [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
+ pas->start(actualNs);
+ });
+ }
+}
+
+AudioTrackToken::~AudioTrackToken() {
+ // APM has a back pointer to AudioToken, which is accessible on toString().
+ // We first remove ourselves to prevent use after free.
+ AudioPowerManager::getAudioPowerManager().clear_token_ptr(this);
+ if (mPowerClientStats) {
+ mPowerClientStats->getCommandThread().add(
+ "stop",
+ [pas = mPowerClientStats, actualNs = systemTime(SYSTEM_TIME_BOOTTIME)]() {
+ pas->stop(actualNs);
+ });
+ }
+}
+
+std::string AudioTrackToken::toString() const {
+ std::string result("Track-");
+ result.append(std::to_string(mId)).append(": ")
+ .append(mPowerClientStats ? mPowerClientStats->toString() : std::string("null"));
+ if (!mAdditional.empty()) {
+ result.append(" ").append(mAdditional);
+ }
+ return result;
+}
+
+std::unique_ptr<Token> createAudioTrackToken(uid_t uid, const std::string& additional) {
+ return AudioPowerManager::getAudioPowerManager().startTrack(uid, additional);
+}
+
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/AudioToken.h b/media/psh_utils/AudioToken.h
new file mode 100644
index 0000000..aa25b04
--- /dev/null
+++ b/media/psh_utils/AudioToken.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <psh_utils/PowerClientStats.h>
+#include <psh_utils/Token.h>
+
+#include <atomic>
+#include <memory>
+#include <string>
+
+namespace android::media::psh_utils {
+
+class AudioClientToken : public Token {
+public:
+ AudioClientToken(std::shared_ptr<PowerClientStats> powerClientStats, pid_t pid, uid_t uid,
+ const std::string& additional);
+ ~AudioClientToken() override;
+
+ // AudioPowerManager may call toString() while AudioToken is in its dtor.
+ // It is safe so long as toString is final.
+ std::string toString() const final;
+
+private:
+ const std::shared_ptr<PowerClientStats> mPowerClientStats;
+ const pid_t mPid;
+ const std::string mAdditional;
+ const size_t mId;
+ static constinit std::atomic<size_t> sIdCounter;
+};
+
+class AudioThreadToken : public Token {
+public:
+ AudioThreadToken(
+ pid_t tid, const std::string& wakeLockName,
+ WakeFlag wakeFlag, const std::string& additional);
+ ~AudioThreadToken() override;
+
+ // AudioPowerManager may call toString() while AudioToken is in its dtor.
+ // It is safe so long as toString is final.
+ std::string toString() const final;
+
+private:
+ const pid_t mTid;
+ const std::string mWakeLockName;
+ const WakeFlag mWakeFlag;
+ const std::string mAdditional;
+ const size_t mId;
+ static constinit std::atomic<size_t> sIdCounter;
+};
+
+class AudioTrackToken : public Token {
+public:
+ AudioTrackToken(
+ std::shared_ptr<PowerClientStats> powerClientStats, const std::string& additional);
+ ~AudioTrackToken() override;
+
+ // AudioPowerManager may call toString() while AudioToken is in its dtor.
+ // It is safe so long as toString is final.
+ std::string toString() const final;
+
+private:
+ const std::shared_ptr<PowerClientStats> mPowerClientStats;
+ const std::string mAdditional;
+ const size_t mId;
+ static constinit std::atomic<size_t> sIdCounter;
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/PowerClientStats.cpp b/media/psh_utils/PowerClientStats.cpp
new file mode 100644
index 0000000..65f65a44
--- /dev/null
+++ b/media/psh_utils/PowerClientStats.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <psh_utils/PowerClientStats.h>
+#include <mediautils/ServiceUtilities.h>
+
+namespace android::media::psh_utils {
+
+/* static */
+audio_utils::CommandThread& PowerClientStats::getCommandThread() {
+ [[clang::no_destroy]] static audio_utils::CommandThread ct;
+ return ct;
+}
+
+PowerClientStats::PowerClientStats(uid_t uid, const std::string& additional)
+ : mUid(uid), mAdditional(additional) {}
+
+void PowerClientStats::start(int64_t actualNs) {
+ std::lock_guard l(mMutex);
+ ++mTokenCount;
+ if (mStartNs == 0) mStartNs = actualNs;
+ if (mStartStats) return;
+ mStartStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+}
+
+void PowerClientStats::stop(int64_t actualNs) {
+ std::lock_guard l(mMutex);
+ if (--mTokenCount > 0) return;
+ if (mStartNs != 0) mCumulativeNs += actualNs - mStartNs;
+ mStartNs = 0;
+ if (!mStartStats) return;
+ const auto stopStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+ if (stopStats && stopStats != mStartStats) {
+ *mCumulativeStats += *stopStats - *mStartStats;
+ }
+ mStartStats.reset();
+}
+
+void PowerClientStats::addPid(pid_t pid) {
+ std::lock_guard l(mMutex);
+ mPids.emplace(pid);
+}
+
+size_t PowerClientStats::removePid(pid_t pid) {
+ std::lock_guard l(mMutex);
+ mPids.erase(pid);
+ return mPids.size();
+}
+
+std::string PowerClientStats::toString(bool stats, const std::string& prefix) const {
+ std::lock_guard l(mMutex);
+
+ // Adjust delta time and stats if currently running.
+ auto cumulativeStats = mCumulativeStats;
+ auto cumulativeNs = mCumulativeNs;
+ if (mStartNs) cumulativeNs += systemTime(SYSTEM_TIME_BOOTTIME) - mStartNs;
+ if (mStartStats) {
+ const auto stopStats = PowerStatsCollector::getCollector().getStats(kStatTimeToleranceNs);
+ if (stopStats && stopStats != mStartStats) {
+ auto newStats = std::make_shared<PowerStats>(*cumulativeStats);
+ *newStats += *stopStats - *mStartStats;
+ cumulativeStats = newStats;
+ }
+ }
+
+ std::string result(prefix);
+ result.append("uid: ")
+ .append(std::to_string(mUid))
+ .append(" ").append(mediautils::UidInfo::getInfo(mUid)->package)
+ .append(" streams: ").append(std::to_string(mTokenCount))
+ .append(" seconds: ").append(std::to_string(cumulativeNs * 1e-9));
+ result.append(" {");
+ for (auto pid : mPids) {
+ result.append(" ").append(std::to_string(pid));
+ }
+ result.append(" }");
+ if (!mAdditional.empty()) {
+ result.append("\n").append(prefix).append(mAdditional);
+ }
+ if (stats) {
+ std::string prefix2(prefix);
+ prefix2.append(" ");
+ result.append("\n").append(cumulativeStats->normalizedEnergy(prefix2));
+ }
+ return result;
+}
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/benchmarks/Android.bp b/media/psh_utils/benchmarks/Android.bp
index 20efaa9..2382c69 100644
--- a/media/psh_utils/benchmarks/Android.bp
+++ b/media/psh_utils/benchmarks/Android.bp
@@ -17,14 +17,15 @@
"-Werror",
],
static_libs: [
- "libaudioutils",
"libpshutils",
],
shared_libs: [
+ "libaudioutils",
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
+ "libmediautils",
"libutils",
],
}
@@ -38,14 +39,37 @@
"-Werror",
],
static_libs: [
- "libaudioutils",
"libpshutils",
],
shared_libs: [
+ "libaudioutils",
"libbase",
"libbinder_ndk",
"libcutils",
"liblog",
+ "libmediautils",
+ "libutils",
+ ],
+}
+
+cc_benchmark {
+ name: "audio_token_benchmark",
+
+ srcs: ["audio_token_benchmark.cpp"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ static_libs: [
+ "libpshutils",
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "libbase",
+ "libbinder_ndk",
+ "libcutils",
+ "liblog",
+ "libmediautils",
"libutils",
],
}
diff --git a/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp b/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
index d3f815c..4d8b224 100644
--- a/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
+++ b/media/psh_utils/benchmarks/audio_powerstats_benchmark.cpp
@@ -26,6 +26,140 @@
#include <thread>
#include <vector>
+/*
+Pixel 9 XL Pro
+---------------------------------------------------------------------------------------------------------------
+Benchmark Time CPU Iteration
+---------------------------------------------------------------------------------------------------------------
+audio_powerstats_benchmark:
+ #MemoryFixture/CacheAccess/64/0/0/1 5.195761589711465 ns 5.183635029038574 ns 135160912
+ #MemoryFixture/CacheAccess/128/0/0/1 10.37270431027728 ns 10.341754343667125 ns 67574354
+ #MemoryFixture/CacheAccess/256/0/0/1 20.767353363364098 ns 20.708496782017836 ns 33809541
+ #MemoryFixture/CacheAccess/512/0/0/1 41.53473855852046 ns 41.45724926375999 ns 16900399
+ #MemoryFixture/CacheAccess/1024/0/0/1 82.89673650172568 ns 82.68064919937272 ns 8462177
+ #MemoryFixture/CacheAccess/2048/0/0/1 165.77648929323732 ns 165.45127650324827 ns 4227878
+ #MemoryFixture/CacheAccess/4096/0/0/1 331.9272979248067 ns 331.0722959129879 ns 2114919
+ #MemoryFixture/CacheAccess/8192/0/0/1 663.8090302013887 ns 662.2813002594532 ns 1054528
+ #MemoryFixture/CacheAccess/16384/0/0/1 1327.4224893455748 ns 1324.0114138292752 ns 529095
+ #MemoryFixture/CacheAccess/32768/0/0/1 2657.1037276954685 ns 2651.8974883509522 ns 263970
+ #MemoryFixture/CacheAccess/65536/0/0/1 5314.170125835522 ns 5305.20127734871 ns 131679
+ #MemoryFixture/CacheAccess/131072/0/0/1 10624.517848490625 ns 10602.467739493763 ns 66056
+ #MemoryFixture/CacheAccess/262144/0/0/1 21271.09560700047 ns 21224.851075464823 ns 32916
+ #MemoryFixture/CacheAccess/524288/0/0/1 42556.76641626909 ns 42444.65628786041 ns 16508
+ #MemoryFixture/CacheAccess/1048576/0/0/1 85440.6313100312 ns 85076.15703685701 ns 8221
+ #MemoryFixture/CacheAccess/2097152/0/0/1 170908.37391089948 ns 169402.58059051324 ns 4132
+ #MemoryFixture/CacheAccess/4194304/0/0/1 373635.4350000207 ns 372955.40777777723 ns 1800
+ #MemoryFixture/CacheAccess/8388608/0/0/1 685101.2127660838 ns 681594.2330754338 ns 1034
+ #MemoryFixture/CacheAccess/16777216/0/0/1 1588009.158696047 ns 1581510.0217391246 ns 460
+ #MemoryFixture/CacheAccess/33554432/0/0/1 2721626.5387591715 ns 2708149.166666674 ns 258
+ #MemoryFixture/CacheAccess/67108864/0/0/1 5433705.728680161 ns 5413515.914728661 ns 129
+ #MemoryFixture/CacheAccess/64/1/0/1 5.201213751848433 ns 5.180967321755995 ns 135673202
+ #MemoryFixture/CacheAccess/128/1/0/1 10.386209252693448 ns 10.351378045484042 ns 67486234
+ #MemoryFixture/CacheAccess/256/1/0/1 20.742666405371747 ns 20.686210353062208 ns 33848169
+ #MemoryFixture/CacheAccess/512/1/0/1 41.52781367071582 ns 41.4438085044977 ns 16870391
+ #MemoryFixture/CacheAccess/1024/1/0/1 83.03849985460687 ns 82.6732197351271 ns 8442915
+ #MemoryFixture/CacheAccess/2048/1/0/1 166.02706801365886 ns 165.60695561393828 ns 4226169
+ #MemoryFixture/CacheAccess/4096/1/0/1 332.05696890075365 ns 331.3395040136246 ns 2112679
+ #MemoryFixture/CacheAccess/8192/1/0/1 664.3009073119205 ns 662.5811781316487 ns 1055315
+ #MemoryFixture/CacheAccess/16384/1/0/1 1329.0792867154223 ns 1325.0185471435798 ns 527251
+ #MemoryFixture/CacheAccess/32768/1/0/1 2652.9089904482526 ns 2645.5388137876826 ns 264236
+ #MemoryFixture/CacheAccess/65536/1/0/1 5312.635002724743 ns 5300.412875575496 ns 132064
+ #MemoryFixture/CacheAccess/131072/1/0/1 10625.299202810635 ns 10594.376178351697 ns 65982
+ #MemoryFixture/CacheAccess/262144/1/0/1 21270.763359464152 ns 21206.192921372138 ns 33029
+ #MemoryFixture/CacheAccess/524288/1/0/1 42496.14168177758 ns 42381.692498487435 ns 16530
+ #MemoryFixture/CacheAccess/1048576/1/0/1 85425.34302253627 ns 85063.54206182965 ns 8119
+ #MemoryFixture/CacheAccess/2097152/1/0/1 170961.8011639407 ns 169732.18840931158 ns 4124
+ #MemoryFixture/CacheAccess/4194304/1/0/1 440086.77439029363 ns 439010.07195122127 ns 1640
+ #MemoryFixture/CacheAccess/8388608/1/0/1 677684.5246376056 ns 675888.058937202 ns 1035
+ #MemoryFixture/CacheAccess/16777216/1/0/1 1571417.6297115851 ns 1566423.4922394755 ns 451
+ #MemoryFixture/CacheAccess/33554432/1/0/1 2723418.325581582 ns 2708535.8062015465 ns 258
+ #MemoryFixture/CacheAccess/67108864/1/0/1 5435209.372094963 ns 5413991.821705426 ns 129
+ #MemoryFixture/CacheAccess/64/2/0/1 5.204700890931938 ns 5.183036658664568 ns 135406460
+ #MemoryFixture/CacheAccess/128/2/0/1 10.376355078178406 ns 10.348754235460566 ns 67518337
+ #MemoryFixture/CacheAccess/256/2/0/1 20.726238269323797 ns 20.670377070062745 ns 33834057
+ #MemoryFixture/CacheAccess/512/2/0/1 41.49336362336435 ns 41.38084547087122 ns 16890919
+ #MemoryFixture/CacheAccess/1024/2/0/1 82.96761236822086 ns 82.7676652782051 ns 8440753
+ #MemoryFixture/CacheAccess/2048/2/0/1 165.90277344671065 ns 165.63781837950896 ns 4223301
+ #MemoryFixture/CacheAccess/4096/2/0/1 332.08415463794364 ns 331.07455763248197 ns 2110971
+ #MemoryFixture/CacheAccess/8192/2/0/1 662.569068830069 ns 661.1656746088121 ns 1055382
+ #MemoryFixture/CacheAccess/16384/2/0/1 1327.7767031437843 ns 1324.268331214332 ns 528552
+ #MemoryFixture/CacheAccess/32768/2/0/1 2654.714983405558 ns 2647.9097623853727 ns 264546
+ #MemoryFixture/CacheAccess/65536/2/0/1 5304.774145979664 ns 5290.380748589911 ns 131554
+ #MemoryFixture/CacheAccess/131072/2/0/1 10631.0978039924 ns 10602.125724165107 ns 65938
+ #MemoryFixture/CacheAccess/262144/2/0/1 21258.936606489668 ns 21202.585867458216 ns 33016
+ #MemoryFixture/CacheAccess/524288/2/0/1 42460.85577331506 ns 42355.304775195626 ns 16481
+ #MemoryFixture/CacheAccess/1048576/2/0/1 85428.60153206348 ns 85160.29036964968 ns 8224
+ #MemoryFixture/CacheAccess/2097152/2/0/1 170233.91140170072 ns 169409.06511740564 ns 4131
+ #MemoryFixture/CacheAccess/4194304/2/0/1 402022.9022378908 ns 401018.78327444167 ns 1698
+ #MemoryFixture/CacheAccess/8388608/2/0/1 677677.2908216701 ns 675843.1642512042 ns 1035
+ #MemoryFixture/CacheAccess/16777216/2/0/1 1554294.1339100641 ns 1549490.831533465 ns 463
+ #MemoryFixture/CacheAccess/33554432/2/0/1 2722937.453488912 ns 2709007.093023249 ns 258
+ #MemoryFixture/CacheAccess/67108864/2/0/1 5435791.6511618495 ns 5415184.511627913 ns 129
+ #MemoryFixture/CacheAccess/64/0/2/1 5.198916380394579 ns 5.178607363536682 ns 135270162
+ #MemoryFixture/CacheAccess/128/0/2/1 10.39285189976819 ns 10.361873548918089 ns 67571996
+ #MemoryFixture/CacheAccess/256/0/2/1 20.75920269645178 ns 20.69937217558235 ns 33765810
+ #MemoryFixture/CacheAccess/512/0/2/1 41.51556112567147 ns 41.372342254073665 ns 16947585
+ #MemoryFixture/CacheAccess/1024/0/2/1 82.96516513710067 ns 82.78508396196703 ns 8459485
+ #MemoryFixture/CacheAccess/2048/0/2/1 166.19624228249646 ns 165.74873814180103 ns 4221552
+ #MemoryFixture/CacheAccess/4096/0/2/1 331.7269469760912 ns 330.91601941885546 ns 2111762
+ #MemoryFixture/CacheAccess/8192/0/2/1 663.8953077112178 ns 662.4540856828183 ns 1059419
+ #MemoryFixture/CacheAccess/16384/0/2/1 1326.843343898467 ns 1323.254749209487 ns 527193
+ #MemoryFixture/CacheAccess/32768/0/2/1 2656.6743123958327 ns 2651.2139933123217 ns 264069
+ #MemoryFixture/CacheAccess/65536/0/2/1 5316.515245822549 ns 5306.343742646622 ns 131741
+ #MemoryFixture/CacheAccess/131072/0/2/1 10623.00981164003 ns 10584.927048634307 ns 66044
+ #MemoryFixture/CacheAccess/262144/0/2/1 21210.760294289023 ns 21148.895028460767 ns 33028
+ #MemoryFixture/CacheAccess/524288/0/2/1 42522.49017237178 ns 42412.58560628969 ns 16535
+ #MemoryFixture/CacheAccess/1048576/0/2/1 86800.15632693251 ns 86501.64057114806 ns 8124
+ #MemoryFixture/CacheAccess/2097152/0/2/1 177705.58147680553 ns 177010.52665832458 ns 3995
+ #MemoryFixture/CacheAccess/4194304/0/2/1 449051.5944408481 ns 448237.065698044 ns 1583
+ #MemoryFixture/CacheAccess/8388608/0/2/1 1389931.2189924652 ns 1386035.8565891527 ns 516
+ #MemoryFixture/CacheAccess/16777216/0/2/1 4438020.074999826 ns 4420751.918750021 ns 160
+ #MemoryFixture/CacheAccess/33554432/0/2/1 1.730178560976084E7 ns 1.7182623121951293E7 ns 41
+ #MemoryFixture/CacheAccess/67108864/0/2/1 5.283456416664952E7 ns 5.258297450000053E7 ns 12
+ #MemoryFixture/CacheAccess/64/1/2/1 5.204121573005314 ns 5.179569988739665 ns 135600170
+ #MemoryFixture/CacheAccess/128/1/2/1 10.387460007442089 ns 10.354541036512236 ns 67512560
+ #MemoryFixture/CacheAccess/256/1/2/1 20.77893771735786 ns 20.727591539055314 ns 33750321
+ #MemoryFixture/CacheAccess/512/1/2/1 41.4739992379063 ns 41.315239742240664 ns 16908639
+ #MemoryFixture/CacheAccess/1024/1/2/1 82.95454097741914 ns 82.7976946763163 ns 8446970
+ #MemoryFixture/CacheAccess/2048/1/2/1 165.86154320354674 ns 165.43862697234525 ns 4233855
+ #MemoryFixture/CacheAccess/4096/1/2/1 331.8942415618145 ns 331.28362462222265 ns 2109704
+ #MemoryFixture/CacheAccess/8192/1/2/1 663.6968508366361 ns 662.640989545053 ns 1057011
+ #MemoryFixture/CacheAccess/16384/1/2/1 1328.002697434852 ns 1325.3893625606 ns 527909
+ #MemoryFixture/CacheAccess/32768/1/2/1 2656.826225607798 ns 2651.831997636693 ns 264032
+ #MemoryFixture/CacheAccess/65536/1/2/1 5313.403312198365 ns 5296.6562514184625 ns 132178
+ #MemoryFixture/CacheAccess/131072/1/2/1 10603.411688232678 ns 10580.430523642488 ns 66152
+ #MemoryFixture/CacheAccess/262144/1/2/1 21213.68814698657 ns 21160.64858647625 ns 33038
+ #MemoryFixture/CacheAccess/524288/1/2/1 42446.96972817497 ns 42358.49900102921 ns 16517
+ #MemoryFixture/CacheAccess/1048576/1/2/1 85427.89922199522 ns 85099.99477267203 ns 8226
+ #MemoryFixture/CacheAccess/2097152/1/2/1 179576.28781830988 ns 178747.97179230847 ns 4006
+ #MemoryFixture/CacheAccess/4194304/1/2/1 453971.4271099782 ns 453200.38874680526 ns 1564
+ #MemoryFixture/CacheAccess/8388608/1/2/1 1413810.749999729 ns 1409767.6830708506 ns 508
+ #MemoryFixture/CacheAccess/16777216/1/2/1 4481396.176099637 ns 4463691.635220161 ns 159
+ #MemoryFixture/CacheAccess/33554432/1/2/1 1.7363190725006916E7 ns 1.7271956449999947E7 ns 40
+ #MemoryFixture/CacheAccess/67108864/1/2/1 5.310257300000861E7 ns 5.283166808333325E7 ns 12
+ #MemoryFixture/CacheAccess/64/2/2/1 5.194585073441566 ns 5.169936491706671 ns 135797225
+ #MemoryFixture/CacheAccess/128/2/2/1 10.375776978615239 ns 10.351150907177248 ns 67504271
+ #MemoryFixture/CacheAccess/256/2/2/1 20.73537619800892 ns 20.682392672592464 ns 33819437
+ #MemoryFixture/CacheAccess/512/2/2/1 41.46680809632523 ns 41.35825233901641 ns 16913944
+ #MemoryFixture/CacheAccess/1024/2/2/1 82.84606240770246 ns 82.6134204462559 ns 8446202
+ #MemoryFixture/CacheAccess/2048/2/2/1 165.87278324509214 ns 165.32429617950757 ns 4232933
+ #MemoryFixture/CacheAccess/4096/2/2/1 331.2406082982817 ns 330.5629607515063 ns 2116922
+ #MemoryFixture/CacheAccess/8192/2/2/1 663.159315900038 ns 661.6959690484747 ns 1056103
+ #MemoryFixture/CacheAccess/16384/2/2/1 1327.5666883524236 ns 1324.3426747207684 ns 528758
+ #MemoryFixture/CacheAccess/32768/2/2/1 2654.9809699966722 ns 2648.132907418347 ns 264372
+ #MemoryFixture/CacheAccess/65536/2/2/1 5314.47981229803 ns 5303.806613499892 ns 131912
+ #MemoryFixture/CacheAccess/131072/2/2/1 10606.19082560071 ns 10585.181869071148 ns 66097
+ #MemoryFixture/CacheAccess/262144/2/2/1 21187.819721722273 ns 21154.040502117125 ns 33060
+ #MemoryFixture/CacheAccess/524288/2/2/1 42442.62465239758 ns 42311.67198645875 ns 16542
+ #MemoryFixture/CacheAccess/1048576/2/2/1 85539.82432104382 ns 85200.15385547924 ns 8248
+ #MemoryFixture/CacheAccess/2097152/2/2/1 180928.070870083 ns 180122.69382093282 ns 3965
+ #MemoryFixture/CacheAccess/4194304/2/2/1 456790.68648981495 ns 455950.1693600544 ns 1547
+ #MemoryFixture/CacheAccess/8388608/2/2/1 1427351.7287124782 ns 1423232.2613861358 ns 505
+ #MemoryFixture/CacheAccess/16777216/2/2/1 4513772.829113805 ns 4495839.088607608 ns 158
+ #MemoryFixture/CacheAccess/33554432/2/2/1 1.7454686475002743E7 ns 1.7364546800000016E7 ns 40
+ #MemoryFixture/CacheAccess/67108864/2/2/1 5.2963768833327174E7 ns 5.266439433333403E7 ns 12
+
+ */
float result = 0;
using android::media::psh_utils::CoreClass;
diff --git a/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp b/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
index 9e581bc..021eb5a 100644
--- a/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
+++ b/media/psh_utils/benchmarks/audio_powerstatscollector_benchmark.cpp
@@ -22,16 +22,17 @@
#include <benchmark/benchmark.h>
/*
- Pixel 8 Pro
+ Pixel 9 Pro XL
+ (tolerance is the amount of time a cached value is valid).
------------------------------------------------------------------------------------------
Benchmark Time CPU Iteration
------------------------------------------------------------------------------------------
audio_powerstatscollector_benchmark:
- #BM_StatsToleranceMs/0 1.2005660120994434E8 ns 2532739.72 ns 100
- #BM_StatsToleranceMs/50 1281.095987079007 ns 346.0322183913503 ns 2022168
- #BM_StatsToleranceMs/100 459.9668862534226 ns 189.47902626735942 ns 2891307
- #BM_StatsToleranceMs/200 233.8438662484292 ns 149.84041813854736 ns 4407343
- #BM_StatsToleranceMs/500 184.42197142314103 ns 144.86896036787098 ns 7295167
+ #BM_StatsToleranceMs/0 6.346578290999787E7 ns 2069264.56 ns 100
+ #BM_StatsToleranceMs/50 454.12461256065177 ns 203.1644161064639 ns 2615571
+ #BM_StatsToleranceMs/100 167.74983887731364 ns 101.99598388920647 ns 5436852
+ #BM_StatsToleranceMs/200 102.57950838168422 ns 79.40969988086803 ns 7600815
+ #BM_StatsToleranceMs/500 86.87348495571898 ns 75.24841434306252 ns 9789318
*/
// We check how expensive it is to query stats depending
diff --git a/media/psh_utils/benchmarks/audio_token_benchmark.cpp b/media/psh_utils/benchmarks/audio_token_benchmark.cpp
new file mode 100644
index 0000000..47003c0
--- /dev/null
+++ b/media/psh_utils/benchmarks/audio_token_benchmark.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_token_benchmark"
+#include <utils/Log.h>
+
+#include <psh_utils/Token.h>
+
+#include <benchmark/benchmark.h>
+
+/*
+ Pixel 9 Pro XL
+------------------------------------------------------------------------------------------
+ Benchmark Time CPU Iteration
+------------------------------------------------------------------------------------------
+audio_token_benchmark:
+ #BM_ClientToken 494.6548907301575 ns 492.4932166101717 ns 1376819
+ #BM_ThreadToken 140.34316175293938 ns 139.91778452790845 ns 5000397
+ #BM_TrackToken 944.0571625384163 ns 893.7912613357879 ns 643096
+*/
+
+static void BM_ClientToken(benchmark::State& state) {
+ constexpr pid_t kPid = 10;
+ constexpr uid_t kUid = 100;
+ while (state.KeepRunning()) {
+ auto token = android::media::psh_utils::createAudioClientToken(
+ kPid, kUid);
+ benchmark::ClobberMemory();
+ }
+}
+
+BENCHMARK(BM_ClientToken);
+
+static void BM_ThreadToken(benchmark::State& state) {
+ constexpr pid_t kTid = 20;
+ constexpr const char* kWakeLockTag = "thread";
+ while (state.KeepRunning()) {
+ auto token = android::media::psh_utils::createAudioThreadToken(
+ kTid, kWakeLockTag);
+ benchmark::ClobberMemory();
+ }
+}
+
+BENCHMARK(BM_ThreadToken);
+
+static void BM_TrackToken(benchmark::State& state) {
+ constexpr pid_t kPid = 10;
+ constexpr uid_t kUid = 100;
+ auto clientToken = android::media::psh_utils::createAudioClientToken(
+ kPid, kUid);
+ while (state.KeepRunning()) {
+ auto token = android::media::psh_utils::createAudioTrackToken(kUid);
+ benchmark::ClobberMemory();
+ }
+}
+
+BENCHMARK(BM_TrackToken);
+
+BENCHMARK_MAIN();
diff --git a/media/psh_utils/include/psh_utils/AudioPowerManager.h b/media/psh_utils/include/psh_utils/AudioPowerManager.h
new file mode 100644
index 0000000..47dfdb2
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/AudioPowerManager.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "PowerClientStats.h"
+#include "PowerStatsCollector.h"
+#include "Token.h"
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/linked_hash_map.h>
+#include <list>
+#include <map>
+#include <unordered_map>
+#include <unordered_set>
+
+namespace android::media::psh_utils {
+
+/**
+ * AudioPowerManager is a singleton class that
+ * serializes the power, wakelock, and performance
+ * messages
+ */
+class AudioPowerManager {
+ friend class AudioClientToken;
+ friend class AudioThreadToken;
+ friend class AudioTrackToken;
+
+public:
+ static AudioPowerManager& getAudioPowerManager();
+
+ /**
+ * Returns a token indicating that a client is started.
+ * This is associated with an application.
+ */
+ std::unique_ptr<Token> startClient(pid_t pid, uid_t uid,
+ const std::string& additional);
+
+ /**
+ * Returns a token that represents a start instance for uid.
+ * This is typically associated with an AudioTrack / AudioRecord start.
+ */
+ std::unique_ptr<Token> startTrack(uid_t uid, const std::string& additional);
+
+ /**
+ * Returns a token that represents a wakelock for a Thread start.
+ */
+ std::unique_ptr<Token> startThread(
+ pid_t pid, const std::string& wakeLockName,
+ WakeFlag wakeFlag, const std::string& additional);
+
+ std::string toString() const;
+
+ static bool enabled();
+
+private:
+ // For AudioToken dtor only.
+ void clear_token_ptr(Token* token);
+ void stopClient(pid_t pid);
+
+ static constexpr size_t kHistory = 6;
+
+ mutable std::mutex mMutex;
+ std::unordered_set<Token *> mOutstandingTokens GUARDED_BY(mMutex);
+ std::unordered_map<pid_t, uid_t> mPidToUid GUARDED_BY(mMutex);
+ std::map<uid_t, std::shared_ptr<PowerClientStats>> mPowerClientStats GUARDED_BY(mMutex);
+ audio_utils::linked_hash_map<uid_t, std::shared_ptr<PowerClientStats>>
+ mHistoricalClients GUARDED_BY(mMutex);
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/include/psh_utils/PowerClientStats.h b/media/psh_utils/include/psh_utils/PowerClientStats.h
new file mode 100644
index 0000000..6e27e41
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/PowerClientStats.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include "PowerStats.h"
+#include "PowerStatsCollector.h"
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/CommandThread.h>
+#include <memory>
+#include <set>
+
+namespace android::media::psh_utils {
+
+/**
+ * PowerClientStats accumulates power measurements based on start and stop events.
+ *
+ * The start and stop events must eventually be matched, but several start events
+ * in a row only results in the power counted once.
+ */
+class PowerClientStats {
+public:
+ // A command thread is used for tokens to dispatch start and stop sequentially
+ // with less overhead to the caller.
+ static audio_utils::CommandThread& getCommandThread();
+
+ /**
+ * Creates an UID based power stat tracker.
+ *
+ * @param uid uid of app
+ * @param additional string to be printed out.
+ */
+ PowerClientStats(uid_t uid, const std::string& additional);
+
+ /**
+ * Starts power tracking.
+ */
+ void start(int64_t actualNs) EXCLUDES(mMutex);
+
+ /**
+ * Stops power tracking (saves the difference) - must be paired with start().
+ */
+ void stop(int64_t actualNs) EXCLUDES(mMutex);
+
+ /**
+ * Adds a pid to the App for string printing.
+ */
+ void addPid(pid_t pid) EXCLUDES(mMutex);
+
+ /**
+ * Removes the pid from the App for string printing.
+ */
+ size_t removePid(pid_t pid) EXCLUDES(mMutex);
+
+ /**
+ * Returns the string info.
+ * @param stats if true returns the stats.
+ * @return stat string.
+ */
+ std::string toString(bool stats = false, const std::string& prefix = {})
+ const EXCLUDES(mMutex);
+
+private:
+ // Snapshots are taken no more often than 500ms.
+ static constexpr int64_t kStatTimeToleranceNs = 500'000'000;
+
+ mutable std::mutex mMutex;
+ const uid_t mUid;
+ const std::string mName;
+ const std::string mAdditional;
+ std::set<pid_t> mPids GUARDED_BY(mMutex); // pids sharing same uid
+ int64_t mTokenCount GUARDED_BY(mMutex) = 0;
+ int64_t mStartNs GUARDED_BY(mMutex) = 0;
+ std::shared_ptr<const PowerStats> mStartStats GUARDED_BY(mMutex);
+
+ // Cumulative time while active: sum of deltas of (stop - start).
+ int64_t mCumulativeNs GUARDED_BY(mMutex) = 0;
+ // Cumulative stats while active: sum of deltas of (stop - start),
+ // where snapshots are quantized to ~500ms accuracy.
+ std::shared_ptr<PowerStats> mCumulativeStats GUARDED_BY(mMutex) =
+ std::make_shared<PowerStats>();
+};
+
+} // namespace android::media::psh_utils
diff --git a/media/psh_utils/include/psh_utils/Token.h b/media/psh_utils/include/psh_utils/Token.h
new file mode 100644
index 0000000..2b52d11
--- /dev/null
+++ b/media/psh_utils/include/psh_utils/Token.h
@@ -0,0 +1,62 @@
+
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace android::media::psh_utils {
+
+class Token {
+public:
+ virtual ~Token() = default;
+ virtual std::string toString() const = 0;
+};
+
+// Client tokens (one per Audio Client PID)
+std::unique_ptr<Token> createAudioClientToken(pid_t pid, uid_t uid,
+ const std::string& additional = {});
+
+enum class WakeFlag {
+ kNone = 0,
+ kLowLatency = 1,
+ kLowPower = 2,
+};
+
+inline std::string toString(WakeFlag wakeFlag) {
+ std::string result;
+ for (const auto& [flag, name] : std::initializer_list<std::pair<WakeFlag, std::string>> {
+ {WakeFlag::kLowLatency, "kLowLatency"},
+ {WakeFlag::kLowPower, "kLowPower"},
+ }) {
+ if (static_cast<int>(flag) & static_cast<int>(wakeFlag)) {
+ if (!result.empty()) result.append("|");
+ result.append(name);
+ }
+ }
+ return result;
+}
+
+// Thread tokens (one per ThreadBase PID started).
+std::unique_ptr<Token> createAudioThreadToken(
+ pid_t pid, const std::string& wakeLockName,
+ WakeFlag wakeFlag = WakeFlag::kNone, const std::string& additional = {});
+
+// AudioTrack/AudioRecord tokens.
+std::unique_ptr<Token> createAudioTrackToken(uid_t uid, const std::string& additional = {});
+
+} // namespace android::media::psh_utils
diff --git a/media/tests/benchmark/MediaBenchmarkTest/Android.bp b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
index d41a7f9..8f9ee86 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -36,8 +36,8 @@
resource_dirs: ["res"],
libs: [
- "android.test.runner",
- "android.test.base",
+ "android.test.runner.stubs.system",
+ "android.test.base.stubs.system",
],
jni_libs: [
@@ -69,6 +69,6 @@
java_defaults {
name: "MediaBenchmark-defaults",
- min_sdk_version: "29",
- target_sdk_version: "30",
+ min_sdk_version: "35",
+ target_sdk_version: "35",
}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
index 28c2654..bc0c16f 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
+++ b/media/tests/benchmark/MediaBenchmarkTest/AndroidManifest.xml
@@ -26,7 +26,7 @@
tools:ignore="AllowBackup,GoogleAppIndexingWarning,MissingApplicationIcon"
tools:remove="android:appComponentFactory">
</application>
- <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31"/>
+ <uses-sdk android:minSdkVersion="35" android:targetSdkVersion="35"/>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
android:targetPackage="com.android.media.benchmark"
android:label="Benchmark Media Test"/>
diff --git a/media/tests/benchmark/MediaBenchmarkTest/build.gradle b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
index a2af701..87fc24c 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/build.gradle
+++ b/media/tests/benchmark/MediaBenchmarkTest/build.gradle
@@ -27,11 +27,11 @@
apply plugin: 'com.android.application'
android {
- compileSdkVersion 30
+ compileSdkVersion 35
defaultConfig {
applicationId "com.android.media.benchmark"
minSdkVersion 29
- targetSdkVersion 30
+ targetSdkVersion 35
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
index afd70a3..c68a990 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/DecoderTest.java
@@ -46,6 +46,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
@@ -118,7 +119,7 @@
}
@Test(timeout = PER_TEST_TIMEOUT_MS)
- public void testDecoder() throws IOException {
+ public void testDecoder() throws IOException, InterruptedException {
File inputFile = new File(mInputFilePath + mInputFile);
assertTrue("Cannot find " + mInputFile + " in directory " + mInputFilePath,
inputFile.exists());
@@ -133,7 +134,7 @@
extractor.selectExtractorTrack(currentTrack);
MediaFormat format = extractor.getFormat(currentTrack);
String mime = format.getString(MediaFormat.KEY_MIME);
- ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ List<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
assertTrue("No suitable codecs found for file: " + mInputFile + " track : " +
currentTrack + " mime: " + mime, (mediaCodecs.size() > 0));
@@ -205,7 +206,7 @@
extractor.selectExtractorTrack(currentTrack);
MediaFormat format = extractor.getFormat(currentTrack);
String mime = format.getString(MediaFormat.KEY_MIME);
- ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
+ List<String> mediaCodecs = CodecUtils.selectCodecs(mime, false);
for (String codecName : mediaCodecs) {
Log.i("Test: %s\n", mInputFile);
Native nativeDecoder = new Native();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
index 4202732..4ce5214 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/androidTest/java/com/android/media/benchmark/tests/EncoderTest.java
@@ -50,6 +50,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertEquals;
@@ -150,7 +151,7 @@
}
@BeforeClass
- public static void prepareInput() throws IOException {
+ public static void prepareInput() throws IOException, InterruptedException {
mDecodedFileFullHd = new File(mFileDirPath + DECODE_FULLHD_UNPACKED);
int status = decodeFile(mInputFilePath + DECODE_FULLHD_INPUT, mDecodedFileFullHd);
@@ -165,7 +166,8 @@
assertEquals("Decoder returned error " + status, 0, status);
}
- private static int decodeFile(String inputFileName, File outputDecodeFile) throws IOException {
+ private static int decodeFile(String inputFileName, File outputDecodeFile)
+ throws IOException, InterruptedException {
int status = -1;
File inputFile = new File(inputFileName);
assertTrue("Cannot open input file " + inputFileName, inputFile.exists());
@@ -220,7 +222,7 @@
int status;
int frameSize;
- ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
+ List<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
assertTrue("No suitable codecs found for mimetype: " + mMime, (mediaCodecs.size() > 0));
Boolean[] encodeMode = {true, false};
// Encoding the decoded input file
@@ -297,7 +299,7 @@
@Test(timeout = PER_TEST_TIMEOUT_MS)
public void testNativeEncoder() {
- ArrayList<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
+ List<String> mediaCodecs = CodecUtils.selectCodecs(mMime, true);
assertTrue("No suitable codecs found for mimetype: " + mMime, (mediaCodecs.size() > 0));
for (String codecName : mediaCodecs) {
Native nativeEncoder = new Native();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
index 1e10b37..f223242 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/CodecUtils.java
@@ -5,6 +5,7 @@
import android.media.MediaFormat;
import android.os.Build;
import java.util.ArrayList;
+import java.util.List;
public class CodecUtils {
private CodecUtils() {}
@@ -15,7 +16,7 @@
* @param isEncoder Specifies encoder or decoder
* @return ArrayList of codec names
*/
- public static ArrayList<String> selectCodecs(String mimeType, boolean isEncoder) {
+ public static List<String> selectCodecs(String mimeType, boolean isEncoder) {
MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
MediaCodecInfo[] codecInfos = codecList.getCodecInfos();
ArrayList<String> supportedCodecs = new ArrayList<>();
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
index e947ef6..e9b337d 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Decoder.java
@@ -28,7 +28,10 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
import com.android.media.benchmark.library.IBufferXfer;
@@ -37,28 +40,28 @@
private static final boolean DEBUG = false;
private static final int kQueueDequeueTimeoutUs = 1000;
- private final Object mLock = new Object();
- private MediaCodec mCodec;
- private Surface mSurface = null;
- private boolean mRender = false;
- private ArrayList<BufferInfo> mInputBufferInfo;
- private Stats mStats;
- private String mMime;
+ protected final Object mLock = new Object();
+ protected MediaCodec mCodec;
+ protected Surface mSurface = null;
+ protected boolean mRender = false;
+ protected ArrayList<BufferInfo> mInputBufferInfo;
+ protected Stats mStats;
+ protected String mMime;
- private boolean mSawInputEOS;
- private boolean mSawOutputEOS;
- private boolean mSignalledError;
+ protected boolean mSawInputEOS;
+ protected boolean mSawOutputEOS;
+ protected boolean mSignalledError;
- private int mNumInFramesProvided;
- private int mNumInFramesRequired;
+ protected int mNumInFramesProvided;
+ protected int mNumInFramesRequired;
- private int mNumOutputFrame;
- private int mIndex;
+ protected int mNumOutputFrame;
+ protected int mIndex;
- private ArrayList<ByteBuffer> mInputBuffer;
- private FileOutputStream mOutputStream;
- private FrameReleaseQueue mFrameReleaseQueue = null;
- private IBufferXfer.ISendBuffer mIBufferSend = null;
+ protected ArrayList<ByteBuffer> mInputBuffer;
+ protected FileOutputStream mOutputStream;
+ protected FrameReleaseQueue mFrameReleaseQueue = null;
+ protected IBufferXfer.ISendBuffer mIBufferSend = null;
/* success for decoder */
public static final int DECODE_SUCCESS = 0;
@@ -71,7 +74,9 @@
@Override
public boolean receiveBuffer(IBufferXfer.BufferXferInfo info) {
MediaCodec codec = (MediaCodec)info.obj;
- codec.releaseOutputBuffer(info.idx, mRender);
+ if (info.isComplete) {
+ codec.releaseOutputBuffer(info.idx, mRender);
+ }
return true;
}
@Override
@@ -133,6 +138,49 @@
}
}
+ protected void setCallback(MediaCodec codec) {
+ codec.setCallback(new MediaCodec.Callback() {
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ onInputAvailable(inputBufferId, mediaCodec);
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+
+
+ }
+
/**
* Decodes the given input buffer,
* provided valid list of buffer info and format are passed as inputs.
@@ -146,9 +194,10 @@
* DECODE_CREATE_ERROR for decoder not created
* @throws IOException if the codec cannot be created.
*/
- public int decode(@NonNull ArrayList<ByteBuffer> inputBuffer,
- @NonNull ArrayList<BufferInfo> inputBufferInfo, final boolean asyncMode,
- @NonNull MediaFormat format, String codecName) throws IOException {
+ public int decode(@NonNull List<ByteBuffer> inputBuffer,
+ @NonNull List<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName)
+ throws IOException, InterruptedException {
mInputBuffer = new ArrayList<>(inputBuffer.size());
mInputBuffer.addAll(inputBuffer);
mInputBufferInfo = new ArrayList<>(inputBufferInfo.size());
@@ -170,64 +219,34 @@
mFrameReleaseQueue.setMediaCodec(mCodec);
mFrameReleaseQueue.setMime(mMime);
}
+
if (asyncMode) {
- mCodec.setCallback(new MediaCodec.Callback() {
- @Override
- public void onInputBufferAvailable(
- @NonNull MediaCodec mediaCodec, int inputBufferId) {
- try {
- mStats.addInputTime();
- onInputAvailable(inputBufferId, mediaCodec);
- } catch (Exception e) {
- e.printStackTrace();
- Log.e(TAG, e.toString());
- }
- }
-
- @Override
- public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
- int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
- mStats.addOutputTime();
- onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
- if (mSawOutputEOS) {
- synchronized (mLock) { mLock.notify(); }
- }
- }
-
- @Override
- public void onOutputFormatChanged(
- @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
- Log.i(TAG, "Output format changed. Format: " + format.toString());
- }
-
- @Override
- public void onError(
- @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
- mSignalledError = true;
- Log.e(TAG, "Codec Error: " + e.toString());
- e.printStackTrace();
- synchronized (mLock) { mLock.notify(); }
- }
- });
+ setCallback(mCodec);
}
int isEncoder = 0;
if (DEBUG) {
Log.d(TAG, "Media Format : " + format.toString());
}
mCodec.configure(format, mSurface, null, isEncoder);
+
mCodec.start();
- Log.i(TAG, "Codec started ");
+ Log.i(TAG, "Codec started async mode ? " + asyncMode);
long eTime = mStats.getCurTime();
mStats.setInitTime(mStats.getTimeDiff(sTime, eTime));
mStats.setStartTime();
if (asyncMode) {
try {
- synchronized (mLock) { mLock.wait(); }
- if (mSignalledError) {
- return DECODE_DECODER_ERROR;
+ synchronized (mLock) {
+ while (!mSawOutputEOS && !mSignalledError) {
+ mLock.wait();
+ }
+ if (mSignalledError) {
+ return DECODE_DECODER_ERROR;
+ }
}
} catch (InterruptedException e) {
- e.printStackTrace();
+ Log.e(TAG, "Error in waiting");
+ throw e;
}
} else {
while (!mSawOutputEOS && !mSignalledError) {
@@ -319,7 +338,7 @@
return mCodec.getOutputFormat();
}
- private void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ protected void onInputAvailable(int inputBufferId, MediaCodec mediaCodec) {
if (inputBufferId >= 0) {
ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
BufferInfo bufInfo;
@@ -351,7 +370,7 @@
}
}
- private void onOutputAvailable(
+ protected void onOutputAvailable(
MediaCodec mediaCodec, int outputBufferId, BufferInfo outputBufferInfo) {
if (mSawOutputEOS || outputBufferId < 0) {
return;
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
index 63d17ee..3aa38d1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Encoder.java
@@ -200,7 +200,8 @@
* @throws IOException If the codec cannot be created.
*/
public int encode(String codecName, MediaFormat encodeFormat, String mime, int frameRate,
- int sampleRate, int frameSize, boolean asyncMode) throws IOException {
+ int sampleRate, int frameSize, boolean asyncMode)
+ throws IOException, InterruptedException {
mInputBufferSize = (mInputStream != null) ? mInputStream.getChannel().size() : 0;
mOffset = 0;
mFrameRate = frameRate;
@@ -275,12 +276,16 @@
mStats.setStartTime();
if (asyncMode) {
try {
- synchronized (mLock) { mLock.wait(); }
- if (mSignalledError) {
- return ENCODE_ENCODER_ERROR;
+ synchronized (mLock) {
+ while (!mSawOutputEOS && !mSignalledError) {
+ mLock.wait();
+ }
+ if (mSignalledError) {
+ return ENCODE_ENCODER_ERROR;
+ }
}
} catch (InterruptedException e) {
- e.printStackTrace();
+ throw e;
}
} else {
while (!mSawOutputEOS && !mSignalledError) {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
index f3024e7..1c0f810 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Extractor.java
@@ -76,6 +76,21 @@
public MediaCodec.BufferInfo getBufferInfo() { return this.mBufferInfo; }
/**
+ * Returns the maximum sample size for the selected track
+ * @return max sample size in the given track
+ */
+ public int getMaxSampleSize() {
+ int size = 0;
+ int maxSampleSize = 0;
+ while ((size = (int) mExtractor.getSampleSize()) != -1) {
+ maxSampleSize = Math.max(maxSampleSize, size);
+ mExtractor.advance();
+ }
+ mExtractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+ return maxSampleSize;
+ }
+
+ /**
* Returns the duration of the sample
*/
public long getClipDuration() { return this.mDurationUs; }
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
index 90731ed..20a2573 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/FrameReleaseQueue.java
@@ -185,7 +185,7 @@
try {
mCodec.releaseOutputBuffer(curFrameInfo.bufferId, actualRender);
} catch (IllegalStateException e) {
- e.printStackTrace();
+ throw(e);
}
});
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
index a75962c..c97a35c 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXfer.java
@@ -28,6 +28,7 @@
public Object obj;
int flag;
int bytesRead;
+ boolean isComplete = true;
long presentationTimeUs;
}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
index ab55df5..3e6cee1 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/IBufferXferImpl.java
@@ -16,9 +16,9 @@
package com.android.media.benchmark.library;
-/**
+/*
* Class that manages the buffer senders
-*/
+ */
import com.android.media.benchmark.library.IBufferXfer;
import java.util.ArrayDeque;
import android.util.Log;
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java
new file mode 100644
index 0000000..cb92f06
--- /dev/null
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/MultiAccessUnitDecoder.java
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.media.benchmark.library;
+
+import android.view.Surface;
+
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import com.android.media.benchmark.library.IBufferXfer;
+import com.android.media.benchmark.library.Decoder;
+
+public class MultiAccessUnitDecoder extends Decoder {
+ private static final String TAG = "MultiAccessUnitDecoder";
+ private static final boolean DEBUG = false;
+ private final ArrayDeque<BufferInfo> mInputInfos = new ArrayDeque<>();
+
+ @Override
+ public void setCallback(MediaCodec codec) {
+ mCodec.setCallback(new MediaCodec.Callback() {
+ boolean isUsingLargeFrameMode = false;
+
+ @Override
+ public void onInputBufferAvailable(
+ @NonNull MediaCodec mediaCodec, int inputBufferId) {
+ try {
+ mStats.addInputTime();
+ if (isUsingLargeFrameMode) {
+ onInputsAvailable(inputBufferId, mediaCodec);
+ } else {
+ onInputAvailable(inputBufferId, mediaCodec);
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ Log.e(TAG, e.toString());
+ }
+ }
+
+ @Override
+ public void onOutputBufferAvailable(@NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull MediaCodec.BufferInfo bufferInfo) {
+ mStats.addOutputTime();
+ onOutputAvailable(mediaCodec, outputBufferId, bufferInfo);
+ if (mSawOutputEOS) {
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputBuffersAvailable(
+ @NonNull MediaCodec mediaCodec,
+ int outputBufferId, @NonNull ArrayDeque<BufferInfo> infos) {
+ int i = 0;
+ while(i++ < infos.size()) {
+ mStats.addOutputTime();
+ }
+ onOutputsAvailable(mediaCodec, outputBufferId, infos);
+ if (mSawOutputEOS) {
+ synchronized (mLock) { mLock.notify(); }
+ }
+ }
+
+ @Override
+ public void onOutputFormatChanged(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaFormat format) {
+ Log.i(TAG, "Output format changed. Format: " + format.toString());
+ final int maxOutputSize = format.getNumber(
+ MediaFormat.KEY_BUFFER_BATCH_MAX_OUTPUT_SIZE, 0).intValue();
+ isUsingLargeFrameMode = (maxOutputSize > 0);
+ }
+
+ @Override
+ public void onError(
+ @NonNull MediaCodec mediaCodec, @NonNull MediaCodec.CodecException e) {
+ mSignalledError = true;
+ Log.e(TAG, "Codec Error: " + e.toString());
+ e.printStackTrace();
+ synchronized (mLock) { mLock.notify(); }
+ }
+ });
+
+ }
+ /**
+ * Decodes the given input buffer,
+ * provided valid list of buffer info and format are passed as inputs.
+ *
+ * @param inputBuffer Decode the provided list of ByteBuffers
+ * @param inputBufferInfo List of buffer info corresponding to provided input buffers
+ * @param asyncMode Will run on async implementation if true
+ * @param format For creating the decoder if codec name is empty and configuring it
+ * @param codecName Will create the decoder with codecName
+ * @return DECODE_SUCCESS if decode was successful, DECODE_DECODER_ERROR for fail,
+ * DECODE_CREATE_ERROR for decoder not created
+ * @throws IOException if the codec cannot be created.
+ */
+ @Override
+ public int decode(@NonNull List<ByteBuffer> inputBuffer,
+ @NonNull List<BufferInfo> inputBufferInfo, final boolean asyncMode,
+ @NonNull MediaFormat format, String codecName)
+ throws IOException, InterruptedException {
+ return super.decode(inputBuffer, inputBufferInfo, asyncMode, format, codecName);
+ }
+
+ private void onInputsAvailable(int inputBufferId, MediaCodec mediaCodec) {
+ if (inputBufferId >= 0) {
+ ByteBuffer inputCodecBuffer = mediaCodec.getInputBuffer(inputBufferId);
+ BufferInfo bufInfo;
+ mInputInfos.clear();
+ int offset = 0;
+ while (mNumInFramesProvided < mNumInFramesRequired) {
+ bufInfo = mInputBufferInfo.get(mIndex);
+ mSawInputEOS = (bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ if (inputCodecBuffer.remaining() < bufInfo.size) {
+ if (mInputInfos.size() == 0) {
+ Log.d(TAG, "SampleSize " + inputCodecBuffer.remaining()
+ + "greater than MediaCodec Buffer size " + bufInfo.size);
+ }
+ break;
+ }
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ bufInfo.offset = offset; offset += bufInfo.size;
+ mInputInfos.add(bufInfo);
+ mNumInFramesProvided++;
+ mIndex = mNumInFramesProvided % (mInputBufferInfo.size() - 1);
+ }
+ if (mNumInFramesProvided >= mNumInFramesRequired) {
+ mIndex = mInputBufferInfo.size() - 1;
+ bufInfo = mInputBufferInfo.get(mIndex);
+ if (inputCodecBuffer.remaining() > bufInfo.size) {
+ if ((bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) == 0) {
+ Log.e(TAG, "Error in EOS flag for Decoder");
+ }
+ mSawInputEOS = (bufInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ inputCodecBuffer.put(mInputBuffer.get(mIndex).array());
+ bufInfo.offset = offset; offset += bufInfo.size;
+ mInputInfos.add(bufInfo);
+ mNumInFramesProvided++;
+ }
+ }
+ if (mInputInfos.size() == 0) {
+ Log.d(TAG, " No inputs to queue");
+ } else {
+ mStats.addFrameSize(offset);
+ mediaCodec.queueInputBuffers(inputBufferId, mInputInfos);
+ }
+ }
+ }
+
+ private void onOutputsAvailable(MediaCodec mc, int outputBufferId,
+ ArrayDeque<BufferInfo> infos) {
+ if (mSawOutputEOS || outputBufferId < 0) {
+ return;
+ }
+ Iterator<BufferInfo> iter = infos.iterator();
+ while (iter.hasNext()) {
+ BufferInfo bufferInfo = iter.next();
+ mNumOutputFrame++;
+ if (DEBUG) {
+ Log.d(TAG,
+ "In OutputBufferAvailable ,"
+ + " output frame number = " + mNumOutputFrame
+ + " timestamp = " + bufferInfo.presentationTimeUs
+ + " size = " + bufferInfo.size);
+ }
+ if (mIBufferSend != null) {
+ IBufferXfer.BufferXferInfo info = new IBufferXfer.BufferXferInfo();
+ info.buf = mc.getOutputBuffer(outputBufferId);
+ info.idx = outputBufferId;
+ info.obj = mc;
+ info.bytesRead = bufferInfo.size;
+ info.presentationTimeUs = bufferInfo.presentationTimeUs;
+ info.flag = bufferInfo.flags;
+ info.isComplete = iter.hasNext() ? false : true;
+ mIBufferSend.sendBuffer(this, info);
+ }
+ mSawOutputEOS |= (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ }
+ if (mOutputStream != null) {
+ try {
+ ByteBuffer outputBuffer = mc.getOutputBuffer(outputBufferId);
+ byte[] bytesOutput = new byte[outputBuffer.remaining()];
+ outputBuffer.get(bytesOutput);
+ mOutputStream.write(bytesOutput);
+ } catch (IOException e) {
+ e.printStackTrace();
+ Log.d(TAG, "Error Dumping File: Exception " + e.toString());
+ }
+ }
+ if (mIBufferSend == null) {
+ mc.releaseOutputBuffer(outputBufferId, mRender);
+ }
+ if (mSawOutputEOS) {
+ Log.i(TAG, "Large frame - saw output EOS");
+ }
+ // we don't support frame release queue for large audio frame
+ }
+}
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
index 340b539..786290d 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Muxer.java
@@ -23,6 +23,7 @@
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.List;
public class Muxer {
private Stats mStats;
@@ -61,8 +62,8 @@
* @param inputBufferInfo Buffer information related to these samples
* @return Returns Status as 0 if write operation is successful, -1 otherwise
*/
- public int mux(int trackIndex, ArrayList<ByteBuffer> inputExtractedBuffer,
- ArrayList<MediaCodec.BufferInfo> inputBufferInfo) {
+ public int mux(int trackIndex, List<ByteBuffer> inputExtractedBuffer,
+ List<MediaCodec.BufferInfo> inputBufferInfo) {
mStats.setStartTime();
for (int sampleCount = 0; sampleCount < inputExtractedBuffer.size(); sampleCount++) {
try {
diff --git a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
index 0ebf798..17de1e7 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
+++ b/media/tests/benchmark/MediaBenchmarkTest/src/main/java/com/android/media/benchmark/library/Stats.java
@@ -23,6 +23,7 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
+import java.util.List;
/**
* Measures Performance.
@@ -88,9 +89,9 @@
public long getStartTime() { return mStartTimeNs; }
- public ArrayList<Long> getOutputTimers() { return mOutputTimer; }
+ public List<Long> getOutputTimers() { return mOutputTimer; }
- public ArrayList<Long> getInputTimers() { return mInputTimer; }
+ public List<Long> getInputTimers() { return mInputTimer; }
public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); }
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index ffcde42..679b111 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "ServiceUtilities"
#include <audio_utils/clock.h>
+#include <android-base/properties.h>
#include <binder/AppOpsManager.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -28,9 +29,11 @@
#include <media/AidlConversionUtil.h>
#include <android/content/AttributionSourceState.h>
-#include <iterator>
#include <algorithm>
+#include <iterator>
+#include <mutex>
#include <pwd.h>
+#include <thread>
/* When performing permission checks we do not use permission cache for
* runtime permissions (protection level dangerous) as they may change at
@@ -41,6 +44,10 @@
namespace android {
+namespace {
+constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
+}
+
using content::AttributionSourceState;
static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_AUDIO");
@@ -115,7 +122,7 @@
return std::optional<AttributionSourceState>{myAttributionSource};
}
- static bool checkRecordingInternal(const AttributionSourceState &attributionSource,
+ static int checkRecordingInternal(const AttributionSourceState &attributionSource,
const uint32_t virtualDeviceId,
const String16 &msg, bool start, audio_source_t source) {
// Okay to not track in app ops as audio server or media server is us and if
@@ -138,15 +145,15 @@
const int32_t attributedOpCode = getOpForSource(source);
permission::PermissionChecker permissionChecker;
- bool permitted = false;
+ int permitted;
if (start) {
- permitted = (permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
+ permitted = permissionChecker.checkPermissionForStartDataDeliveryFromDatasource(
sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
- attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
+ attributedOpCode);
} else {
- permitted = (permissionChecker.checkPermissionForPreflightFromDatasource(
+ permitted = permissionChecker.checkPermissionForPreflightFromDatasource(
sAndroidPermissionRecordAudio, resolvedAttributionSource.value(), msg,
- attributedOpCode) != permission::PermissionChecker::PERMISSION_HARD_DENIED);
+ attributedOpCode);
}
return permitted;
@@ -156,17 +163,17 @@
bool recordingAllowed(const AttributionSourceState &attributionSource, audio_source_t source) {
return checkRecordingInternal(attributionSource, DEVICE_ID_DEFAULT, String16(), /*start*/ false,
- source);
+ source) != PERMISSION_HARD_DENIED;
}
bool recordingAllowed(const AttributionSourceState &attributionSource,
const uint32_t virtualDeviceId,
audio_source_t source) {
return checkRecordingInternal(attributionSource, virtualDeviceId,
- String16(), /*start*/ false, source);
+ String16(), /*start*/ false, source) != PERMISSION_HARD_DENIED;
}
-bool startRecording(const AttributionSourceState& attributionSource,
+int startRecording(const AttributionSourceState& attributionSource,
const uint32_t virtualDeviceId,
const String16& msg,
audio_source_t source) {
@@ -392,6 +399,106 @@
return NO_ERROR;
}
+// TODO(b/285588444), clean this up on main, but soak it for backporting purposes for now
+namespace {
+class BluetoothPermissionCache {
+ static constexpr auto SYSPROP_NAME = "cache_key.system_server.package_info";
+ const String16 BLUETOOTH_PERM {"android.permission.BLUETOOTH_CONNECT"};
+ mutable std::mutex mLock;
+ // Cached property conditionally defined, since only avail on bionic. On host, don't inval cache
+#if defined(__BIONIC__)
+ // Unlocked, but only accessed from mListenerThread
+ base::CachedProperty mCachedProperty;
+#endif
+ // This thread is designed to never join/terminate, so no signal is fine
+ const std::thread mListenerThread;
+ GUARDED_BY(mLock)
+ std::string mPropValue;
+ GUARDED_BY(mLock)
+ std::unordered_map<uid_t, bool> mCache;
+ PermissionController mPc{};
+public:
+ BluetoothPermissionCache()
+#if defined(__BIONIC__)
+ : mCachedProperty{SYSPROP_NAME},
+ mListenerThread([this]() mutable {
+ while (true) {
+ std::string newVal = mCachedProperty.WaitForChange() ?: "";
+ std::lock_guard l{mLock};
+ if (newVal != mPropValue) {
+ ALOGV("Bluetooth permission update");
+ mPropValue = newVal;
+ mCache.clear();
+ }
+ }
+ })
+#endif
+ {}
+
+ bool checkPermission(uid_t uid, pid_t pid) {
+ std::lock_guard l{mLock};
+ auto it = mCache.find(uid);
+ if (it == mCache.end()) {
+ it = mCache.insert({uid, mPc.checkPermission(BLUETOOTH_PERM, pid, uid)}).first;
+ }
+ return it->second;
+ }
+};
+
+// Don't call this from locks, since it potentially calls up to system server!
+// Check for non-app UIDs above this method!
+bool checkBluetoothPermission(const AttributionSourceState& attr) {
+ [[clang::no_destroy]] static BluetoothPermissionCache impl{};
+ return impl.checkPermission(attr.uid, attr.pid);
+}
+} // anonymous
+
+/**
+ * Determines if the MAC address in Bluetooth device descriptors returned by APIs of
+ * a native audio service (audio flinger, audio policy) must be anonymized.
+ * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission
+ * are not anonymized.
+ *
+ * @param attributionSource The attribution source of the calling app.
+ * @param caller string identifying the caller for logging.
+ * @return true if the MAC addresses must be anonymized, false otherwise.
+ */
+bool mustAnonymizeBluetoothAddress(
+ const AttributionSourceState& attributionSource, const String16&) {
+ uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
+ bool res;
+ switch(multiuser_get_app_id(uid)) {
+ case AID_ROOT:
+ case AID_SYSTEM:
+ case AID_RADIO:
+ case AID_BLUETOOTH:
+ case AID_MEDIA:
+ case AID_AUDIOSERVER:
+ // Don't anonymize for privileged clients
+ res = false;
+ break;
+ default:
+ res = !checkBluetoothPermission(attributionSource);
+ break;
+ }
+ ALOGV("%s uid: %d, result: %d", __func__, uid, res);
+ return res;
+}
+
+/**
+ * Modifies the passed MAC address string in place for consumption by unprivileged clients.
+ * the string is assumed to have a valid MAC address format.
+ * the anonymization must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java
+ *
+ * @param address input/output the char string contining the MAC address to anonymize.
+ */
+void anonymizeBluetoothAddress(char *address) {
+ if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) {
+ return;
+ }
+ memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX"));
+}
+
sp<content::pm::IPackageManagerNative> MediaPackageManager::retrievePackageManager() {
const sp<IServiceManager> sm = defaultServiceManager();
if (sm == nullptr) {
@@ -473,35 +580,38 @@
}
}
+namespace mediautils {
+
// How long we hold info before we re-fetch it (24 hours) if we found it previously.
static constexpr nsecs_t INFO_EXPIRATION_NS = 24 * 60 * 60 * NANOS_PER_SECOND;
// Maximum info records we retain before clearing everything.
static constexpr size_t INFO_CACHE_MAX = 1000;
// The original code is from MediaMetricsService.cpp.
-mediautils::UidInfo::Info mediautils::UidInfo::getInfo(uid_t uid)
+std::shared_ptr<const UidInfo::Info> UidInfo::getCachedInfo(uid_t uid)
{
+ std::shared_ptr<const UidInfo::Info> info;
+
const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- struct mediautils::UidInfo::Info info;
{
std::lock_guard _l(mLock);
auto it = mInfoMap.find(uid);
if (it != mInfoMap.end()) {
info = it->second;
ALOGV("%s: uid %d expiration %lld now %lld",
- __func__, uid, (long long)info.expirationNs, (long long)now);
- if (info.expirationNs <= now) {
+ __func__, uid, (long long)info->expirationNs, (long long)now);
+ if (info->expirationNs <= now) {
// purge the stale entry and fall into re-fetching
ALOGV("%s: entry for uid %d expired, now %lld",
__func__, uid, (long long)now);
mInfoMap.erase(it);
- info.uid = (uid_t)-1; // this is always fully overwritten
+ info.reset(); // force refetch
}
}
}
// if we did not find it in our map, look it up
- if (info.uid == (uid_t)(-1)) {
+ if (!info) {
sp<IServiceManager> sm = defaultServiceManager();
sp<content::pm::IPackageManagerNative> package_mgr;
if (sm.get() == nullptr) {
@@ -586,17 +696,30 @@
// first clear if we have too many cached elements. This would be rare.
if (mInfoMap.size() >= INFO_CACHE_MAX) mInfoMap.clear();
- // always overwrite
- info.uid = uid;
- info.package = std::move(pkg);
- info.installer = std::move(installer);
- info.versionCode = versionCode;
- info.expirationNs = now + (notFound ? 0 : INFO_EXPIRATION_NS);
+ info = std::make_shared<const UidInfo::Info>(
+ uid,
+ std::move(pkg),
+ std::move(installer),
+ versionCode,
+ now + (notFound ? 0 : INFO_EXPIRATION_NS));
ALOGV("%s: adding uid %d package '%s' expirationNs: %lld",
- __func__, uid, info.package.c_str(), (long long)info.expirationNs);
+ __func__, uid, info->package.c_str(), (long long)info->expirationNs);
mInfoMap[uid] = info;
}
return info;
}
+/* static */
+UidInfo& UidInfo::getUidInfo() {
+ [[clang::no_destroy]] static UidInfo uidInfo;
+ return uidInfo;
+}
+
+/* static */
+std::shared_ptr<const UidInfo::Info> UidInfo::getInfo(uid_t uid) {
+ return UidInfo::getUidInfo().getCachedInfo(uid);
+}
+
+} // namespace mediautils
+
} // namespace android
diff --git a/media/utils/TimeCheck.cpp b/media/utils/TimeCheck.cpp
index 658191e..6a5bbbe 100644
--- a/media/utils/TimeCheck.cpp
+++ b/media/utils/TimeCheck.cpp
@@ -184,6 +184,22 @@
}
/* static */
+std::string TimeCheck::signalAudioHals() {
+ std::vector<pid_t> pids = getAudioHalPids();
+ std::string halPids;
+ if (pids.size() != 0) {
+ for (const auto& pid : pids) {
+ ALOGI("requesting tombstone for pid: %d", pid);
+ halPids.append(std::to_string(pid)).append(" ");
+ signalAudioHAL(pid);
+ }
+ // Allow time to complete, usually the caller is forcing restart afterwards.
+ sleep(1);
+ }
+ return halPids;
+}
+
+/* static */
TimerThread& TimeCheck::getTimeCheckThread() {
static TimerThread sTimeCheckThread{};
return sTimeCheckThread;
@@ -302,21 +318,14 @@
// HAL processes which can affect thread behavior.
const auto snapshotAnalysis = getTimeCheckThread().getSnapshotAnalysis(4 /* retiredCount */);
- // Generate audio HAL processes tombstones and allow time to complete
- // before forcing restart
- std::vector<pid_t> pids = TimeCheck::getAudioHalPids();
- std::string halPids = "HAL pids [ ";
- if (pids.size() != 0) {
- for (const auto& pid : pids) {
- ALOGI("requesting tombstone for pid: %d", pid);
- halPids.append(std::to_string(pid)).append(" ");
- signalAudioHAL(pid);
- }
- sleep(1);
+ // Generate audio HAL processes tombstones.
+ std::string halPids = signalAudioHals();
+ if (!halPids.empty()) {
+ halPids = "HAL pids [ " + halPids + "]";
} else {
- ALOGI("No HAL process pid available, skipping tombstones");
+ halPids = "No HAL process pids available";
+ ALOGI("%s", (halPids + ", skipping tombstones").c_str());
}
- halPids.append("]");
LOG_EVENT_STRING(LOGTAG_AUDIO_BINDER_TIMEOUT, tag.c_str());
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index e0fabfd..461e190 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <android/content/pm/IPackageManagerNative.h>
+#include <android-base/thread_annotations.h>
#include <binder/IMemory.h>
#include <binder/PermissionController.h>
#include <cutils/multiuser.h>
@@ -91,7 +92,7 @@
bool recordingAllowed(const AttributionSourceState &attributionSource,
uint32_t virtualDeviceId,
audio_source_t source);
-bool startRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
+int startRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
const String16& msg, audio_source_t source);
void finishRecording(const AttributionSourceState& attributionSource, uint32_t virtualDeviceId,
audio_source_t source);
@@ -113,6 +114,10 @@
bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource);
bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource);
void purgePermissionCache();
+bool mustAnonymizeBluetoothAddress(
+ const AttributionSourceState& attributionSource, const String16& caller);
+void anonymizeBluetoothAddress(char *address);
+
int32_t getOpForSource(audio_source_t source);
AttributionSourceState getCallingAttributionSource();
@@ -167,12 +172,18 @@
*
* \param uid is the uid of the app or service.
*/
- Info getInfo(uid_t uid);
+ std::shared_ptr<const Info> getCachedInfo(uid_t uid);
+
+ /* return a singleton */
+ static UidInfo& getUidInfo();
+
+ /* returns a non-null pointer to a const Info struct */
+ static std::shared_ptr<const Info> getInfo(uid_t uid);
private:
std::mutex mLock;
// TODO: use concurrent hashmap with striped lock.
- std::unordered_map<uid_t, Info> mInfoMap; // GUARDED_BY(mLock)
+ std::unordered_map<uid_t, std::shared_ptr<const Info>> mInfoMap GUARDED_BY(mLock);
};
} // namespace mediautils
diff --git a/media/utils/include/mediautils/TimeCheck.h b/media/utils/include/mediautils/TimeCheck.h
index 3e8d35d..c112863 100644
--- a/media/utils/include/mediautils/TimeCheck.h
+++ b/media/utils/include/mediautils/TimeCheck.h
@@ -107,6 +107,7 @@
static std::string toString();
static void setAudioHalPids(const std::vector<pid_t>& pids);
static std::vector<pid_t> getAudioHalPids();
+ static std::string signalAudioHals();
private:
// Helper class for handling events.
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 264fc4f..01bde42 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -234,6 +234,22 @@
"libpermission",
],
+ export_static_lib_headers: [
+ "libpshutils",
+ ],
+
+ shared: {
+ static_libs: [
+ "libpshutils",
+ ],
+ },
+
+ static: {
+ whole_static_libs: [
+ "libpshutils",
+ ],
+ },
+
cflags: [
"-Wall",
"-Werror",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 37fc1fc..70fa2ca 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "AudioFlinger"
//#define LOG_NDEBUG 0
+#define ATRACE_TAG ATRACE_TAG_AUDIO
+#include <utils/Trace.h>
// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
#define AUDIO_ARRAYS_STATIC_CHECK 1
@@ -24,9 +26,7 @@
#include "Configuration.h"
#include "AudioFlinger.h"
-//#define BUFLOG_NDEBUG 0
-#include <afutils/BufLog.h>
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
#include <afutils/NBAIO_Tee.h>
#include <afutils/Permission.h>
#include <afutils/PropertyUtils.h>
@@ -66,6 +66,7 @@
// not needed with the includes above, added to prevent transitive include dependency.
#include <chrono>
#include <thread>
+#include <string_view>
// ----------------------------------------------------------------------------
@@ -84,6 +85,8 @@
namespace android {
+using namespace std::string_view_literals;
+
using ::android::base::StringPrintf;
using aidl_utils::statusTFromBinderStatus;
using media::IEffectClient;
@@ -100,10 +103,10 @@
static const AudioHalVersionInfo kMaxAAudioPropertyDeviceHalVersion =
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1);
-static constexpr char kDeadlockedString[] = "AudioFlinger may be deadlocked\n";
-static constexpr char kHardwareLockedString[] = "Hardware lock is taken\n";
-static constexpr char kClientLockedString[] = "Client lock is taken\n";
-static constexpr char kNoEffectsFactory[] = "Effects Factory is absent\n";
+constexpr auto kDeadlockedString = "AudioFlinger may be deadlocked\n"sv;
+constexpr auto kHardwareLockedString = "Hardware lock is taken\n"sv;
+constexpr auto kClientLockedString = "Client lock is taken\n"sv;
+constexpr auto kNoEffectsFactory = "Effects Factory is absent\n"sv;
static constexpr char kAudioServiceName[] = "audio";
@@ -114,19 +117,26 @@
// Keep a strong reference to media.log service around forever.
// The service is within our parent process so it can never die in a way that we could observe.
// These two variables are const after initialization.
-static sp<IBinder> sMediaLogServiceAsBinder;
static sp<IMediaLogService> sMediaLogService;
static pthread_once_t sMediaLogOnce = PTHREAD_ONCE_INIT;
static void sMediaLogInit()
{
- sMediaLogServiceAsBinder = defaultServiceManager()->getService(String16("media.log"));
+ auto sMediaLogServiceAsBinder = defaultServiceManager()->getService(String16("media.log"));
if (sMediaLogServiceAsBinder != 0) {
sMediaLogService = interface_cast<IMediaLogService>(sMediaLogServiceAsBinder);
}
}
+static int writeStr(int fd, std::string_view s) {
+ return write(fd, s.data(), s.size());
+}
+
+static int writeStr(int fd, const String8& s) {
+ return write(fd, s.c_str(), s.size());
+}
+
static error::BinderResult<ValidatedAttributionSourceState>
validateAttributionFromContextOrTrustedCaller(AttributionSourceState attr,
const IPermissionProvider& provider) {
@@ -619,6 +629,7 @@
bool isSpatialized;
bool isBitPerfect;
float volume;
+ bool muted;
ret = AudioSystem::getOutputForAttr(&localAttr, &io,
actualSessionId,
&streamType, adjAttributionSource,
@@ -627,7 +638,8 @@
AUDIO_OUTPUT_FLAG_DIRECT),
deviceId, &portId, &secondaryOutputs, &isSpatialized,
&isBitPerfect,
- &volume);
+ &volume,
+ &muted);
if (ret != NO_ERROR) {
config->sample_rate = fullConfig.sample_rate;
config->channel_mask = fullConfig.channel_mask;
@@ -736,42 +748,44 @@
return NULL;
}
-void AudioFlinger::dumpClients_ll(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpClients_ll(int fd, bool dumpAllocators) {
String8 result;
- result.append("Client Allocators:\n");
- for (size_t i = 0; i < mClients.size(); ++i) {
- sp<Client> client = mClients.valueAt(i).promote();
- if (client != 0) {
- result.appendFormat("Client: %d\n", client->pid());
- result.append(client->allocator().dump().c_str());
+ if (dumpAllocators) {
+ result.append("Client Allocators:\n");
+ for (size_t i = 0; i < mClients.size(); ++i) {
+ sp<Client> client = mClients.valueAt(i).promote();
+ if (client != 0) {
+ result.appendFormat("Client: %d\n", client->pid());
+ result.append(client->allocator().dump().c_str());
+ }
}
- }
+ }
result.append("Notification Clients:\n");
result.append(" pid uid name\n");
- for (size_t i = 0; i < mNotificationClients.size(); ++i) {
- const pid_t pid = mNotificationClients[i]->getPid();
- const uid_t uid = mNotificationClients[i]->getUid();
- const mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
- result.appendFormat("%6d %6u %s\n", pid, uid, info.package.c_str());
+ for (const auto& [ _, client ] : mNotificationClients) {
+ const uid_t uid = client->getUid();
+ const std::shared_ptr<const mediautils::UidInfo::Info> info =
+ mediautils::UidInfo::getInfo(uid);
+ result.appendFormat("%6d %6u %s\n",
+ client->getPid(), uid, info->package.c_str());
}
result.append("Global session refs:\n");
result.append(" session cnt pid uid name\n");
for (size_t i = 0; i < mAudioSessionRefs.size(); i++) {
AudioSessionRef *r = mAudioSessionRefs[i];
- const mediautils::UidInfo::Info info = mUidInfo.getInfo(r->mUid);
+ const std::shared_ptr<const mediautils::UidInfo::Info> info =
+ mediautils::UidInfo::getInfo(r->mUid);
result.appendFormat(" %7d %4d %7d %6u %s\n", r->mSessionid, r->mCnt, r->mPid,
- r->mUid, info.package.c_str());
+ r->mUid, info->package.c_str());
}
- write(fd, result.c_str(), result.size());
+ writeStr(fd, result);
}
-void AudioFlinger::dumpInternals_l(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpInternals_l(int fd) {
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
@@ -779,7 +793,7 @@
snprintf(buffer, SIZE, "Hardware status: %d\n", hardwareStatus);
result.append(buffer);
- write(fd, result.c_str(), result.size());
+ writeStr(fd, result);
dprintf(fd, "Vibrator infos(size=%zu):\n", mAudioVibratorInfos.size());
for (const auto& vibratorInfo : mAudioVibratorInfos) {
@@ -789,8 +803,43 @@
mBluetoothLatencyModesEnabled ? "" : "not ");
}
-void AudioFlinger::dumpPermissionDenial(int fd, const Vector<String16>& args __unused)
-{
+void AudioFlinger::dumpStats(int fd) {
+ // Dump binder stats
+ dprintf(fd, "\nIAudioFlinger binder call profile:\n");
+ writeStr(fd, getIAudioFlingerStatistics().dump());
+
+ extern mediautils::MethodStatistics<int>& getIEffectStatistics();
+ dprintf(fd, "\nIEffect binder call profile:\n");
+ writeStr(fd, getIEffectStatistics().dump());
+
+ // Automatically fetch HIDL or AIDL statistics.
+ const std::string_view halType = (mDevicesFactoryHal->getHalVersion().getType() ==
+ AudioHalVersionInfo::Type::HIDL)
+ ? METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL
+ : METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL;
+ const std::shared_ptr<std::vector<std::string>> halClassNames =
+ mediautils::getStatisticsClassesForModule(halType);
+ if (halClassNames) {
+ for (const auto& className : *halClassNames) {
+ auto stats = mediautils::getStatisticsForClass(className);
+ if (stats) {
+ dprintf(fd, "\n%s binder call profile:\n", className.c_str());
+ writeStr(fd, stats->dump());
+ }
+ }
+ }
+
+ dprintf(fd, "\nTimeCheck:\n");
+ writeStr(fd, mediautils::TimeCheck::toString());
+ dprintf(fd, "\n");
+ // dump mutex stats
+ writeStr(fd, audio_utils::mutex::all_stats_to_string());
+ // dump held mutexes
+ writeStr(fd, audio_utils::mutex::all_threads_to_string());
+
+}
+
+void AudioFlinger::dumpPermissionDenial(int fd) {
const size_t SIZE = 256;
char buffer[SIZE];
String8 result;
@@ -799,52 +848,102 @@
IPCThreadState::self()->getCallingPid(),
IPCThreadState::self()->getCallingUid());
result.append(buffer);
- write(fd, result.c_str(), result.size());
+ writeStr(fd, result);
+}
+
+static void dump_printHelp(int fd) {
+ constexpr static auto helpStr =
+ "AudioFlinger dumpsys help options\n"
+ " -h/--help: Print this help text\n"
+ " --hal: Include dump of audio hal\n"
+ " --stats: Include call/lock/watchdog stats\n"
+ " --effects: Include effect definitions\n"
+ " --memory: Include memory dump\n"
+ " -a/--all: Print all except --memory\n"sv;
+
+ write(fd, helpStr.data(), helpStr.length());
}
status_t AudioFlinger::dump(int fd, const Vector<String16>& args)
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
+ using afutils::FallibleLockGuard;
if (!dumpAllowed()) {
- dumpPermissionDenial(fd, args);
- } else {
- // get state of hardware lock
- const bool hardwareLocked = afutils::dumpTryLock(hardwareMutex());
- if (!hardwareLocked) {
- String8 result(kHardwareLockedString);
- write(fd, result.c_str(), result.size());
+ dumpPermissionDenial(fd);
+ return NO_ERROR;
+ }
+ // Arg parsing
+ struct {
+ bool shouldDumpMem, shouldDumpStats, shouldDumpHal, shouldDumpEffects;
+ } parsedArgs {}; // zero-init
+
+ for (const auto& arg : args) {
+ const String8 utf8arg{arg};
+ if (utf8arg == "-h" || utf8arg == "--help") {
+ dump_printHelp(fd);
+ return NO_ERROR;
+ }
+ if (utf8arg == "-a" || utf8arg == "--all") {
+ parsedArgs.shouldDumpStats = true;
+ parsedArgs.shouldDumpHal = true;
+ parsedArgs.shouldDumpEffects = true;
+ continue;
+ }
+ if (utf8arg == "--hal") {
+ parsedArgs.shouldDumpHal = true;
+ continue;
+ }
+ if (utf8arg == "--stats") {
+ parsedArgs.shouldDumpStats = true;
+ continue;
+ }
+ if (utf8arg == "--effects") {
+ parsedArgs.shouldDumpEffects = true;
+ continue;
+ }
+ if (utf8arg == "--memory") {
+ parsedArgs.shouldDumpMem = true;
+ continue;
+ }
+ // Unknown arg silently ignored
+ }
+
+ {
+ std::string res;
+ res.reserve(100);
+ res += "Start begin: ";
+ const auto startTimeStr = audio_utils_time_string_from_ns(mStartTime);
+ res += startTimeStr.time;
+ const auto startFinishedTime = getStartupFinishedTime();
+ if (startFinishedTime != 0) {
+ res += "\nStart end: ";
+ const auto startEndStr = audio_utils_time_string_from_ns(startFinishedTime);
+ res += startEndStr.time;
} else {
- hardwareMutex().unlock();
+ res += "\nStartup not yet finished!";
+ }
+ const auto nowTimeStr = audio_utils_time_string_from_ns(audio_utils_get_real_time_ns());
+ res += "\nNow: ";
+ res += nowTimeStr.time;
+ res += "\n";
+ writeStr(fd, res);
+ }
+ // get state of hardware lock
+ {
+ FallibleLockGuard l{hardwareMutex()};
+ if (!l) writeStr(fd, kHardwareLockedString);
+ }
+ {
+ FallibleLockGuard l{mutex()};
+ if (!l) writeStr(fd, kDeadlockedString);
+ {
+ FallibleLockGuard ll{clientMutex()};
+ if (!ll) writeStr(fd, kClientLockedString);
+ dumpClients_ll(fd, parsedArgs.shouldDumpMem);
}
- const bool locked = afutils::dumpTryLock(mutex());
+ dumpInternals_l(fd);
- // failed to lock - AudioFlinger is probably deadlocked
- if (!locked) {
- String8 result(kDeadlockedString);
- write(fd, result.c_str(), result.size());
- }
-
- const bool clientLocked = afutils::dumpTryLock(clientMutex());
- if (!clientLocked) {
- String8 result(kClientLockedString);
- write(fd, result.c_str(), result.size());
- }
-
- if (mEffectsFactoryHal != 0) {
- mEffectsFactoryHal->dumpEffects(fd);
- } else {
- String8 result(kNoEffectsFactory);
- write(fd, result.c_str(), result.size());
- }
-
- dumpClients_ll(fd, args);
- if (clientLocked) {
- clientMutex().unlock();
- }
-
- dumpInternals_l(fd, args);
-
+ dprintf(fd, "\n ## BEGIN thread dump \n");
// dump playback threads
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
mPlaybackThreads.valueAt(i)->dump(fd, args);
@@ -862,130 +961,84 @@
// dump orphan effect chains
if (mOrphanEffectChains.size() != 0) {
- write(fd, " Orphan Effect Chains\n", strlen(" Orphan Effect Chains\n"));
+ writeStr(fd, " Orphan Effect Chains\n");
for (size_t i = 0; i < mOrphanEffectChains.size(); i++) {
mOrphanEffectChains.valueAt(i)->dump(fd, args);
}
}
- // dump all hardware devs
- for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
- sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
- dev->dump(fd, args);
- }
-
- mPatchPanel->dump(fd);
-
- mDeviceEffectManager->dump(fd);
-
- std::string melOutput = mMelReporter->dump();
- write(fd, melOutput.c_str(), melOutput.size());
+ // dump historical threads in the last 10 seconds
+ writeStr(fd, mThreadLog.dumpToString(
+ "Historical Thread Log ", 0 /* lines */,
+ audio_utils_get_real_time_ns() - 10 * 60 * NANOS_PER_SECOND));
// dump external setParameters
+ dprintf(fd, "\n ## BEGIN setParameters dump \n");
auto dumpLogger = [fd](SimpleLog& logger, const char* name) {
- dprintf(fd, "\n%s setParameters:\n", name);
+ dprintf(fd, "\n %s setParameters:\n", name);
logger.dump(fd, " " /* prefix */);
};
dumpLogger(mRejectedSetParameterLog, "Rejected");
dumpLogger(mAppSetParameterLog, "App");
dumpLogger(mSystemSetParameterLog, "System");
- // dump historical threads in the last 10 seconds
- const std::string threadLog = mThreadLog.dumpToString(
- "Historical Thread Log ", 0 /* lines */,
- audio_utils_get_real_time_ns() - 10 * 60 * NANOS_PER_SECOND);
- write(fd, threadLog.c_str(), threadLog.size());
- BUFLOG_RESET;
+ dprintf(fd, "\n ## BEGIN misc af dump \n");
+ mPatchPanel->dump(fd);
+ mDeviceEffectManager->dump(fd);
+ writeStr(fd, mMelReporter->dump());
- if (locked) {
- mutex().unlock();
+ if (media::psh_utils::AudioPowerManager::enabled()) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.display.id", value, "Unknown build");
+ std::string build(value);
+ writeStr(fd, build + "\n");
+ writeStr(fd, media::psh_utils::AudioPowerManager::getAudioPowerManager().toString());
}
-#ifdef TEE_SINK
- // NBAIO_Tee dump is safe to call outside of AF lock.
- NBAIO_Tee::dumpAll(fd, "_DUMP");
-#endif
- // append a copy of media.log here by forwarding fd to it, but don't attempt
- // to lookup the service if it's not running, as it will block for a second
- if (sMediaLogServiceAsBinder != 0) {
- dprintf(fd, "\nmedia.log:\n");
- sMediaLogServiceAsBinder->dump(fd, args);
- }
-
- // check for optional arguments
- bool dumpMem = false;
- bool unreachableMemory = false;
- for (const auto &arg : args) {
- if (arg == String16("-m")) {
- dumpMem = true;
- } else if (arg == String16("--unreachable")) {
- unreachableMemory = true;
+ if (parsedArgs.shouldDumpEffects) {
+ dprintf(fd, "\n ## BEGIN effects dump \n");
+ if (mEffectsFactoryHal != 0) {
+ mEffectsFactoryHal->dumpEffects(fd);
+ } else {
+ writeStr(fd, kNoEffectsFactory);
}
}
- if (dumpMem) {
- dprintf(fd, "\nDumping memory:\n");
- std::string s = dumpMemoryAddresses(100 /* limit */);
- write(fd, s.c_str(), s.size());
- }
- if (unreachableMemory) {
- dprintf(fd, "\nDumping unreachable memory:\n");
- // TODO - should limit be an argument parameter?
- std::string s = GetUnreachableMemoryString(true /* contents */, 100 /* limit */);
- write(fd, s.c_str(), s.size());
- }
- {
- std::string timeCheckStats = getIAudioFlingerStatistics().dump();
- dprintf(fd, "\nIAudioFlinger binder call profile:\n");
- write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-
- extern mediautils::MethodStatistics<int>& getIEffectStatistics();
- timeCheckStats = getIEffectStatistics().dump();
- dprintf(fd, "\nIEffect binder call profile:\n");
- write(fd, timeCheckStats.c_str(), timeCheckStats.size());
-
- // Automatically fetch HIDL or AIDL statistics.
- const std::string_view halType = (mDevicesFactoryHal->getHalVersion().getType() ==
- AudioHalVersionInfo::Type::HIDL)
- ? METHOD_STATISTICS_MODULE_NAME_AUDIO_HIDL
- : METHOD_STATISTICS_MODULE_NAME_AUDIO_AIDL;
- const std::shared_ptr<std::vector<std::string>> halClassNames =
- mediautils::getStatisticsClassesForModule(halType);
- if (halClassNames) {
- for (const auto& className : *halClassNames) {
- auto stats = mediautils::getStatisticsForClass(className);
- if (stats) {
- timeCheckStats = stats->dump();
- dprintf(fd, "\n%s binder call profile:\n", className.c_str());
- write(fd, timeCheckStats.c_str(), timeCheckStats.size());
- }
- }
+ if (parsedArgs.shouldDumpHal) {
+ dprintf(fd, "\n ## BEGIN HAL dump \n");
+ FallibleLockGuard ll{hardwareMutex()};
+ // dump all hardware devs
+ for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
+ sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
+ dev->dump(fd, args);
}
-
- timeCheckStats = mediautils::TimeCheck::toString();
- dprintf(fd, "\nTimeCheck:\n");
- write(fd, timeCheckStats.c_str(), timeCheckStats.size());
- dprintf(fd, "\n");
}
- // dump mutex stats
- const auto mutexStats = audio_utils::mutex::all_stats_to_string();
- write(fd, mutexStats.c_str(), mutexStats.size());
+ } // end af lock
- // dump held mutexes
- const auto mutexThreadInfo = audio_utils::mutex::all_threads_to_string();
- write(fd, mutexThreadInfo.c_str(), mutexThreadInfo.size());
+ if (parsedArgs.shouldDumpStats) {
+ dprintf(fd, "\n ## BEGIN stats dump \n");
+ dumpStats(fd);
}
+
+ if (parsedArgs.shouldDumpMem) {
+ dprintf(fd, "\n ## BEGIN memory dump \n");
+ writeStr(fd, dumpMemoryAddresses(100 /* limit */));
+ dprintf(fd, "\nDumping unreachable memory:\n");
+ // TODO - should limit be an argument parameter?
+ writeStr(fd, GetUnreachableMemoryString(true /* contents */, 100 /* limit */));
+ }
+
return NO_ERROR;
}
-sp<Client> AudioFlinger::registerPid(pid_t pid)
+sp<Client> AudioFlinger::registerClient(pid_t pid, uid_t uid)
{
audio_utils::lock_guard _cl(clientMutex());
// If pid is already in the mClients wp<> map, then use that entry
// (for which promote() is always != 0), otherwise create a new entry and Client.
sp<Client> client = mClients.valueFor(pid).promote();
if (client == 0) {
- client = sp<Client>::make(sp<IAfClientCallback>::fromExisting(this), pid);
+ client = sp<Client>::make(sp<IAfClientCallback>::fromExisting(this), pid, uid);
mClients.add(pid, client);
}
@@ -1052,6 +1105,7 @@
status_t AudioFlinger::createTrack(const media::CreateTrackRequest& _input,
media::CreateTrackResponse& _output)
{
+ ATRACE_CALL();
// Local version of VALUE_OR_RETURN, specific to this method's calling conventions.
CreateTrackInput input = VALUE_OR_RETURN_STATUS(CreateTrackInput::fromAidl(_input));
CreateTrackOutput output;
@@ -1065,6 +1119,7 @@
bool isSpatialized = false;
bool isBitPerfect = false;
float volume;
+ bool muted;
audio_io_handle_t effectThreadId = AUDIO_IO_HANDLE_NONE;
std::vector<int> effectIds;
@@ -1125,7 +1180,7 @@
lStatus = AudioSystem::getOutputForAttr(&localAttr, &output.outputId, sessionId, &streamType,
adjAttributionSource, &input.config, input.flags,
&output.selectedDeviceId, &portId, &secondaryOutputs,
- &isSpatialized, &isBitPerfect, &volume);
+ &isSpatialized, &isBitPerfect, &volume, &muted);
if (lStatus != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
ALOGE("createTrack() getOutputForAttr() return error %d or invalid output handle", lStatus);
@@ -1162,7 +1217,7 @@
goto Exit;
}
- client = registerPid(adjAttributionSource.pid);
+ client = registerClient(adjAttributionSource.pid, adjAttributionSource.uid);
IAfPlaybackThread* effectThread = nullptr;
sp<IAfEffectChain> effectChain = nullptr;
@@ -1182,7 +1237,7 @@
if (effectThread == nullptr) {
effectChain = getOrphanEffectChain_l(sessionId);
}
- ALOGV("createTrack() sessionId: %d volume: %f", sessionId, volume);
+ ALOGV("createTrack() sessionId: %d volume: %f muted %d", sessionId, volume, muted);
output.sampleRate = input.config.sample_rate;
output.frameCount = input.frameCount;
@@ -1197,7 +1252,7 @@
input.sharedBuffer, sessionId, &output.flags,
callingPid, adjAttributionSource, input.clientInfo.clientTid,
&lStatus, portId, input.audioTrackCallback, isSpatialized,
- isBitPerfect, &output.afTrackFlags, volume);
+ isBitPerfect, &output.afTrackFlags, volume, muted);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (track == 0));
// we don't abort yet if lStatus != NO_ERROR; there is still work to be done regardless
@@ -1621,7 +1676,7 @@
}
status_t AudioFlinger::setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output)
+ bool muted, audio_io_handle_t output)
{
// check calling permissions
if (!settingsAllowed()) {
@@ -1643,14 +1698,14 @@
if (volumeInterface == NULL) {
return BAD_VALUE;
}
- volumeInterface->setStreamVolume(stream, value);
+ volumeInterface->setStreamVolume(stream, value, muted);
return NO_ERROR;
}
status_t AudioFlinger::setPortsVolume(
- const std::vector<audio_port_handle_t>& ports, float volume, audio_io_handle_t output)
-{
+ const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+ audio_io_handle_t output) {
for (const auto& port : ports) {
if (port == AUDIO_PORT_HANDLE_NONE) {
return BAD_VALUE;
@@ -1665,12 +1720,12 @@
audio_utils::lock_guard lock(mutex());
IAfPlaybackThread *thread = checkPlaybackThread_l(output);
if (thread != nullptr) {
- return thread->setPortsVolume(ports, volume);
+ return thread->setPortsVolume(ports, volume, muted);
}
const sp<IAfMmapThread> mmapThread = checkMmapThread_l(output);
if (mmapThread != nullptr && mmapThread->isOutput()) {
IAfMmapPlaybackThread *mmapPlaybackThread = mmapThread->asIAfMmapPlaybackThread().get();
- return mmapPlaybackThread->setPortsVolume(ports, volume);
+ return mmapPlaybackThread->setPortsVolume(ports, volume, muted);
}
return BAD_VALUE;
}
@@ -2162,24 +2217,22 @@
void AudioFlinger::registerClient(const sp<media::IAudioFlingerClient>& client)
{
- audio_utils::lock_guard _l(mutex());
if (client == 0) {
return;
}
- pid_t pid = IPCThreadState::self()->getCallingPid();
+ const pid_t pid = IPCThreadState::self()->getCallingPid();
const uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ audio_utils::lock_guard _l(mutex());
{
audio_utils::lock_guard _cl(clientMutex());
- if (mNotificationClients.indexOfKey(pid) < 0) {
- sp<NotificationClient> notificationClient = new NotificationClient(this,
- client,
- pid,
- uid);
+ if (mNotificationClients.count(pid) == 0) {
+ auto notificationClient = sp<NotificationClient>::make(
+ this, client, pid, uid);
ALOGV("registerClient() client %p, pid %d, uid %u",
notificationClient.get(), pid, uid);
- mNotificationClients.add(pid, notificationClient);
-
+ mNotificationClients[pid] = notificationClient;
sp<IBinder> binder = IInterface::asBinder(client);
binder->linkToDeath(notificationClient);
}
@@ -2206,7 +2259,7 @@
audio_utils::lock_guard _l(mutex());
{
audio_utils::lock_guard _cl(clientMutex());
- mNotificationClients.removeItem(pid);
+ mNotificationClients.erase(pid);
}
ALOGV("%d died, releasing its sessions", pid);
@@ -2247,11 +2300,13 @@
legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(ioDesc));
audio_utils::lock_guard _l(clientMutex());
- size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- if ((pid == 0) || (mNotificationClients.keyAt(i) == pid)) {
- mNotificationClients.valueAt(i)->audioFlingerClient()->ioConfigChanged(eventAidl,
- descAidl);
+ if (pid != 0) {
+ if (auto it = mNotificationClients.find(pid); it != mNotificationClients.end()) {
+ it->second->audioFlingerClient()->ioConfigChanged(eventAidl, descAidl);
+ }
+ } else {
+ for (const auto& [ client_pid, client] : mNotificationClients) {
+ client->audioFlingerClient()->ioConfigChanged(eventAidl, descAidl);
}
}
}
@@ -2265,9 +2320,8 @@
audio_utils::lock_guard _l(clientMutex());
size_t size = mNotificationClients.size();
- for (size_t i = 0; i < size; i++) {
- mNotificationClients.valueAt(i)->audioFlingerClient()
- ->onSupportedLatencyModesChanged(outputAidl, modesAidl);
+ for (const auto& [_, client] : mNotificationClients) {
+ client->audioFlingerClient()->onSupportedLatencyModesChanged(outputAidl, modesAidl);
}
}
@@ -2326,6 +2380,9 @@
pid_t pid,
uid_t uid)
: mAudioFlinger(audioFlinger), mPid(pid), mUid(uid), mAudioFlingerClient(client)
+ , mClientToken(media::psh_utils::AudioPowerManager::enabled()
+ ? media::psh_utils::createAudioClientToken(pid, uid)
+ : nullptr)
{
}
@@ -2335,7 +2392,7 @@
void AudioFlinger::NotificationClient::binderDied(const wp<IBinder>& who __unused)
{
- sp<NotificationClient> keep(this);
+ const auto keep = sp<NotificationClient>::fromExisting(this);
mAudioFlinger->removeNotificationClient(mPid);
}
@@ -2455,7 +2512,7 @@
output.selectedDeviceId = input.selectedDeviceId;
output.flags = input.flags;
- client = registerPid(VALUE_OR_FATAL(aidl2legacy_int32_t_pid_t(adjAttributionSource.pid)));
+ client = registerClient(adjAttributionSource.pid, adjAttributionSource.uid);
// Not a conventional loop, but a retry loop for at most two iterations total.
// Try first maybe with FAST flag then try again without FAST flag if that fails.
@@ -3021,7 +3078,7 @@
audio_config_base_t *mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
const audio_attributes_t attributes)
{
AudioHwDevice *outHwDev = findSuitableHwDev_l(module, deviceType);
@@ -3056,7 +3113,7 @@
mHardwareStatus = AUDIO_HW_IDLE;
if (status == NO_ERROR) {
- if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
+ if (*flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
const sp<IAfMmapPlaybackThread> thread = IAfMmapPlaybackThread::create(
this, *output, outHwDev, outputStream, mSystemReady);
mMmapThreads.add(*output, thread);
@@ -3065,22 +3122,22 @@
return thread;
} else {
sp<IAfPlaybackThread> thread;
- if (flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
+ if (*flags & AUDIO_OUTPUT_FLAG_BIT_PERFECT) {
thread = IAfPlaybackThread::createBitPerfectThread(
this, outputStream, *output, mSystemReady);
ALOGV("%s() created bit-perfect output: ID %d thread %p",
__func__, *output, thread.get());
- } else if (flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
+ } else if (*flags & AUDIO_OUTPUT_FLAG_SPATIALIZER) {
thread = IAfPlaybackThread::createSpatializerThread(this, outputStream, *output,
mSystemReady, mixerConfig);
ALOGV("openOutput_l() created spatializer output: ID %d thread %p",
*output, thread.get());
- } else if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ } else if (*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
thread = IAfPlaybackThread::createOffloadThread(this, outputStream, *output,
mSystemReady, halConfig->offload_info);
ALOGV("openOutput_l() created offload output: ID %d thread %p",
*output, thread.get());
- } else if ((flags & AUDIO_OUTPUT_FLAG_DIRECT)
+ } else if ((*flags & AUDIO_OUTPUT_FLAG_DIRECT)
|| !IAfThreadBase::isValidPcmSinkFormat(halConfig->format)
|| !IAfThreadBase::isValidPcmSinkChannelMask(halConfig->channel_mask)) {
thread = IAfPlaybackThread::createDirectOutputThread(this, outputStream, *output,
@@ -3144,7 +3201,7 @@
audio_utils::lock_guard _l(mutex());
const sp<IAfThreadBase> thread = openOutput_l(module, &output, &halConfig,
- &mixerConfig, deviceType, address, flags, attributes);
+ &mixerConfig, deviceType, address, &flags, attributes);
if (thread != 0) {
uint32_t latencyMs = 0;
if ((flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0) {
@@ -3602,7 +3659,7 @@
// is likely proxied by mediaserver (e.g CameraService) and releaseAudioSessionId() can be
// called from a different pid leaving a stale session reference. Also we don't know how
// to clear this reference if the client process dies.
- if (mNotificationClients.indexOfKey(caller) < 0) {
+ if (mNotificationClients.count(caller) == 0) {
ALOGW("acquireAudioSessionId() unknown client %d for session %d", caller, audioSession);
return;
}
@@ -4063,7 +4120,8 @@
0ns /* timeout */,
frameCountToBeReady,
track->getSpeed(),
- 1.f /* volume */);
+ 1.f /* volume */,
+ track->getPortMute() /* muted */);
status = patchTrack->initCheck();
if (status != NO_ERROR) {
ALOGE("Secondary output patchTrack init failed: %d", status);
@@ -4378,7 +4436,7 @@
audio_utils::lock_guard _l(mutex());
if (sessionId == AUDIO_SESSION_DEVICE) {
- sp<Client> client = registerPid(currentPid);
+ sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
ALOGV("%s device type %#x address %s", __func__, device.mType, device.getAddress());
handle = mDeviceEffectManager->createEffect_l(
&descOut, device, client, effectClient, mPatchPanel->patches_l(),
@@ -4440,7 +4498,7 @@
goto Exit;
}
ALOGV("%s() got io %d for effect %s", __func__, io, descOut.name);
- sp<Client> client = registerPid(currentPid);
+ sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
handle = createOrphanEffect_l(client, effectClient, priority, sessionId,
&descOut, &enabledOut, &lStatus, pinned,
@@ -4502,7 +4560,7 @@
}
}
- sp<Client> client = registerPid(currentPid);
+ sp<Client> client = registerClient(currentPid, adjAttributionSource.uid);
// create effect on selected output thread
bool pinned = !audio_is_global_session(sessionId) && isSessionAcquired_l(sessionId);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 545fa36..042194f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -27,6 +27,7 @@
#include "IAfTrack.h"
#include "MelReporter.h"
#include "PatchCommandThread.h"
+#include "audio_utils/clock.h"
// External classes
#include <audio_utils/mutex.h>
@@ -38,6 +39,7 @@
#include <media/audiohal/DevicesFactoryHalInterface.h>
#include <mediautils/ServiceUtilities.h>
#include <mediautils/Synchronization.h>
+#include <psh_utils/AudioPowerManager.h>
// not needed with the includes above, added to prevent transitive include dependency.
#include <utils/KeyedVector.h>
@@ -64,6 +66,11 @@
status_t resetReferencesForTest();
+ // Called by main when startup finished -- for logging purposes only
+ void startupFinished() {
+ mStartupFinishedTime.store(audio_utils_get_real_time_ns(), std::memory_order_release);
+ }
+
private:
// ---- begin IAudioFlinger interface
@@ -92,12 +99,12 @@
status_t getMasterBalance(float* balance) const final EXCLUDES_AudioFlinger_Mutex;
status_t setStreamVolume(audio_stream_type_t stream, float value,
- audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
+ bool muted, audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
status_t setStreamMute(audio_stream_type_t stream, bool muted) final
EXCLUDES_AudioFlinger_Mutex;
status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
- audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
+ bool muted, audio_io_handle_t output) final EXCLUDES_AudioFlinger_Mutex;
status_t setMode(audio_mode_t mode) final EXCLUDES_AudioFlinger_Mutex;
@@ -336,7 +343,7 @@
audio_config_base_t* mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t* flags,
audio_attributes_t attributes) final REQUIRES(mutex());
const DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>&
getAudioHwDevs_l() const final REQUIRES(mutex(), hardwareMutex()) {
@@ -419,6 +426,10 @@
sp<EffectsFactoryHalInterface> getEffectsFactory();
+ int64_t getStartupFinishedTime() {
+ return mStartupFinishedTime.load(std::memory_order_acquire);
+ }
+
public:
// TODO(b/292281786): Remove this when Oboeservice can get access to
// openMmapStream through an IAudioFlinger handle directly.
@@ -468,9 +479,10 @@
// AudioFlinger::setParameters() updates with mutex().
std::atomic_uint32_t mScreenState{};
- void dumpPermissionDenial(int fd, const Vector<String16>& args);
- void dumpClients_ll(int fd, const Vector<String16>& args) REQUIRES(mutex(), clientMutex());
- void dumpInternals_l(int fd, const Vector<String16>& args) REQUIRES(mutex());
+ void dumpPermissionDenial(int fd);
+ void dumpClients_ll(int fd, bool dumpAllocators) REQUIRES(mutex(), clientMutex());
+ void dumpInternals_l(int fd) REQUIRES(mutex());
+ void dumpStats(int fd);
SimpleLog mThreadLog{16}; // 16 Thread history limit
@@ -499,6 +511,7 @@
const pid_t mPid;
const uid_t mUid;
const sp<media::IAudioFlingerClient> mAudioFlingerClient;
+ const std::unique_ptr<media::psh_utils::Token> mClientToken;
};
// --- MediaLogNotifier ---
@@ -698,8 +711,7 @@
DefaultKeyedVector<audio_io_handle_t, sp<IAfRecordThread>> mRecordThreads GUARDED_BY(mutex());
- DefaultKeyedVector<pid_t, sp<NotificationClient>> mNotificationClients
- GUARDED_BY(clientMutex());
+ std::map<pid_t, sp<NotificationClient>> mNotificationClients GUARDED_BY(clientMutex());
// updated by atomic_fetch_add_explicit
volatile atomic_uint_fast32_t mNextUniqueIds[AUDIO_UNIQUE_ID_USE_MAX]; // ctor init
@@ -726,7 +738,8 @@
// Audio data transfer is directly handled by the client creating the MMAP stream
DefaultKeyedVector<audio_io_handle_t, sp<IAfMmapThread>> mMmapThreads GUARDED_BY(mutex());
- sp<Client> registerPid(pid_t pid) EXCLUDES_AudioFlinger_ClientMutex; // always returns non-0
+ // always returns non-null
+ sp<Client> registerClient(pid_t pid, uid_t uid) EXCLUDES_AudioFlinger_ClientMutex;
sp<IAfEffectHandle> createOrphanEffect_l(const sp<Client>& client,
const sp<media::IEffectClient>& effectClient,
@@ -777,8 +790,6 @@
bool mSystemReady GUARDED_BY(mutex()) = false;
std::atomic<bool> mAudioPolicyReady = false;
- mediautils::UidInfo mUidInfo GUARDED_BY(mutex());
-
// no mutex needed.
SimpleLog mRejectedSetParameterLog;
SimpleLog mAppSetParameterLog;
@@ -802,6 +813,10 @@
// Local interface to AudioPolicyService, late inited, but logically const
mediautils::atomic_sp<media::IAudioPolicyServiceLocal> mAudioPolicyServiceLocal;
+
+ const int64_t mStartTime = audio_utils_get_real_time_ns();
+ // Late-inited from main()
+ std::atomic<int64_t> mStartupFinishedTime {};
};
// ----------------------------------------------------------------------------
diff --git a/services/audioflinger/Client.cpp b/services/audioflinger/Client.cpp
index 93599ac..4858469 100644
--- a/services/audioflinger/Client.cpp
+++ b/services/audioflinger/Client.cpp
@@ -18,9 +18,10 @@
namespace android {
-Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid)
+Client::Client(const sp<IAfClientCallback>& afClientCallback, pid_t pid, uid_t uid)
: mAfClientCallback(afClientCallback)
, mPid(pid)
+ , mUid(uid)
, mClientAllocator(AllocatorFactory::getClientAllocator()) {}
// Client destructor must be called with AudioFlinger::mClientLock held
@@ -34,4 +35,4 @@
return mClientAllocator;
}
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/audioflinger/Client.h b/services/audioflinger/Client.h
index ff0d751..c2fef39 100644
--- a/services/audioflinger/Client.h
+++ b/services/audioflinger/Client.h
@@ -42,13 +42,14 @@
class Client : public RefBase {
public:
- Client(const sp<IAfClientCallback>& audioFlinger, pid_t pid);
+ Client(const sp<IAfClientCallback>& audioFlinger, pid_t pid, uid_t uid);
// TODO(b/289139675) make Client container.
// Client destructor must be called with AudioFlinger::mClientLock held
~Client() override;
AllocatorFactory::ClientAllocator& allocator();
pid_t pid() const { return mPid; }
+ uid_t uid() const { return mUid; }
const auto& afClientCallback() const { return mAfClientCallback; }
private:
@@ -56,6 +57,7 @@
const sp<IAfClientCallback> mAfClientCallback;
const pid_t mPid;
+ const uid_t mUid;
AllocatorFactory::ClientAllocator mClientAllocator;
};
diff --git a/services/audioflinger/DeviceEffectManager.cpp b/services/audioflinger/DeviceEffectManager.cpp
index 7cb9329..42c6401 100644
--- a/services/audioflinger/DeviceEffectManager.cpp
+++ b/services/audioflinger/DeviceEffectManager.cpp
@@ -22,7 +22,7 @@
#include "EffectConfiguration.h"
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
#include <audio_utils/primitives.h>
#include <media/audiohal/EffectsFactoryHalInterface.h>
#include <utils/Log.h>
@@ -208,10 +208,9 @@
}
void DeviceEffectManager::dump(int fd)
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
- const bool locked = afutils::dumpTryLock(mutex());
- if (!locked) {
+ afutils::FallibleLockGuard l{mutex()};
+ if (!l) {
String8 result("DeviceEffectManager may be deadlocked\n");
write(fd, result.c_str(), result.size());
}
@@ -227,10 +226,6 @@
effect->dump2(fd, 4);
}
}
-
- if (locked) {
- mutex().unlock();
- }
}
size_t DeviceEffectManager::removeEffect(const sp<IAfDeviceEffectProxy>& effect)
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 84505d3..b9d3ebe 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -24,7 +24,7 @@
#include "Client.h"
#include "EffectConfiguration.h"
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
#include <audio_utils/channels.h>
#include <audio_utils/primitives.h>
#include <media/AudioCommonTypes.h>
@@ -506,52 +506,50 @@
}
void EffectBase::dump(int fd, const Vector<String16>& args __unused) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
String8 result;
result.appendFormat("\tEffect ID %d:\n", mId);
- const bool locked = afutils::dumpTryLock(mutex());
- // failed to lock - AudioFlinger is probably deadlocked
- if (!locked) {
- result.append("\t\tCould not lock Fx mutex:\n");
- }
- bool isInternal = isInternal_l();
- result.append("\t\tSession State Registered Internal Enabled Suspended:\n");
- result.appendFormat("\t\t%05d %03d %s %s %s %s\n",
- mSessionId, mState, mPolicyRegistered ? "y" : "n", isInternal ? "y" : "n",
- ((isInternal && isEnabled()) || (!isInternal && mPolicyEnabled)) ? "y" : "n",
- mSuspended ? "y" : "n");
-
- result.append("\t\tDescriptor:\n");
- char uuidStr[64];
- AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
- result.appendFormat("\t\t- UUID: %s\n", uuidStr);
- AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
- result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
- result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
- mDescriptor.apiVersion,
- mDescriptor.flags,
- effectFlagsToString(mDescriptor.flags).c_str());
- result.appendFormat("\t\t- name: %s\n",
- mDescriptor.name);
-
- result.appendFormat("\t\t- implementor: %s\n",
- mDescriptor.implementor);
-
- result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
- result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
- char buffer[256];
- for (size_t i = 0; i < mHandles.size(); ++i) {
- IAfEffectHandle *handle = mHandles[i];
- if (handle != NULL && !handle->disconnected()) {
- handle->dumpToBuffer(buffer, sizeof(buffer));
- result.append(buffer);
+ {
+ afutils::FallibleLockGuard l{mutex()};
+ // failed to lock - AudioFlinger is probably deadlocked
+ if (!l) {
+ result.append("\t\tCould not lock Fx mutex:\n");
}
- }
- if (locked) {
- mutex().unlock();
+ bool isInternal = isInternal_l();
+ result.append("\t\tSession State Registered Internal Enabled Suspended:\n");
+ result.appendFormat("\t\t%05d %03d %s %s %s %s\n",
+ mSessionId, mState, mPolicyRegistered ? "y" : "n", isInternal ? "y" : "n",
+ ((isInternal && isEnabled()) || (!isInternal && mPolicyEnabled)) ? "y" : "n",
+ mSuspended ? "y" : "n");
+
+ result.append("\t\tDescriptor:\n");
+ char uuidStr[64];
+ AudioEffect::guidToString(&mDescriptor.uuid, uuidStr, sizeof(uuidStr));
+ result.appendFormat("\t\t- UUID: %s\n", uuidStr);
+ AudioEffect::guidToString(&mDescriptor.type, uuidStr, sizeof(uuidStr));
+ result.appendFormat("\t\t- TYPE: %s\n", uuidStr);
+ result.appendFormat("\t\t- apiVersion: %08X\n\t\t- flags: %08X (%s)\n",
+ mDescriptor.apiVersion,
+ mDescriptor.flags,
+ effectFlagsToString(mDescriptor.flags).c_str());
+ result.appendFormat("\t\t- name: %s\n",
+ mDescriptor.name);
+
+ result.appendFormat("\t\t- implementor: %s\n",
+ mDescriptor.implementor);
+
+ result.appendFormat("\t\t%zu Clients:\n", mHandles.size());
+ result.append("\t\t\t Pid Priority Ctrl Locked client server\n");
+ char buffer[256];
+ for (size_t i = 0; i < mHandles.size(); ++i) {
+ IAfEffectHandle *handle = mHandles[i];
+ if (handle != NULL && !handle->disconnected()) {
+ handle->dumpToBuffer(buffer, sizeof(buffer));
+ result.append(buffer);
+ }
+ }
}
write(fd, result.c_str(), result.length());
@@ -1710,13 +1708,11 @@
return ss.str();
}
-void EffectModule::dump(int fd, const Vector<String16>& args) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
-{
+void EffectModule::dump(int fd, const Vector<String16>& args) const {
EffectBase::dump(fd, args);
String8 result;
- const bool locked = afutils::dumpTryLock(mutex());
+ afutils::FallibleLockGuard l{mutex()};
result.append("\t\tStatus Engine:\n");
result.appendFormat("\t\t%03d %p\n",
@@ -1758,9 +1754,6 @@
(void)mEffectInterface->dump(fd);
}
- if (locked) {
- mutex().unlock();
- }
}
// ----------------------------------------------------------------------------
@@ -2203,22 +2196,20 @@
}
void EffectHandle::dumpToBuffer(char* buffer, size_t size) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
- const bool locked = mCblk != nullptr && afutils::dumpTryLock(mCblk->lock);
+ std::optional<afutils::FallibleLockGuard> guard;
+ if (mCblk != nullptr) {
+ guard.emplace(mCblk->lock);
+ }
snprintf(buffer, size, "\t\t\t%5d %5d %3s %3s %5u %5u\n",
(mClient == 0) ? getpid() : mClient->pid(),
mPriority,
mHasControl ? "yes" : "no",
- locked ? "yes" : "no",
+ guard.has_value() && *guard ? "yes" : "no",
mCblk ? mCblk->clientIndex : 0,
mCblk ? mCblk->serverIndex : 0
);
-
- if (locked) {
- mCblk->lock.unlock();
- }
}
#undef LOG_TAG
@@ -2803,41 +2794,36 @@
}
void EffectChain::dump(int fd, const Vector<String16>& args) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
String8 result;
-
+ afutils::FallibleLockGuard l{mutex()};
const size_t numEffects = mEffects.size();
result.appendFormat(" %zu effects for session %d\n", numEffects, mSessionId);
-
- if (numEffects) {
- const bool locked = afutils::dumpTryLock(mutex());
- // failed to lock - AudioFlinger is probably deadlocked
- if (!locked) {
- result.append("\tCould not lock mutex:\n");
- }
-
- const std::string inBufferStr = dumpInOutBuffer(true /* isInput */, mInBuffer);
- const std::string outBufferStr = dumpInOutBuffer(false /* isInput */, mOutBuffer);
- result.appendFormat("\t%-*s%-*s Active tracks:\n",
- (int)inBufferStr.size(), "In buffer ",
- (int)outBufferStr.size(), "Out buffer ");
- result.appendFormat("\t%s %s %d\n",
- inBufferStr.c_str(), outBufferStr.c_str(), mActiveTrackCnt);
+ if (numEffects == 0) {
write(fd, result.c_str(), result.size());
+ return;
+ }
- for (size_t i = 0; i < numEffects; ++i) {
- sp<IAfEffectModule> effect = mEffects[i];
- if (effect != 0) {
- effect->dump(fd, args);
- }
- }
- if (locked) {
- mutex().unlock();
+ // failed to lock - AudioFlinger is probably deadlocked
+ if (!l) {
+ result.append("\tCould not lock mutex:\n");
+ }
+
+ const std::string inBufferStr = dumpInOutBuffer(true /* isInput */, mInBuffer);
+ const std::string outBufferStr = dumpInOutBuffer(false /* isInput */, mOutBuffer);
+ result.appendFormat("\t%-*s%-*s Active tracks:\n",
+ (int)inBufferStr.size(), "In buffer ",
+ (int)outBufferStr.size(), "Out buffer ");
+ result.appendFormat("\t%s %s %d\n",
+ inBufferStr.c_str(), outBufferStr.c_str(), mActiveTrackCnt);
+ write(fd, result.c_str(), result.size());
+
+ for (size_t i = 0; i < numEffects; ++i) {
+ sp<IAfEffectModule> effect = mEffects[i];
+ if (effect != 0) {
+ effect->dump(fd, args);
}
- } else {
- write(fd, result.c_str(), result.size());
}
}
@@ -3712,13 +3698,13 @@
}
void DeviceEffectProxy::dump2(int fd, int spaces) const
-NO_THREAD_SAFETY_ANALYSIS // conditional try lock
{
const Vector<String16> args;
EffectBase::dump(fd, args);
- const bool locked = afutils::dumpTryLock(proxyMutex());
- if (!locked) {
+ afutils::FallibleLockGuard l{proxyMutex()};
+
+ if (!l) {
String8 result("DeviceEffectProxy may be deadlocked\n");
write(fd, result.c_str(), result.size());
}
@@ -3745,10 +3731,6 @@
effect->dump(fd, args);
}
}
-
- if (locked) {
- proxyMutex().unlock();
- }
}
#undef LOG_TAG
diff --git a/services/audioflinger/IAfEffect.h b/services/audioflinger/IAfEffect.h
index 3452e94..3a059b6 100644
--- a/services/audioflinger/IAfEffect.h
+++ b/services/audioflinger/IAfEffect.h
@@ -345,7 +345,8 @@
// sendMetadata_l() must be called with thread->mLock held
virtual void sendMetadata_l(const std::vector<playback_track_metadata_v7_t>& allMetadata,
- const std::optional<const std::vector<playback_track_metadata_v7_t>> spatializedMetadata);
+ const std::optional<const std::vector<playback_track_metadata_v7_t>>
+ spatializedMetadata) = 0;
virtual void dump(int fd, const Vector<String16>& args) const = 0;
};
diff --git a/services/audioflinger/IAfPatchPanel.h b/services/audioflinger/IAfPatchPanel.h
index 37dce3a..15b6ddf 100644
--- a/services/audioflinger/IAfPatchPanel.h
+++ b/services/audioflinger/IAfPatchPanel.h
@@ -82,7 +82,7 @@
audio_config_base_t* mixerConfig,
audio_devices_t deviceType,
const String8& address,
- audio_output_flags_t flags,
+ audio_output_flags_t* flags,
audio_attributes_t attributes) REQUIRES(mutex()) = 0;
virtual audio_utils::mutex& mutex() const
RETURN_CAPABILITY(audio_utils::AudioFlinger_Mutex) = 0;
diff --git a/services/audioflinger/IAfThread.h b/services/audioflinger/IAfThread.h
index 8596acb..a13819c 100644
--- a/services/audioflinger/IAfThread.h
+++ b/services/audioflinger/IAfThread.h
@@ -402,7 +402,7 @@
// the Thread is not busy releasing the Tracks, during which the Thread mutex
// may be temporarily unlocked. Some Track methods will use this method to
// avoid races.
- virtual void waitWhileThreadBusy_l(audio_utils::unique_lock& ul)
+ virtual void waitWhileThreadBusy_l(audio_utils::unique_lock<audio_utils::mutex>& ul)
REQUIRES(mutex()) = 0;
// The ThreadloopExecutor is used to defer functors or dtors
@@ -481,7 +481,8 @@
bool isSpatialized,
bool isBitPerfect,
audio_output_flags_t* afTrackFlags,
- float volume)
+ float volume,
+ bool muted)
REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
virtual status_t addTrack_l(const sp<IAfTrack>& track) REQUIRES(mutex()) = 0;
@@ -558,8 +559,8 @@
virtual void setTracksInternalMute(std::map<audio_port_handle_t, bool>* tracksInternalMute)
EXCLUDES_ThreadBase_Mutex = 0;
- virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
- EXCLUDES_ThreadBase_Mutex = 0;
+ virtual status_t setPortsVolume(const std::vector<audio_port_handle_t> &portIds, float volume,
+ bool muted) EXCLUDES_ThreadBase_Mutex = 0;
};
class IAfDirectOutputThread : public virtual IAfPlaybackThread {
@@ -700,8 +701,8 @@
virtual AudioStreamOut* clearOutput() EXCLUDES_ThreadBase_Mutex = 0;
- virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
- EXCLUDES_ThreadBase_Mutex = 0;
+ virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+ bool muted) EXCLUDES_ThreadBase_Mutex = 0;
};
class IAfMmapCaptureThread : public virtual IAfMmapThread {
diff --git a/services/audioflinger/IAfTrack.h b/services/audioflinger/IAfTrack.h
index ee834d6..1b10f81 100644
--- a/services/audioflinger/IAfTrack.h
+++ b/services/audioflinger/IAfTrack.h
@@ -291,7 +291,18 @@
float speed = 1.0f,
bool isSpatialized = false,
bool isBitPerfect = false,
- float volume = 0.0f);
+ float volume = 0.0f,
+ bool muted = false);
+
+ static constexpr std::string_view getLogHeader() {
+ using namespace std::literals;
+ return "Type Id Active Client(pid/uid) Session Port Id S Flags "
+ " Format Chn mask SRate "
+ "ST Usg CT "
+ " G db L dB R dB VS dB PortVol dB PortMuted"
+ " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect InternalMute"
+ " Latency\n"sv;
+ }
virtual void pause() = 0;
virtual void flush() = 0;
@@ -466,7 +477,14 @@
const android::content::AttributionSourceState& attributionSource,
pid_t creatorPid,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
- float volume = 0.0f);
+ float volume = 0.0f,
+ bool muted = false);
+
+ static constexpr std::string_view getLogHeader() {
+ using namespace std::literals;
+ return "Client(pid/uid) Session Port Id"
+ " Format Chn mask SRate Flags Usg/Src PortVol dB PortMuted\n"sv;
+ };
// protected by MMapThread::mLock
virtual void setSilenced_l(bool silenced) = 0;
@@ -511,6 +529,13 @@
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
int32_t startFrames = -1);
+ static constexpr std::string_view getLogHeader() {
+ using namespace std::literals;
+ return "Active Id Client(pid/uid) Session Port Id S Flags "
+ " Format Chn mask SRate Source "
+ " Server FrmCnt FrmRdy Sil Latency\n"sv;
+ }
+
// clear the buffer overflow flag
virtual void clearOverflow() = 0;
// set the buffer overflow flag and return previous value
@@ -587,7 +612,8 @@
* the lowest possible latency
* even if it might glitch. */
float speed = 1.0f,
- float volume = 1.0f);
+ float volume = 1.0f,
+ bool muted = false);
};
class IAfPatchRecord : public virtual IAfRecordTrack, public virtual IAfPatchTrackBase {
diff --git a/services/audioflinger/MmapTracks.h b/services/audioflinger/MmapTracks.h
index 8758bd0..30bbd5d 100644
--- a/services/audioflinger/MmapTracks.h
+++ b/services/audioflinger/MmapTracks.h
@@ -36,7 +36,8 @@
const android::content::AttributionSourceState& attributionSource,
pid_t creatorPid,
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE,
- float volume = 0.0f);
+ float volume = 0.0f,
+ bool muted = false);
~MmapTrack() override;
status_t initCheck() const final;
@@ -71,7 +72,11 @@
void setPortVolume(float volume) override {
mVolume = volume;
}
+ void setPortMute(bool muted) override {
+ mMuteState.muteFromPortVolume = muted;
+ }
float getPortVolume() const override { return mVolume; }
+ bool getPortMute() const override { return mMuteState.muteFromPortVolume; }
private:
DISALLOW_COPY_AND_ASSIGN(MmapTrack);
@@ -86,6 +91,7 @@
void onTimestamp(const ExtendedTimestamp ×tamp) final;
const pid_t mPid;
+ const uid_t mUid;
bool mSilenced; // protected by MMapThread::mLock
bool mSilencedNotified; // protected by MMapThread::mLock
@@ -99,4 +105,4 @@
float mVolume = 0.0f;
}; // end of Track
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 02d4fc2..be59299 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -268,7 +268,7 @@
&mixerConfig,
outputDevice,
outputDeviceAddress,
- flags,
+ &flags,
attributes);
ALOGV("mAfPatchPanelCallback->openOutput_l() returned %p", thread.get());
if (thread == 0) {
@@ -650,7 +650,8 @@
{} /*timeout*/,
frameCountToBeReady,
1.0f /*speed*/,
- 1.0f /*volume*/);
+ 1.0f /*volume*/,
+ false /*muted*/);
status = mPlayback.checkTrack(tempPatchTrack.get());
if (status != NO_ERROR) {
return status;
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 84758a4..70bab6a 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -97,7 +97,8 @@
float speed = 1.0f,
bool isSpatialized = false,
bool isBitPerfect = false,
- float volume = 0.0f);
+ float volume = 0.0f,
+ bool muted = false);
~Track() override;
status_t initCheck() const final;
void appendDumpHeader(String8& result) const final;
@@ -226,7 +227,9 @@
// VolumePortInterface implementation
void setPortVolume(float volume) override;
+ void setPortMute(bool muted) override;
float getPortVolume() const override { return mVolume; }
+ bool getPortMute() const override { return mMuteState.load().muteFromPortVolume; }
protected:
@@ -410,9 +413,9 @@
// TODO: replace PersistableBundle with own struct
// access these two variables only when holding player thread lock.
std::unique_ptr<os::PersistableBundle> mMuteEventExtras;
- mute_state_t mMuteState;
- bool mInternalMute = false;
- std::atomic<float> mVolume = 0.0f;
+ std::atomic<mute_state_t> mMuteState;
+ bool mInternalMute = false;
+ std::atomic<float> mVolume = 0.0f;
}; // end of Track
@@ -510,7 +513,8 @@
* the lowest possible latency
* even if it might glitch. */
float speed = 1.0f,
- float volume = 1.0f);
+ float volume = 1.0f,
+ bool muted = false);
~PatchTrack() override;
size_t framesReady() const final;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 56f4e18..1c0b749 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -27,7 +27,7 @@
#include "MelReporter.h"
#include "ResamplerBufferProvider.h"
-#include <afutils/DumpTryLock.h>
+#include <afutils/FallibleLockGuard.h>
#include <afutils/Permission.h>
#include <afutils/TypedLogger.h>
#include <afutils/Vibrator.h>
@@ -81,6 +81,7 @@
#include <powermanager/PowerManager.h>
#include <private/android_filesystem_config.h>
#include <private/media/AudioTrackShared.h>
+#include <psh_utils/AudioPowerManager.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio_effects/effect_downmix.h>
#include <system/audio_effects/effect_ns.h>
@@ -1041,27 +1042,25 @@
}
void 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()));
- const bool locked = afutils::dumpTryLock(mutex());
- if (!locked) {
- dprintf(fd, " Thread may be deadlocked\n");
- }
-
- dumpBase_l(fd, args);
- dumpInternals_l(fd, args);
- dumpTracks_l(fd, args);
- dumpEffectChains_l(fd, args);
-
- if (locked) {
- mutex().unlock();
+ {
+ afutils::FallibleLockGuard l{mutex()};
+ if (!l) {
+ dprintf(fd, " Thread may be deadlocked\n");
+ }
+ dumpBase_l(fd, args);
+ dumpInternals_l(fd, args);
+ dumpTracks_l(fd, args);
+ dumpEffectChains_l(fd, args);
}
dprintf(fd, " Local log:\n");
- mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
+ const auto logHeader = this->getLocalLogHeader();
+ write(fd, logHeader.data(), logHeader.length());
+ mLocalLog.dump(fd, " " /* prefix */);
// --all does the statistics
bool dumpAll = false;
@@ -1196,6 +1195,8 @@
return String16("MmapCapture");
case SPATIALIZER:
return String16("AudioSpatial");
+ case BIT_PERFECT:
+ return String16("AudioBitPerfect");
default:
ALOG_ASSERT(false);
return String16("AudioUnknown");
@@ -1216,6 +1217,10 @@
{} /* historyTag */);
if (status.isOk()) {
mWakeLockToken = binder;
+ if (media::psh_utils::AudioPowerManager::enabled()) {
+ mThreadToken = media::psh_utils::createAudioThreadToken(
+ getTid(), String8(getWakeLockTag()).c_str());
+ }
}
ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status.exceptionCode());
}
@@ -1241,6 +1246,7 @@
}
mWakeLockToken.clear();
}
+ mThreadToken.reset();
}
void ThreadBase::getPowerManager_l() {
@@ -2399,7 +2405,8 @@
bool isSpatialized,
bool isBitPerfect,
audio_output_flags_t *afTrackFlags,
- float volume)
+ float volume,
+ bool muted)
{
size_t frameCount = *pFrameCount;
size_t notificationFrameCount = *pNotificationFrameCount;
@@ -2728,7 +2735,7 @@
nullptr /* buffer */, (size_t)0 /* bufferSize */, sharedBuffer,
sessionId, creatorPid, attributionSource, trackFlags,
IAfTrackBase::TYPE_DEFAULT, portId, SIZE_MAX /*frameCountToBeReady*/,
- speed, isSpatialized, isBitPerfect, volume);
+ speed, isSpatialized, isBitPerfect, volume, muted);
lStatus = track != 0 ? track->initCheck() : (status_t) NO_MEMORY;
if (lStatus != NO_ERROR) {
@@ -2836,10 +2843,14 @@
}
}
-void PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void PlaybackThread::setStreamVolume(audio_stream_type_t stream, float value, bool muted)
{
+ ALOGV("%s: stream %d value %f muted %d", __func__, stream, value, muted);
audio_utils::lock_guard _l(mutex());
mStreamTypes[stream].volume = value;
+ if (com_android_media_audio_ring_my_car()) {
+ mStreamTypes[stream].mute = muted;
+ }
broadcast_l();
}
@@ -2857,13 +2868,14 @@
}
status_t PlaybackThread::setPortsVolume(
- const std::vector<audio_port_handle_t>& portIds, float volume) {
+ const std::vector<audio_port_handle_t>& portIds, float volume, bool muted) {
audio_utils::lock_guard _l(mutex());
for (const auto& portId : portIds) {
for (size_t i = 0; i < mTracks.size(); i++) {
sp<IAfTrack> track = mTracks[i].get();
if (portId == track->portId()) {
track->setPortVolume(volume);
+ track->setPortMute(muted);
break;
}
}
@@ -3248,9 +3260,9 @@
// Calculate size of normal sink buffer relative to the HAL output buffer size
double multiplier = 1.0;
- // Note: mType == SPATIALIZER does not support FastMixer.
- if (mType == MIXER && (kUseFastMixer == FastMixer_Static ||
- kUseFastMixer == FastMixer_Dynamic)) {
+ // Note: mType == SPATIALIZER does not support FastMixer and DEEP is by definition not "fast"
+ if ((mType == MIXER && !(mOutput->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) &&
+ (kUseFastMixer == FastMixer_Static || kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
@@ -4057,7 +4069,13 @@
// FIXME could this be made local to while loop?
writeFrames = 0;
- cacheParameters_l();
+ {
+ audio_utils::lock_guard l(mutex());
+
+ cacheParameters_l();
+ checkSilentMode_l();
+ }
+
mSleepTimeUs = mIdleSleepTimeUs;
if (mType == MIXER || mType == SPATIALIZER) {
@@ -4082,8 +4100,6 @@
// suspended mode (for now) to help schedule the wait time until next iteration.
nsecs_t timeLoopNextNs = 0;
- checkSilentMode_l();
-
audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
sendCheckOutputStageEffectsEvent();
@@ -5112,6 +5128,12 @@
}
}
+std::string PlaybackThread::getLocalLogHeader() const {
+ using namespace std::literals;
+ static constexpr auto indent = " "
+ " "sv;
+ return std::string{indent}.append(IAfTrack::getLogHeader());
+}
// ----------------------------------------------------------------------------
/* static */
@@ -5175,7 +5197,16 @@
break;
case FastMixer_Static:
case FastMixer_Dynamic:
- initFastMixer = mFrameCount < mNormalFrameCount;
+ if (mType == MIXER && (output->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER)) {
+ /* Do not init fast mixer on deep buffer, warn if buffers are confed too small */
+ initFastMixer = false;
+ ALOGW_IF(mFrameCount * 1000 / mSampleRate < kMinNormalSinkBufferSizeMs,
+ "HAL DEEP BUFFER Buffer (%zu ms) is smaller than set minimal buffer "
+ "(%u ms), seems like a configuration error",
+ mFrameCount * 1000 / mSampleRate, kMinNormalSinkBufferSizeMs);
+ } else {
+ initFastMixer = mFrameCount < mNormalFrameCount;
+ }
break;
}
ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
@@ -5264,7 +5295,10 @@
mFastMixerNBLogWriter = afThreadCallback->newWriter_l(kFastMixerLogSize, "FastMixer");
state->mNBLogWriter = mFastMixerNBLogWriter.get();
sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+ sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ }
NBLog::thread_info_t info;
info.id = mId;
@@ -5323,8 +5357,11 @@
}
state->mCommand = FastMixerState::EXIT;
sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
- mFastMixer->join();
+ {
+ audio_utils::mutex::scoped_join_wait_check queueWaitCheck(mFastMixer->getTid());
+ sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ mFastMixer->join();
+ }
// Though the fast mixer thread has exited, it's state queue is still valid.
// We'll use that extract the final state which contains one remaining fast track
// corresponding to our sub-mix.
@@ -5404,7 +5441,10 @@
FastThreadDumpState::kSamplingNforLowRamDevice : FastThreadDumpState::kSamplingN);
#endif
sq->end();
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+ sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ }
if (kUseFastMixer == FastMixer_Dynamic) {
mNormalSink = mPipeSink;
}
@@ -5437,7 +5477,10 @@
mFastMixerFutex = 0;
sq->end();
// BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
- sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+ sq->push(FastMixerStateQueue::BLOCK_UNTIL_ACKED);
+ }
if (kUseFastMixer == FastMixer_Dynamic) {
mNormalSink = mOutputSink;
}
@@ -5822,7 +5865,7 @@
volume = masterVolume * mStreamTypes[track->streamType()].volume;
}
} else {
- if (track->isPlaybackRestricted()) {
+ if (track->isPlaybackRestricted() || track->getPortMute()) {
volume = 0.f;
} else {
volume = masterVolume * track->getPortVolume();
@@ -5846,7 +5889,8 @@
mStreamTypes[track->streamType()].mute,
track->isPlaybackRestricted(),
vlf == 0.f && vrf == 0.f,
- vh == 0.f});
+ vh == 0.f,
+ /*muteFromPortVolume=*/false});
} else {
track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
/*muteState=*/{masterVolume == 0.f,
@@ -5854,7 +5898,8 @@
/* muteFromStreamMuted= */ false,
track->isPlaybackRestricted(),
vlf == 0.f && vrf == 0.f,
- vh == 0.f});
+ vh == 0.f,
+ track->getPortMute()});
}
vlf *= volume;
vrf *= volume;
@@ -6018,7 +6063,7 @@
}
} else {
v = masterVolume * track->getPortVolume();
- if (track->isPlaybackRestricted()) {
+ if (track->isPlaybackRestricted() || track->getPortMute()) {
v = 0;
}
}
@@ -6048,7 +6093,8 @@
mStreamTypes[track->streamType()].mute,
track->isPlaybackRestricted(),
vlf == 0.f && vrf == 0.f,
- vh == 0.f});
+ vh == 0.f,
+ /*muteFromPortVolume=*/false});
} else {
track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
/*muteState=*/{masterVolume == 0.f,
@@ -6056,7 +6102,8 @@
/* muteFromStreamMuted= */ false,
track->isPlaybackRestricted(),
vlf == 0.f && vrf == 0.f,
- vh == 0.f});
+ vh == 0.f,
+ track->getPortMute()});
}
// now apply the master volume and stream type volume and shaper volume
vlf *= v * vh;
@@ -6333,7 +6380,10 @@
//
// This occurs with BT suspend when we idle the FastMixer with
// active tracks, which may be added or removed.
- sq->push(coldIdle ? FastMixerStateQueue::BLOCK_NEVER : block);
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastMixer->getTid());
+ sq->push(coldIdle ? FastMixerStateQueue::BLOCK_NEVER : block);
+ }
}
#ifdef AUDIO_WATCHDOG
if (pauseAudioWatchdog && mAudioWatchdog != 0) {
@@ -6811,7 +6861,8 @@
mStreamTypes[track->streamType()].mute,
track->isPlaybackRestricted(),
clientVolumeMute,
- shaperVolume == 0.f});
+ shaperVolume == 0.f,
+ /*muteFromPortVolume=*/false});
} else {
if (mMasterMute || track->isPlaybackRestricted()) {
left = right = 0;
@@ -6839,7 +6890,8 @@
/* muteFromStreamMuted= */ false,
track->isPlaybackRestricted(),
clientVolumeMute,
- shaperVolume == 0.f});
+ shaperVolume == 0.f,
+ track->getPortMute()});
}
if (lastTrack) {
@@ -7292,11 +7344,14 @@
{
PlaybackThread::flushHw_l();
mOutput->flush();
- mHwPaused = false;
mFlushPending = false;
mTimestampVerifier.discontinuity(discontinuityForStandbyOrFlush());
mTimestamp.clear();
mMonotonicFrameCounter.onFlush();
+ // We do not reset mHwPaused which is hidden from the Track client.
+ // Note: the client track in Tracks.cpp and AudioTrack.cpp
+ // has a FLUSHED state but the DirectOutputThread does not;
+ // those tracks will continue to show isStopped().
}
int64_t DirectOutputThread::computeWaitTimeNs_l() const {
@@ -7862,6 +7917,9 @@
audio_utils::lock_guard l(mutex());
localTracks = std::move(mOutputTracks);
mOutputTracks.clear();
+ for (size_t i = 0; i < localTracks.size(); ++i) {
+ localTracks[i]->destroy();
+ }
}
localTracks.clear();
outputTracks.clear();
@@ -7935,8 +7993,9 @@
return;
}
if (!audioserver_flags::portid_volume_management()) {
- thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f);
+ thread->setStreamVolume(AUDIO_STREAM_PATCH, /*volume=*/1.0f, /*muted=*/false);
}
+
mOutputTracks.add(outputTrack);
ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread);
updateWaitTime_l();
@@ -8303,8 +8362,10 @@
afThreadCallback->newWriter_l(kFastCaptureLogSize, "FastCapture");
state->mNBLogWriter = mFastCaptureNBLogWriter.get();
sq->end();
- sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
-
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastCapture->getTid());
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+ }
// start the fast capture
mFastCapture->run("FastCapture", ANDROID_PRIORITY_URGENT_AUDIO);
pid_t tid = mFastCapture->getTid();
@@ -8338,8 +8399,11 @@
}
state->mCommand = FastCaptureState::EXIT;
sq->end();
- sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
- mFastCapture->join();
+ {
+ audio_utils::mutex::scoped_join_wait_check queueWaitCheck(mFastCapture->getTid());
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_PUSHED);
+ mFastCapture->join();
+ }
mFastCapture.clear();
}
mAfThreadCallback->unregisterWriter(mFastCaptureNBLogWriter);
@@ -8972,7 +9036,11 @@
mFastCaptureFutex = 0;
sq->end();
// BLOCK_UNTIL_PUSHED would be insufficient, as we need it to stop doing I/O now
- sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+ {
+ audio_utils::mutex::scoped_queue_wait_check queueWaitCheck(mFastCapture->getTid());
+ sq->push(FastCaptureStateQueue::BLOCK_UNTIL_ACKED);
+ }
+
#if 0
if (kUseFastCapture == FastCapture_Dynamic) {
// FIXME
@@ -10205,6 +10273,13 @@
}
}
+std::string RecordThread::getLocalLogHeader() const {
+ using namespace std::literals;
+ static constexpr auto indent = " "
+ " "sv;
+ return std::string{indent}.append(IAfRecordTrack::getLogHeader());
+}
+
// ----------------------------------------------------------------------------
// Mmap
// ----------------------------------------------------------------------------
@@ -10424,6 +10499,7 @@
const auto localSessionId = mSessionId;
auto localAttr = mAttr;
float volume = 0.0f;
+ bool muted = false;
if (isOutput()) {
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = mSampleRate;
@@ -10448,7 +10524,8 @@
&secondaryOutputs,
&isSpatialized,
&isBitPerfect,
- &volume);
+ &volume,
+ &muted);
mutex().lock();
mAttr = localAttr;
ALOGD_IF(!secondaryOutputs.empty(),
@@ -10518,7 +10595,7 @@
mChannelMask, mSessionId, isOutput(),
client.attributionSource,
IPCThreadState::self()->getCallingPid(), portId,
- volume);
+ volume, muted);
if (!isOutput()) {
track->setSilenced_l(isClientSilenced_l(portId));
}
@@ -11085,6 +11162,13 @@
write(fd, result.c_str(), result.size());
}
+std::string MmapThread::getLocalLogHeader() const {
+ using namespace std::literals;
+ static constexpr auto indent = " "
+ " "sv;
+ return std::string{indent}.append(IAfMmapTrack::getLogHeader());
+}
+
/* static */
sp<IAfMmapPlaybackThread> IAfMmapPlaybackThread::create(
const sp<IAfThreadCallback>& afThreadCallback, audio_io_handle_t id,
@@ -11169,10 +11253,14 @@
}
}
-void MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value)
+void MmapPlaybackThread::setStreamVolume(audio_stream_type_t stream, float value, bool muted)
{
+ ALOGV("%s: stream %d value %f muted %d", __func__, stream, value, muted);
audio_utils::lock_guard _l(mutex());
mStreamTypes[stream].volume = value;
+ if (com_android_media_audio_ring_my_car()) {
+ mStreamTypes[stream].mute = muted;
+ }
if (stream == mStreamType) {
broadcast_l();
}
@@ -11194,12 +11282,13 @@
}
status_t MmapPlaybackThread::setPortsVolume(
- const std::vector<audio_port_handle_t>& portIds, float volume) {
+ const std::vector<audio_port_handle_t>& portIds, float volume, bool muted) {
audio_utils::lock_guard _l(mutex());
for (const auto& portId : portIds) {
for (const sp<IAfMmapTrack>& track : mActiveTracks) {
if (portId == track->portId()) {
track->setPortVolume(volume);
+ track->setPortMute(muted);
break;
}
}
@@ -11257,7 +11346,11 @@
// will be broadcasted to all tracks. Thus, take arbitrarily first track volume.
size_t numtracks = mActiveTracks.size();
if (numtracks) {
- volume = mMasterVolume * mActiveTracks[0]->getPortVolume();
+ if (mActiveTracks[0]->getPortMute()) {
+ volume = 0;
+ } else {
+ volume = mMasterVolume * mActiveTracks[0]->getPortVolume();
+ }
}
}
}
@@ -11301,7 +11394,8 @@
// TODO(b/241533526): adjust logic to include mute from AppOps
false /*muteFromPlaybackRestricted*/,
false /*muteFromClientVolume*/,
- false /*muteFromVolumeShaper*/});
+ false /*muteFromVolumeShaper*/,
+ false /*muteFromPortVolume*/});
} else {
track->processMuteEvent_l(mAfThreadCallback->getOrCreateAudioManager(),
/*muteState=*/{mMasterMute,
@@ -11310,7 +11404,8 @@
// TODO(b/241533526): adjust logic to include mute from AppOps
false /*muteFromPlaybackRestricted*/,
false /*muteFromClientVolume*/,
- false /*muteFromVolumeShaper*/});
+ false /*muteFromVolumeShaper*/,
+ track->getPortMute()});
}
}
}
@@ -11598,6 +11693,7 @@
void BitPerfectThread::setTracksInternalMute(
std::map<audio_port_handle_t, bool>* tracksInternalMute) {
+ audio_utils::lock_guard _l(mutex());
for (auto& track : mTracks) {
if (auto it = tracksInternalMute->find(track->portId()); it != tracksInternalMute->end()) {
track->setInternalMute(it->second);
@@ -11614,6 +11710,11 @@
// Return the bit perfect track if all other tracks are muted
for (const auto& track : mActiveTracks) {
if (track->isBitPerfect()) {
+ if (track->getInternalMute()) {
+ // There can only be one bit-perfect client active. If it is mute internally,
+ // there is no need to stream bit-perfectly.
+ break;
+ }
bitPerfectTrack = track;
} else if (track->getFinalVolume() != 0.f) {
allOtherTracksMuted = false;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index a7a2630..0c5a2c3 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -33,6 +33,7 @@
#include <fastpath/FastMixer.h>
#include <mediautils/Synchronization.h>
#include <mediautils/ThreadSnapshot.h>
+#include <psh_utils/Token.h>
#include <timing/MonotonicFrameCounter.h>
#include <utils/Log.h>
@@ -575,6 +576,9 @@
return mThreadloopExecutor;
}
+ // Used to print the header for the local log on a particular thread type
+ virtual std::string getLocalLogHeader() const { return {}; };
+
protected:
// entry describing an effect being suspended in mSuspendedSessions keyed vector
@@ -622,7 +626,8 @@
* ThreadBase_Mutex during this time. No other mutex is held.
*/
- void waitWhileThreadBusy_l(audio_utils::unique_lock& ul) final REQUIRES(mutex()) {
+ void waitWhileThreadBusy_l(audio_utils::unique_lock<audio_utils::mutex>& ul)
+ final REQUIRES(mutex()) {
// the wait returns immediately if the predicate is satisfied.
mThreadBusyCv.wait(ul, [&]{ return mThreadBusy == false;});
}
@@ -725,6 +730,7 @@
char mThreadName[kThreadNameLength]; // guaranteed NUL-terminated
sp<os::IPowerManager> mPowerManager GUARDED_BY(mutex());
sp<IBinder> mWakeLockToken GUARDED_BY(mutex());
+ std::unique_ptr<media::psh_utils::Token> mThreadToken GUARDED_BY(mutex());
const sp<PMDeathRecipient> mDeathRecipient;
// list of suspended effects per session and per type. The first (outer) vector is
// keyed by session ID, the second (inner) by type UUID timeLow field
@@ -885,7 +891,7 @@
bool mHasChanged = false;
};
- SimpleLog mLocalLog; // locked internally
+ SimpleLog mLocalLog {/* maxLogLines= */ 120}; // locked internally
// mThreadloopExecutor contains deferred functors and object (dtors) to
// be executed at the end of the processing period, without any
@@ -1014,11 +1020,12 @@
void setMasterVolume(float value) final;
void setMasterBalance(float balance) override EXCLUDES_ThreadBase_Mutex;
void setMasterMute(bool muted) final;
- void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+ void setStreamVolume(audio_stream_type_t stream, float value, bool muted) final
+ EXCLUDES_ThreadBase_Mutex;
void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
- status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
- final EXCLUDES_ThreadBase_Mutex;
+ status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+ bool muted) final EXCLUDES_ThreadBase_Mutex;
void setVolumeForOutput_l(float left, float right) const final;
@@ -1045,7 +1052,8 @@
bool isSpatialized,
bool isBitPerfect,
audio_output_flags_t* afTrackFlags,
- float volume) final
+ float volume,
+ bool muted) final
REQUIRES(audio_utils::AudioFlinger_Mutex);
bool isTrackActive(const sp<IAfTrack>& track) const final {
@@ -1227,6 +1235,9 @@
override EXCLUDES_ThreadBase_Mutex {
// Do nothing. It is only used for bit perfect thread
}
+
+ std::string getLocalLogHeader() const override;
+
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -2131,6 +2142,8 @@
return !(mInput == nullptr || mInput->stream == nullptr);
}
+ std::string getLocalLogHeader() const override;
+
protected:
void dumpInternals_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
void dumpTracks_l(int fd, const Vector<String16>& args) override REQUIRES(mutex());
@@ -2322,6 +2335,8 @@
bool isStreamInitialized() const override { return false; }
+ std::string getLocalLogHeader() const override;
+
void setClientSilencedState_l(audio_port_handle_t portId, bool silenced) REQUIRES(mutex()) {
mClientSilencedStates[portId] = silenced;
}
@@ -2392,11 +2407,13 @@
// Needs implementation?
void setMasterBalance(float /* value */) final EXCLUDES_ThreadBase_Mutex {}
void setMasterMute(bool muted) final EXCLUDES_ThreadBase_Mutex;
- void setStreamVolume(audio_stream_type_t stream, float value) final EXCLUDES_ThreadBase_Mutex;
+
+ void setStreamVolume(audio_stream_type_t stream, float value, bool muted) final
+ EXCLUDES_ThreadBase_Mutex;
void setStreamMute(audio_stream_type_t stream, bool muted) final EXCLUDES_ThreadBase_Mutex;
float streamVolume(audio_stream_type_t stream) const final EXCLUDES_ThreadBase_Mutex;
- status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume)
- final EXCLUDES_ThreadBase_Mutex;
+ status_t setPortsVolume(const std::vector<audio_port_handle_t>& portIds, float volume,
+ bool muted) final EXCLUDES_ThreadBase_Mutex;
void setMasterMute_l(bool muted) REQUIRES(mutex()) { mMasterMute = muted; }
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 1342b7b..cde7fc2 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -24,6 +24,7 @@
#include <android-base/macros.h> // DISALLOW_COPY_AND_ASSIGN
#include <datapath/TrackMetrics.h>
#include <mediautils/BatteryNotifier.h>
+#include <psh_utils/AudioPowerManager.h>
#include <atomic> // avoid transitive dependency
#include <list> // avoid transitive dependency
@@ -240,17 +241,13 @@
* Called when a track moves to active state to record its contribution to battery usage.
* Track state transitions should eventually be handled within the track class.
*/
- void beginBatteryAttribution() final {
- mBatteryStatsHolder.emplace(uid());
- }
+ void beginBatteryAttribution() final;
/**
* Called when a track moves out of the active state to record its contribution
* to battery usage.
*/
- void endBatteryAttribution() final {
- mBatteryStatsHolder.reset();
- }
+ void endBatteryAttribution() final;
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -400,6 +397,7 @@
std::atomic_flag mChangeNotified = ATOMIC_FLAG_INIT;
// RAII object for battery stats book-keeping
std::optional<mediautils::BatteryStatsAudioHandle> mBatteryStatsHolder;
+ std::unique_ptr<media::psh_utils::Token> mTrackToken;
};
class PatchTrackBase : public PatchProxyBufferProvider, public virtual IAfPatchTrackBase
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5aa58a2..980ef22 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -318,13 +318,25 @@
{
const auto thread = mThread.promote();
if (thread == nullptr) return;
- thread->getThreadloopExecutor().defer(
- [track = wp<TrackBase>::fromExisting(this)] {
- const auto actual = track.promote();
+ auto weakTrack = wp<TrackBase>::fromExisting(this);
+ thread->getThreadloopExecutor().defer([weakTrack] {
+ const auto actual = weakTrack.promote();
if (actual) actual->restartIfDisabled();
});
}
+void TrackBase::beginBatteryAttribution() {
+ mBatteryStatsHolder.emplace(uid());
+ if (media::psh_utils::AudioPowerManager::enabled()) {
+ mTrackToken = media::psh_utils::createAudioTrackToken(uid());
+ }
+}
+
+void TrackBase::endBatteryAttribution() {
+ mBatteryStatsHolder.reset();
+ mTrackToken.reset();
+}
+
PatchTrackBase::PatchTrackBase(const sp<ClientProxy>& proxy,
IAfThreadBase* thread, const Timeout& timeout)
: mProxy(proxy)
@@ -716,7 +728,8 @@
float speed,
bool isSpatialized,
bool isBitPerfect,
- float volume) {
+ float volume,
+ bool muted) {
return sp<Track>::make(thread,
client,
streamType,
@@ -738,7 +751,8 @@
speed,
isSpatialized,
isBitPerfect,
- volume);
+ volume,
+ muted);
}
// Track constructor must be called with AudioFlinger::mLock and ThreadBase::mLock held
@@ -764,7 +778,8 @@
float speed,
bool isSpatialized,
bool isBitPerfect,
- float volume)
+ float volume,
+ bool muted)
: TrackBase(thread, client, attr, sampleRate, format, channelMask, frameCount,
// TODO: Using unsecurePointer() has some associated security pitfalls
// (see declaration for details).
@@ -848,11 +863,13 @@
}
populateUsageAndContentTypeFromStreamType();
+ setPortMute(muted);
// Audio patch and call assistant volume are always max
if (mAttr.usage == AUDIO_USAGE_CALL_ASSISTANT
|| mAttr.usage == AUDIO_USAGE_VIRTUAL_SOURCE) {
mVolume = 1.0f;
+ setPortMute(false);
}
mServerLatencySupported = checkServerLatencySupported(format, flags);
@@ -988,13 +1005,8 @@
void Track::appendDumpHeader(String8& result) const
{
- result.appendFormat("Type Id Active Client Session Port Id S Flags "
- " Format Chn mask SRate "
- "ST Usg CT "
- " G db L dB R dB VS dB PortVol dB "
- " Server FrmCnt FrmRdy F Underruns Flushed BitPerfect InternalMute"
- "%s\n",
- isServerLatencySupported() ? " Latency" : "");
+ const auto res = IAfTrack::getLogHeader();
+ result.append(res.data(), res.size());
}
void Track::appendDump(String8& result, bool active) const
@@ -1074,13 +1086,14 @@
? 'r' /* buffer reduced */: bufferSizeInFrames > mFrameCount
? 'e' /* error */ : ' ' /* identical */;
- result.appendFormat("%7s %6u %7u %7u %2s 0x%03X "
+ result.appendFormat("%7s %7u/%7u %7u %7u %2s 0x%03X "
"%08X %08X %6u "
"%2u %3x %2x "
- "%5.2g %5.2g %5.2g %5.2g%c %11.2g "
+ "%5.2g %5.2g %5.2g %5.2g%c %11.2g %12s"
"%08X %6zu%c %6zu %c %9u%c %7u %10s %12s",
active ? "yes" : "no",
- (mClient == 0) ? getpid() : mClient->pid(),
+ mClient ? mClient->pid() : getpid() ,
+ mClient ? mClient->uid() : getuid(),
mSessionId,
mPortId,
getTrackStateAsCodedString(),
@@ -1100,6 +1113,7 @@
20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
vsVolume.second ? 'A' : ' ', // if any VolumeShapers active
20.0 * log10(mVolume),
+ getPortMute() ? "true" : "false",
mCblk->mServer,
bufferSizeInFrames,
@@ -1606,8 +1620,25 @@
if (mType != TYPE_PATCH) {
// Do not recursively propagate a PatchTrack setPortVolume to
// downstream PatchTracks.
- forEachTeePatchTrack_l([volume](const auto& patchTrack) {
- patchTrack->setPortVolume(volume); });
+ forEachTeePatchTrack_l([volume](const auto &patchTrack) {
+ patchTrack->setPortVolume(volume);
+ });
+ }
+}
+
+void Track::setPortMute(bool muted) {
+ mute_state_t newMuteState = mMuteState.load();
+ if (newMuteState.muteFromPortVolume == muted) {
+ return;
+ }
+ newMuteState.muteFromPortVolume = muted;
+ mMuteState.store(newMuteState);
+ if (mType != TYPE_PATCH) {
+ // Do not recursively propagate a PatchTrack setPortVolume to
+ // downstream PatchTracks.
+ forEachTeePatchTrack_l([muted](const auto &patchTrack) {
+ patchTrack->setPortMute(muted);
+ });
}
}
@@ -1712,8 +1743,8 @@
}
if (result == OK) {
- ALOGI("%s(%d): processed mute state for port ID %d from %d to %d", __func__, id(), mPortId,
- static_cast<int>(mMuteState), static_cast<int>(muteState));
+ ALOGI("%s(%d): processed mute state for port ID %d from %#x to %#x", __func__, id(),
+ mPortId, static_cast<int>(mMuteState.load()), static_cast<int>(muteState));
mMuteState = muteState;
} else {
ALOGW("%s(%d): cannot process mute state for port ID %d, status error %d", __func__, id(),
@@ -2490,7 +2521,8 @@
* the lowest possible latency
* even if it might glitch. */
float speed,
- float volume)
+ float volume,
+ bool muted)
{
return sp<PatchTrack>::make(
playbackThread,
@@ -2505,7 +2537,8 @@
timeout,
frameCountToBeReady,
speed,
- volume);
+ volume,
+ muted);
}
PatchTrack::PatchTrack(IAfPlaybackThread* playbackThread,
@@ -2520,14 +2553,15 @@
const Timeout& timeout,
size_t frameCountToBeReady,
float speed,
- float volume)
+ float volume,
+ bool muted)
: Track(playbackThread, NULL, streamType,
AUDIO_ATTRIBUTES_INITIALIZER,
sampleRate, format, channelMask, frameCount,
buffer, bufferSize, nullptr /* sharedBuffer */,
AUDIO_SESSION_NONE, getpid(), audioServerAttributionSource(getpid()), flags,
TYPE_PATCH, AUDIO_PORT_HANDLE_NONE, frameCountToBeReady, speed,
- false /*isSpatialized*/, false /*isBitPerfect*/, volume),
+ false /*isSpatialized*/, false /*isBitPerfect*/, volume, muted),
PatchTrackBase(mCblk ? new AudioTrackClientProxy(mCblk, mBuffer, frameCount, mFrameSize,
true /*clientInServer*/) : nullptr,
playbackThread, timeout)
@@ -2977,21 +3011,20 @@
void RecordTrack::appendDumpHeader(String8& result) const
{
- result.appendFormat("Active Id Client Session Port Id S Flags "
- " Format Chn mask SRate Source "
- " Server FrmCnt FrmRdy Sil%s\n",
- isServerLatencySupported() ? " Latency" : "");
+ const auto res = IAfRecordTrack::getLogHeader();
+ result.append(res.data(), res.size());
}
void RecordTrack::appendDump(String8& result, bool active) const
{
- result.appendFormat("%c%5s %6d %6u %7u %7u %2s 0x%03X "
+ result.appendFormat("%c%5s %6d %7u/%7u %7u %7u %2s 0x%03X "
"%08X %08X %6u %6X "
"%08X %6zu %6zu %3c",
isFastTrack() ? 'F' : ' ',
active ? "yes" : "no",
mId,
- (mClient == 0) ? getpid() : mClient->pid(),
+ mClient ? mClient->pid() : getpid(),
+ mClient ? mClient->uid() : getuid(),
mSessionId,
mPortId,
getTrackStateAsCodedString(),
@@ -3512,7 +3545,8 @@
const android::content::AttributionSourceState& attributionSource,
pid_t creatorPid,
audio_port_handle_t portId,
- float volume)
+ float volume,
+ bool muted)
{
return sp<MmapTrack>::make(
thread,
@@ -3525,7 +3559,8 @@
attributionSource,
creatorPid,
portId,
- volume);
+ volume,
+ muted);
}
MmapTrack::MmapTrack(IAfThreadBase* thread,
@@ -3538,7 +3573,8 @@
const AttributionSourceState& attributionSource,
pid_t creatorPid,
audio_port_handle_t portId,
- float volume)
+ float volume,
+ bool muted)
: TrackBase(thread, NULL, attr, sampleRate, format,
channelMask, (size_t)0 /* frameCount */,
nullptr /* buffer */, (size_t)0 /* bufferSize */,
@@ -3549,14 +3585,17 @@
TYPE_DEFAULT, portId,
std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_MMAP) + std::to_string(portId)),
mPid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.pid))),
+ mUid(VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid))),
mSilenced(false), mSilencedNotified(false), mVolume(volume)
{
+ mMuteState.muteFromPortVolume = muted;
// Once this item is logged by the server, the client can add properties.
mTrackMetrics.logConstructor(creatorPid, uid(), id());
if (isOut && (attr.usage == AUDIO_USAGE_CALL_ASSISTANT
|| attr.usage == AUDIO_USAGE_VIRTUAL_SOURCE)) {
// Audio patch and call assistant volume are always max
mVolume = 1.0f;
+ mMuteState.muteFromPortVolume = false;
}
}
@@ -3636,14 +3675,15 @@
void MmapTrack::appendDumpHeader(String8& result) const
{
- result.appendFormat("Client Session Port Id Format Chn mask SRate Flags %s %s\n",
- isOut() ? "Usg CT": "Source", isOut() ? "PortVol dB" : "");
+ const auto res = IAfMmapTrack::getLogHeader();
+ result.append(res.data(), res.size());
}
void MmapTrack::appendDump(String8& result, bool active __unused) const
{
- result.appendFormat("%6u %7u %7u %08X %08X %6u 0x%03X ",
+ result.appendFormat("%7u/%7u %7u %7u %08X %08X %6u 0x%03X ",
mPid,
+ mUid,
mSessionId,
mPortId,
mFormat,
@@ -3651,10 +3691,11 @@
mSampleRate,
mAttr.flags);
if (isOut()) {
- result.appendFormat("%3x %2x", mAttr.usage, mAttr.content_type);
+ result.appendFormat("%4x %2x", mAttr.usage, mAttr.content_type);
result.appendFormat("%11.2g", 20.0 * log10(mVolume));
+ result.appendFormat("%12s", mMuteState.muteFromPortVolume ? "true" : "false");
} else {
- result.appendFormat("%6x", mAttr.source);
+ result.appendFormat("%7x", mAttr.source);
}
result.append("\n");
}
diff --git a/services/audioflinger/afutils/DumpTryLock.h b/services/audioflinger/afutils/DumpTryLock.h
deleted file mode 100644
index 05e050e..0000000
--- a/services/audioflinger/afutils/DumpTryLock.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- * Copyright 2023, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <audio_utils/mutex.h>
-#include <utils/Mutex.h>
-
-namespace android::afutils {
-
-inline bool dumpTryLock(Mutex& mutex)
-{
- static constexpr int kDumpLockTimeoutNs = 1'000'000'000;
- const status_t err = mutex.timedLock(kDumpLockTimeoutNs);
- return err == NO_ERROR;
-}
-
-// Note: the std::timed_mutex try_lock_for and try_lock_until methods are inefficient.
-// It is better to use std::mutex and call this method.
-//
-inline bool dumpTryLock(audio_utils::mutex& mutex) TRY_ACQUIRE(true, mutex)
-{
- static constexpr int64_t kDumpLockTimeoutNs = 1'000'000'000;
- return mutex.try_lock(kDumpLockTimeoutNs);
-}
-
-} // android::afutils
diff --git a/services/audioflinger/afutils/FallibleLockGuard.h b/services/audioflinger/afutils/FallibleLockGuard.h
new file mode 100644
index 0000000..a2e66f6
--- /dev/null
+++ b/services/audioflinger/afutils/FallibleLockGuard.h
@@ -0,0 +1,69 @@
+/*
+ *
+ * Copyright 2024, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <android-base/thread_annotations.h>
+#include <audio_utils/mutex.h>
+#include <utils/Mutex.h>
+
+#include <functional>
+
+namespace android::afutils {
+
+// Lock guard with a acquire timeout, which for the purpose of thread safety annotations acts as if
+// it has the capability (i.e. the thread annotations *lie*). Used for dump utilities, where if we
+// are deadlocked, we access without the lock since we are about to abort due to watchdog anyway.
+// If the lock was truly successfully acquired, unlock on dtor. Like all guards (if successful),
+// this guard is solely responsible for locking on ctor/unlocking on dtor, and the mutex reference
+// must be valid for the lifetime of the object
+class [[nodiscard]] SCOPED_CAPABILITY FallibleLockGuard {
+ public:
+ static constexpr int kDefaultTimeout = 1'000'000'000;
+
+ explicit FallibleLockGuard(Mutex& mutex, int64_t timeoutNs = kDefaultTimeout) ACQUIRE(mutex) {
+ if (mutex.timedLock(timeoutNs) == NO_ERROR) {
+ mUnlockFunc = [&mutex]() NO_THREAD_SAFETY_ANALYSIS { mutex.unlock(); };
+ }
+ }
+
+ explicit FallibleLockGuard(audio_utils::mutex& mutex, int64_t timeoutNs = kDefaultTimeout)
+ ACQUIRE(mutex) {
+ if (mutex.try_lock(timeoutNs)) {
+ mUnlockFunc = [&mutex]() NO_THREAD_SAFETY_ANALYSIS { mutex.unlock(); };
+ }
+ }
+
+ FallibleLockGuard(const FallibleLockGuard& other) = delete;
+
+ FallibleLockGuard(FallibleLockGuard&& other) {
+ mUnlockFunc.swap(other.mUnlockFunc);
+ }
+
+ FallibleLockGuard& operator=(const FallibleLockGuard& other) = delete;
+
+ // Return if the underlying lock was successfully locked
+ explicit operator bool() const { return static_cast<bool>(mUnlockFunc); }
+
+ ~FallibleLockGuard() RELEASE() {
+ if (mUnlockFunc) mUnlockFunc();
+ }
+
+ private:
+ std::function<void()> mUnlockFunc;
+};
+} // android::afutils
diff --git a/services/audioflinger/datapath/AudioHwDevice.cpp b/services/audioflinger/datapath/AudioHwDevice.cpp
index 5314e9e..c2e538c 100644
--- a/services/audioflinger/datapath/AudioHwDevice.cpp
+++ b/services/audioflinger/datapath/AudioHwDevice.cpp
@@ -41,19 +41,20 @@
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t deviceType,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
struct audio_config *config,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
struct audio_config originalConfig = *config;
- auto outputStream = new AudioStreamOut(this, flags);
+ auto outputStream = new AudioStreamOut(this);
// Try to open the HAL first using the current format.
ALOGV("openOutputStream(), try sampleRate %d, format %#x, channelMask %#x", config->sample_rate,
config->format, config->channel_mask);
- status_t status = outputStream->open(handle, deviceType, config, address, sourceMetadata);
+ status_t status = outputStream->open(handle, deviceType, config, flags, address,
+ sourceMetadata);
if (status != NO_ERROR) {
delete outputStream;
@@ -67,19 +68,25 @@
// If the data is encoded then try again using wrapped PCM.
const bool wrapperNeeded = !audio_has_proportional_frames(originalConfig.format)
- && ((flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
- && ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
+ && ((*flags & AUDIO_OUTPUT_FLAG_DIRECT) != 0)
+ && ((*flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0);
if (wrapperNeeded) {
if (SPDIFEncoder::isFormatSupported(originalConfig.format)) {
- outputStream = new SpdifStreamOut(this, flags, originalConfig.format);
- status = outputStream->open(handle, deviceType, &originalConfig, address,
+ outputStream = new SpdifStreamOut(this, originalConfig.format);
+ status = outputStream->open(handle, deviceType, &originalConfig, flags, address,
sourceMetadata);
if (status != NO_ERROR) {
ALOGE("ERROR - openOutputStream(), SPDIF open returned %d",
status);
delete outputStream;
outputStream = nullptr;
+ } else {
+ // on success, we need to assign the actual HAL stream config so that clients
+ // know and can later patch correctly.
+ config->format = originalConfig.format;
+ config->channel_mask = originalConfig.channel_mask;
+ config->sample_rate = originalConfig.sample_rate;
}
} else {
ALOGE("ERROR - openOutputStream(), SPDIFEncoder does not support format 0x%08x",
@@ -153,6 +160,12 @@
status);
delete inputStream;
inputStream = nullptr;
+ } else {
+ // on success, we need to assign the actual HAL stream config so that clients
+ // know and can later patch correctly.
+ config->format = originalConfig.format;
+ config->channel_mask = originalConfig.channel_mask;
+ config->sample_rate = originalConfig.sample_rate;
}
} else {
ALOGE("ERROR - openInputStream(), SPDIFDecoder does not support format 0x%08x",
diff --git a/services/audioflinger/datapath/AudioHwDevice.h b/services/audioflinger/datapath/AudioHwDevice.h
index e1a9018..6a35b91 100644
--- a/services/audioflinger/datapath/AudioHwDevice.h
+++ b/services/audioflinger/datapath/AudioHwDevice.h
@@ -85,7 +85,7 @@
AudioStreamOut **ppStreamOut,
audio_io_handle_t handle,
audio_devices_t deviceType,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
struct audio_config *config,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
diff --git a/services/audioflinger/datapath/AudioStreamOut.cpp b/services/audioflinger/datapath/AudioStreamOut.cpp
index c65373e..7aadda3 100644
--- a/services/audioflinger/datapath/AudioStreamOut.cpp
+++ b/services/audioflinger/datapath/AudioStreamOut.cpp
@@ -30,9 +30,8 @@
namespace android {
// ----------------------------------------------------------------------------
-AudioStreamOut::AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags)
+AudioStreamOut::AudioStreamOut(AudioHwDevice *dev)
: audioHwDev(dev)
- , flags(flags)
{
}
@@ -93,14 +92,16 @@
audio_io_handle_t handle,
audio_devices_t deviceType,
struct audio_config *config,
+ audio_output_flags_t *flagsPtr,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
sp<StreamOutHalInterface> outStream;
- const audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
- ? (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
- : flags;
+ audio_output_flags_t customFlags = (config->format == AUDIO_FORMAT_IEC61937)
+ ? (audio_output_flags_t)(*flagsPtr | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+ : *flagsPtr;
+ *flagsPtr = flags = customFlags;
int status = hwDev()->openOutputStream(
handle,
diff --git a/services/audioflinger/datapath/AudioStreamOut.h b/services/audioflinger/datapath/AudioStreamOut.h
index 2bf94a1..1857099 100644
--- a/services/audioflinger/datapath/AudioStreamOut.h
+++ b/services/audioflinger/datapath/AudioStreamOut.h
@@ -37,16 +37,17 @@
public:
AudioHwDevice * const audioHwDev;
sp<StreamOutHalInterface> stream;
- const audio_output_flags_t flags;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
[[nodiscard]] sp<DeviceHalInterface> hwDev() const;
- AudioStreamOut(AudioHwDevice *dev, audio_output_flags_t flags);
+ explicit AudioStreamOut(AudioHwDevice *dev);
virtual status_t open(
audio_io_handle_t handle,
audio_devices_t deviceType,
struct audio_config *config,
+ audio_output_flags_t *flagsPtr,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata);
diff --git a/services/audioflinger/datapath/SpdifStreamIn.cpp b/services/audioflinger/datapath/SpdifStreamIn.cpp
index 98ce712..0090bc5 100644
--- a/services/audioflinger/datapath/SpdifStreamIn.cpp
+++ b/services/audioflinger/datapath/SpdifStreamIn.cpp
@@ -81,6 +81,11 @@
outputDevice,
outputDeviceAddress);
+ // reset config back to whatever is returned by HAL
+ config->sample_rate = customConfig.sample_rate;
+ config->format = customConfig.format;
+ config->channel_mask = customConfig.channel_mask;
+
ALOGI("SpdifStreamIn::open() status = %d", status);
#ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.cpp b/services/audioflinger/datapath/SpdifStreamOut.cpp
index d3983b0..a565955 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.cpp
+++ b/services/audioflinger/datapath/SpdifStreamOut.cpp
@@ -33,10 +33,8 @@
* PCM then we need to wrap the data in an SPDIF wrapper.
*/
SpdifStreamOut::SpdifStreamOut(AudioHwDevice *dev,
- audio_output_flags_t flags,
audio_format_t format)
- // Tell the HAL that the data will be compressed audio wrapped in a data burst.
- : AudioStreamOut(dev, (audio_output_flags_t) (flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO))
+ : AudioStreamOut(dev)
, mSpdifEncoder(this, format)
{
}
@@ -45,6 +43,7 @@
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
+ audio_output_flags_t *flags,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata)
{
@@ -63,6 +62,8 @@
customConfig.format = AUDIO_FORMAT_PCM_16_BIT;
customConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ // Tell the HAL that the data will be compressed audio wrapped in a data burst.
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO);
// Always print this because otherwise it could be very confusing if the
// HAL and AudioFlinger are using different formats.
@@ -76,9 +77,15 @@
handle,
devices,
&customConfig,
+ flags,
address,
sourceMetadata);
+ // reset config back to whatever is returned by HAL
+ config->sample_rate = customConfig.sample_rate;
+ config->format = customConfig.format;
+ config->channel_mask = customConfig.channel_mask;
+
ALOGI("SpdifStreamOut::open() status = %d", status);
#ifdef TEE_SINK
diff --git a/services/audioflinger/datapath/SpdifStreamOut.h b/services/audioflinger/datapath/SpdifStreamOut.h
index 1cd8f65..3241d6f 100644
--- a/services/audioflinger/datapath/SpdifStreamOut.h
+++ b/services/audioflinger/datapath/SpdifStreamOut.h
@@ -36,13 +36,13 @@
class SpdifStreamOut : public AudioStreamOut {
public:
- SpdifStreamOut(AudioHwDevice *dev, audio_output_flags_t flags,
- audio_format_t format);
+ SpdifStreamOut(AudioHwDevice *dev, audio_format_t format);
status_t open(
audio_io_handle_t handle,
audio_devices_t devices,
struct audio_config *config,
+ audio_output_flags_t *flags,
const char *address,
const std::vector<playback_track_metadata_v7_t>& sourceMetadata) override;
diff --git a/services/audioflinger/datapath/VolumeInterface.h b/services/audioflinger/datapath/VolumeInterface.h
index 1564fe1..02b6ade 100644
--- a/services/audioflinger/datapath/VolumeInterface.h
+++ b/services/audioflinger/datapath/VolumeInterface.h
@@ -25,7 +25,7 @@
virtual void setMasterVolume(float value) = 0;
virtual void setMasterBalance(float balance) = 0;
virtual void setMasterMute(bool muted) = 0;
- virtual void setStreamVolume(audio_stream_type_t stream, float value) = 0;
+ virtual void setStreamVolume(audio_stream_type_t stream, float value, bool muted) = 0;
virtual void setStreamMute(audio_stream_type_t stream, bool muted) = 0;
// TODO(b/290699744) add "get" prefix for getter below.
virtual float streamVolume(audio_stream_type_t stream) const = 0;
diff --git a/services/audioflinger/datapath/VolumePortInterface.h b/services/audioflinger/datapath/VolumePortInterface.h
index fb1c463..fe3b782 100644
--- a/services/audioflinger/datapath/VolumePortInterface.h
+++ b/services/audioflinger/datapath/VolumePortInterface.h
@@ -23,7 +23,10 @@
class VolumePortInterface : public virtual RefBase {
public:
virtual void setPortVolume(float volume) = 0;
+ virtual void setPortMute(bool mute) = 0;
virtual float getPortVolume() const = 0;
+ /** Returns the muted state defined by the volume group which is playing on this port. */
+ virtual bool getPortMute() const = 0;
};
} // namespace android
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index e849bb4..3539f00 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -148,7 +148,8 @@
output_type_t *outputType,
bool *isSpatialized,
bool *isBitPerfect,
- float *volume) = 0;
+ float *volume,
+ bool *muted) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding
// stream.
virtual status_t startOutput(audio_port_handle_t portId) = 0;
@@ -197,6 +198,7 @@
// setting volume for all devices
virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
int index,
+ bool muted,
audio_devices_t device) = 0;
// retrieve current volume index for the specified stream and the
@@ -208,6 +210,7 @@
virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
int index,
+ bool muted,
audio_devices_t device) = 0;
virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
int &index,
@@ -478,7 +481,7 @@
audio_config_base_t *mixerConfig,
const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_attributes_t audioAttributes) = 0;
// creates a special output that is duplicated to the two outputs passed as arguments.
// The duplication is performed by a special mixer thread in the AudioFlinger.
@@ -514,7 +517,7 @@
// set a stream volume for a particular output. For the same user setting, a given stream type
// can have different volumes
// for each output (destination device) it is attached to.
- virtual status_t setStreamVolume(audio_stream_type_t stream, float volume,
+ virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, bool muted,
audio_io_handle_t output, int delayMs = 0) = 0;
/**
* Set volume for given AudioTrack port ids for a particular output.
@@ -522,12 +525,13 @@
* can have different volumes for each output (destination device) it is attached to.
* @param ports to consider
* @param volume to apply
+ * @param muted to apply
* @param output to consider
* @param delayMs to use
* @return NO_ERROR if successful
*/
virtual status_t setPortsVolume(const std::vector<audio_port_handle_t>& ports, float volume,
- audio_io_handle_t output, int delayMs = 0) = 0;
+ bool muted, audio_io_handle_t output, int delayMs = 0) = 0;
// function enabling to send proprietary informations directly from audio policy manager to
// audio hardware interface.
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index ee6af4c..d499222 100644
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -26,6 +26,27 @@
using StreamTypeVector = std::vector<audio_stream_type_t>;
+/**
+ * Legacy audio policy product strategies IDs. These strategies are supported by the default
+ * policy engine.
+ * IMPORTANT NOTE: the order of this enum is important as it determines the priority
+ * between active strategies for routing decisions: lower enum value => higher prioriy
+ */
+enum legacy_strategy {
+ STRATEGY_NONE = -1,
+ STRATEGY_PHONE,
+ STRATEGY_SONIFICATION,
+ STRATEGY_ENFORCED_AUDIBLE,
+ STRATEGY_ACCESSIBILITY,
+ STRATEGY_SONIFICATION_RESPECTFUL,
+ STRATEGY_MEDIA,
+ STRATEGY_DTMF,
+ STRATEGY_CALL_ASSISTANT,
+ STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
+ STRATEGY_REROUTING,
+ STRATEGY_PATCH,
+};
+
static const audio_attributes_t defaultAttr = AUDIO_ATTRIBUTES_INITIALIZER;
static const std::set<audio_usage_t > gHighPriorityUseCases = {
diff --git a/services/audiopolicy/common/managerdefinitions/Android.bp b/services/audiopolicy/common/managerdefinitions/Android.bp
index 4dedcd6..0e1d090 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.bp
+++ b/services/audiopolicy/common/managerdefinitions/Android.bp
@@ -39,6 +39,7 @@
"android.media.audiopolicy-aconfig-cc",
"audioclient-types-aidl-cpp",
"audiopolicy-types-aidl-cpp",
+ "com.android.media.audio-aconfig-cc",
"com.android.media.audioserver-aconfig-cc",
"libaconfig_storage_read_api_cc",
"libaudioclient_aidl_conversion",
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 3c296e7..9bceee7 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -89,7 +89,9 @@
class VolumeActivity : public ActivityTracking
{
public:
- bool isMuted() const { return mMuteCount > 0; }
+ bool isMutedInternally() const { return mMuteCount > 0; }
+ bool isMutedByGroup() const { return mMutedByGroup > 0; }
+ void setMutedByGroup(bool mutedByGroup) { mMutedByGroup = mutedByGroup; }
int getMuteCount() const { return mMuteCount; }
int incMuteCount() { return ++mMuteCount; }
int decMuteCount() { return mMuteCount > 0 ? --mMuteCount : -1; }
@@ -107,6 +109,7 @@
private:
int mMuteCount = 0; /**< mute request counter */
+ bool mMutedByGroup = false; /**< mute from AudioService, does not add to counter */
float mCurVolumeDb = NAN; /**< current volume in dB. */
bool mIsVoice = false; /** true if this volume source is used for voice call volume */
};
@@ -209,16 +212,25 @@
return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
mVolumeActivities.at(vs).getActivityCount() : 0;
}
- bool isMuted(VolumeSource vs) const
+ bool isMutedInternally(VolumeSource vs) const
{
return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
- mVolumeActivities.at(vs).isMuted() : false;
+ mVolumeActivities.at(vs).isMutedInternally() : false;
}
int getMuteCount(VolumeSource vs) const
{
return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
mVolumeActivities.at(vs).getMuteCount() : 0;
}
+ bool isMutedByGroup(VolumeSource vs)
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities)?
+ mVolumeActivities.at(vs).isMutedByGroup() : false;
+ }
+ bool hasVolumeSource(VolumeSource vs)
+ {
+ return mVolumeActivities.find(vs) != std::end(mVolumeActivities);
+ }
int incMuteCount(VolumeSource vs)
{
return mVolumeActivities[vs].incMuteCount();
@@ -227,10 +239,11 @@
{
return mVolumeActivities[vs].decMuteCount();
}
- void setCurVolume(VolumeSource vs, float volumeDb, bool isVoiceVolSrc)
+ void setCurVolume(VolumeSource vs, float volumeDb, bool mutedByGroup, bool isVoiceVolSrc)
{
// Even if not activity for this source registered, need to create anyway
mVolumeActivities[vs].setVolume(volumeDb);
+ mVolumeActivities[vs].setMutedByGroup(mutedByGroup);
mVolumeActivities[vs].setIsVoice(isVoiceVolSrc);
}
float getCurVolume(VolumeSource vs) const
@@ -412,7 +425,7 @@
const audio_config_base_t *mixerConfig,
const DeviceVector &devices,
audio_stream_type_t stream,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_io_handle_t *output,
audio_attributes_t attributes);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 1f6002f..b193cb8 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,10 +16,10 @@
#pragma once
+#include <optional>
#include <string>
#include <unordered_map>
#include <unordered_set>
-#include <vector>
#include <DeviceDescriptor.h>
#include <HwModule.h>
@@ -49,6 +49,7 @@
static const constexpr char* const kDefaultConfigSource = "AudioPolicyConfig::setDefault";
// The suffix of the "engine default" implementation shared library name.
static const constexpr char* const kDefaultEngineLibraryNameSuffix = "default";
+ static const constexpr char* const kCapEngineLibraryNameSuffix = "configurable";
// Creates the default (fallback) configuration.
static sp<const AudioPolicyConfig> createDefault();
@@ -140,6 +141,12 @@
void setDefault();
+ void setUseDeepBufferForMediaOverrideForTests(bool useDeepBufferForMedia)
+ {
+ mUseDeepBufferForMediaOverride = useDeepBufferForMedia;
+ }
+ bool useDeepBufferForMedia() const;
+
private:
friend class sp<AudioPolicyConfig>;
@@ -157,6 +164,7 @@
sp<DeviceDescriptor> mDefaultOutputDevice;
bool mIsCallScreenModeSupported = false;
SurroundFormats mSurroundFormats;
+ std::optional<bool> mUseDeepBufferForMediaOverride;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index d206637..26bb94f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -137,6 +137,7 @@
class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
+ sp<HwModule> getModuleFromHandle(audio_module_handle_t handle) const;
sp<HwModule> getModuleFromName(const char *name) const;
/**
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
index fd8b81a..ebfc597 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurves.h
@@ -41,6 +41,8 @@
virtual status_t initVolume(int indexMin, int indexMax) = 0;
virtual std::vector<audio_attributes_t> getAttributes() const = 0;
virtual std::vector<audio_stream_type_t> getStreamTypes() const = 0;
+ virtual void setIsMuted(bool isMuted) = 0;
+ virtual bool isMuted() const = 0;
virtual void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const = 0;
};
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 848051c..c417462 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -22,6 +22,7 @@
#include <AudioPolicyInterface.h>
#include "AudioOutputDescriptor.h"
#include "AudioPolicyMix.h"
+#include <com_android_media_audio.h>
#include "IOProfile.h"
#include "Volume.h"
#include "HwModule.h"
@@ -161,7 +162,7 @@
return false;
}
-bool AudioOutputDescriptor::setVolume(float volumeDb, bool /*muted*/,
+bool AudioOutputDescriptor::setVolume(float volumeDb, bool mutedByGroup,
VolumeSource volumeSource,
const StreamTypeVector &/*streams*/,
const DeviceTypeSet& deviceTypes,
@@ -169,7 +170,6 @@
bool force,
bool isVoiceVolSrc)
{
-
if (!supportedDevices().containsDeviceAmongTypes(deviceTypes)) {
ALOGV("%s output ID %d unsupported device %s",
__func__, getId(), toString(deviceTypes).c_str());
@@ -177,10 +177,14 @@
}
// We actually change the volume if:
// - the float value returned by computeVolume() changed
+ // - the muted state changed
// - the force flag is set
- if (volumeDb != getCurVolume(volumeSource) || force) {
- ALOGV("%s for volumeSrc %d, volume %f, delay %d", __func__, volumeSource, volumeDb, delayMs);
- setCurVolume(volumeSource, volumeDb, isVoiceVolSrc);
+ const bool mutedChanged =
+ com_android_media_audio_ring_my_car() && (isMutedByGroup(volumeSource) != mutedByGroup);
+ if (volumeDb != getCurVolume(volumeSource) || mutedChanged || force) {
+ ALOGV("%s for volumeSrc %d, volume %f, mutedByGroup %d, delay %d", __func__, volumeSource,
+ volumeDb, mutedByGroup, delayMs);
+ setCurVolume(volumeSource, volumeDb, mutedByGroup, isVoiceVolSrc);
return true;
}
return false;
@@ -497,7 +501,7 @@
}
void SwAudioOutputDescriptor::setSwMute(
- bool muted, VolumeSource vs, const StreamTypeVector &streamTypes,
+ bool mutedByGroup, VolumeSource vs, const StreamTypeVector &streamTypes,
const DeviceTypeSet& deviceTypes, uint32_t delayMs) {
// volume source active and more than one volume source is active, otherwise, no-op or let
// setVolume controlling SW and/or HW Gains
@@ -506,11 +510,11 @@
for (const auto& devicePort : devices()) {
if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
devicePort->hasGainController(true /*canUseForVolume*/)) {
- float volumeAmpl = muted ? 0.0f : Volume::DbToAmpl(0);
ALOGV("%s: output: %d, vs: %d, muted: %d, active vs count: %zu", __func__,
- mIoHandle, vs, muted, getActiveVolumeSources().size());
+ mIoHandle, vs, mutedByGroup, getActiveVolumeSources().size());
for (const auto &stream : streamTypes) {
- mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ mClientInterface->setStreamVolume(stream, Volume::DbToAmpl(0), mutedByGroup,
+ mIoHandle, delayMs);
}
return;
}
@@ -521,11 +525,12 @@
for (const auto &devicePort: devices()) {
if (isSingleDeviceType(deviceTypes, devicePort->type()) &&
devicePort->hasGainController(true /*canUseForVolume*/)) {
- float volumeAmpl = muted ? 0.0f : Volume::DbToAmpl(0);
+ float volumeAmpl = Volume::DbToAmpl(0);
ALOGV("%s: output: %d, vs: %d, muted: %d, active vs count: %zu", __func__,
- mIoHandle, vs, muted, getActiveVolumeSources().size());
+ mIoHandle, vs, mutedByGroup, getActiveVolumeSources().size());
mClientInterface->setPortsVolume(
- getPortsForVolumeSource(vs), volumeAmpl, mIoHandle, delayMs);
+ getPortsForVolumeSource(vs), Volume::DbToAmpl(0), mutedByGroup,
+ mIoHandle, delayMs);
return;
}
}
@@ -533,7 +538,7 @@
}
}
-bool SwAudioOutputDescriptor::setVolume(float volumeDb, bool muted,
+bool SwAudioOutputDescriptor::setVolume(float volumeDb, bool mutedByGroup,
VolumeSource vs, const StreamTypeVector &streamTypes,
const DeviceTypeSet& deviceTypes,
uint32_t delayMs,
@@ -542,18 +547,22 @@
{
StreamTypeVector streams = streamTypes;
if (!AudioOutputDescriptor::setVolume(
- volumeDb, muted, vs, streamTypes, deviceTypes, delayMs, force, isVoiceVolSrc)) {
+ volumeDb, mutedByGroup, vs, streamTypes, deviceTypes, delayMs, force, isVoiceVolSrc)) {
if (hasStream(streamTypes, AUDIO_STREAM_BLUETOOTH_SCO)) {
VolumeSource callVolSrc = getVoiceSource();
- if (callVolSrc != VOLUME_SOURCE_NONE && volumeDb != getCurVolume(callVolSrc)) {
- setCurVolume(callVolSrc, volumeDb, true);
+ const bool mutedChanged =
+ com_android_media_audio_ring_my_car() && hasVolumeSource(callVolSrc) &&
+ (isMutedByGroup(callVolSrc) != mutedByGroup);
+ if (callVolSrc != VOLUME_SOURCE_NONE &&
+ (volumeDb != getCurVolume(callVolSrc) || mutedChanged)) {
+ setCurVolume(callVolSrc, volumeDb, mutedByGroup, true);
float volumeAmpl = Volume::DbToAmpl(volumeDb);
if (audioserver_flags::portid_volume_management()) {
mClientInterface->setPortsVolume(getPortsForVolumeSource(callVolSrc),
- volumeAmpl, mIoHandle, delayMs);
+ volumeAmpl, mutedByGroup, mIoHandle, delayMs);
} else {
mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL,
- volumeAmpl, mIoHandle, delayMs);
+ volumeAmpl, mutedByGroup, mIoHandle, delayMs);
}
}
}
@@ -580,18 +589,19 @@
// Allows to mute SW Gain on AudioFlinger only for volume group with explicit
// stream(s)
if (!streamTypes.empty() || (getActiveVolumeSources().size() == 1)) {
- const bool canMute = muted && (volumeDb != 0.0f) && !streamTypes.empty();
- float volumeAmpl = canMute ? 0.0f : Volume::DbToAmpl(0);
+ const bool canMute = mutedByGroup && !streamTypes.empty();
+ const float volumeAmpl = Volume::DbToAmpl(0);
for (const auto &stream: streams) {
- mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ mClientInterface->setStreamVolume(stream, volumeAmpl, canMute, mIoHandle,
+ delayMs);
}
}
} else {
- float volumeAmpl = (muted && volumeDb != 0.0f) ? 0.0f : Volume::DbToAmpl(0);
+ float volumeAmpl = Volume::DbToAmpl(0);
ALOGV("%s: output: %d, vs: %d, active vs count: %zu", __func__,
mIoHandle, vs, getActiveVolumeSources().size());
mClientInterface->setPortsVolume(
- getPortsForVolumeSource(vs), volumeAmpl, mIoHandle, delayMs);
+ getPortsForVolumeSource(vs), volumeAmpl, mutedByGroup, mIoHandle, delayMs);
}
AudioGains gains = devicePort->getGains();
int gainMinValueInMb = gains[0]->getMinValueInMb();
@@ -615,26 +625,27 @@
if (audioserver_flags::portid_volume_management()) {
if (callVolSrc != VOLUME_SOURCE_NONE) {
mClientInterface->setPortsVolume(getPortsForVolumeSource(callVolSrc), volumeAmpl,
- mIoHandle, delayMs);
+ mutedByGroup, mIoHandle, delayMs);
}
} else {
- mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mIoHandle,
- delayMs);
+ mClientInterface->setStreamVolume(AUDIO_STREAM_VOICE_CALL, volumeAmpl, mutedByGroup,
+ mIoHandle, delayMs);
}
if (callVolSrc != VOLUME_SOURCE_NONE) {
- setCurVolume(callVolSrc, getCurVolume(vs), true);
+ setCurVolume(callVolSrc, getCurVolume(vs), mutedByGroup, true);
}
}
if (audioserver_flags::portid_volume_management()) {
- ALOGV("%s output %d for volumeSource %d, volume %f, delay %d active=%d", __func__,
- mIoHandle, vs, volumeDb, delayMs, isActive(vs));
- mClientInterface->setPortsVolume(getPortsForVolumeSource(vs), volumeAmpl, mIoHandle,
- delayMs);
+ ALOGV("%s output %d for volumeSource %d, volume %f, mutedByGroup %d, delay %d active=%d",
+ __func__, mIoHandle, vs, volumeDb, mutedByGroup, delayMs, isActive(vs));
+ mClientInterface->setPortsVolume(getPortsForVolumeSource(vs), volumeAmpl, mutedByGroup,
+ mIoHandle, delayMs);
} else {
for (const auto &stream : streams) {
- ALOGV("%s output %d for volumeSource %d, volume %f, delay %d stream=%s", __func__,
- mIoHandle, vs, volumeDb, delayMs, toString(stream).c_str());
- mClientInterface->setStreamVolume(stream, volumeAmpl, mIoHandle, delayMs);
+ ALOGV("%s output %d for volumeSource %d, volume %f, mutedByGroup %d delay %d stream=%s",
+ __func__, mIoHandle, vs, volumeDb, mutedByGroup, delayMs,
+ toString(stream).c_str());
+ mClientInterface->setStreamVolume(stream, volumeAmpl, mutedByGroup, mIoHandle, delayMs);
}
}
return true;
@@ -656,7 +667,7 @@
const audio_config_base_t *mixerConfig,
const DeviceVector &devices,
audio_stream_type_t stream,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_io_handle_t *output,
audio_attributes_t attributes)
{
@@ -686,7 +697,7 @@
// create a default one
if ((mProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
lHalConfig.offload_info.format == AUDIO_FORMAT_DEFAULT) {
- flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
+ *flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
lHalConfig.offload_info = AUDIO_INFO_INITIALIZER;
lHalConfig.offload_info.sample_rate = lHalConfig.sample_rate;
lHalConfig.offload_info.channel_mask = lHalConfig.channel_mask;
@@ -704,7 +715,7 @@
lMixerConfig = *mixerConfig;
}
- mFlags = (audio_output_flags_t)(mFlags | flags);
+ mFlags = (audio_output_flags_t)(mFlags | *flags);
// If no mixer config is specified for a spatializer output, default to 5.1 for proper
// configuration of the final downmixer or spatializer
@@ -722,8 +733,9 @@
&lMixerConfig,
device,
&mLatency,
- mFlags,
+ &mFlags,
attributes);
+ *flags = mFlags;
if (status == NO_ERROR) {
LOG_ALWAYS_FATAL_IF(*output == AUDIO_IO_HANDLE_NONE,
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
index 4edd11f..723887d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "APM_Config"
+#include <android-base/properties.h>
#include <AudioPolicyConfig.h>
#include <IOProfile.h>
#include <Serializer.h>
@@ -269,6 +270,9 @@
mSurroundFormats = VALUE_OR_RETURN_STATUS(
aidl2legacy_SurroundSoundConfig_SurroundFormats(aidl.surroundSoundConfig));
mSource = kAidlConfigSource;
+ if (aidl.engineConfig.capSpecificConfig.has_value()) {
+ setEngineLibraryNameSuffix(kCapEngineLibraryNameSuffix);
+ }
// No need to augmentData() as AIDL HAL must provide correct mic addresses.
return NO_ERROR;
}
@@ -338,7 +342,13 @@
AUDIO_FORMAT_AAC_XHE}},
{AUDIO_FORMAT_DOLBY_TRUEHD, {}},
{AUDIO_FORMAT_E_AC3_JOC, {}},
- {AUDIO_FORMAT_AC4, {}}};
+ {AUDIO_FORMAT_AC4, {}}, // L0-3
+ {AUDIO_FORMAT_AC4_L4, {}}};
+}
+
+bool AudioPolicyConfig::useDeepBufferForMedia() const {
+ if (mUseDeepBufferForMediaOverride.has_value()) return *mUseDeepBufferForMediaOverride;
+ return property_get_bool("audio.deep_buffer.media", false /* default_value */);
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 6696b45..2d8231a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -283,6 +283,16 @@
dumpAudioRouteVector(mRoutes, dst, spaces);
}
+sp<HwModule> HwModuleCollection::getModuleFromHandle(audio_module_handle_t handle) const
+{
+ for (const auto& module : *this) {
+ if (module->getHandle() == handle) {
+ return module;
+ }
+ }
+ return nullptr;
+}
+
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
{
for (const auto& module : *this) {
diff --git a/services/audiopolicy/config/surround_sound_configuration_5_0.xml b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
index 590a181..6a268d8 100644
--- a/services/audiopolicy/config/surround_sound_configuration_5_0.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_5_0.xml
@@ -27,5 +27,6 @@
<format name="AUDIO_FORMAT_DTS_HD" />
<format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
<format name="AUDIO_FORMAT_AC4" />
+ <format name="AUDIO_FORMAT_AC4_L4" />
</formats>
</surroundSound>
diff --git a/services/audiopolicy/config/surround_sound_configuration_aidl.xml b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
index cf15711..51ccaa9 100644
--- a/services/audiopolicy/config/surround_sound_configuration_aidl.xml
+++ b/services/audiopolicy/config/surround_sound_configuration_aidl.xml
@@ -30,5 +30,6 @@
<format name="AUDIO_FORMAT_DTS_UHD_P2" />
<format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
<format name="AUDIO_FORMAT_AC4" />
+ <format name="AUDIO_FORMAT_AC4_L4" />
</formats>
</surroundSound>
diff --git a/services/audiopolicy/engine/common/Android.bp b/services/audiopolicy/engine/common/Android.bp
index d8aac37..7daa064 100644
--- a/services/audiopolicy/engine/common/Android.bp
+++ b/services/audiopolicy/engine/common/Android.bp
@@ -64,5 +64,6 @@
],
defaults: [
"aconfig_lib_cc_static_link.defaults",
+ "latest_android_media_audio_common_types_cpp_static",
],
}
diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h
index b9c94a4..edb2e29 100644
--- a/services/audiopolicy/engine/common/include/EngineBase.h
+++ b/services/audiopolicy/engine/common/include/EngineBase.h
@@ -129,6 +129,8 @@
product_strategy_t getProductStrategyByName(const std::string &name) const;
+ std::string getProductStrategyName(product_strategy_t id) const;
+
AudioPolicyManagerObserver *getApmObserver() const { return mApmObserver; }
inline bool isInCall() const
diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h
index 1593be0..9b1125d 100644
--- a/services/audiopolicy/engine/common/include/ProductStrategy.h
+++ b/services/audiopolicy/engine/common/include/ProductStrategy.h
@@ -46,7 +46,7 @@
using VolumeGroupAttributesVector = std::vector<VolumeGroupAttributes>;
public:
- ProductStrategy(const std::string &name);
+ ProductStrategy(const std::string &name, int id = PRODUCT_STRATEGY_NONE);
void addAttributes(const VolumeGroupAttributes &volumeGroupAttributes);
@@ -92,6 +92,10 @@
bool isDefault() const;
+ bool isPatchStrategy() const {
+ return getVolumeGroupForStreamType(AUDIO_STREAM_PATCH) != VOLUME_GROUP_NONE;
+ }
+
void dump(String8 *dst, int spaces = 0) const;
private:
diff --git a/services/audiopolicy/engine/common/include/VolumeCurve.h b/services/audiopolicy/engine/common/include/VolumeCurve.h
index 2e75ff1..e5f7a41 100644
--- a/services/audiopolicy/engine/common/include/VolumeCurve.h
+++ b/services/audiopolicy/engine/common/include/VolumeCurve.h
@@ -179,6 +179,12 @@
}
StreamTypeVector getStreamTypes() const override { return mStreams; }
+ void setIsMuted(bool isMuted)
+ {
+ mIsMuted = isMuted;
+ }
+ bool isMuted() const { return mIsMuted; }
+
void dump(String8 *dst, int spaces = 0, bool curvePoints = false) const override;
private:
@@ -187,6 +193,7 @@
int mIndexMin; /**< min volume index. */
int mIndexMax; /**< max volume index. */
const bool mCanBeMuted = true; /**< true is the stream can be muted. */
+ bool mIsMuted = false; /**< true if the stream is currently muted. */
AttributesVector mAttributes;
StreamTypeVector mStreams; /**< Keep it for legacy. */
diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp
index e259e6e..fb8379e 100644
--- a/services/audiopolicy/engine/common/src/EngineBase.cpp
+++ b/services/audiopolicy/engine/common/src/EngineBase.cpp
@@ -116,6 +116,15 @@
return PRODUCT_STRATEGY_NONE;
}
+std::string EngineBase::getProductStrategyName(product_strategy_t id) const {
+ for (const auto &iter : mProductStrategies) {
+ if (iter.second->getId() == id) {
+ return iter.second->getName();
+ }
+ }
+ return "";
+}
+
engineConfig::ParsingResult EngineBase::loadAudioPolicyEngineConfig(
const media::audio::common::AudioHalEngineConfig& aidlConfig)
{
@@ -240,7 +249,7 @@
loadVolumeConfig(mVolumeGroups, volumeConfig);
}
for (auto& strategyConfig : result.parsedConfig->productStrategies) {
- sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name);
+ sp<ProductStrategy> strategy = new ProductStrategy(strategyConfig.name, strategyConfig.id);
for (const auto &group : strategyConfig.attributesGroups) {
const auto &iter = std::find_if(begin(mVolumeGroups), end(mVolumeGroups),
[&group](const auto &volumeGroup) {
@@ -302,6 +311,9 @@
}
StrategyVector orderedStrategies;
for (const auto &iter : strategies) {
+ if (iter.second->isPatchStrategy()) {
+ continue;
+ }
orderedStrategies.push_back(iter.second->getId());
}
return orderedStrategies;
@@ -733,6 +745,9 @@
auto defaultDevices = DeviceVector(getApmObserver()->getDefaultOutputDevice());
for (const auto &iter : getProductStrategies()) {
const auto &strategy = iter.second;
+ if (strategy->isPatchStrategy()) {
+ continue;
+ }
mDevicesForStrategies[strategy->getId()] = defaultDevices;
setStrategyDevices(strategy, defaultDevices);
}
@@ -741,6 +756,9 @@
void EngineBase::updateDeviceSelectionCache() {
for (const auto &iter : getProductStrategies()) {
const auto& strategy = iter.second;
+ if (strategy->isPatchStrategy()) {
+ continue;
+ }
auto devices = getDevicesForProductStrategy(strategy->getId());
mDevicesForStrategies[strategy->getId()] = devices;
setStrategyDevices(strategy, devices);
diff --git a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
index 548a20d..c4bf64a 100644
--- a/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
+++ b/services/audiopolicy/engine/common/src/EngineDefaultConfig.h
@@ -18,14 +18,17 @@
#include <EngineConfig.h>
+#include <media/AudioProductStrategy.h>
+#include <policy.h>
#include <system/audio.h>
namespace android {
+
/**
* @brief AudioProductStrategies hard coded array of strategies to fill new engine API contract.
*/
const engineConfig::ProductStrategies gOrderedStrategies = {
- {"STRATEGY_PHONE",
+ {"STRATEGY_PHONE", STRATEGY_PHONE,
{
{AUDIO_STREAM_VOICE_CALL, "AUDIO_STREAM_VOICE_CALL",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VOICE_COMMUNICATION, AUDIO_SOURCE_DEFAULT,
@@ -37,7 +40,7 @@
}
},
},
- {"STRATEGY_SONIFICATION",
+ {"STRATEGY_SONIFICATION", STRATEGY_SONIFICATION,
{
{AUDIO_STREAM_RING, "AUDIO_STREAM_RING",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
@@ -49,7 +52,7 @@
}
},
},
- {"STRATEGY_ENFORCED_AUDIBLE",
+ {"STRATEGY_ENFORCED_AUDIBLE", STRATEGY_ENFORCED_AUDIBLE,
{
{AUDIO_STREAM_ENFORCED_AUDIBLE, "AUDIO_STREAM_ENFORCED_AUDIBLE",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
@@ -57,7 +60,7 @@
}
},
},
- {"STRATEGY_ACCESSIBILITY",
+ {"STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY,
{
{AUDIO_STREAM_ACCESSIBILITY, "AUDIO_STREAM_ACCESSIBILITY",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
@@ -65,7 +68,7 @@
}
},
},
- {"STRATEGY_SONIFICATION_RESPECTFUL",
+ {"STRATEGY_SONIFICATION_RESPECTFUL", STRATEGY_SONIFICATION_RESPECTFUL,
{
{AUDIO_STREAM_NOTIFICATION, "AUDIO_STREAM_NOTIFICATION",
{
@@ -77,7 +80,7 @@
}
},
},
- {"STRATEGY_MEDIA",
+ {"STRATEGY_MEDIA", STRATEGY_MEDIA,
{
{AUDIO_STREAM_ASSISTANT, "AUDIO_STREAM_ASSISTANT",
{{AUDIO_CONTENT_TYPE_SPEECH, AUDIO_USAGE_ASSISTANT,
@@ -103,7 +106,7 @@
}
},
},
- {"STRATEGY_DTMF",
+ {"STRATEGY_DTMF", STRATEGY_DTMF,
{
{AUDIO_STREAM_DTMF, "AUDIO_STREAM_DTMF",
{
@@ -113,7 +116,7 @@
}
},
},
- {"STRATEGY_CALL_ASSISTANT",
+ {"STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT,
{
{AUDIO_STREAM_CALL_ASSISTANT, "AUDIO_STREAM_CALL_ASSISTANT",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_CALL_ASSISTANT, AUDIO_SOURCE_DEFAULT,
@@ -121,7 +124,7 @@
}
},
},
- {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER",
+ {"STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
{
{AUDIO_STREAM_TTS, "AUDIO_STREAM_TTS",
{
@@ -140,7 +143,7 @@
* For compatibility reason why apm volume config file, volume group name is the stream type.
*/
const engineConfig::ProductStrategies gOrderedSystemStrategies = {
- {"STRATEGY_REROUTING",
+ {"STRATEGY_REROUTING", STRATEGY_REROUTING,
{
{AUDIO_STREAM_REROUTING, "AUDIO_STREAM_REROUTING",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_VIRTUAL_SOURCE, AUDIO_SOURCE_DEFAULT,
@@ -148,7 +151,7 @@
}
},
},
- {"STRATEGY_PATCH",
+ {"STRATEGY_PATCH", STRATEGY_PATCH,
{
{AUDIO_STREAM_PATCH, "AUDIO_STREAM_PATCH",
{{AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_USAGE_UNKNOWN, AUDIO_SOURCE_DEFAULT,
diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
index 0d25955..8ed7403 100644
--- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp
+++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp
@@ -19,6 +19,7 @@
#include "ProductStrategy.h"
+#include <android/media/audio/common/AudioHalProductStrategy.h>
#include <media/AudioProductStrategy.h>
#include <media/TypeConverter.h>
#include <utils/String8.h>
@@ -30,11 +31,20 @@
namespace android {
-ProductStrategy::ProductStrategy(const std::string &name) :
+using media::audio::common::AudioHalProductStrategy;
+
+/*
+ * Note on the id: either is provided (legacy strategies have hard coded id, aidl have
+ * own id, enforced to be started from VENDOR_STRATEGY_ID_START.
+ * REROUTING & PATCH system strategies are added.
+ * To prevent from collision, generate from VENDOR_STRATEGY_ID_START when id is not provided.
+ */
+ProductStrategy::ProductStrategy(const std::string &name, int id) :
mName(name),
- mId(static_cast<product_strategy_t>(HandleGenerator<uint32_t>::getNextHandle()))
-{
-}
+ mId((static_cast<product_strategy_t>(id) != PRODUCT_STRATEGY_NONE) ?
+ static_cast<product_strategy_t>(id) :
+ static_cast<product_strategy_t>(AudioHalProductStrategy::VENDOR_STRATEGY_ID_START +
+ HandleGenerator<uint32_t>::getNextHandle())) {}
void ProductStrategy::addAttributes(const VolumeGroupAttributes &volumeGroupAttributes)
{
diff --git a/services/audiopolicy/engine/config/Android.bp b/services/audiopolicy/engine/config/Android.bp
index ab2c134..d771605 100644
--- a/services/audiopolicy/engine/config/Android.bp
+++ b/services/audiopolicy/engine/config/Android.bp
@@ -10,6 +10,9 @@
cc_library {
name: "libaudiopolicyengine_config",
+ defaults: [
+ "latest_android_media_audio_common_types_cpp_shared",
+ ],
export_include_dirs: ["include"],
include_dirs: [
"external/libxml2/include",
diff --git a/services/audiopolicy/engine/config/include/EngineConfig.h b/services/audiopolicy/engine/config/include/EngineConfig.h
index 119dbd6..054bdae 100644
--- a/services/audiopolicy/engine/config/include/EngineConfig.h
+++ b/services/audiopolicy/engine/config/include/EngineConfig.h
@@ -71,6 +71,7 @@
struct ProductStrategy {
std::string name;
+ int id;
AttributesGroups attributesGroups;
};
diff --git a/services/audiopolicy/engine/config/src/EngineConfig.cpp b/services/audiopolicy/engine/config/src/EngineConfig.cpp
index 3f9ae19..714ab78 100644
--- a/services/audiopolicy/engine/config/src/EngineConfig.cpp
+++ b/services/audiopolicy/engine/config/src/EngineConfig.cpp
@@ -20,7 +20,6 @@
#include <sstream>
#include <stdarg.h>
#include <string>
-#include <string>
#include <vector>
#include <unordered_map>
@@ -42,6 +41,7 @@
namespace android {
+using media::audio::common::AudioStreamType;
using utilities::convertTo;
namespace engineConfig {
@@ -66,6 +66,9 @@
STRATEGY_ENTRY(ACCESSIBILITY)};
#undef STRATEGY_ENTRY
+ if (id >= media::audio::common::AudioHalProductStrategy::VENDOR_STRATEGY_ID_START) {
+ return std::to_string(id);
+ }
auto it = productStrategyMap.find(id);
if (it == productStrategyMap.end()) {
return base::unexpected(BAD_VALUE);
@@ -76,8 +79,12 @@
ConversionResult<AttributesGroup> aidl2legacy_AudioHalAttributeGroup_AttributesGroup(
const media::audio::common::AudioHalAttributesGroup& aidl) {
AttributesGroup legacy;
- legacy.stream = VALUE_OR_RETURN(
- aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
+ // StreamType may only be set to AudioStreamType.INVALID when using the
+ // Configurable Audio Policy (CAP) engine. An AudioHalAttributesGroup with
+ // AudioStreamType.INVALID is used when the volume group and attributes are
+ // not associated to any AudioStreamType.
+ legacy.stream = ((aidl.streamType == AudioStreamType::INVALID) ? AUDIO_STREAM_DEFAULT :
+ VALUE_OR_RETURN(aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType)));
legacy.volumeGroup = aidl.volumeGroupName;
legacy.attributesVect = VALUE_OR_RETURN(convertContainer<AttributesVector>(
aidl.attributes, aidl2legacy_AudioAttributes_audio_attributes_t));
@@ -87,8 +94,9 @@
ConversionResult<ProductStrategy> aidl2legacy_AudioHalProductStrategy_ProductStrategy(
const media::audio::common::AudioHalProductStrategy& aidl) {
ProductStrategy legacy;
- legacy.name = VALUE_OR_RETURN(
- aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id));
+ legacy.name = aidl.name.value_or(VALUE_OR_RETURN(
+ aidl2legacy_AudioHalProductStrategy_ProductStrategyType(aidl.id)));
+ legacy.id = aidl.id;
legacy.attributesGroups = VALUE_OR_RETURN(convertContainer<AttributesGroups>(
aidl.attributesGroups,
aidl2legacy_AudioHalAttributeGroup_AttributesGroup));
@@ -148,7 +156,6 @@
aidl.volumeCurves, aidl2legacy_AudioHalVolumeCurve_VolumeCurve));
return legacy;
}
-
} // namespace
template<typename E, typename C>
@@ -175,6 +182,7 @@
struct Attributes {
static constexpr const char *name = "name";
+ static constexpr const char *id = "id";
};
static android::status_t deserialize(_xmlDoc *doc, const _xmlNode *root, Collection &ps);
};
@@ -533,13 +541,21 @@
ALOGE("ProductStrategyTraits No attribute %s found", Attributes::name);
return BAD_VALUE;
}
+ int id = PRODUCT_STRATEGY_NONE;
+ std::string idLiteral = getXmlAttribute(child, Attributes::id);
+ if (!idLiteral.empty()) {
+ if (!convertTo(idLiteral, id)) {
+ return BAD_VALUE;
+ }
+ ALOGV("%s: %s, %s = %d", __FUNCTION__, name.c_str(), Attributes::id, id);
+ }
ALOGV("%s: %s = %s", __FUNCTION__, Attributes::name, name.c_str());
size_t skipped = 0;
AttributesGroups attrGroups;
deserializeCollection<AttributesGroupTraits>(doc, child, attrGroups, skipped);
- strategies.push_back({name, attrGroups});
+ strategies.push_back({name, id, attrGroups});
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/Android.bp b/services/audiopolicy/engineconfigurable/Android.bp
index a0a4bdf..1c98faf 100644
--- a/services/audiopolicy/engineconfigurable/Android.bp
+++ b/services/audiopolicy/engineconfigurable/Android.bp
@@ -36,10 +36,10 @@
"libbase_headers",
],
static_libs: [
+ "libaudiopolicycapengine_config",
"libaudiopolicyengine_common",
"libaudiopolicyengine_config",
"libaudiopolicyengineconfigurable_pfwwrapper",
-
],
shared_libs: [
"libaudio_aidl_conversion_common_cpp",
@@ -56,5 +56,13 @@
],
defaults: [
"aconfig_lib_cc_static_link.defaults",
+ "latest_android_media_audio_common_types_cpp_shared",
+ ],
+ required: [
+ "CapClass.xml",
+ "CapProductStrategies.xml",
+ "CapSubsystem-CommonTypes.xml",
+ "CapSubsystem.xml",
+ "ParameterFrameworkConfigurationCap.xml",
],
}
diff --git a/services/audiopolicy/engineconfigurable/config/Android.bp b/services/audiopolicy/engineconfigurable/config/Android.bp
index 8dd13e8..95a7cf8 100644
--- a/services/audiopolicy/engineconfigurable/config/Android.bp
+++ b/services/audiopolicy/engineconfigurable/config/Android.bp
@@ -38,6 +38,53 @@
}
filegroup {
+ name: "audio_policy_engine_aidl_criterion_types_template",
+ srcs: ["example/common/audio_policy_engine_criterion_types_aidl.xml.in"],
+}
+
+filegroup {
name: "audio_policy_engine_criteria",
srcs: ["example/common/audio_policy_engine_criteria.xml"],
}
+
+cc_library_headers {
+ name: "libaudiopolicycapengine_config_headers",
+ export_include_dirs: ["include"],
+}
+
+cc_library {
+ name: "libaudiopolicycapengine_config",
+ defaults: [
+ "latest_android_media_audio_common_types_cpp_shared",
+ ],
+ export_header_lib_headers: [
+ "libaudiopolicycapengine_config_headers",
+ ],
+ include_dirs: [
+ "external/libxml2/include",
+ ],
+ srcs: [
+ "src/CapEngineConfig.cpp",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+ shared_libs: [
+ "libaudio_aidl_conversion_common_cpp",
+ "libaudiopolicycomponents",
+ "libaudiopolicyengine_config",
+ "libcutils",
+ "liblog",
+ "libmedia_helper",
+ "libutils",
+ "libxml2",
+ ],
+ header_libs: [
+ "libaudio_system_headers",
+ "libaudioclient_headers",
+ "libaudiopolicycapengine_config_headers",
+ "libmedia_headers",
+ ],
+}
diff --git a/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
new file mode 100644
index 0000000..dc2517b
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/example/common/audio_policy_engine_criterion_types_aidl.xml.in
@@ -0,0 +1,96 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<criterion_types>
+ <criterion_type name="OutputDevicesMaskType" type="inclusive"/>
+ <criterion_type name="InputDevicesMaskType" type="inclusive"/>
+ <criterion_type name="OutputDevicesAddressesType" type="inclusive">
+ <values>
+ <!-- legacy remote submix -->
+ <value literal="0" numerical="1"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="InputDevicesAddressesType" type="inclusive">
+ <values>
+ <!-- legacy remote submix -->
+ <value literal="0" numerical="1"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="AndroidModeType" type="exclusive"/>
+ <criterion_type name="ForceUseForCommunicationType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="SPEAKER" numerical="1"/>
+ <value literal="BT_SCO" numerical="3"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForMediaType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="SPEAKER" numerical="1"/>
+ <value literal="HEADPHONES" numerical="2"/>
+ <value literal="BT_A2DP" numerical="4"/>
+ <value literal="WIRED_ACCESSORY" numerical="5"/>
+ <value literal="ANALOG_DOCK" numerical="8"/>
+ <value literal="DIGITAL_DOCK" numerical="9"/>
+ <value literal="NO_BT_A2DP" numerical="10"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForRecordType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="BT_SCO" numerical="3"/>
+ <value literal="WIRED_ACCESSORY" numerical="5"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForDockType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="WIRED_ACCESSORY" numerical="5"/>
+ <value literal="BT_CAR_DOCK" numerical="6"/>
+ <value literal="BT_DESK_DOCK" numerical="7"/>
+ <value literal="ANALOG_DOCK" numerical="8"/>
+ <value literal="DIGITAL_DOCK" numerical="9"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForSystemType" type="exclusive" >
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="SYSTEM_ENFORCED" numerical="11"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForHdmiSystemAudioType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="HDMI_SYSTEM_AUDIO_ENFORCED" numerical="12"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForEncodedSurroundType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="ENCODED_SURROUND_NEVER" numerical="13"/>
+ <value literal="ENCODED_SURROUND_ALWAYS" numerical="14"/>
+ <value literal="ENCODED_SURROUND_MANUAL" numerical="15"/>
+ </values>
+ </criterion_type>
+ <criterion_type name="ForceUseForVibrateRingingType" type="exclusive">
+ <values>
+ <value literal="NONE" numerical="0"/>
+ <value literal="BT_SCO" numerical="3"/>
+ </values>
+ </criterion_type>
+</criterion_types>
+
+
diff --git a/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h b/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h
new file mode 100644
index 0000000..6c55a49
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/include/CapEngineConfig.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <EngineConfig.h>
+
+#include <android/media/audio/common/AudioHalEngineConfig.h>
+#include <system/audio_policy.h>
+#include <string>
+#include <vector>
+
+namespace android {
+namespace capEngineConfig {
+
+static const char *const gCriterionTypeSuffix = "Type";
+static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
+static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
+static const char *const gPhoneStateCriterionName = "TelephonyMode";
+static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
+static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
+
+/**
+* Order MUST be aligned with definition of audio_policy_force_use_t within audio_policy.h
+*/
+static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
+{
+ [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] = "ForceUseForCommunication",
+ [AUDIO_POLICY_FORCE_FOR_MEDIA] = "ForceUseForMedia",
+ [AUDIO_POLICY_FORCE_FOR_RECORD] = "ForceUseForRecord",
+ [AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
+ [AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
+ [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
+ [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
+ [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
+};
+
+using ParameterValues = std::vector<std::string>;
+
+struct ConfigurableElement {
+ std::string path;
+};
+
+struct ConfigurableElementValue {
+ ConfigurableElement configurableElement;
+ std::string value;
+};
+using ConfigurableElementValues = std::vector<ConfigurableElementValue>;
+
+struct CapSetting {
+ std::string configurationName;
+ ConfigurableElementValues configurableElementValues;
+};
+using CapSettings = std::vector<CapSetting>;
+
+struct CapConfiguration {
+ std::string name;
+ std::string rule;
+};
+
+using ConfigurableElementPaths = std::vector<std::string>;
+using CapConfigurations = std::vector<CapConfiguration>;
+
+struct CapConfigurableDomain {
+ std::string name;
+ CapConfigurations configurations;
+ CapSettings settings;
+};
+
+struct CapCriterion {
+ engineConfig::Criterion criterion;
+ engineConfig::CriterionType criterionType;
+};
+
+using CapCriteria = std::vector<CapCriterion>;
+using CapConfigurableDomains = std::vector<CapConfigurableDomain>;
+
+struct CapConfig {
+ CapCriteria capCriteria;
+ CapConfigurableDomains capConfigurableDomains;
+};
+
+/** Result of `parse(const char*)` */
+struct ParsingResult {
+ /** Parsed config, nullptr if the xml lib could not load the file */
+ std::unique_ptr<CapConfig> parsedConfig;
+ size_t nbSkippedElement; //< Number of skipped invalid product strategies
+};
+
+/** Convert the provided Cap Settings configuration.
+ * @return audio policy usage @see Config
+ */
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig);
+
+}
+}
diff --git a/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
new file mode 100644
index 0000000..a1b4470
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/config/src/CapEngineConfig.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cinttypes>
+#include <cstdint>
+#include <istream>
+#include <map>
+#include <sstream>
+#include <stdarg.h>
+#include <string>
+#include <string>
+#include <vector>
+
+#define LOG_TAG "APM::AudioPolicyEngine/CapConfig"
+//#define LOG_NDEBUG 0
+
+#include "CapEngineConfig.h"
+#include <TypeConverter.h>
+#include <Volume.h>
+#include <cutils/properties.h>
+#include <media/AidlConversion.h>
+#include <media/AidlConversionCppNdk.h>
+#include <media/AidlConversionUtil.h>
+#include <media/TypeConverter.h>
+#include <media/convert.h>
+#include <system/audio_config.h>
+#include <utils/Log.h>
+
+namespace android {
+
+using utilities::convertTo;
+using media::audio::common::AudioDeviceAddress;
+using media::audio::common::AudioDeviceDescription;
+using media::audio::common::AudioHalCapCriterion;
+using media::audio::common::AudioHalCapParameter;
+using media::audio::common::AudioHalCapRule;
+using media::audio::common::AudioSource;
+using media::audio::common::AudioStreamType;
+using media::audio::common::AudioHalCapCriterionV2;
+using ::android::base::unexpected;
+
+namespace capEngineConfig {
+
+static constexpr const char *gLegacyOutputDevicePrefix = "AUDIO_DEVICE_OUT_";
+static constexpr const char *gLegacyInputDevicePrefix = "AUDIO_DEVICE_IN_";
+static constexpr const char *gLegacyStreamPrefix = "AUDIO_STREAM_";
+static constexpr const char *gLegacySourcePrefix = "AUDIO_SOURCE_";
+static constexpr const char *gPolicyParamPrefix = "/Policy/policy/";
+
+namespace {
+
+ConversionResult<std::string> truncatePrefixToLower(const std::string& legacyName,
+ const std::string& legacyPrefix) {
+ std::size_t pos = legacyName.find(legacyPrefix);
+ if (pos == std::string::npos) {
+ return unexpected(BAD_VALUE);
+ }
+ std::string capName = legacyName.substr(pos + legacyPrefix.length());
+ std::transform(capName.begin(), capName.end(), capName.begin(),
+ [](unsigned char c) { return std::tolower(c); });
+ return capName;
+}
+
+ConversionResult<std::string> truncatePrefix(const std::string& name, const std::string& prefix) {
+ std::size_t pos = name.find(prefix);
+ if (pos == std::string::npos) {
+ return unexpected(BAD_VALUE);
+ }
+ std::string capName = name.substr(pos + prefix.length());
+ return capName;
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2_CapName(
+ const AudioHalCapCriterionV2& aidl) {
+ switch (aidl.getTag()) {
+ case AudioHalCapCriterionV2::availableInputDevices:
+ return gInputDeviceCriterionName;
+ case AudioHalCapCriterionV2::availableOutputDevices:
+ return gOutputDeviceCriterionName;
+ case AudioHalCapCriterionV2::availableInputDevicesAddresses:
+ return gInputDeviceAddressCriterionName;
+ case AudioHalCapCriterionV2::availableOutputDevicesAddresses:
+ return gOutputDeviceAddressCriterionName;
+ case AudioHalCapCriterionV2::telephonyMode:
+ return gPhoneStateCriterionName;
+ case AudioHalCapCriterionV2::forceConfigForUse: {
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
+ return gForceUseCriterionTag[VALUE_OR_RETURN(
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+ aidlCriterion.forceUse))];
+ }
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
+ const AudioDeviceDescription& aidl) {
+ audio_devices_t legacyDeviceType = VALUE_OR_RETURN(
+ aidl2legacy_AudioDeviceDescription_audio_devices_t(aidl));
+ bool isOut = audio_is_output_devices(legacyDeviceType);
+ std::string legacyTypeLiteral;
+ if (!::android::DeviceConverter::toString(legacyDeviceType, legacyTypeLiteral)) {
+ ALOGE("%s Invalid strategy device type %d", __func__, legacyDeviceType);
+ return unexpected(BAD_VALUE);
+ }
+ return truncatePrefix(legacyTypeLiteral,
+ isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix);
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
+ const AudioHalCapCriterionV2::Type& aidl) {
+ switch (aidl.getTag()) {
+ case AudioHalCapCriterionV2::Type::availableDevicesType:
+ return aidl2legacy_AudioHalCapCriterionV2TypeDevice_CapCriterionValue(
+ aidl.get<AudioHalCapCriterionV2::Type::availableDevicesType>());
+ case AudioHalCapCriterionV2::Type::availableDevicesAddressesType:
+ return aidl.get<AudioHalCapCriterionV2::Type::availableDevicesAddressesType>().template
+ get<AudioDeviceAddress::id>();
+ case AudioHalCapCriterionV2::Type::telephonyModeType:
+ return toString(aidl.get<AudioHalCapCriterionV2::Type::telephonyModeType>());
+ case AudioHalCapCriterionV2::Type::forcedConfigType:
+ return toString(aidl.get<AudioHalCapCriterionV2::Type::forcedConfigType>());
+ default:
+ return unexpected(BAD_VALUE);
+ }
+}
+
+ConversionResult<std::string> aidl2legacy_AudioHalCapRule_CapRule(
+ const AudioHalCapRule& aidlRule) {
+ std::string rule;
+ switch (aidlRule.compoundRule) {
+ case AudioHalCapRule::CompoundRule::ANY:
+ rule += "Any";
+ break;
+ case AudioHalCapRule::CompoundRule::ALL:
+ rule += "All";
+ break;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+ rule += "{";
+ if (!aidlRule.nestedRules.empty()) {
+ for (const auto& nestedRule: aidlRule.nestedRules) {
+ rule += VALUE_OR_FATAL(aidl2legacy_AudioHalCapRule_CapRule(nestedRule));
+ }
+ if (!aidlRule.criterionRules.empty()) {
+ rule += ",";
+ }
+ }
+ bool isFirstCriterionRule = true;
+ for (const auto& criterionRule: aidlRule.criterionRules) {
+ if (!isFirstCriterionRule) {
+ rule += ",";
+ }
+ isFirstCriterionRule = false;
+ std::string selectionCriterion = VALUE_OR_RETURN(
+ aidl2legacy_AudioHalCapCriterionV2_CapName(criterionRule.criterion));
+ std::string matchesWhen;
+ std::string value = VALUE_OR_RETURN(
+ aidl2legacy_AudioHalCapCriterionV2Type_CapCriterionValue(
+ criterionRule.criterionTypeValue));
+
+ switch (criterionRule.matchingRule) {
+ case AudioHalCapRule::MatchingRule::IS:
+ matchesWhen = "Is";
+ break;
+ case AudioHalCapRule::MatchingRule::IS_NOT:
+ matchesWhen = "IsNot";
+ break;
+ case AudioHalCapRule::MatchingRule::INCLUDES:
+ matchesWhen = "Includes";
+ break;
+ case AudioHalCapRule::MatchingRule::EXCLUDES:
+ matchesWhen = "Excludes";
+ break;
+ default:
+ return unexpected(BAD_VALUE);
+ }
+ rule += selectionCriterion + " " + matchesWhen + " " + value;
+ }
+ rule += "}";
+ return rule;
+}
+
+ConversionResult<CapConfiguration> aidl2legacy_AudioHalCapConfiguration_CapConfiguration(
+ const media::audio::common::AudioHalCapConfiguration& aidl) {
+ CapConfiguration legacy;
+ legacy.name = aidl.name;
+ legacy.rule = VALUE_OR_FATAL(aidl2legacy_AudioHalCapRule_CapRule(aidl.rule));
+ return legacy;
+}
+
+ConversionResult<ConfigurableElementValue> aidl2legacy_ParameterSetting_ConfigurableElementValue(
+ const AudioHalCapParameter& aidl) {
+ ConfigurableElementValue legacy;
+ std::string literalValue;
+ switch (aidl.getTag()) {
+ case AudioHalCapParameter::selectedStrategyDevice: {
+ auto strategyDevice = aidl.get<AudioHalCapParameter::selectedStrategyDevice>();
+ literalValue = std::to_string(strategyDevice.isSelected);
+ audio_devices_t legacyType = VALUE_OR_RETURN(
+ aidl2legacy_AudioDeviceDescription_audio_devices_t(strategyDevice.device));
+ std::string legacyTypeLiteral;
+ if (!::android::OutputDeviceConverter::toString(legacyType, legacyTypeLiteral)) {
+ ALOGE("%s Invalid device type %d", __func__, legacyType);
+ return unexpected(BAD_VALUE);
+ }
+ std::string deviceLiteral = VALUE_OR_RETURN(
+ truncatePrefixToLower(legacyTypeLiteral, gLegacyOutputDevicePrefix));
+ if (deviceLiteral == "default") {
+ deviceLiteral = "stub";
+ }
+ legacy.configurableElement.path = std::string(gPolicyParamPrefix)
+ + "product_strategies/vx_" + std::to_string(strategyDevice.id)
+ + "/selected_output_devices/mask/" + deviceLiteral;
+ break;
+ }
+ case AudioHalCapParameter::strategyDeviceAddress: {
+ auto strategyAddress = aidl.get<AudioHalCapParameter::strategyDeviceAddress>();
+ legacy.configurableElement.path = std::string(gPolicyParamPrefix)
+ + "product_strategies/vx_" + std::to_string(strategyAddress.id)
+ + "/device_address";
+ literalValue = strategyAddress.deviceAddress.get<AudioDeviceAddress::id>();
+ break;
+ }
+ case AudioHalCapParameter::selectedInputSourceDevice: {
+ auto inputSourceDevice = aidl.get<AudioHalCapParameter::selectedInputSourceDevice>();
+ literalValue = std::to_string(inputSourceDevice.isSelected);
+ audio_devices_t legacyType = VALUE_OR_RETURN(
+ aidl2legacy_AudioDeviceDescription_audio_devices_t(inputSourceDevice.device));
+ std::string legacyTypeLiteral;
+ if (!::android::InputDeviceConverter::toString(legacyType, legacyTypeLiteral)) {
+ ALOGE("%s Invalid input source device type %d", __func__, legacyType);
+ return unexpected(BAD_VALUE);
+ }
+ std::string deviceLiteral = VALUE_OR_RETURN(
+ truncatePrefixToLower(legacyTypeLiteral, gLegacyInputDevicePrefix));
+ if (deviceLiteral == "default") {
+ deviceLiteral = "stub";
+ }
+ audio_source_t legacySource = VALUE_OR_RETURN(aidl2legacy_AudioSource_audio_source_t(
+ inputSourceDevice.inputSource));
+ std::string inputSourceLiteral;
+ if (!::android::SourceTypeConverter::toString(legacySource, inputSourceLiteral)) {
+ ALOGE("%s Invalid input source %d", __func__, legacySource);
+ return unexpected(BAD_VALUE);
+ }
+ inputSourceLiteral = VALUE_OR_RETURN(
+ truncatePrefixToLower(inputSourceLiteral, gLegacySourcePrefix));
+ legacy.configurableElement.path = std::string(gPolicyParamPrefix) + "input_sources/"
+ + inputSourceLiteral + "/applicable_input_device/mask/" + deviceLiteral;
+ break;
+ }
+ case AudioHalCapParameter::streamVolumeProfile: {
+ auto streamVolumeProfile = aidl.get<AudioHalCapParameter::streamVolumeProfile>();
+ audio_stream_type_t legacyStreamType = VALUE_OR_RETURN(
+ aidl2legacy_AudioStreamType_audio_stream_type_t(streamVolumeProfile.stream));
+ std::string legacyStreamLiteral;
+ if (!::android::StreamTypeConverter::toString(legacyStreamType, legacyStreamLiteral)) {
+ ALOGE("%s Invalid stream type %d", __func__, legacyStreamType);
+ return unexpected(BAD_VALUE);
+ }
+ legacyStreamLiteral = VALUE_OR_RETURN(
+ truncatePrefixToLower(legacyStreamLiteral, gLegacyStreamPrefix));
+
+ audio_stream_type_t legacyProfile = VALUE_OR_RETURN(
+ aidl2legacy_AudioStreamType_audio_stream_type_t(streamVolumeProfile.profile));
+ std::string legacyProfileLiteral;
+ if (!::android::StreamTypeConverter::toString(legacyProfile, legacyProfileLiteral)) {
+ ALOGE("%s Invalid profile %d", __func__, legacyProfile);
+ return unexpected(BAD_VALUE);
+ }
+ literalValue = VALUE_OR_RETURN(
+ truncatePrefixToLower(legacyProfileLiteral, gLegacyStreamPrefix));
+ legacy.configurableElement.path = std::string(gPolicyParamPrefix) + "streams/"
+ + legacyStreamLiteral + "/applicable_volume_profile/volume_profile";
+ break;
+ }
+ default:
+ return unexpected(BAD_VALUE);
+ }
+ legacy.value = literalValue;
+ return legacy;
+}
+
+ConversionResult<CapSetting> aidl2legacy_AudioHalCapConfiguration_CapSetting(
+ const media::audio::common::AudioHalCapConfiguration& aidl) {
+ CapSetting legacy;
+ legacy.configurationName = aidl.name;
+ legacy.configurableElementValues = VALUE_OR_RETURN(convertContainer<ConfigurableElementValues>(
+ aidl.parameterSettings, aidl2legacy_ParameterSetting_ConfigurableElementValue));
+ return legacy;
+}
+
+ConversionResult<CapConfigurableDomain> aidl2legacy_AudioHalCapDomain_CapConfigurableDomain(
+ const media::audio::common::AudioHalCapDomain& aidl) {
+ CapConfigurableDomain legacy;
+ legacy.name = aidl.name;
+ legacy.configurations = VALUE_OR_RETURN(convertContainer<CapConfigurations>(
+ aidl.configurations,
+ aidl2legacy_AudioHalCapConfiguration_CapConfiguration));
+ legacy.settings = VALUE_OR_RETURN(convertContainer<CapSettings>(
+ aidl.configurations,
+ aidl2legacy_AudioHalCapConfiguration_CapSetting));
+ return legacy;
+}
+
+ConversionResult<CapCriterion> aidl2legacy_AudioHalCapCriterionV2_Criterion(
+ const AudioHalCapCriterionV2& aidl) {
+ CapCriterion capCriterion;
+ engineConfig::Criterion& criterion = capCriterion.criterion;
+ engineConfig::CriterionType& criterionType = capCriterion.criterionType;
+
+ auto loadForceUseCriterion = [](const auto &aidlCriterion, auto &criterion,
+ auto &criterionType) -> status_t {
+ uint32_t legacyForceUse = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(
+ aidlCriterion.forceUse));
+ criterion.typeName = criterionType.name;
+ criterionType.name = criterion.typeName + gCriterionTypeSuffix;
+ criterionType.isInclusive =
+ (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+ criterion.name = gForceUseCriterionTag[legacyForceUse];
+ criterion.defaultLiteralValue = toString(aidlCriterion.defaultValue);
+ if (aidlCriterion.values.empty()) {
+ return BAD_VALUE;
+ }
+ for (auto &value : aidlCriterion.values) {
+ uint32_t legacyForcedConfig = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioPolicyForcedConfig_audio_policy_forced_cfg_t(value));
+ criterionType.valuePairs.push_back({legacyForcedConfig, 0, toString(value)});
+ }
+ return NO_ERROR;
+ };
+
+ auto loadDevicesCriterion = [](const auto &aidlCriterion, auto &criterion,
+ auto &criterionType) -> status_t {
+ criterionType.name = criterion.name + gCriterionTypeSuffix;
+ criterionType.isInclusive =
+ (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+ criterion.typeName = criterionType.name;
+ int shift = 0;
+ if (aidlCriterion.values.empty()) {
+ return BAD_VALUE;
+ }
+ for (const auto &value : aidlCriterion.values) {
+ audio_devices_t legacyDeviceType = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_AudioDeviceDescription_audio_devices_t(value));
+ bool isOut = audio_is_output_devices(legacyDeviceType);
+ std::string legacyTypeLiteral;
+ if (!::android::DeviceConverter::toString(legacyDeviceType, legacyTypeLiteral)) {
+ ALOGE("%s Invalid device type %d", __func__, legacyDeviceType);
+ return BAD_VALUE;
+ }
+ std::string deviceLiteral = VALUE_OR_RETURN_STATUS(truncatePrefix(legacyTypeLiteral,
+ isOut ? gLegacyOutputDevicePrefix : gLegacyInputDevicePrefix));
+ uint64_t pfwCriterionValue = 1 << shift++;
+ criterionType.valuePairs.push_back(
+ {pfwCriterionValue, static_cast<int32_t>(legacyDeviceType), deviceLiteral});
+ ALOGV("%s: adding %" PRIu64 " %d %s %s", __func__, pfwCriterionValue, legacyDeviceType,
+ toString(value.type).c_str(), deviceLiteral.c_str());
+ }
+ return NO_ERROR;
+ };
+
+ auto loadDeviceAddressesCriterion = [](const auto &aidlCriterion, auto &criterion,
+ auto &criterionType) -> status_t {
+ criterionType.name = criterion.name + gCriterionTypeSuffix;
+ criterionType.isInclusive =
+ (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+ criterion.typeName = criterionType.name;
+ int shift = 0;
+ for (auto &value : aidlCriterion.values) {
+ uint64_t pfwCriterionValue = 1 << shift++;
+ if (value.getTag() != AudioDeviceAddress::id) {
+ return BAD_VALUE;
+ }
+ std::string address = value.template get<AudioDeviceAddress::id>();
+ criterionType.valuePairs.push_back({pfwCriterionValue, 0, address});
+ }
+ return NO_ERROR;
+ };
+
+ switch (aidl.getTag()) {
+ case AudioHalCapCriterionV2::availableInputDevices: {
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::availableInputDevices>();
+ criterion.name = gInputDeviceCriterionName;
+ if (loadDevicesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ }
+ case AudioHalCapCriterionV2::availableOutputDevices: {
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::availableOutputDevices>();
+ criterion.name = gOutputDeviceCriterionName;
+ if (loadDevicesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ }
+ case AudioHalCapCriterionV2::availableInputDevicesAddresses: {
+ auto aidlCriterion =
+ aidl.get<AudioHalCapCriterionV2::availableInputDevicesAddresses>();
+ criterion.name = gInputDeviceAddressCriterionName;
+ if (loadDeviceAddressesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ }
+ case AudioHalCapCriterionV2::availableOutputDevicesAddresses: {
+ auto aidlCriterion =
+ aidl.get<AudioHalCapCriterionV2::availableOutputDevicesAddresses>();
+ criterion.name = gOutputDeviceAddressCriterionName;
+ if (loadDeviceAddressesCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ }
+ case AudioHalCapCriterionV2::telephonyMode: {
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::telephonyMode>();
+ criterion.name = gPhoneStateCriterionName;
+ criterionType.name = criterion.name + gCriterionTypeSuffix;
+ criterionType.isInclusive =
+ (aidlCriterion.logic == AudioHalCapCriterionV2::LogicalDisjunction::INCLUSIVE);
+ criterion.typeName = criterionType.name;
+ criterion.defaultLiteralValue = toString( aidlCriterion.defaultValue);
+ if (aidlCriterion.values.empty()) {
+ return unexpected(BAD_VALUE);
+ }
+ for (auto &value : aidlCriterion.values) {
+ uint32_t legacyMode =
+ VALUE_OR_RETURN(aidl2legacy_AudioMode_audio_mode_t(value));
+ criterionType.valuePairs.push_back({legacyMode, 0, toString(value)});
+ }
+ break;
+ }
+ case AudioHalCapCriterionV2::forceConfigForUse: {
+ auto aidlCriterion = aidl.get<AudioHalCapCriterionV2::forceConfigForUse>();
+ if (loadForceUseCriterion(aidlCriterion, criterion, criterionType) != NO_ERROR) {
+ return unexpected(BAD_VALUE);
+ }
+ break;
+ }
+ default:
+ return unexpected(BAD_VALUE);
+ }
+ return capCriterion;
+}
+
+} // namespace
+
+ParsingResult convert(const ::android::media::audio::common::AudioHalEngineConfig& aidlConfig) {
+ auto config = std::make_unique<capEngineConfig::CapConfig>();
+
+ if (!aidlConfig.capSpecificConfig.has_value() ||
+ !aidlConfig.capSpecificConfig.value().domains.has_value()) {
+ ALOGE("%s: no Cap Engine config", __func__);
+ return ParsingResult{};
+ }
+ for (auto& aidlCriteria: aidlConfig.capSpecificConfig.value().criteriaV2.value()) {
+ if (aidlCriteria.has_value()) {
+ if (auto conv = aidl2legacy_AudioHalCapCriterionV2_Criterion(aidlCriteria.value());
+ conv.ok()) {
+ config->capCriteria.push_back(std::move(conv.value()));
+ } else {
+ return ParsingResult{};
+ }
+ }
+ }
+ size_t skippedElement = 0;
+ for (auto& aidlDomain: aidlConfig.capSpecificConfig.value().domains.value()) {
+ if (aidlDomain.has_value()) {
+ if (auto conv = aidl2legacy_AudioHalCapDomain_CapConfigurableDomain(aidlDomain.value());
+ conv.ok()) {
+ config->capConfigurableDomains.push_back(std::move(conv.value()));
+ } else {
+ return ParsingResult{};
+ }
+ } else {
+ skippedElement += 1;
+ }
+ }
+ return {.parsedConfig=std::move(config), .nbSkippedElement=skippedElement};
+}
+} // namespace capEngineConfig
+} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/data/Android.bp b/services/audiopolicy/engineconfigurable/data/Android.bp
new file mode 100644
index 0000000..303cabc
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/Android.bp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_av_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_av_license"],
+}
+
+prebuilt_etc {
+ name: "CapClass.xml",
+ src: ":CapClass",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+ name: "CapSubsystem.xml",
+ src: ":CapSubsystem",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+ name: "CapSubsystem-CommonTypes.xml",
+ src: ":buildaidlcommontypesstructure_gen",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+ name: "CapProductStrategies.xml",
+ src: ":cap_product_strategies_structure",
+ sub_dir: "parameter-framework/Structure/Policy",
+}
+
+prebuilt_etc {
+ name: "ParameterFrameworkConfigurationCap.xml",
+ src: ":ParameterFrameworkConfigurationCapSrc_gen",
+ sub_dir: "parameter-framework",
+}
+
+genrule {
+ name: "ParameterFrameworkConfigurationCapSrc_gen",
+ out: ["ParameterFrameworkConfigurationCap.xml"],
+ srcs: [":ParameterFrameworkConfigurationCapSrc"],
+ product_variables: {
+ debuggable: {
+ cmd: "sed -e 's|TuningAllowed=\"false\"|TuningAllowed=\"true\" ServerPort=\"unix:///dev/socket/audioserver/policy_debug\"|g' <$(in) > $(out)",
+ },
+ },
+ cmd: "cp -f $(in) $(out)",
+}
+
+genrule {
+ name: "buildaidlcommontypesstructure_gen",
+ defaults: ["buildcommontypesstructurerule"],
+ out: ["CapSubsystem-CommonTypes.xml"],
+}
+
+filegroup {
+ name: "ParameterFrameworkConfigurationCapSrc",
+ srcs: ["etc/ParameterFrameworkConfigurationCap.xml"],
+}
+
+filegroup {
+ name: "cap_product_strategies_structure",
+ srcs: ["etc/Structure/CapProductStrategies.xml"],
+}
+
+filegroup {
+ name: "CapSubsystem",
+ srcs: ["etc/Structure/CapSubsystem.xml"],
+}
+
+filegroup {
+ name: "aidl_common_types_structure_template",
+ srcs: ["etc/Structure/CapSubsystem-CommonTypes.xml.in"],
+}
+
+filegroup {
+ name: "CapClass",
+ srcs: ["etc/Structure/CapClass.xml"],
+}
diff --git a/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml b/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml
new file mode 100644
index 0000000..bac7a25
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/ParameterFrameworkConfigurationCap.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ParameterFrameworkConfiguration xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ SystemClassName="Policy" TuningAllowed="false">
+
+ <SubsystemPlugins>
+ <Location Folder="">
+ <Plugin Name="libpolicy-subsystem.so"/>
+ </Location>
+ </SubsystemPlugins>
+ <StructureDescriptionFileLocation Path="Structure/Policy/CapClass.xml"/>
+</ParameterFrameworkConfiguration>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml
new file mode 100644
index 0000000..e233673
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapClass.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SystemClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:noNamespaceSchemaLocation="../../Schemas/SystemClass.xsd" Name="Policy">
+ <SubsystemInclude Path="CapSubsystem.xml"/>
+</SystemClass>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml
new file mode 100644
index 0000000..61f056a
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapProductStrategies.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+ <!-- This structure is expected to be in the system partition and provisionned a maximum
+ allowed strategies to be used by vendor. -->
+ <ComponentType Name="ProductStrategies" Description="">
+ <Component Name="vx_1000" Type="ProductStrategy" Mapping="Identifier:1000,Name:vx_1000"/>
+ <Component Name="vx_1001" Type="ProductStrategy" Mapping="Identifier:1001,Name:vx_1001"/>
+ <Component Name="vx_1002" Type="ProductStrategy" Mapping="Identifier:1002,Name:vx_1002"/>
+ <Component Name="vx_1003" Type="ProductStrategy" Mapping="Identifier:1003,Name:vx_1003"/>
+ <Component Name="vx_1004" Type="ProductStrategy" Mapping="Identifier:1004,Name:vx_1004"/>
+ <Component Name="vx_1005" Type="ProductStrategy" Mapping="Identifier:1005,Name:vx_1005"/>
+ <Component Name="vx_1006" Type="ProductStrategy" Mapping="Identifier:1006,Name:vx_1006"/>
+ <Component Name="vx_1007" Type="ProductStrategy" Mapping="Identifier:1007,Name:vx_1007"/>
+ <Component Name="vx_1008" Type="ProductStrategy" Mapping="Identifier:1008,Name:vx_1008"/>
+ <Component Name="vx_1009" Type="ProductStrategy" Mapping="Identifier:1009,Name:vx_1009"/>
+ <Component Name="vx_1010" Type="ProductStrategy" Mapping="Identifier:1010,Name:vx_1010"/>
+ <Component Name="vx_1011" Type="ProductStrategy" Mapping="Identifier:1011,Name:vx_1011"/>
+ <Component Name="vx_1012" Type="ProductStrategy" Mapping="Identifier:1012,Name:vx_1012"/>
+ <Component Name="vx_1013" Type="ProductStrategy" Mapping="Identifier:1013,Name:vx_1013"/>
+ <Component Name="vx_1014" Type="ProductStrategy" Mapping="Identifier:1014,Name:vx_1014"/>
+ <Component Name="vx_1015" Type="ProductStrategy" Mapping="Identifier:1015,Name:vx_1015"/>
+ <Component Name="vx_1016" Type="ProductStrategy" Mapping="Identifier:1016,Name:vx_1016"/>
+ <Component Name="vx_1017" Type="ProductStrategy" Mapping="Identifier:1017,Name:vx_1017"/>
+ <Component Name="vx_1018" Type="ProductStrategy" Mapping="Identifier:1018,Name:vx_1018"/>
+ <Component Name="vx_1019" Type="ProductStrategy" Mapping="Identifier:1019,Name:vx_1019"/>
+ <Component Name="vx_1020" Type="ProductStrategy" Mapping="Identifier:1020,Name:vx_1020"/>
+ <Component Name="vx_1021" Type="ProductStrategy" Mapping="Identifier:1021,Name:vx_1021"/>
+ <Component Name="vx_1022" Type="ProductStrategy" Mapping="Identifier:1022,Name:vx_1022"/>
+ <Component Name="vx_1023" Type="ProductStrategy" Mapping="Identifier:1023,Name:vx_1023"/>
+ <Component Name="vx_1024" Type="ProductStrategy" Mapping="Identifier:1024,Name:vx_1024"/>
+ <Component Name="vx_1025" Type="ProductStrategy" Mapping="Identifier:1025,Name:vx_1025"/>
+ <Component Name="vx_1026" Type="ProductStrategy" Mapping="Identifier:1026,Name:vx_1026"/>
+ <Component Name="vx_1027" Type="ProductStrategy" Mapping="Identifier:1027,Name:vx_1027"/>
+ <Component Name="vx_1028" Type="ProductStrategy" Mapping="Identifier:1028,Name:vx_1028"/>
+ <Component Name="vx_1029" Type="ProductStrategy" Mapping="Identifier:1029,Name:vx_1029"/>
+ <Component Name="vx_1030" Type="ProductStrategy" Mapping="Identifier:1030,Name:vx_1030"/>
+ <Component Name="vx_1031" Type="ProductStrategy" Mapping="Identifier:1031,Name:vx_1031"/>
+ <Component Name="vx_1032" Type="ProductStrategy" Mapping="Identifier:1032,Name:vx_1032"/>
+ <Component Name="vx_1033" Type="ProductStrategy" Mapping="Identifier:1033,Name:vx_1033"/>
+ <Component Name="vx_1034" Type="ProductStrategy" Mapping="Identifier:1034,Name:vx_1034"/>
+ <Component Name="vx_1035" Type="ProductStrategy" Mapping="Identifier:1035,Name:vx_1035"/>
+ <Component Name="vx_1036" Type="ProductStrategy" Mapping="Identifier:1036,Name:vx_1036"/>
+ <Component Name="vx_1037" Type="ProductStrategy" Mapping="Identifier:1037,Name:vx_1037"/>
+ <Component Name="vx_1038" Type="ProductStrategy" Mapping="Identifier:1038,Name:vx_1038"/>
+ <Component Name="vx_1039" Type="ProductStrategy" Mapping="Identifier:1039,Name:vx_1039"/>
+ </ComponentType>
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in
new file mode 100644
index 0000000..2c4c7b5
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem-CommonTypes.xml.in
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ComponentTypeSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xsi:noNamespaceSchemaLocation="Schemas/ComponentTypeSet.xsd">
+ <!-- Output devices definition as a bitfield for the supported devices per output
+ profile. It must match with the output device enum parameter.
+ -->
+ <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+
+ <!--#################### GLOBAL COMPONENTS END ####################-->
+
+ <!-- Automatically filled from audio-base.h file -->
+ <ComponentType Name="OutputDevicesMask" Description="64bit representation of devices">
+ <BitParameterBlock Name="mask" Size="64">
+ </BitParameterBlock>
+ </ComponentType>
+
+ <!-- Input devices definition as a bitfield for the supported devices per Input
+ profile. It must match with the Input device enum parameter.
+ -->
+ <!-- Automatically filled from audio-base.h file -->
+ <ComponentType Name="InputDevicesMask" Description="64bit representation of devices">
+ <BitParameterBlock Name="mask" Size="64">
+ </BitParameterBlock>
+ </ComponentType>
+
+ <!--#################### STREAM COMMON TYPES BEGIN ####################-->
+ <!-- Automatically filled from audio-base.h file. VolumeProfileType is associated to stream type -->
+ <ComponentType Name="VolumeProfileType">
+ <EnumParameter Name="volume_profile" Size="32">
+ </EnumParameter>
+ </ComponentType>
+
+ <ComponentType Name="Stream" Mapping="Stream">
+ <Component Name="applicable_volume_profile" Type="VolumeProfileType"
+ Description="Volume profile followed by a given stream type."/>
+ </ComponentType>
+
+ <!--#################### STREAM COMMON TYPES END ####################-->
+
+ <!--#################### INPUT SOURCE COMMON TYPES BEGIN ####################-->
+
+ <ComponentType Name="InputSource">
+ <Component Name="applicable_input_device" Type="InputDevicesMask"
+ Mapping="InputSource" Description="Selected Input device"/>
+ </ComponentType>
+
+ <!--#################### INPUT SOURCE COMMON TYPES END ####################-->
+
+ <!--#################### PRODUCT STRATEGY COMMON TYPES BEGIN ####################-->
+
+ <ComponentType Name="ProductStrategy" Mapping="ProductStrategy">
+ <Component Name="selected_output_devices" Type="OutputDevicesMask"/>
+ <StringParameter Name="device_address" MaxLength="256"
+ Description="if any, device address associated"/>
+ </ComponentType>
+
+ <!--#################### PRODUCT STRATEGY COMMON TYPES END ####################-->
+
+</ComponentTypeSet>
diff --git a/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml
new file mode 100644
index 0000000..45a0bd4
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/data/etc/Structure/CapSubsystem.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<Subsystem xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns:xi="http://www.w3.org/2001/XInclude"
+ xsi:noNamespaceSchemaLocation="Schemas/Subsystem.xsd"
+ Name="policy" Type="Policy">
+
+ <ComponentLibrary>
+ <!--#################### GLOBAL COMPONENTS BEGIN ####################-->
+ <!-- Common Types definition -->
+ <xi:include href="CapSubsystem-CommonTypes.xml"/>
+ <xi:include href="CapProductStrategies.xml"/>
+
+
+ <!--#################### GLOBAL COMPONENTS END ####################-->
+
+ <!--#################### STREAM BEGIN ####################-->
+
+ <ComponentType Name="Streams" Description="associated to audio_stream_type_t definition">
+ <Component Name="voice_call" Type="Stream" Mapping="Name:AUDIO_STREAM_VOICE_CALL"/>
+ <Component Name="system" Type="Stream" Mapping="Name:AUDIO_STREAM_SYSTEM"/>
+ <Component Name="ring" Type="Stream" Mapping="Name:AUDIO_STREAM_RING"/>
+ <Component Name="music" Type="Stream" Mapping="Name:AUDIO_STREAM_MUSIC"/>
+ <Component Name="alarm" Type="Stream" Mapping="Name:AUDIO_STREAM_ALARM"/>
+ <Component Name="notification" Type="Stream" Mapping="Name:AUDIO_STREAM_NOTIFICATION"/>
+ <Component Name="bluetooth_sco" Type="Stream" Mapping="Name:AUDIO_STREAM_BLUETOOTH_SCO"/>
+ <Component Name="enforced_audible" Type="Stream" Mapping="Name:AUDIO_STREAM_ENFORCED_AUDIBLE"
+ Description="Sounds that cannot be muted by user and must be routed to speaker"/>
+ <Component Name="dtmf" Type="Stream" Mapping="Name:AUDIO_STREAM_DTMF"/>
+ <Component Name="tts" Type="Stream" Mapping="Name:AUDIO_STREAM_TTS"
+ Description="Transmitted Through Speaker. Plays over speaker only, silent on other devices"/>
+ <Component Name="accessibility" Type="Stream" Mapping="Name:AUDIO_STREAM_ACCESSIBILITY"
+ Description="For accessibility talk back prompts"/>
+ <Component Name="assistant" Type="Stream" Mapping="Name:AUDIO_STREAM_ASSISTANT"
+ Description="used by a virtual assistant like Google Assistant, Bixby, etc."/>
+ <Component Name="rerouting" Type="Stream" Mapping="Name:AUDIO_STREAM_REROUTING"
+ Description="For dynamic policy output mixes"/>
+ <Component Name="patch" Type="Stream" Mapping="Name:AUDIO_STREAM_PATCH"
+ Description="For internal audio flinger tracks. Fixed volume"/>
+ </ComponentType>
+
+ <!--#################### STREAM END ####################-->
+
+ <!--#################### INPUT SOURCE BEGIN ####################-->
+
+ <ComponentType Name="InputSources" Description="associated to audio_source_t definition,
+ identifier mapping must match the value of the enum">
+ <Component Name="default" Type="InputSource" Mapping="Name:AUDIO_SOURCE_DEFAULT"/>
+ <Component Name="mic" Type="InputSource" Mapping="Name:AUDIO_SOURCE_MIC"/>
+ <Component Name="voice_uplink" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_UPLINK"/>
+ <Component Name="voice_downlink" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_DOWNLINK"/>
+ <Component Name="voice_call" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_CALL"/>
+ <Component Name="camcorder" Type="InputSource" Mapping="Name:AUDIO_SOURCE_CAMCORDER"/>
+ <Component Name="voice_recognition" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_RECOGNITION"/>
+ <Component Name="voice_communication" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_COMMUNICATION"/>
+ <Component Name="remote_submix" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_REMOTE_SUBMIX"/>
+ <Component Name="unprocessed" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_UNPROCESSED"/>
+ <Component Name="voice_performance" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_VOICE_PERFORMANCE"/>
+ <Component Name="echo_reference" Type="InputSource"
+ Mapping="Name:AUDIO_SOURCE_ECHO_REFERENCE"/>
+ <Component Name="fm_tuner" Type="InputSource" Mapping="Name:AUDIO_SOURCE_FM_TUNER"/>
+ <Component Name="hotword" Type="InputSource" Mapping="Name:AUDIO_SOURCE_HOTWORD"/>
+ </ComponentType>
+ <!--#################### INPUT SOURCE END ####################-->
+ </ComponentLibrary>
+
+ <InstanceDefinition>
+ <Component Name="streams" Type="Streams"/>
+ <Component Name="input_sources" Type="InputSources"/>
+ <Component Name="product_strategies" Type="ProductStrategies"/>
+ </InstanceDefinition>
+</Subsystem>
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 9fd8b8e..e0b7210 100644
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -98,7 +98,8 @@
virtual bool setDeviceTypesForProductStrategy(product_strategy_t strategy,
uint64_t devices) = 0;
- virtual product_strategy_t getProductStrategyByName(const std::string &address) = 0;
+ virtual product_strategy_t getProductStrategyByName(const std::string &name) = 0;
+ virtual std::string getProductStrategyName(product_strategy_t id) const = 0;
protected:
virtual ~AudioPolicyPluginInterface() {}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
index 7fe111f..e4f44d5 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/Android.bp
@@ -50,6 +50,7 @@
genrule {
name: "buildcommontypesstructure_gen",
defaults: ["buildcommontypesstructurerule"],
+ out: ["PolicySubsystem-CommonTypes.xml"],
}
filegroup {
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
index c9a77a4..27a290f 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Android.bp
@@ -45,4 +45,7 @@
"libparameter",
"libutils",
],
+ defaults: [
+ "aconfig_lib_cc_shared_link.defaults",
+ ],
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
index 8bd7f66..bf5767d 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/PolicySubsystem.cpp
@@ -72,7 +72,7 @@
);
addSubsystemObjectFactory(
new TSubsystemObjectFactory<ProductStrategy>(
- mProductStrategyComponentName, (1 << MappingKeyName))
+ mProductStrategyComponentName, (1 << MappingKeyName) | (1 << MappingKeyIdentifier))
);
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
index ebd9456..06efbf28 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/ProductStrategy.cpp
@@ -18,10 +18,7 @@
#include "PolicyMappingKeys.h"
#include "PolicySubsystem.h"
-using std::string;
-using android::product_strategy_t;
-
-ProductStrategy::ProductStrategy(const string &mappingValue,
+ProductStrategy::ProductStrategy(const std::string &mappingValue,
CInstanceConfigurableElement *instanceConfigurableElement,
const CMappingContext &context,
core::log::Logger& logger)
@@ -30,26 +27,32 @@
mappingValue,
MappingKeyAmend1,
(MappingKeyAmendEnd - MappingKeyAmend1 + 1),
- context)
-{
- std::string name(context.getItem(MappingKeyName));
+ context) {
+
+ size_t id = context.getItemAsInteger(MappingKeyIdentifier);
+ std::string nameFromStructure(context.getItem(MappingKeyName));
ALOG_ASSERT(instanceConfigurableElement != nullptr, "Invalid Configurable Element");
mPolicySubsystem = static_cast<const PolicySubsystem *>(
- instanceConfigurableElement->getBelongingSubsystem());
+ instanceConfigurableElement->getBelongingSubsystem());
ALOG_ASSERT(mPolicySubsystem != nullptr, "Invalid Policy Subsystem");
mPolicyPluginInterface = mPolicySubsystem->getPolicyPluginInterface();
ALOG_ASSERT(mPolicyPluginInterface != nullptr, "Invalid Policy Plugin Interface");
- mId = mPolicyPluginInterface->getProductStrategyByName(name);
+ mId = static_cast<android::product_strategy_t>(id);
+ std::string name = mPolicyPluginInterface->getProductStrategyName(mId);
+ if (name.empty()) {
+ name = nameFromStructure;
+ mId = mPolicyPluginInterface->getProductStrategyByName(name);
+ }
ALOG_ASSERT(mId != PRODUCT_STRATEGY_INVALID, "Product Strategy %s not found", name.c_str());
ALOGE("Product Strategy %s added", name.c_str());
}
-bool ProductStrategy::sendToHW(string & /*error*/)
+bool ProductStrategy::sendToHW(std::string & /*error*/)
{
Device deviceParams;
blackboardRead(&deviceParams, sizeof(deviceParams));
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index ccd4316..45da7b0 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -71,27 +71,75 @@
}
status_t Engine::loadFromHalConfigWithFallback(
- const media::audio::common::AudioHalEngineConfig& config __unused) {
- // b/242678729. Need to implement for the configurable engine.
- return INVALID_OPERATION;
-}
+ const media::audio::common::AudioHalEngineConfig& aidlConfig) {
-status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
-{
- status_t loadResult = loadAudioPolicyEngineConfig(xmlFilePath);
- if (loadResult < 0) {
- ALOGE("Policy Engine configuration is invalid.");
+ auto capResult = capEngineConfig::convert(aidlConfig);
+ if (capResult.parsedConfig == nullptr) {
+ ALOGE("%s CapEngine Config invalid", __func__);
+ return BAD_VALUE;
}
- return loadResult;
-}
-
-status_t Engine::initCheck()
-{
+ status_t ret = loadWithFallback(aidlConfig);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ auto loadCriteria= [this](const auto& capCriteria) {
+ for (auto& capCriterion : capCriteria) {
+ mPolicyParameterMgr->addCriterion(capCriterion.criterion.name,
+ capCriterion.criterionType.isInclusive,
+ capCriterion.criterionType.valuePairs,
+ capCriterion.criterion.defaultLiteralValue);
+ }
+ };
+ loadCriteria(capResult.parsedConfig->capCriteria);
std::string error;
if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
return NO_INIT;
}
+ return mPolicyParameterMgr->setConfiguration(capResult);
+}
+
+status_t Engine::loadFromXmlConfigWithFallback(const std::string& xmlFilePath)
+{
+ status_t status = loadWithFallback(xmlFilePath);
+ std::string error;
+ if (mPolicyParameterMgr == nullptr || mPolicyParameterMgr->start(error) != NO_ERROR) {
+ ALOGE("%s: could not start Policy PFW: %s", __FUNCTION__, error.c_str());
+ return NO_INIT;
+ }
+ return status;
+}
+
+template<typename T>
+status_t Engine::loadWithFallback(const T& configSource) {
+ auto result = EngineBase::loadAudioPolicyEngineConfig(configSource);
+ ALOGE_IF(result.nbSkippedElement != 0,
+ "Policy Engine configuration is partially invalid, skipped %zu elements",
+ result.nbSkippedElement);
+
+ auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
+ for (auto& criterion : configCriteria) {
+ engineConfig::CriterionType criterionType;
+ for (auto &configCriterionType : configCriterionTypes) {
+ if (configCriterionType.name == criterion.typeName) {
+ criterionType = configCriterionType;
+ break;
+ }
+ }
+ ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
+ criterion.name.c_str());
+ mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
+ criterionType.valuePairs,
+ criterion.defaultLiteralValue);
+ }
+ };
+
+ loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
+ return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
+}
+
+status_t Engine::initCheck()
+{
return EngineBase::initCheck();
}
@@ -199,32 +247,6 @@
return EngineBase::setDeviceConnectionState(device, state);
}
-status_t Engine::loadAudioPolicyEngineConfig(const std::string& xmlFilePath)
-{
- auto result = EngineBase::loadAudioPolicyEngineConfig(xmlFilePath);
-
- // Custom XML Parsing
- auto loadCriteria= [this](const auto& configCriteria, const auto& configCriterionTypes) {
- for (auto& criterion : configCriteria) {
- engineConfig::CriterionType criterionType;
- for (auto &configCriterionType : configCriterionTypes) {
- if (configCriterionType.name == criterion.typeName) {
- criterionType = configCriterionType;
- break;
- }
- }
- ALOG_ASSERT(not criterionType.name.empty(), "Invalid criterion type for %s",
- criterion.name.c_str());
- mPolicyParameterMgr->addCriterion(criterion.name, criterionType.isInclusive,
- criterionType.valuePairs,
- criterion.defaultLiteralValue);
- }
- };
-
- loadCriteria(result.parsedConfig->criteria, result.parsedConfig->criterionTypes);
- return result.nbSkippedElement == 0? NO_ERROR : BAD_VALUE;
-}
-
status_t Engine::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role,
const AudioDeviceTypeAddrVector &devices)
{
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 4f3e620..d9ebbe7 100644
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -16,10 +16,11 @@
#pragma once
-#include "EngineBase.h"
-#include <EngineInterface.h>
-#include <AudioPolicyPluginInterface.h>
#include "Collection.h"
+#include "EngineBase.h"
+#include <AudioPolicyPluginInterface.h>
+#include <CapEngineConfig.h>
+#include <EngineInterface.h>
namespace android {
class AudioPolicyManagerObserver;
@@ -107,8 +108,14 @@
{
return EngineBase::getProductStrategyByName(name);
}
+ std::string getProductStrategyName(product_strategy_t id) const override {
+ return EngineBase::getProductStrategyName(id);
+ }
private:
+ template<typename T>
+ status_t loadWithFallback(const T& configSource);
+
android::status_t disableDevicesForStrategy(product_strategy_t strategy,
const DeviceVector &devicesToDisable);
void enableDevicesForStrategy(product_strategy_t strategy, const DeviceVector &devicesToEnable);
@@ -140,8 +147,6 @@
template <typename Property, typename Key>
bool setPropertyForKey(const Property &property, const Key &key);
- status_t loadAudioPolicyEngineConfig(const std::string& xmlFilePath);
-
DeviceVector getCachedDevices(product_strategy_t ps) const;
///
diff --git a/services/audiopolicy/engineconfigurable/tools/Android.bp b/services/audiopolicy/engineconfigurable/tools/Android.bp
index d1fb2fb..7ae124c 100644
--- a/services/audiopolicy/engineconfigurable/tools/Android.bp
+++ b/services/audiopolicy/engineconfigurable/tools/Android.bp
@@ -23,7 +23,7 @@
}
//##################################################################################################
-// Tools for audio policy engine criterion type configuration file
+// Legacy tools for audio policy engine criterion type configuration file
//
python_binary_host {
name: "buildPolicyCriterionTypes",
@@ -57,6 +57,40 @@
}
//##################################################################################################
+// Tools for audio policy engine criterion type configuration file
+//
+python_binary_host {
+ name: "capBuildPolicyCriterionTypes",
+ main: "capBuildPolicyCriterionTypes.py",
+ srcs: [
+ "capBuildPolicyCriterionTypes.py",
+ ],
+}
+
+genrule_defaults {
+ name: "capbuildpolicycriteriontypesrule",
+ tools: ["capBuildPolicyCriterionTypes"],
+ cmd: "cp $(locations :audio_policy_configuration_files) $(genDir)/. && " +
+ "cp $(location :audio_policy_configuration_top_file) $(genDir)/audio_policy_configuration.xml && " +
+ "$(location capBuildPolicyCriterionTypes) " +
+ " --androidaudiobaseheader $(location :libaudio_system_audio_base) " +
+ " --androidaudiocommonbaseheader $(location :libaudio_system_audio_common_base) " +
+ "--audiopolicyconfigurationfile $(genDir)/audio_policy_configuration.xml " +
+ "--criteriontypes $(location :audio_policy_engine_aidl_criterion_types_template) " +
+ "--outputfile $(out)",
+ srcs: [
+ // The commented inputs must be provided to use this genrule_defaults
+ // @todo uncomment if 1428659 is merged":android_audio_base_header_file",
+ ":audio_policy_engine_aidl_criterion_types_template",
+ ":libaudio_system_audio_base",
+ ":libaudio_system_audio_common_base",
+ // ":audio_policy_configuration_top_file",
+ // ":audio_policy_configuration_files",
+ ],
+ out: ["audio_policy_engine_criterion_types.xml"],
+}
+
+//##################################################################################################
// Tools for audio policy engine parameter framework configurable domains
//
python_binary_host {
@@ -84,6 +118,7 @@
cmd: "mkdir -p $(genDir)/Structure/Policy && " +
"cp $(locations :audio_policy_pfw_structure_files) $(genDir)/Structure/Policy && " +
"cp $(location :audio_policy_pfw_toplevel) $(genDir)/top_level && " +
+ "sed -i -e 's|TuningAllowed=\"false\"|TuningAllowed=\"true\" ServerPort=\"unix:///dev/socket/audioserver/policy_debug\"|g' $(genDir)/top_level &&" +
"$(location domainGeneratorPolicy) " +
"--validate " +
"--domain-generator-tool $(location domainGeneratorConnector) " +
@@ -106,7 +141,7 @@
}
//##################################################################################################
-// Tools for policy parameter-framework product strategies structure file generation
+// Legacy tools for policy parameter-framework product strategies structure file generation
//
python_binary_host {
name: "buildStrategiesStructureFile",
@@ -154,5 +189,4 @@
":common_types_structure_template",
":libaudio_system_audio_base",
],
- out: ["PolicySubsystem-CommonTypes.xml"],
}
diff --git a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
index f69d346..6eabc57 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildStrategiesStructureFile.py
@@ -75,7 +75,7 @@
strategy_components = strategies_root.find('ComponentType')
for strategy_name in strategies:
- context_mapping = "".join(map(str, ["Name:", strategy_name]))
+ context_mapping = "".join(map(str, ["Identifier:-1,Name:", strategy_name]))
strategy_pfw_name = strategy_name.replace('STRATEGY_', '').lower()
ET.SubElement(strategy_components, "Component",
Name=strategy_pfw_name, Type="ProductStrategy",
diff --git a/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
new file mode 100755
index 0000000..b873830
--- /dev/null
+++ b/services/audiopolicy/engineconfigurable/tools/capBuildPolicyCriterionTypes.py
@@ -0,0 +1,368 @@
+#!/usr/bin/python3
+
+#
+# Copyright 2018, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import argparse
+import re
+import sys
+import os
+import logging
+import xml.etree.ElementTree as ET
+import xml.etree.ElementInclude as EI
+import xml.dom.minidom as MINIDOM
+from collections import OrderedDict
+
+#
+# Helper script that helps to feed at build time the XML criterion types file used by
+# the engineconfigurable to start the parameter-framework.
+# It prevents to fill them manually and avoid divergences with android.
+#
+# The Device Types criterion types are fed from audio-base.h file with the option
+# --androidaudiobaseheader <path/to/android/audio/base/file/audio-base.h>
+#
+# The Device Addresses criterion types are fed from the audio policy configuration file
+# in order to discover all the devices for which the address matter.
+# --audiopolicyconfigurationfile <path/to/audio_policy_configuration.xml>
+#
+# The reference file of criterion types must also be set as an input of the script:
+# --criteriontypes <path/to/criterion/file/audio_criterion_types.xml.in>
+#
+# At last, the output of the script shall be set also:
+# --outputfile <path/to/out/vendor/etc/audio_criterion_types.xml>
+#
+
+def parseArgs():
+ argparser = argparse.ArgumentParser(description="Parameter-Framework XML \
+ audio criterion type file generator.\n\
+ Exit with the number of (recoverable or not) \
+ error that occurred.")
+ argparser.add_argument('--androidaudiobaseheader',
+ help="Android Audio Base C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--androidaudiocommonbaseheader',
+ help="Android Audio CommonBase C header file, Mandatory.",
+ metavar="ANDROID_AUDIO_COMMON_BASE_HEADER",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--audiopolicyconfigurationfile',
+ help="Android Audio Policy Configuration file, Mandatory.",
+ metavar="(AUDIO_POLICY_CONFIGURATION_FILE)",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--criteriontypes',
+ help="Criterion types XML base file, in \
+ '<criterion_types> \
+ <criterion_type name="" type=<inclusive|exclusive> \
+ values=<value1,value2,...>/>' \
+ format. Mandatory.",
+ metavar="CRITERION_TYPE_FILE",
+ type=argparse.FileType('r'),
+ required=True)
+ argparser.add_argument('--outputfile',
+ help="Criterion types outputfile file. Mandatory.",
+ metavar="CRITERION_TYPE_OUTPUT_FILE",
+ type=argparse.FileType('w'),
+ required=True)
+ argparser.add_argument('--verbose',
+ action='store_true')
+
+ return argparser.parse_args()
+
+
+output_devices_type_value = {}
+input_devices_type_value = {}
+
+def generateXmlCriterionTypesFile(criterionTypes, addressCriteria, criterionTypesFile, outputFile):
+
+ logging.info("Importing criterionTypesFile {}".format(criterionTypesFile))
+ criterion_types_in_tree = ET.parse(criterionTypesFile)
+
+ criterion_types_root = criterion_types_in_tree.getroot()
+
+ for criterion_name, values_dict in criterionTypes.items():
+ for criterion_type in criterion_types_root.findall('criterion_type'):
+ if criterion_type.get('name') == criterion_name:
+ values_node = ET.SubElement(criterion_type, "values")
+ ordered_values = OrderedDict(sorted(values_dict.items(), key=lambda x: x[1]))
+ for key, value in ordered_values.items():
+ value_node = ET.SubElement(values_node, "value")
+ value_node.set('numerical', str(value))
+ value_node.set('literal', key)
+
+ if criterion_type.get('name') == "OutputDevicesMaskType":
+ value_node.set('android_type', output_devices_type_value[key])
+ if criterion_type.get('name') == "InputDevicesMaskType":
+ value_node.set('android_type', input_devices_type_value[key])
+
+ if addressCriteria:
+ for criterion_name, values_list in addressCriteria.items():
+ for criterion_type in criterion_types_root.findall('criterion_type'):
+ if criterion_type.get('name') == criterion_name:
+ index = 0
+ existing_values_node = criterion_type.find("values")
+ if existing_values_node is not None:
+ for existing_value in existing_values_node.findall('value'):
+ if existing_value.get('numerical') == str(1 << index):
+ index += 1
+ values_node = existing_values_node
+ else:
+ values_node = ET.SubElement(criterion_type, "values")
+
+ for value in values_list:
+ value_node = ET.SubElement(values_node, "value", literal=value)
+ value_node.set('numerical', str(1 << index))
+ index += 1
+
+ xmlstr = ET.tostring(criterion_types_root, encoding='utf8', method='xml')
+ reparsed = MINIDOM.parseString(xmlstr)
+ prettyXmlStr = reparsed.toprettyxml(newl='\r\n')
+ prettyXmlStr = os.linesep.join([s for s in prettyXmlStr.splitlines() if s.strip()])
+ outputFile.write(prettyXmlStr)
+
+def capitalizeLine(line):
+ return ' '.join((w.capitalize() for w in line.split(' ')))
+
+
+#
+# Parse the audio policy configuration file and output a dictionary of device criteria addresses
+#
+def parseAndroidAudioPolicyConfigurationFile(audiopolicyconfigurationfile):
+
+ logging.info("Checking Audio Policy Configuration file {}".format(audiopolicyconfigurationfile))
+ #
+ # extract all devices addresses from audio policy configuration file
+ #
+ address_criteria_mapping_table = {
+ 'sink' : "OutputDevicesAddressesType",
+ 'source' : "InputDevicesAddressesType"}
+
+ address_criteria = {
+ 'OutputDevicesAddressesType' : [],
+ 'InputDevicesAddressesType' : []}
+
+ old_working_dir = os.getcwd()
+ print("Current working directory %s" % old_working_dir)
+
+ new_dir = os.path.join(old_working_dir, audiopolicyconfigurationfile.name)
+
+ policy_in_tree = ET.parse(audiopolicyconfigurationfile)
+ os.chdir(os.path.dirname(os.path.normpath(new_dir)))
+
+ print("new working directory %s" % os.getcwd())
+
+ policy_root = policy_in_tree.getroot()
+ EI.include(policy_root)
+
+ os.chdir(old_working_dir)
+
+ for device in policy_root.iter('devicePort'):
+ for key in address_criteria_mapping_table.keys():
+ if device.get('role') == key and device.get('address'):
+ logging.info("{}: <{}>".format(key, device.get('address')))
+ address_criteria[address_criteria_mapping_table[key]].append(device.get('address'))
+
+ for criteria in address_criteria:
+ values = ','.join(address_criteria[criteria])
+ logging.info("{}: <{}>".format(criteria, values))
+
+ return address_criteria
+
+#
+# Parse the audio-base.h file and output a dictionary of android dependent criterion types:
+# -Android Mode
+# -Output devices type
+# -Input devices type
+#
+def parseAndroidAudioFile(androidaudiobaseheaderFile, androidaudiocommonbaseheaderFile):
+ #
+ # Adaptation table between Android Enumeration prefix and Audio PFW Criterion type names
+ #
+ criterion_mapping_table = {
+ 'HAL_AUDIO_MODE' : "AndroidModeType",
+ 'AUDIO_DEVICE_OUT' : "OutputDevicesMaskType",
+ 'AUDIO_DEVICE_IN' : "InputDevicesMaskType"}
+
+ all_criteria = {
+ 'AndroidModeType' : {},
+ 'OutputDevicesMaskType' : {},
+ 'InputDevicesMaskType' : {}}
+
+ #
+ # _CNT, _MAX, _ALL and _NONE are prohibited values as ther are just helpers for enum users.
+ #
+ ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
+
+ multi_bit_outputdevice_shift = 32
+ multi_bit_inputdevice_shift = 32
+
+ criteria_pattern = re.compile(
+ r"\s*V\((?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+ r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
+ r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
+
+ logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
+
+ for line_number, line in enumerate(androidaudiobaseheaderFile):
+ match = criteria_pattern.match(line)
+ if match:
+ logging.debug("The following line is VALID: {}:{}\n{}".format(
+ androidaudiobaseheaderFile.name, line_number, line))
+
+ criterion_name = criterion_mapping_table[match.groupdict()['type']]
+ criterion_literal = ''.join(match.groupdict()['literal'])
+ criterion_numerical_value = match.groupdict()['values']
+
+ if criterion_name == "InputDevicesMaskType":
+ # Remove ambient and in_communication since they were deprecated
+ logging.info("Remove deprecated device {}".format(criterion_literal))
+ if criterion_literal == "AMBIENT" or criterion_literal == "COMMUNICATION":
+ logging.info("Remove deprecated device {}".format(criterion_literal))
+ continue
+ # for AUDIO_DEVICE_IN: rename default to stub
+ elif criterion_literal == "DEFAULT":
+ criterion_numerical_value = str(int("0x40000000", 0))
+ input_devices_type_value[criterion_literal] = "0xC0000000"
+ else:
+ try:
+ string_int = int(criterion_numerical_value, 0)
+ # Append AUDIO_DEVICE_IN for android type tag
+ input_devices_type_value[criterion_literal] = hex(string_int | 2147483648)
+
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+ .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_inputdevice_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_inputdevice_shift += 1
+ criterion_numerical_value = str(string_int)
+
+ except ValueError:
+ # Handle the exception
+ logging.info("value {}:{} for criterion {} is not a number, ignoring"
+ .format(criterion_numerical_value, criterion_literal, criterion_name))
+ continue
+
+ if criterion_name == "OutputDevicesMaskType":
+ if criterion_literal == "DEFAULT":
+ criterion_numerical_value = str(int("0x40000000", 0))
+ output_devices_type_value[criterion_literal] = "0x40000000"
+ else:
+ try:
+ string_int = int(criterion_numerical_value, 0)
+ output_devices_type_value[criterion_literal] = criterion_numerical_value
+
+ num_bits = bin(string_int).count("1")
+ if num_bits > 1:
+ logging.info("The value {}:{} is for criterion {} binary rep {} has {} bits sets"
+ .format(criterion_numerical_value, criterion_literal, criterion_name, bin(string_int), num_bits))
+ string_int = 2**multi_bit_outputdevice_shift
+ logging.info("new val assigned is {} {}" .format(string_int, bin(string_int)))
+ multi_bit_outputdevice_shift += 1
+ criterion_numerical_value = str(string_int)
+
+ except ValueError:
+ # Handle the exception
+ logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+ .format(criterion_numerical_value, criterion_literal, criterion_name))
+ continue
+
+ try:
+ string_int = int(criterion_numerical_value, 0)
+
+ except ValueError:
+ # Handle the exception
+ logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+ .format(criterion_numerical_value, criterion_literal, criterion_name))
+ continue
+
+ # Remove duplicated numerical values
+ if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
+ logging.info("criterion {} duplicated values:".format(criterion_name))
+ logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
+ logging.info("KEEPING LATEST")
+ for key in list(all_criteria[criterion_name]):
+ if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
+ del all_criteria[criterion_name][key]
+
+ all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
+
+ logging.debug("type:{},".format(criterion_name))
+ logging.debug("iteral:{},".format(criterion_literal))
+ logging.debug("values:{}.".format(criterion_numerical_value))
+
+ logging.info("Checking Android Common Header file {}".format(androidaudiocommonbaseheaderFile))
+
+ criteria_pattern = re.compile(
+ r"\s*(?P<type>(?:"+'|'.join(criterion_mapping_table.keys()) + "))_" \
+ r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
+ r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])?[0-9a-fA-F]+|[0-9]+)")
+
+ for line_number, line in enumerate(androidaudiocommonbaseheaderFile):
+ match = criteria_pattern.match(line)
+ if match:
+ logging.debug("The following line is VALID: {}:{}\n{}".format(
+ androidaudiocommonbaseheaderFile.name, line_number, line))
+
+ criterion_name = criterion_mapping_table[match.groupdict()['type']]
+ criterion_literal = ''.join(match.groupdict()['literal'])
+ criterion_numerical_value = match.groupdict()['values']
+
+ try:
+ string_int = int(criterion_numerical_value, 0)
+ except ValueError:
+ # Handle the exception
+ logging.info("The value {}:{} is for criterion {} is not a number, ignoring"
+ .format(criterion_numerical_value, criterion_literal, criterion_name))
+ continue
+
+ # Remove duplicated numerical values
+ if int(criterion_numerical_value, 0) in all_criteria[criterion_name].values():
+ logging.info("criterion {} duplicated values:".format(criterion_name))
+ logging.info("{}:{}".format(criterion_numerical_value, criterion_literal))
+ logging.info("KEEPING LATEST")
+ for key in list(all_criteria[criterion_name]):
+ if all_criteria[criterion_name][key] == int(criterion_numerical_value, 0):
+ del all_criteria[criterion_name][key]
+
+ all_criteria[criterion_name][criterion_literal] = int(criterion_numerical_value, 0)
+
+ logging.debug("type:{},".format(criterion_name))
+ logging.debug("iteral:{},".format(criterion_literal))
+ logging.debug("values:{}.".format(criterion_numerical_value))
+
+ return all_criteria
+
+
+def main():
+ logging.root.setLevel(logging.INFO)
+ args = parseArgs()
+
+ all_criteria = parseAndroidAudioFile(args.androidaudiobaseheader,
+ args.androidaudiocommonbaseheader)
+
+ address_criteria = parseAndroidAudioPolicyConfigurationFile(args.audiopolicyconfigurationfile)
+
+ criterion_types = args.criteriontypes
+
+ generateXmlCriterionTypesFile(all_criteria, address_criteria, criterion_types, args.outputfile)
+
+# If this file is directly executed
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/services/audiopolicy/engineconfigurable/wrapper/Android.bp b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
index 78d5fa3..506b19b 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/Android.bp
+++ b/services/audiopolicy/engineconfigurable/wrapper/Android.bp
@@ -19,10 +19,12 @@
],
header_libs: [
"libaudiofoundation_headers",
+ "libaudiopolicycapengine_config_headers",
"libaudiopolicycommon",
"libbase_headers",
],
shared_libs: [
+ "libaudiopolicyengine_config",
"liblog",
"libmedia_helper",
"libparameter",
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index 099d55d..0bcde8d 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -18,13 +18,13 @@
//#define LOG_NDEBUG 0
#include "ParameterManagerWrapper.h"
+#include <ParameterMgrFullConnector.h>
#include <ParameterMgrPlatformConnector.h>
#include <SelectionCriterionTypeInterface.h>
#include <SelectionCriterionInterface.h>
#include <media/convert.h>
#include <algorithm>
#include <cutils/bitops.h>
-#include <cutils/config_utils.h>
#include <cutils/misc.h>
#include <fstream>
#include <limits>
@@ -64,31 +64,10 @@
namespace audio_policy {
const char *const ParameterManagerWrapper::mPolicyPfwDefaultConfFileName =
- "/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
+ "/etc/parameter-framework/ParameterFrameworkConfigurationCap.xml";
const char *const ParameterManagerWrapper::mPolicyPfwVendorConfFileName =
"/vendor/etc/parameter-framework/ParameterFrameworkConfigurationPolicy.xml";
-static const char *const gInputDeviceCriterionName = "AvailableInputDevices";
-static const char *const gOutputDeviceCriterionName = "AvailableOutputDevices";
-static const char *const gPhoneStateCriterionName = "TelephonyMode";
-static const char *const gOutputDeviceAddressCriterionName = "AvailableOutputDevicesAddresses";
-static const char *const gInputDeviceAddressCriterionName = "AvailableInputDevicesAddresses";
-
-/**
- * Order MUST be align with defintiion of audio_policy_force_use_t within audio_policy.h
- */
-static const char *const gForceUseCriterionTag[AUDIO_POLICY_FORCE_USE_CNT] =
-{
- [AUDIO_POLICY_FORCE_FOR_COMMUNICATION] = "ForceUseForCommunication",
- [AUDIO_POLICY_FORCE_FOR_MEDIA] = "ForceUseForMedia",
- [AUDIO_POLICY_FORCE_FOR_RECORD] = "ForceUseForRecord",
- [AUDIO_POLICY_FORCE_FOR_DOCK] = "ForceUseForDock",
- [AUDIO_POLICY_FORCE_FOR_SYSTEM] = "ForceUseForSystem",
- [AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] = "ForceUseForHdmiSystemAudio",
- [AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND] = "ForceUseForEncodedSurround",
- [AUDIO_POLICY_FORCE_FOR_VIBRATE_RINGING] = "ForceUseForVibrateRinging"
-};
-
template <>
struct ParameterManagerWrapper::parameterManagerElementSupported<ISelectionCriterionInterface> {};
template <>
@@ -100,9 +79,9 @@
{
// Connector
if (access(mPolicyPfwVendorConfFileName, R_OK) == 0) {
- mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwVendorConfFileName);
+ mPfwConnector = new CParameterMgrFullConnector(mPolicyPfwVendorConfFileName);
} else {
- mPfwConnector = new CParameterMgrPlatformConnector(mPolicyPfwDefaultConfFileName);
+ mPfwConnector = new CParameterMgrFullConnector(mPolicyPfwDefaultConfFileName);
}
// Logger
@@ -130,13 +109,13 @@
std::get<2>(pair).c_str(), name.c_str());
criterionType->addValuePair(std::get<0>(pair), std::get<2>(pair), error);
- if (name == gOutputDeviceCriterionName) {
+ if (name == capEngineConfig::gOutputDeviceCriterionName) {
ALOGV("%s: Adding mOutputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
__func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
mOutputDeviceToCriterionTypeMap[androidType] = std::get<0>(pair);
}
- if (name == gInputDeviceCriterionName) {
+ if (name == capEngineConfig::gInputDeviceCriterionName) {
ALOGV("%s: Adding mInputDeviceToCriterionTypeMap %d %" PRIu64" for criterionType %s",
__func__, std::get<1>(pair), std::get<0>(pair), name.c_str());
audio_devices_t androidType = static_cast<audio_devices_t>(std::get<1>(pair));
@@ -207,10 +186,11 @@
status_t ParameterManagerWrapper::setPhoneState(audio_mode_t mode)
{
- ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
+ ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gPhoneStateCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
+ ALOGE("%s: no criterion found for %s", __FUNCTION__,
+ capEngineConfig::gPhoneStateCriterionName);
return BAD_VALUE;
}
if (!isValueValidForCriterion(criterion, static_cast<int>(mode))) {
@@ -223,10 +203,11 @@
audio_mode_t ParameterManagerWrapper::getPhoneState() const
{
- const ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gPhoneStateCriterionName, mPolicyCriteria);
+ const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gPhoneStateCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gPhoneStateCriterionName);
+ ALOGE("%s: no criterion found for %s", __FUNCTION__,
+ capEngineConfig::gPhoneStateCriterionName);
return AUDIO_MODE_NORMAL;
}
return static_cast<audio_mode_t>(criterion->getCriterionState());
@@ -240,10 +221,11 @@
return BAD_VALUE;
}
- ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+ ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gForceUseCriterionTag[usage], mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
+ ALOGE("%s: no criterion found for %s", __FUNCTION__,
+ capEngineConfig::gForceUseCriterionTag[usage]);
return BAD_VALUE;
}
if (!isValueValidForCriterion(criterion, static_cast<int>(config))) {
@@ -260,10 +242,11 @@
if (usage > AUDIO_POLICY_FORCE_USE_CNT) {
return AUDIO_POLICY_FORCE_NONE;
}
- const ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gForceUseCriterionTag[usage], mPolicyCriteria);
+ const ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gForceUseCriterionTag[usage], mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __FUNCTION__, gForceUseCriterionTag[usage]);
+ ALOGE("%s: no criterion found for %s", __FUNCTION__,
+ capEngineConfig::gForceUseCriterionTag[usage]);
return AUDIO_POLICY_FORCE_NONE;
}
return static_cast<audio_policy_forced_cfg_t>(criterion->getCriterionState());
@@ -281,8 +264,8 @@
audio_devices_t type, const std::string &address, audio_policy_dev_state_t state)
{
std::string criterionName = audio_is_output_device(type) ?
- gOutputDeviceAddressCriterionName : gInputDeviceAddressCriterionName;
-
+ capEngineConfig::gOutputDeviceAddressCriterionName :
+ capEngineConfig::gInputDeviceAddressCriterionName;
ALOGV("%s: device with address %s %s", __FUNCTION__, address.c_str(),
state != AUDIO_POLICY_DEVICE_STATE_AVAILABLE? "disconnected" : "connected");
ISelectionCriterionInterface *criterion =
@@ -311,12 +294,12 @@
return NO_ERROR;
}
-status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types)
-{
- ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gInputDeviceCriterionName, mPolicyCriteria);
+status_t ParameterManagerWrapper::setAvailableInputDevices(const DeviceTypeSet &types) {
+ ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gInputDeviceCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __func__, gInputDeviceCriterionName);
+ ALOGE("%s: no criterion found for %s", __func__,
+ capEngineConfig::gInputDeviceCriterionName);
return DEAD_OBJECT;
}
criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
@@ -324,12 +307,12 @@
return NO_ERROR;
}
-status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types)
-{
- ISelectionCriterionInterface *criterion =
- getElement<ISelectionCriterionInterface>(gOutputDeviceCriterionName, mPolicyCriteria);
+status_t ParameterManagerWrapper::setAvailableOutputDevices(const DeviceTypeSet &types) {
+ ISelectionCriterionInterface *criterion = getElement<ISelectionCriterionInterface>(
+ capEngineConfig::gOutputDeviceCriterionName, mPolicyCriteria);
if (criterion == NULL) {
- ALOGE("%s: no criterion found for %s", __func__, gOutputDeviceCriterionName);
+ ALOGE("%s: no criterion found for %s", __func__,
+ capEngineConfig::gOutputDeviceCriterionName);
return DEAD_OBJECT;
}
criterion->setCriterionState(convertDeviceTypesToCriterionValue(types));
@@ -344,21 +327,15 @@
uint64_t ParameterManagerWrapper::convertDeviceTypeToCriterionValue(audio_devices_t type) const {
bool isOut = audio_is_output_devices(type);
- uint32_t typeMask = isOut ? type : (type & ~AUDIO_DEVICE_BIT_IN);
-
const auto &adapters = isOut ? mOutputDeviceToCriterionTypeMap : mInputDeviceToCriterionTypeMap;
- // Only multibit devices need adaptation.
- if (popcount(typeMask) > 1) {
- const auto &adapter = adapters.find(type);
- if (adapter != adapters.end()) {
- ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
- adapter->second);
- return adapter->second;
- }
- ALOGE("%s: failed to find map for multibit device %d", __func__, type);
- return 0;
+ const auto &adapter = adapters.find(type);
+ if (adapter != adapters.end()) {
+ ALOGV("%s: multibit device %d converted to criterion %" PRIu64, __func__, type,
+ adapter->second);
+ return adapter->second;
}
- return typeMask;
+ ALOGE("%s: failed to find map for multibit device %d", __func__, type);
+ return 0;
}
uint64_t ParameterManagerWrapper::convertDeviceTypesToCriterionValue(
@@ -382,5 +359,88 @@
return deviceTypes;
}
+void ParameterManagerWrapper::createDomain(const std::string &domain)
+{
+ std::string error;
+ bool ret = mPfwConnector->createDomain(domain, error);
+ if (!ret) {
+ ALOGD("%s: failed to create domain %s (error=%s)", __func__, domain.c_str(),
+ error.c_str());
+ }
+}
+
+void ParameterManagerWrapper::addConfigurableElementToDomain(const std::string &domain,
+ const std::string &elementPath)
+{
+ std::string error;
+ bool ret = mPfwConnector->addConfigurableElementToDomain(domain, elementPath, error);
+ ALOGE_IF(!ret, "%s: failed to add parameter %s for domain %s (error=%s)",
+ __func__, elementPath.c_str(), domain.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::createConfiguration(const std::string &domain,
+ const std::string &configurationName)
+{
+ std::string error;
+ bool ret = mPfwConnector->createConfiguration(domain, configurationName, error);
+ ALOGE_IF(!ret, "%s: failed to create configuration %s for domain %s (error=%s)",
+ __func__, configurationName.c_str(), domain.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::setApplicationRule(
+ const std::string &domain, const std::string &configurationName, const std::string &rule)
+{
+ std::string error;
+ bool ret = mPfwConnector->setApplicationRule(domain, configurationName, rule, error);
+ ALOGE_IF(!ret, "%s: failed to set rule %s for domain %s and configuration %s (error=%s)",
+ __func__, rule.c_str(), domain.c_str(), configurationName.c_str(), error.c_str());
+}
+
+void ParameterManagerWrapper::accessConfigurationValue(const std::string &domain,
+ const std::string &configurationName, const std::string &elementPath,
+ std::string &value)
+{
+ std::string error;
+ bool ret = mPfwConnector->accessConfigurationValue(domain, configurationName, elementPath,
+ value, /*set=*/ true, error);
+ ALOGE_IF(!ret, "%s: failed to set value %s for parameter %s on domain %s and configuration %s "
+ "(error=%s)", __func__, value.c_str(), elementPath.c_str(), domain.c_str(),
+ configurationName.c_str(), error.c_str());
+}
+
+status_t ParameterManagerWrapper::setConfiguration(
+ const android::capEngineConfig::ParsingResult& capSettings)
+{
+ if (!isStarted()) {
+ return NO_INIT;
+ }
+ std::string error;
+ if (!mPfwConnector->setTuningMode(/* bOn= */ true, error)) {
+ ALOGD("%s: failed to set Tuning Mode error=%s", __FUNCTION__, error.c_str());
+ return DEAD_OBJECT;
+ }
+ for (auto &domain: capSettings.parsedConfig->capConfigurableDomains) {
+ createDomain(domain.name);
+ for (const auto &configurableElementValue : domain.settings[0].configurableElementValues) {
+ addConfigurableElementToDomain(domain.name,
+ configurableElementValue.configurableElement.path);
+ }
+ for (const auto &configuration : domain.configurations) {
+ createConfiguration(domain.name, configuration.name);
+ setApplicationRule(domain.name, configuration.name, configuration.rule);
+ }
+ for (const auto &setting : domain.settings) {
+ for (const auto &configurableElementValue : setting.configurableElementValues) {
+ std::string value = configurableElementValue.value;
+ accessConfigurationValue(domain.name, setting.configurationName,
+ configurableElementValue.configurableElement.path, value);
+ }
+
+ }
+ }
+ mPfwConnector->setTuningMode(/* bOn= */ false, error);
+ return OK;
+}
+
} // namespace audio_policy
} // namespace android
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index fa4ae1e..0c45a60 100644
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -16,6 +16,7 @@
#pragma once
+#include <CapEngineConfig.h>
#include <media/AudioContainers.h>
#include <system/audio.h>
#include <system/audio_policy.h>
@@ -27,7 +28,7 @@
#include <string>
#include <vector>
-class CParameterMgrPlatformConnector;
+class CParameterMgrFullConnector;
class ISelectionCriterionInterface;
struct cnode;
@@ -59,6 +60,9 @@
*/
status_t start(std::string &error);
+ status_t setConfiguration(const android::capEngineConfig::ParsingResult& capSettings);
+
+
/**
* The following API wrap policy action to criteria
*/
@@ -148,6 +152,14 @@
uint64_t criterionValue, bool isOut) const;
private:
+ void createDomain(const std::string &domain);
+ void addConfigurableElementToDomain(const std::string &domain, const std::string &elementPath);
+ void createConfiguration(const std::string &domain, const std::string &configurationName);
+ void setApplicationRule(const std::string &domain, const std::string &configurationName,
+ const std::string &rule);
+ void accessConfigurationValue(const std::string &domain, const std::string &configurationName,
+ const std::string &elementPath, std::string &value);
+
/**
* Apply the configuration of the platform on the policy parameter manager.
* Once all the criteria have been set, the client of the platform state must call
@@ -206,7 +218,7 @@
Criteria mPolicyCriteria; /**< Policy Criterion Map. */
- CParameterMgrPlatformConnector *mPfwConnector; /**< Policy Parameter Manager connector. */
+ CParameterMgrFullConnector *mPfwConnector; /**< Policy Parameter Manager connector. */
ParameterMgrPlatformConnectorLogger *mPfwConnectorLogger; /**< Policy PFW logger. */
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index daef691..7de6939 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -51,7 +51,7 @@
{ "STRATEGY_TRANSMITTED_THROUGH_SPEAKER", STRATEGY_TRANSMITTED_THROUGH_SPEAKER },
{ "STRATEGY_ACCESSIBILITY", STRATEGY_ACCESSIBILITY },
{ "STRATEGY_REROUTING", STRATEGY_REROUTING },
- { "STRATEGY_PATCH", STRATEGY_REROUTING }, // boiler to manage stream patch volume
+ { "STRATEGY_PATCH", STRATEGY_PATCH }, // boiler to manage stream patch volume
{ "STRATEGY_CALL_ASSISTANT", STRATEGY_CALL_ASSISTANT },
};
return legacyStrategy;
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index a6090cf..862b5fd 100644
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -28,20 +28,6 @@
namespace audio_policy
{
-enum legacy_strategy {
- STRATEGY_NONE = -1,
- STRATEGY_MEDIA,
- STRATEGY_PHONE,
- STRATEGY_SONIFICATION,
- STRATEGY_SONIFICATION_RESPECTFUL,
- STRATEGY_DTMF,
- STRATEGY_ENFORCED_AUDIBLE,
- STRATEGY_TRANSMITTED_THROUGH_SPEAKER,
- STRATEGY_ACCESSIBILITY,
- STRATEGY_REROUTING,
- STRATEGY_CALL_ASSISTANT,
-};
-
class Engine : public EngineBase
{
public:
diff --git a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
index fd40c04..a5f37b0 100644
--- a/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
+++ b/services/audiopolicy/fuzzer/audiopolicy_fuzzer.cpp
@@ -266,6 +266,7 @@
bool isSpatialized;
bool isBitPerfect;
float volume;
+ bool muted;
// TODO b/182392769: use attribution source util
AttributionSourceState attributionSource;
@@ -273,7 +274,7 @@
attributionSource.token = sp<BBinder>::make();
if (mManager->getOutputForAttr(&attr, output, AUDIO_SESSION_NONE, &stream, attributionSource,
&config, &flags, selectedDeviceId, portId, {}, &outputType, &isSpatialized,
- &isBitPerfect, &volume) != OK) {
+ &isBitPerfect, &volume, &muted) != OK) {
return false;
}
if (*output == AUDIO_IO_HANDLE_NONE || *portId == AUDIO_PORT_HANDLE_NONE) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 718f958..13db5b3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -123,17 +123,16 @@
}
}
-void AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+status_t AudioPolicyManager::broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
media::DeviceConnectedState state)
{
audio_port_v7 devicePort;
device->toAudioPort(&devicePort);
- if (status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
- status != OK) {
- ALOGE("Error %d while setting connected state %d for device %s",
- status, static_cast<int>(state),
- device->getDeviceTypeAddr().toString(false).c_str());
- }
+ status_t status = mpClientInterface->setDeviceConnectedState(&devicePort, state);
+ ALOGE_IF(status != OK, "Error %d while setting connected state %d for device %s", status,
+ static_cast<int>(state), device->getDeviceTypeAddr().toString(false).c_str());
+
+ return status;
}
status_t AudioPolicyManager::setDeviceConnectionStateInt(
@@ -214,7 +213,14 @@
// Before checking outputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the outputs...)
- broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+ if (broadcastDeviceConnectionState(
+ device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+ mAvailableOutputDevices.remove(device);
+ mHwModules.cleanUpForDevice(device);
+ ALOGE("%s() device %s format %x connection failed", __func__,
+ device->toString().c_str(), device->getEncodedFormat());
+ return INVALID_OPERATION;
+ }
if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
mAvailableOutputDevices.remove(device);
@@ -399,7 +405,14 @@
// Before checking intputs, broadcast connect event to allow HAL to retrieve dynamic
// parameters on newly connected devices (instead of opening the inputs...)
- broadcastDeviceConnectionState(device, media::DeviceConnectedState::CONNECTED);
+ if (broadcastDeviceConnectionState(
+ device, media::DeviceConnectedState::CONNECTED) != NO_ERROR) {
+ mAvailableInputDevices.remove(device);
+ mHwModules.cleanUpForDevice(device);
+ ALOGE("%s() device %s format %x connection failed", __func__,
+ device->toString().c_str(), device->getEncodedFormat());
+ return INVALID_OPERATION;
+ }
// Propagate device availability to Engine
setEngineDeviceConnectionState(device, state);
@@ -1194,8 +1207,7 @@
SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
- if (stream == AUDIO_STREAM_MUSIC &&
- property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+ if (stream == AUDIO_STREAM_MUSIC && mConfig->useDeepBufferForMedia()) {
flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
}
const audio_io_handle_t output = selectOutput(outputs, flags);
@@ -1408,6 +1420,16 @@
(!info->isBitPerfect() || info->getActiveClientCount() == 0)) {
info = nullptr;
}
+
+ if (info != nullptr && info->isBitPerfect() &&
+ (*flags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+ AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)) != 0) {
+ // Reject direct request if a preferred mixer config in use is bit-perfect.
+ ALOGD("%s reject direct request as bit-perfect mixer attributes is active",
+ __func__);
+ return BAD_VALUE;
+ }
+
if (com::android::media::audioserver::
fix_concurrent_playback_behavior_with_bit_perfect_client()) {
if (info != nullptr && info->getUid() == uid &&
@@ -1490,7 +1512,8 @@
output_type_t *outputType,
bool *isSpatialized,
bool *isBitPerfect,
- float *volume)
+ float *volume,
+ bool *muted)
{
// The supplied portId must be AUDIO_PORT_HANDLE_NONE
if (*portId != AUDIO_PORT_HANDLE_NONE) {
@@ -1547,6 +1570,7 @@
outputDesc->addClient(clientDesc);
*volume = Volume::DbToAmpl(outputDesc->getCurVolume(toVolumeSource(resultAttr)));
+ *muted = outputDesc->isMutedByGroup(toVolumeSource(resultAttr));
ALOGV("%s() returns output %d requestedPortId %d selectedDeviceId %d for port ID %d", __func__,
*output, requestedPortId, *selectedDeviceId, *portId);
@@ -1572,6 +1596,13 @@
return NAME_NOT_FOUND;
}
+ // Reject flag combinations that do not make sense. Note that the requested flags might not
+ // have the 'DIRECT' flag set, however once a direct-capable profile is found, it will
+ // combine the requested flags with its own flags, yielding an unsupported combination.
+ if ((flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) != 0) {
+ return NAME_NOT_FOUND;
+ }
+
// Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
// This prevents creating an offloaded track and tearing it down immediately after start
// when audioflinger detects there is an active non offloadable effect.
@@ -1648,14 +1679,19 @@
releaseMsdOutputPatches(devices);
status_t status =
- outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, flags, output,
+ outputDesc->open(config, nullptr /* mixerConfig */, devices, stream, &flags, output,
attributes);
- // only accept an output with the requested parameters
+ // only accept an output with the requested parameters, unless the format can be IEC61937
+ // encapsulated and opened by AudioFlinger as wrapped IEC61937.
+ const bool ignoreRequestedParametersCheck = audio_is_iec61937_compatible(config->format)
+ && (flags & AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO)
+ && audio_has_proportional_frames(outputDesc->getFormat());
if (status != NO_ERROR ||
- (config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
- (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
- (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())) {
+ (!ignoreRequestedParametersCheck &&
+ ((config->sample_rate != 0 && config->sample_rate != outputDesc->getSamplingRate()) ||
+ (config->format != AUDIO_FORMAT_DEFAULT && config->format != outputDesc->getFormat()) ||
+ (config->channel_mask != 0 && config->channel_mask != outputDesc->getChannelMask())))) {
ALOGV("%s failed opening direct output: output %d sample rate %d %d,"
"format %d %d, channel mask %04x %04x", __func__, *output, config->sample_rate,
outputDesc->getSamplingRate(), config->format, outputDesc->getFormat(),
@@ -1675,11 +1711,11 @@
outputDesc->mDirectClientSession = session;
addOutput(*output, outputDesc);
- setOutputDevices(__func__, outputDesc,
- devices,
- true,
- 0,
- NULL);
+ // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+ if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+ hwModule->getHalVersionMajor() >= 3) {
+ setOutputDevices(__func__, outputDesc, devices, true, 0, NULL);
+ }
mPreviousOutputs = mOutputs;
ALOGV("%s returns new direct output %d", __func__, *output);
mpClientInterface->onAudioPortListUpdate();
@@ -1720,8 +1756,7 @@
if (stream != AUDIO_STREAM_MUSIC) {
*flags = (audio_output_flags_t)(*flags &~AUDIO_OUTPUT_FLAG_DEEP_BUFFER);
} else if (/* stream == AUDIO_STREAM_MUSIC && */
- *flags == AUDIO_OUTPUT_FLAG_NONE &&
- property_get_bool("audio.deep_buffer.media", false /* default_value */)) {
+ *flags == AUDIO_OUTPUT_FLAG_NONE && mConfig->useDeepBufferForMedia()) {
// use DEEP_BUFFER as default output for music stream type
*flags = (audio_output_flags_t)AUDIO_OUTPUT_FLAG_DEEP_BUFFER;
}
@@ -2373,11 +2408,15 @@
// If it is first bit-perfect client, reroute all clients that will be routed to
// the bit-perfect sink so that it is guaranteed only bit-perfect stream is active.
PortHandleVector clientsToInvalidate;
+ std::vector<sp<SwAudioOutputDescriptor>> outputsToResetDevice;
for (size_t i = 0; i < mOutputs.size(); i++) {
- if (mOutputs[i] == outputDesc ||
- mOutputs[i]->devices().filter(outputDesc->devices()).isEmpty()) {
+ if (mOutputs[i] == outputDesc || (!mOutputs[i]->devices().isEmpty() &&
+ mOutputs[i]->devices().filter(outputDesc->devices()).isEmpty())) {
continue;
}
+ if (mOutputs[i]->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
+ outputsToResetDevice.push_back(mOutputs[i]);
+ }
for (const auto& c : mOutputs[i]->getClientIterable()) {
clientsToInvalidate.push_back(c->portId());
}
@@ -2387,6 +2426,9 @@
__func__);
mpClientInterface->invalidateTracks(clientsToInvalidate);
}
+ for (const auto& output : outputsToResetDevice) {
+ resetOutputDevice(output, 0 /*delayMs*/, nullptr /*patchHandle*/);
+ }
}
}
}
@@ -2577,8 +2619,7 @@
auto &curves = getVolumeCurves(client->attributes());
if (NO_ERROR != checkAndSetVolume(curves, client->volumeSource(),
curves.getVolumeIndex(outputDesc->devices().types()),
- outputDesc,
- outputDesc->devices().types(), 0 /*delay*/,
+ outputDesc, outputDesc->devices().types(), 0 /*delay*/,
outputDesc->useHwGain() /*force*/)) {
// request AudioService to reinitialize the volume curves asynchronously
ALOGE("checkAndSetVolume failed, requesting volume range init");
@@ -3551,6 +3592,7 @@
status_t AudioPolicyManager::setStreamVolumeIndex(audio_stream_type_t stream,
int index,
+ bool muted,
audio_devices_t device)
{
auto attributes = mEngine->getAttributesForStreamType(stream);
@@ -3560,7 +3602,7 @@
}
ALOGV("%s: stream %s attributes=%s, index %d , device 0x%X", __func__,
toString(stream).c_str(), toString(attributes).c_str(), index, device);
- return setVolumeIndexForAttributes(attributes, index, device);
+ return setVolumeIndexForAttributes(attributes, index, muted, device);
}
status_t AudioPolicyManager::getStreamVolumeIndex(audio_stream_type_t stream,
@@ -3579,6 +3621,7 @@
status_t AudioPolicyManager::setVolumeIndexForAttributes(const audio_attributes_t &attributes,
int index,
+ bool muted,
audio_devices_t device)
{
// Get Volume group matching the Audio Attributes
@@ -3589,6 +3632,11 @@
}
ALOGV("%s: group %d matching with %s index %d",
__FUNCTION__, group, toString(attributes).c_str(), index);
+ if (mEngine->getStreamTypeForAttributes(attributes) == AUDIO_STREAM_PATCH) {
+ ALOGV("%s: cannot change volume for PATCH stream, attrs: %s",
+ __FUNCTION__, toString(attributes).c_str());
+ return NO_ERROR;
+ }
status_t status = NO_ERROR;
IVolumeCurves &curves = getVolumeCurves(attributes);
VolumeSource vs = toVolumeSource(group);
@@ -3598,7 +3646,8 @@
toVolumeSource(AUDIO_STREAM_VOICE_CALL, false) : vs;
product_strategy_t strategy = mEngine->getProductStrategyForAttributes(attributes);
- status = setVolumeCurveIndex(index, device, curves);
+
+ status = setVolumeCurveIndex(index, muted, device, curves);
if (status != NO_ERROR) {
ALOGE("%s failed to set curve index for group %d device 0x%X", __func__, group, device);
return status;
@@ -3660,8 +3709,9 @@
// HW Gain management, do not change the volume
if (desc->useHwGain()) {
applyVolume = false;
+ bool swMute = com_android_media_audio_ring_my_car() ? curves.isMuted() : (index == 0);
// If the volume source is active with higher priority source, ensure at least Sw Muted
- desc->setSwMute((index == 0), vs, curves.getStreamTypes(), curDevices, 0 /*delayMs*/);
+ desc->setSwMute(swMute, vs, curves.getStreamTypes(), curDevices, 0 /*delayMs*/);
for (const auto &productStrategy : mEngine->getOrderedProductStrategies()) {
auto activeClients = desc->clientsList(true /*activeOnly*/, productStrategy,
false /*preferredDevice*/);
@@ -3699,8 +3749,7 @@
//FIXME: workaround for truncated touch sounds
// delayed volume change for system stream to be removed when the problem is
// handled by system UI
- status_t volStatus = checkAndSetVolume(
- curves, vs, index, desc, curDevices,
+ status_t volStatus = checkAndSetVolume(curves, vs, index, desc, curDevices,
((vs == toVolumeSource(AUDIO_STREAM_SYSTEM, false))?
TOUCH_SOUND_FIXED_DELAY_MS : 0));
if (volStatus != NO_ERROR) {
@@ -3729,6 +3778,7 @@
}
status_t AudioPolicyManager::setVolumeCurveIndex(int index,
+ bool muted,
audio_devices_t device,
IVolumeCurves &volumeCurves)
{
@@ -3748,8 +3798,9 @@
// Force max volume if stream cannot be muted
if (!volumeCurves.canBeMuted()) index = volumeCurves.getVolumeIndexMax();
- ALOGV("%s device %08x, index %d", __FUNCTION__ , device, index);
+ ALOGV("%s device %08x, index %d, muted %d", __FUNCTION__ , device, index, muted);
volumeCurves.addCurrentVolumeIndex(device, index);
+ volumeCurves.setIsMuted(muted);
return NO_ERROR;
}
@@ -4374,8 +4425,9 @@
// As done in setDeviceConnectionState, we could also fix default device issue by
// preventing the force re-routing in case of default dev that distinguishes on address.
// Let's give back to engine full device choice decision however.
- bool forceRouting = !newDevices.isEmpty();
- if (outputDesc->mPreferredAttrInfo != nullptr && newDevices != outputDesc->devices()) {
+ bool newDevicesNotEmpty = !newDevices.isEmpty();
+ if (outputDesc->mPreferredAttrInfo != nullptr && newDevices != outputDesc->devices()
+ && newDevicesNotEmpty) {
// If the device is using preferred mixer attributes, the output need to reopen
// with default configuration when the new selected devices are different from
// current routing devices.
@@ -4383,9 +4435,10 @@
continue;
}
- waitMs = setOutputDevices(__func__, outputDesc, newDevices, forceRouting, delayMs,
- nullptr, !skipDelays /*requiresMuteCheck*/,
- !forceRouting /*requiresVolumeCheck*/, skipDelays);
+ waitMs = setOutputDevices(__func__, outputDesc, newDevices,
+ newDevicesNotEmpty /*force*/, delayMs,
+ nullptr /*patchHandle*/, !skipDelays /*requiresMuteCheck*/,
+ !newDevicesNotEmpty /*requiresVolumeCheck*/, skipDelays);
// Only apply special touch sound delay once
delayMs = 0;
}
@@ -4496,6 +4549,9 @@
"Engine could not set preferred devices %s for audio source %d role %d",
dumpAudioDeviceTypeAddrVector(devices).c_str(), audioSource, role);
+ if (status == NO_ERROR) {
+ updateInputRouting();
+ }
return status;
}
@@ -4827,6 +4883,17 @@
flags = (audio_output_flags_t)((flags & relevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);
DeviceVector engineOutputDevices = mEngine->getOutputDevicesForAttributes(*attr);
+ if (std::any_of(engineOutputDevices.begin(), engineOutputDevices.end(),
+ [this, attr](sp<DeviceDescriptor> device) {
+ return getPreferredMixerAttributesInfo(
+ device->getId(),
+ mEngine->getProductStrategyForAttributes(*attr),
+ true /*activeBitPerfectPreferred*/) != nullptr;
+ })) {
+ // Bit-perfect playback is active on one of the selected devices, direct output will
+ // be rejected at this instant.
+ return AUDIO_DIRECT_NOT_SUPPORTED;
+ }
for (const auto& hwModule : mHwModules) {
DeviceVector outputDevices = engineOutputDevices;
// the MSD module checks for different conditions and output devices
@@ -6106,7 +6173,8 @@
audio_devices_t deviceType = device->type();
// Enabling/disabling formats are applied to only HDMI devices. So, this function
// returns formats reported by HDMI devices.
- if (deviceType != AUDIO_DEVICE_OUT_HDMI) {
+ if (deviceType != AUDIO_DEVICE_OUT_HDMI &&
+ deviceType != AUDIO_DEVICE_OUT_HDMI_ARC && deviceType != AUDIO_DEVICE_OUT_HDMI_EARC) {
continue;
}
// Formats reported by sink devices
@@ -6175,13 +6243,13 @@
sp<SwAudioOutputDescriptor> outputDesc;
bool profileUpdated = false;
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromType(
- AUDIO_DEVICE_OUT_HDMI);
+ DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypes(
+ {AUDIO_DEVICE_OUT_HDMI, AUDIO_DEVICE_OUT_HDMI_ARC, AUDIO_DEVICE_OUT_HDMI_EARC});
for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
// Simulate reconnection to update enabled surround sound formats.
String8 address = String8(hdmiOutputDevices[i]->address().c_str());
std::string name = hdmiOutputDevices[i]->getName();
- status_t status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ status_t status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
address.c_str(),
name.c_str(),
@@ -6189,7 +6257,7 @@
if (status != NO_ERROR) {
continue;
}
- status = setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_HDMI,
+ status = setDeviceConnectionStateInt(hdmiOutputDevices[i]->type(),
AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
address.c_str(),
name.c_str(),
@@ -6727,11 +6795,12 @@
sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(outProfile,
mpClientInterface);
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
+ audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
status_t status = outputDesc->open(nullptr /* halConfig */, nullptr /* mixerConfig */,
DeviceVector(supportedDevice),
AUDIO_STREAM_DEFAULT,
- AUDIO_OUTPUT_FLAG_NONE, &output, attributes);
+ &flags, &output, attributes);
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for devices %s on hw module %s",
supportedDevice->toString().c_str(), hwModule->getName());
@@ -7840,7 +7909,8 @@
}
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
- setVolumeSourceMute(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/, DeviceTypeSet());
+ setVolumeSourceMutedInternally(ttsVolumeSource, mute/*on*/, desc, 0 /*delay*/,
+ DeviceTypeSet());
const uint32_t latency = desc->latency() * 2;
if (desc->isActive(latency * 2) && latency > maxLatency) {
maxLatency = latency;
@@ -7934,9 +8004,10 @@
for (const auto &activeVs : outputDesc->getActiveVolumeSources()) {
// make sure that we do not start the temporary mute period too early in case of
// delayed device change
- setVolumeSourceMute(activeVs, true, outputDesc, delayMs);
- setVolumeSourceMute(activeVs, false, outputDesc, delayMs + tempMuteDurationMs,
- devices.types());
+ setVolumeSourceMutedInternally(activeVs, true, outputDesc, delayMs);
+ setVolumeSourceMutedInternally(activeVs, false, outputDesc,
+ delayMs + tempMuteDurationMs,
+ devices.types());
}
}
@@ -8101,9 +8172,21 @@
if (result.source == AUDIO_SOURCE_HOTWORD && !inputDesc->isSoundTrigger()) {
result.source = AUDIO_SOURCE_VOICE_RECOGNITION;
}
- return result; }).
+ return result; });
//only one input device for now
- addSource(device);
+ if (audio_is_remote_submix_device(device->type())) {
+ // remote submix HAL does not support audio conversion, need source device
+ // audio config to match the sink input descriptor audio config, otherwise AIDL
+ // HAL patching will fail
+ audio_port_config srcDevicePortConfig = {};
+ device->toAudioPortConfig(&srcDevicePortConfig, nullptr);
+ srcDevicePortConfig.sample_rate = inputDesc->getSamplingRate();
+ srcDevicePortConfig.channel_mask = inputDesc->getChannelMask();
+ srcDevicePortConfig.format = inputDesc->getFormat();
+ patchBuilder.addSource(srcDevicePortConfig);
+ } else {
+ patchBuilder.addSource(device);
+ }
status = installPatch(__func__, patchHandle, inputDesc.get(), patchBuilder.patch(), 0);
}
}
@@ -8151,6 +8234,9 @@
for (;;) {
sp<IOProfile> firstInexact = nullptr;
+ uint32_t inexactSamplingRate = 0;
+ audio_format_t inexactFormat = AUDIO_FORMAT_INVALID;
+ audio_channel_mask_t inexactChannelMask = AUDIO_CHANNEL_INVALID;
uint32_t updatedSamplingRate = 0;
audio_format_t updatedFormat = AUDIO_FORMAT_INVALID;
audio_channel_mask_t updatedChannelMask = AUDIO_CHANNEL_INVALID;
@@ -8188,14 +8274,17 @@
false /*exactMatchRequiredForInputFlags*/)
!= IOProfile::NO_MATCH) {
firstInexact = profile;
+ inexactSamplingRate = updatedSamplingRate;
+ inexactFormat = updatedFormat;
+ inexactChannelMask = updatedChannelMask;
}
}
}
if (firstInexact != nullptr) {
- samplingRate = updatedSamplingRate;
- format = updatedFormat;
- channelMask = updatedChannelMask;
+ samplingRate = inexactSamplingRate;
+ format = inexactFormat;
+ channelMask = inexactChannelMask;
return firstInexact;
} else if (flags & AUDIO_INPUT_FLAG_RAW) {
flags = (audio_input_flags_t) (flags & ~AUDIO_INPUT_FLAG_RAW); // retry
@@ -8427,8 +8516,11 @@
int delayMs,
bool force)
{
+ // APM is single threaded, and single instance.
+ static std::set<IVolumeCurves*> invalidCurvesReported;
+
// do not change actual attributes volume if the attributes is muted
- if (outputDesc->isMuted(volumeSource)) {
+ if (!com_android_media_audio_ring_my_car() && outputDesc->isMutedInternally(volumeSource)) {
ALOGVV("%s: volume source %d muted count %d active=%d", __func__, volumeSource,
outputDesc->getMuteCount(volumeSource), outputDesc->isActive(volumeSource));
return NO_ERROR;
@@ -8451,19 +8543,32 @@
}
if (curves.getVolumeIndexMin() < 0 || curves.getVolumeIndexMax() < 0) {
- ALOGE("invalid volume index range");
+ if (!invalidCurvesReported.count(&curves)) {
+ invalidCurvesReported.insert(&curves);
+ String8 dump;
+ curves.dump(&dump);
+ ALOGE("invalid volume index range in the curve:\n%s", dump.c_str());
+ }
return BAD_VALUE;
}
float volumeDb = computeVolume(curves, volumeSource, index, deviceTypes);
+ const VolumeSource dtmfVolSrc = toVolumeSource(AUDIO_STREAM_DTMF, false);
if (outputDesc->isFixedVolume(deviceTypes) ||
// Force VoIP volume to max for bluetooth SCO/BLE device except if muted
- (index != 0 && (isVoiceVolSrc || isBtScoVolSrc) &&
+ (index != 0 && (isVoiceVolSrc || isBtScoVolSrc
+ || (isInCall() && (dtmfVolSrc == volumeSource))) &&
(isSingleDeviceType(deviceTypes, audio_is_bluetooth_out_sco_device)
|| isSingleDeviceType(deviceTypes, audio_is_ble_out_device)))) {
volumeDb = 0.0f;
}
- const bool muted = (index == 0) && (volumeDb != 0.0f);
+
+ bool muted;
+ if (!com_android_media_audio_ring_my_car()) {
+ muted = (index == 0) && (volumeDb != 0.0f);
+ } else {
+ muted = curves.isMuted();
+ }
outputDesc->setVolume(volumeDb, muted, volumeSource, curves.getStreamTypes(),
deviceTypes, delayMs, force, isVoiceVolSrc);
@@ -8478,6 +8583,11 @@
void AudioPolicyManager::setVoiceVolume(
int index, IVolumeCurves &curves, bool voiceVolumeManagedByHost, int delayMs) {
float voiceVolume;
+
+ if (com_android_media_audio_ring_my_car() && curves.isMuted()) {
+ index = 0;
+ }
+
// Force voice volume to max or mute for Bluetooth SCO/BLE as other attenuations are managed
// by the headset
if (voiceVolumeManagedByHost) {
@@ -8531,8 +8641,7 @@
ALOGVV("applyStreamVolumes() for device %s", dumpDeviceTypes(deviceTypes).c_str());
for (const auto &volumeGroup : mEngine->getVolumeGroups()) {
auto &curves = getVolumeCurves(toVolumeSource(volumeGroup));
- checkAndSetVolume(curves, toVolumeSource(volumeGroup),
- curves.getVolumeIndex(deviceTypes),
+ checkAndSetVolume(curves, toVolumeSource(volumeGroup), curves.getVolumeIndex(deviceTypes),
outputDesc, deviceTypes, delayMs, force);
}
}
@@ -8555,23 +8664,23 @@
}
}
for (auto source : sourcesToMute) {
- setVolumeSourceMute(source, on, outputDesc, delayMs, deviceTypes);
+ setVolumeSourceMutedInternally(source, on, outputDesc, delayMs, deviceTypes);
}
}
-void AudioPolicyManager::setVolumeSourceMute(VolumeSource volumeSource,
- bool on,
- const sp<AudioOutputDescriptor>& outputDesc,
- int delayMs,
- DeviceTypeSet deviceTypes)
+void AudioPolicyManager::setVolumeSourceMutedInternally(VolumeSource volumeSource,
+ bool on,
+ const sp<AudioOutputDescriptor>& outputDesc,
+ int delayMs,
+ DeviceTypeSet deviceTypes)
{
if (deviceTypes.empty()) {
deviceTypes = outputDesc->devices().types();
}
auto &curves = getVolumeCurves(volumeSource);
if (on) {
- if (!outputDesc->isMuted(volumeSource)) {
+ if (!outputDesc->isMutedInternally(volumeSource)) {
if (curves.canBeMuted() &&
(volumeSource != toVolumeSource(AUDIO_STREAM_ENFORCED_AUDIBLE, false) ||
(mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) ==
@@ -8583,7 +8692,7 @@
// ignored
outputDesc->incMuteCount(volumeSource);
} else {
- if (!outputDesc->isMuted(volumeSource)) {
+ if (!outputDesc->isMutedInternally(volumeSource)) {
ALOGV("%s unmuting non muted attributes!", __func__);
return;
}
@@ -8820,6 +8929,8 @@
mReportedFormatsMap[devDesc] = formats;
if (devDesc->type() == AUDIO_DEVICE_OUT_HDMI ||
+ devDesc->type() == AUDIO_DEVICE_OUT_HDMI_ARC ||
+ devDesc->type() == AUDIO_DEVICE_OUT_HDMI_EARC ||
isDeviceOfModule(devDesc,AUDIO_HARDWARE_MODULE_ID_MSD)) {
modifySurroundFormats(devDesc, &formats);
size_t modifiedNumProfiles = 0;
@@ -8954,7 +9065,7 @@
audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
audio_attributes_t attributes = AUDIO_ATTRIBUTES_INITIALIZER;
status_t status = desc->open(halConfig, mixerConfig, devices,
- AUDIO_STREAM_DEFAULT, flags, &output, attributes);
+ AUDIO_STREAM_DEFAULT, &flags, &output, attributes);
if (status != NO_ERROR) {
ALOGE("%s failed to open output %d", __func__, status);
return nullptr;
@@ -8992,7 +9103,7 @@
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
- status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, flags, &output,
+ status = desc->open(&config, mixerConfig, devices, AUDIO_STREAM_DEFAULT, &flags, &output,
attributes);
if (status != NO_ERROR) {
return nullptr;
@@ -9000,11 +9111,11 @@
}
addOutput(output, desc);
- setOutputDevices(__func__, desc,
- devices,
- true,
- 0,
- NULL);
+ // The version check is essentially to avoid making this call in the case of the HIDL HAL.
+ if (auto hwModule = mHwModules.getModuleFromHandle(mPrimaryModuleHandle); hwModule &&
+ hwModule->getHalVersionMajor() >= 3) {
+ setOutputDevices(__func__, desc, devices, true, 0, NULL);
+ }
sp<DeviceDescriptor> speaker = mAvailableOutputDevices.getDevice(
AUDIO_DEVICE_OUT_SPEAKER, String8(""), AUDIO_FORMAT_DEFAULT);
@@ -9055,6 +9166,13 @@
status_t AudioPolicyManager::getDevicesForAttributes(
const audio_attributes_t &attr, DeviceVector &devices, bool forVolume) {
+ // attr containing source set by AudioAttributes.Builder.setCapturePreset() has precedence
+ // over any usage or content type also present in attr.
+ if (com::android::media::audioserver::enable_audio_input_device_routing() &&
+ attr.source != AUDIO_SOURCE_INVALID) {
+ return getInputDevicesForAttributes(attr, devices);
+ }
+
// Devices are determined in the following precedence:
//
// 1) Devices associated with a dynamic policy matching the attributes. This is often
@@ -9118,6 +9236,15 @@
return NO_ERROR;
}
+status_t AudioPolicyManager::getInputDevicesForAttributes(
+ const audio_attributes_t &attr, DeviceVector &devices) {
+ devices = DeviceVector(
+ mEngine->getInputDeviceForAttributes(attr, 0 /*uid unknown here*/,
+ AUDIO_SESSION_NONE,
+ nullptr /* mix */));
+ return NO_ERROR;
+}
+
status_t AudioPolicyManager::getProfilesForDevices(const DeviceVector& devices,
AudioProfileVector& audioProfiles,
uint32_t flags,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 4736980..20f7b12 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -129,7 +129,8 @@
output_type_t *outputType,
bool *isSpatialized,
bool *isBitPerfect,
- float *volume) override;
+ float *volume,
+ bool *muted) override;
virtual status_t startOutput(audio_port_handle_t portId);
virtual status_t stopOutput(audio_port_handle_t portId);
virtual bool releaseOutput(audio_port_handle_t portId);
@@ -169,6 +170,7 @@
virtual void initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
virtual status_t setStreamVolumeIndex(audio_stream_type_t stream,
int index,
+ bool muted,
audio_devices_t device);
virtual status_t getStreamVolumeIndex(audio_stream_type_t stream,
int *index,
@@ -176,6 +178,7 @@
virtual status_t setVolumeIndexForAttributes(const audio_attributes_t &attr,
int index,
+ bool muted,
audio_devices_t device);
virtual status_t getVolumeIndexForAttributes(const audio_attributes_t &attr,
int &index,
@@ -185,6 +188,7 @@
virtual status_t getMinVolumeIndexForAttributes(const audio_attributes_t &attr, int &index);
status_t setVolumeCurveIndex(int index,
+ bool muted,
audio_devices_t device,
IVolumeCurves &volumeCurves);
@@ -650,7 +654,8 @@
DeviceTypeSet deviceTypes = DeviceTypeSet());
/**
- * @brief setVolumeSourceMute Mute or unmute the volume source on the specified output
+ * @brief setVolumeSourceMutedInternally Mute or unmute the volume source on the specified
+ * output
* @param volumeSource to be muted/unmute (may host legacy streams or by extension set of
* audio attributes)
* @param on true to mute, false to umute
@@ -658,11 +663,11 @@
* @param delayMs
* @param device
*/
- void setVolumeSourceMute(VolumeSource volumeSource,
- bool on,
- const sp<AudioOutputDescriptor>& outputDesc,
- int delayMs = 0,
- DeviceTypeSet deviceTypes = DeviceTypeSet());
+ void setVolumeSourceMutedInternally(VolumeSource volumeSource,
+ bool on,
+ const sp<AudioOutputDescriptor>& outputDesc,
+ int delayMs = 0,
+ DeviceTypeSet deviceTypes = DeviceTypeSet());
audio_mode_t getPhoneState();
@@ -1109,8 +1114,8 @@
// It can give a chance to HAL implementer to retrieve dynamic capabilities associated
// to this device for example.
// TODO avoid opening stream to retrieve capabilities of a profile.
- void broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
- media::DeviceConnectedState state);
+ status_t broadcastDeviceConnectionState(const sp<DeviceDescriptor> &device,
+ media::DeviceConnectedState state);
// updates device caching and output for streams that can influence the
// routing of notifications
@@ -1366,6 +1371,11 @@
DeviceVector &devices,
bool forVolume);
+ // A helper method used by getDevicesForAttributes to retrieve input devices when
+ // capture preset is available in the given audio attributes parameter.
+ status_t getInputDevicesForAttributes(const audio_attributes_t &attr,
+ DeviceVector &devices);
+
status_t getProfilesForDevices(const DeviceVector& devices,
AudioProfileVector& audioProfiles,
uint32_t flags,
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 9a5365c..3ed247b 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -56,7 +56,7 @@
audio_config_base_t *mixerConfig,
const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_attributes_t attributes)
{
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
@@ -74,7 +74,7 @@
request.mixerConfig = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_config_base_t_AudioConfigBase(*mixerConfig, false /*isInput*/));
request.device = VALUE_OR_RETURN_STATUS(legacy2aidl_DeviceDescriptorBase(device));
- request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(flags));
+ request.flags = VALUE_OR_RETURN_STATUS(legacy2aidl_audio_output_flags_t_int32_t_mask(*flags));
request.attributes = VALUE_OR_RETURN_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attributes));
@@ -89,7 +89,9 @@
.channel_mask = halConfig->channel_mask,
.format = halConfig->format,
};
- mAudioPolicyService->registerOutput(*output, config, flags);
+ *flags = VALUE_OR_RETURN_STATUS(
+ aidl2legacy_int32_t_audio_output_flags_t_mask(response.flags));
+ mAudioPolicyService->registerOutput(*output, config, *flags);
}
return status;
}
@@ -184,21 +186,19 @@
}
status_t AudioPolicyService::AudioPolicyClient::setStreamVolume(audio_stream_type_t stream,
- float volume, audio_io_handle_t output,
- int delay_ms)
+ float volume, bool muted, audio_io_handle_t output, int delay_ms)
{
- return mAudioPolicyService->setStreamVolume(stream, volume, output,
- delay_ms);
+ return mAudioPolicyService->setStreamVolume(stream, volume, muted, output, delay_ms);
}
status_t AudioPolicyService::AudioPolicyClient::setPortsVolume(
- const std::vector<audio_port_handle_t> &ports, float volume, audio_io_handle_t output,
- int delayMs)
+ const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+ audio_io_handle_t output, int delayMs)
{
if (ports.empty()) {
return NO_ERROR;
}
- return mAudioPolicyService->setPortsVolume(ports, volume, output, delayMs);
+ return mAudioPolicyService->setPortsVolume(ports, volume, muted, output, delayMs);
}
void AudioPolicyService::AudioPolicyClient::setParameters(audio_io_handle_t io_handle,
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index bb41d00..8fbe1cc 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -79,6 +79,8 @@
using media::audio::common::AudioFormatDescription;
using media::audio::common::AudioMode;
using media::audio::common::AudioOffloadInfo;
+using media::audio::common::AudioPolicyForceUse;
+using media::audio::common::AudioPolicyForcedConfig;
using media::audio::common::AudioSource;
using media::audio::common::AudioStreamType;
using media::audio::common::AudioUsage;
@@ -86,6 +88,10 @@
using media::audio::common::Int;
constexpr int kDefaultVirtualDeviceId = 0;
+namespace {
+constexpr auto PERMISSION_HARD_DENIED = permission::PermissionChecker::PERMISSION_HARD_DENIED;
+constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
+}
const std::vector<audio_usage_t>& SYSTEM_USAGES = {
AUDIO_USAGE_CALL_ASSISTANT,
@@ -284,8 +290,8 @@
return Status::ok();
}
-Status AudioPolicyService::setForceUse(media::AudioPolicyForceUse usageAidl,
- media::AudioPolicyForcedConfig configAidl)
+Status AudioPolicyService::setForceUse(AudioPolicyForceUse usageAidl,
+ AudioPolicyForcedConfig configAidl)
{
audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -316,8 +322,8 @@
return Status::ok();
}
-Status AudioPolicyService::getForceUse(media::AudioPolicyForceUse usageAidl,
- media::AudioPolicyForcedConfig* _aidl_return) {
+Status AudioPolicyService::getForceUse(AudioPolicyForceUse usageAidl,
+ AudioPolicyForcedConfig* _aidl_return) {
audio_policy_force_use_t usage = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioPolicyForceUse_audio_policy_force_use_t(usageAidl));
@@ -424,6 +430,7 @@
bool isSpatialized = false;
bool isBitPerfect = false;
float volume;
+ bool muted;
status_t result = mAudioPolicyManager->getOutputForAttr(&attr, &output, session,
&stream,
attributionSource,
@@ -433,7 +440,8 @@
&outputType,
&isSpatialized,
&isBitPerfect,
- &volume);
+ &volume,
+ &muted);
// FIXME: Introduce a way to check for the the telephony device before opening the output
if (result == NO_ERROR) {
@@ -498,6 +506,7 @@
_aidl_return->attr = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_attributes_t_AudioAttributes(attr));
_aidl_return->volume = volume;
+ _aidl_return->muted = muted;
} else {
_aidl_return->configBase.format = VALUE_OR_RETURN_BINDER_STATUS(
legacy2aidl_audio_format_t_AudioFormatDescription(config.format));
@@ -900,13 +909,13 @@
std::stringstream msg;
msg << "Audio recording on session " << client->session;
+ const auto permitted = startRecording(client->attributionSource, client->virtualDeviceId,
+ String16(msg.str().c_str()), client->attributes.source);
// check calling permissions
- if (!(startRecording(client->attributionSource, client->virtualDeviceId,
- String16(msg.str().c_str()), client->attributes.source)
- || client->attributes.source == AUDIO_SOURCE_FM_TUNER
- || client->attributes.source == AUDIO_SOURCE_REMOTE_SUBMIX
- || client->attributes.source == AUDIO_SOURCE_ECHO_REFERENCE)) {
+ if (permitted == PERMISSION_HARD_DENIED && client->attributes.source != AUDIO_SOURCE_FM_TUNER
+ && client->attributes.source != AUDIO_SOURCE_REMOTE_SUBMIX
+ && client->attributes.source != AUDIO_SOURCE_ECHO_REFERENCE) {
ALOGE("%s permission denied: recording not allowed for attribution source %s",
__func__, client->attributionSource.toString().c_str());
return binderStatusFromStatusT(PERMISSION_DENIED);
@@ -926,13 +935,17 @@
return binderStatusFromStatusT(INVALID_OPERATION);
}
- // Force the possibly silenced client to be unsilenced since we just called
- // startRecording (i.e. we have assumed it is unsilenced).
- // At this point in time, the client is inactive, so no calls to appops are sent in
- // setAppState_l.
- // This ensures existing clients have the same behavior as new clients (starting unsilenced).
+ // Force the possibly silenced client to match the state on the appops side
+ // following the call to startRecording (i.e. unsilenced iff call succeeded)
+ // At this point in time, the client is inactive, so no calls to appops are
+ // sent in setAppState_l. This ensures existing clients have the same
+ // behavior as new clients.
// TODO(b/282076713)
- setAppState_l(client, APP_STATE_TOP);
+ if (permitted == PERMISSION_GRANTED) {
+ setAppState_l(client, APP_STATE_TOP);
+ } else {
+ setAppState_l(client, APP_STATE_IDLE);
+ }
client->active = true;
client->startTimeNs = systemTime();
@@ -1018,8 +1031,10 @@
client->active = false;
client->startTimeNs = 0;
updateUidStates_l();
- finishRecording(client->attributionSource, client->virtualDeviceId,
- client->attributes.source);
+ if (!client->silenced) {
+ finishRecording(client->attributionSource, client->virtualDeviceId,
+ client->attributes.source);
+ }
}
return binderStatusFromStatusT(status);
@@ -1048,7 +1063,11 @@
updateUidStates_l();
// finish the recording app op
- finishRecording(client->attributionSource, client->virtualDeviceId, client->attributes.source);
+ if (!client->silenced) {
+ finishRecording(client->attributionSource, client->virtualDeviceId,
+ client->attributes.source);
+ }
+
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->stopInput(portId));
}
@@ -1154,7 +1173,7 @@
Status AudioPolicyService::setStreamVolumeIndex(AudioStreamType streamAidl,
const AudioDeviceDescription& deviceAidl,
- int32_t indexAidl) {
+ int32_t indexAidl, bool muted) {
audio_stream_type_t stream = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioStreamType_audio_stream_type_t(streamAidl));
int index = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int>(indexAidl));
@@ -1176,6 +1195,7 @@
AutoCallerClear acc;
return binderStatusFromStatusT(mAudioPolicyManager->setStreamVolumeIndex(stream,
index,
+ muted,
device));
}
@@ -1204,7 +1224,7 @@
Status AudioPolicyService::setVolumeIndexForAttributes(
const media::audio::common::AudioAttributes& attrAidl,
- const AudioDeviceDescription& deviceAidl, int32_t indexAidl) {
+ const AudioDeviceDescription& deviceAidl, int32_t indexAidl, bool muted) {
audio_attributes_t attributes = VALUE_OR_RETURN_BINDER_STATUS(
aidl2legacy_AudioAttributes_audio_attributes_t(attrAidl));
int index = VALUE_OR_RETURN_BINDER_STATUS(convertIntegral<int>(indexAidl));
@@ -1224,7 +1244,7 @@
audio_utils::lock_guard _l(mMutex);
AutoCallerClear acc;
return binderStatusFromStatusT(
- mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, device));
+ mAudioPolicyManager->setVolumeIndexForAttributes(attributes, index, muted, device));
}
Status AudioPolicyService::getVolumeIndexForAttributes(
@@ -1671,6 +1691,19 @@
return Status::ok();
}
+template <typename Port>
+void anonymizePortBluetoothAddress(Port& port) {
+ if (port.type != AUDIO_PORT_TYPE_DEVICE) {
+ return;
+ }
+ if (!(audio_is_a2dp_device(port.ext.device.type)
+ || audio_is_ble_device(port.ext.device.type)
+ || audio_is_bluetooth_sco_device(port.ext.device.type)
+ || audio_is_hearing_aid_out_device(port.ext.device.type))) {
+ return;
+ }
+ anonymizeBluetoothAddress(port.ext.device.address);
+}
Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
media::AudioPortType typeAidl, Int* count,
@@ -1689,14 +1722,27 @@
std::unique_ptr<audio_port_v7[]> ports(new audio_port_v7[num_ports]);
unsigned int generation;
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
+ const AttributionSourceState attributionSource = getCallingAttributionSource();
AutoCallerClear acc;
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
- mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
- numPortsReq = std::min(numPortsReq, num_ports);
+ {
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ // AudioPolicyManager->listAudioPorts makes a deep copy of port structs into ports
+ // so it is safe to access after releasing the mutex
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->listAudioPorts(
+ role, type, &num_ports, ports.get(), &generation)));
+ numPortsReq = std::min(numPortsReq, num_ports);
+ }
+
+ if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+ for (size_t i = 0; i < numPortsReq; ++i) {
+ anonymizePortBluetoothAddress(ports[i]);
+ }
+ }
+
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
legacy2aidl_audio_port_v7_AudioPortFw)));
@@ -1719,12 +1765,24 @@
Status AudioPolicyService::getAudioPort(int portId,
media::AudioPortFw* _aidl_return) {
audio_port_v7 port{ .id = portId };
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
+
+ const AttributionSourceState attributionSource = getCallingAttributionSource();
AutoCallerClear acc;
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+
+ {
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ // AudioPolicyManager->getAudioPort makes a deep copy of the port struct into port
+ // so it is safe to access after releasing the mutex
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
+ }
+
+ if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+ anonymizePortBluetoothAddress(port);
+ }
+
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
return Status::ok();
}
@@ -1786,14 +1844,32 @@
std::unique_ptr<audio_patch[]> patches(new audio_patch[num_patches]);
unsigned int generation;
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
+ const AttributionSourceState attributionSource = getCallingAttributionSource();
AutoCallerClear acc;
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
- mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
- numPatchesReq = std::min(numPatchesReq, num_patches);
+
+ {
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
+ }
+ // AudioPolicyManager->listAudioPatches makes a deep copy of patches structs into patches
+ // so it is safe to access after releasing the mutex
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
+ numPatchesReq = std::min(numPatchesReq, num_patches);
+ }
+
+ if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
+ for (size_t i = 0; i < numPatchesReq; ++i) {
+ for (size_t j = 0; j < patches[i].num_sources; ++j) {
+ anonymizePortBluetoothAddress(patches[i].sources[j]);
+ }
+ for (size_t j = 0; j < patches[i].num_sinks; ++j) {
+ anonymizePortBluetoothAddress(patches[i].sinks[j]);
+ }
+ }
+ }
+
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(patches.get(), patches.get() + numPatchesReq,
std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 29a3f8a..290a036 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -61,6 +61,10 @@
static const String16 sManageAudioPolicyPermission("android.permission.MANAGE_AUDIO_POLICY");
+namespace {
+constexpr auto PERMISSION_GRANTED = permission::PermissionChecker::PERMISSION_GRANTED;
+}
+
// Creates an association between Binder code to name for IAudioPolicyService.
#define IAUDIOPOLICYSERVICE_BINDER_METHOD_MACRO_LIST \
BINDER_METHOD_ENTRY(onNewAudioModulesAvailable) \
@@ -193,9 +197,7 @@
media::AudioPolicyConfig apmConfig;
if (status_t status = clientInterface->getAudioPolicyConfig(&apmConfig); status == OK) {
auto config = AudioPolicyConfig::loadFromApmAidlConfigWithFallback(apmConfig);
- LOG_ALWAYS_FATAL_IF(config->getEngineLibraryNameSuffix() !=
- AudioPolicyConfig::kDefaultEngineLibraryNameSuffix,
- "Only default engine is currently supported with the AIDL HAL");
+ ALOGD("%s loading APM engine %s", __func__, config->getEngineLibraryNameSuffix().c_str());
apm = new AudioPolicyManager(config,
loadApmEngineLibraryAndCreateEngine(
config->getEngineLibraryNameSuffix(), apmConfig.engineConfig),
@@ -1221,9 +1223,10 @@
} else {
std::stringstream msg;
msg << "Audio recording un-silenced on session " << client->session;
- if (!startRecording(client->attributionSource, client->virtualDeviceId,
- String16(msg.str().c_str()), client->attributes.source)) {
- silenced = true;
+ if (startRecording(client->attributionSource, client->virtualDeviceId,
+ String16(msg.str().c_str()), client->attributes.source)
+ != PERMISSION_GRANTED) {
+ return;
}
}
}
@@ -1807,6 +1810,7 @@
++numTimesBecameEmpty;
}
mLastCommand = command;
+ status_t createAudioPatchStatus;
switch (command->mCommand) {
case SET_VOLUME: {
@@ -1816,6 +1820,7 @@
ul.unlock();
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
+ data->mIsMuted,
data->mIO);
ul.lock();
}break;
@@ -1826,6 +1831,7 @@
ul.unlock();
command->mStatus = AudioSystem::setPortsVolume(data->mPorts,
data->mVolume,
+ data->mMuted,
data->mIO);
ul.lock();
} break;
@@ -1874,10 +1880,11 @@
ALOGV("AudioCommandThread() processing create audio patch");
sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
if (af == 0) {
- command->mStatus = PERMISSION_DENIED;
+ createAudioPatchStatus = PERMISSION_DENIED;
} else {
ul.unlock();
- command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+ createAudioPatchStatus = af->createAudioPatch(&data->mPatch,
+ &data->mHandle);
ul.lock();
}
} break;
@@ -2046,8 +2053,28 @@
{
audio_utils::lock_guard _l(command->mMutex);
if (command->mWaitStatus) {
+ if (command->mCommand == CREATE_AUDIO_PATCH) {
+ command->mStatus = createAudioPatchStatus;
+ }
command->mWaitStatus = false;
command->mCond.notify_one();
+ } else if (command->mCommand == CREATE_AUDIO_PATCH &&
+ command->mStatus == TIMED_OUT &&
+ createAudioPatchStatus == NO_ERROR) {
+ // Because of special handling in insertCommand_l() the CREATE_AUDIO_PATCH
+ // command wait status can be only false in case timeout (see TIMED_OUT)
+ // happened.
+ CreateAudioPatchData *createData =
+ (CreateAudioPatchData *)command->mParam.get();
+ ALOGW("AudioCommandThread() no caller awaiting for handle(%d) after \
+ processing create audio patch, going to release it",
+ createData->mHandle);
+ sp<AudioCommand> releaseCommand = new AudioCommand();
+ releaseCommand->mCommand = RELEASE_AUDIO_PATCH;
+ ReleaseAudioPatchData *releaseData = new ReleaseAudioPatchData();
+ releaseData->mHandle = createData->mHandle;
+ releaseCommand->mParam = releaseData;
+ insertCommand_l(releaseCommand, 0);
}
}
waitTime = -1;
@@ -2125,6 +2152,7 @@
status_t AudioPolicyService::AudioCommandThread::volumeCommand(audio_stream_type_t stream,
float volume,
+ bool muted,
audio_io_handle_t output,
int delayMs)
{
@@ -2133,6 +2161,7 @@
sp<VolumeData> data = new VolumeData();
data->mStream = stream;
data->mVolume = volume;
+ data->mIsMuted = muted;
data->mIO = output;
command->mParam = data;
command->mWaitStatus = true;
@@ -2142,14 +2171,15 @@
}
status_t AudioPolicyService::AudioCommandThread::volumePortsCommand(
- const std::vector<audio_port_handle_t> &ports, float volume, audio_io_handle_t output,
- int delayMs)
+ const std::vector<audio_port_handle_t> &ports, float volume, bool muted,
+ audio_io_handle_t output, int delayMs)
{
sp<AudioCommand> command = new AudioCommand();
command->mCommand = SET_PORTS_VOLUME;
sp<VolumePortsData> data = new VolumePortsData();
data->mPorts = ports;
data->mVolume = volume;
+ data->mMuted = muted;
data->mIO = output;
command->mParam = data;
command->mWaitStatus = true;
@@ -2607,7 +2637,8 @@
// Disable wait for status if delay is not 0.
// Except for create audio patch command because the returned patch handle
- // is needed by audio policy manager
+ // is needed by audio policy manager. Audio patch created after timeout
+ // (see TIMED_OUT) will be released from threadLoop().
if (delayMs != 0 && command->mCommand != CREATE_AUDIO_PATCH) {
command->mWaitStatus = false;
}
@@ -2652,17 +2683,18 @@
int AudioPolicyService::setStreamVolume(audio_stream_type_t stream,
float volume,
+ bool muted,
audio_io_handle_t output,
int delayMs)
{
- return (int)mAudioCommandThread->volumeCommand(stream, volume,
+ return (int)mAudioCommandThread->volumeCommand(stream, volume, muted,
output, delayMs);
}
int AudioPolicyService::setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
- audio_io_handle_t output, int delayMs)
+ bool muted, audio_io_handle_t output, int delayMs)
{
- return (int)mAudioCommandThread->volumePortsCommand(ports, volume, output, delayMs);
+ return (int)mAudioCommandThread->volumePortsCommand(ports, volume, muted, output, delayMs);
}
int AudioPolicyService::setVoiceVolume(float volume, int delayMs)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d5d4f97..2ce82c0 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -106,10 +106,10 @@
const std::string& deviceName,
const AudioFormatDescription& encodedFormat) override;
binder::Status setPhoneState(AudioMode state, int32_t uid) override;
- binder::Status setForceUse(media::AudioPolicyForceUse usage,
- media::AudioPolicyForcedConfig config) override;
- binder::Status getForceUse(media::AudioPolicyForceUse usage,
- media::AudioPolicyForcedConfig* _aidl_return) override;
+ binder::Status setForceUse(android::media::audio::common::AudioPolicyForceUse usage,
+ android::media::audio::common::AudioPolicyForcedConfig config) override;
+ binder::Status getForceUse(android::media::audio::common::AudioPolicyForceUse usage,
+ android::media::audio::common::AudioPolicyForcedConfig* _aidl_return) override;
binder::Status getOutput(AudioStreamType stream, int32_t* _aidl_return) override;
binder::Status getOutputForAttr(const media::audio::common::AudioAttributes& attr,
int32_t session,
@@ -136,13 +136,13 @@
int32_t indexMax) override;
binder::Status setStreamVolumeIndex(AudioStreamType stream,
const AudioDeviceDescription& device,
- int32_t index) override;
+ int32_t index, bool muted) override;
binder::Status getStreamVolumeIndex(AudioStreamType stream,
const AudioDeviceDescription& device,
int32_t* _aidl_return) override;
binder::Status setVolumeIndexForAttributes(const media::audio::common::AudioAttributes& attr,
const AudioDeviceDescription& device,
- int32_t index) override;
+ int32_t index, bool muted) override;
binder::Status getVolumeIndexForAttributes(const media::audio::common::AudioAttributes& attr,
const AudioDeviceDescription& device,
int32_t* _aidl_return) override;
@@ -353,6 +353,7 @@
virtual status_t setStreamVolume(audio_stream_type_t stream,
float volume,
+ bool muted,
audio_io_handle_t output,
int delayMs = 0);
@@ -364,12 +365,13 @@
*
* @param ports to consider
* @param volume to set
+ * @param muted to set
* @param output to consider
* @param delayMs to use
* @return NO_ERROR if successful
*/
virtual status_t setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
- audio_io_handle_t output, int delayMs = 0);
+ bool muted, audio_io_handle_t output, int delayMs = 0);
virtual status_t setVoiceVolume(float volume, int delayMs = 0);
void doOnNewAudioModulesAvailable();
@@ -625,10 +627,10 @@
virtual bool threadLoop();
void exit();
- status_t volumeCommand(audio_stream_type_t stream, float volume,
+ status_t volumeCommand(audio_stream_type_t stream, float volume, bool muted,
audio_io_handle_t output, int delayMs = 0);
status_t volumePortsCommand(const std::vector<audio_port_handle_t> &ports,
- float volume, audio_io_handle_t output, int delayMs = 0);
+ float volume, bool muted, audio_io_handle_t output, int delayMs = 0);
status_t parametersCommand(audio_io_handle_t ioHandle,
const char *keyValuePairs, int delayMs = 0);
status_t voiceVolumeCommand(float volume, int delayMs = 0);
@@ -700,6 +702,7 @@
public:
audio_stream_type_t mStream;
float mVolume;
+ bool mIsMuted;
audio_io_handle_t mIO;
};
@@ -707,13 +710,15 @@
public:
std::vector<audio_port_handle_t> mPorts;
float mVolume;
+ bool mMuted;
audio_io_handle_t mIO;
std::string dumpPorts() {
- return std::string("volume ") + std::to_string(mVolume) + " on IO " +
- std::to_string(mIO) + " and ports " +
- std::accumulate(std::begin(mPorts), std::end(mPorts), std::string{},
- [] (const std::string& ls, int rs) {
- return ls + std::to_string(rs) + " "; });
+ return std::string("volume ") + std::to_string(mVolume) + std::string("muted ") +
+ std::to_string(mMuted) + " on IO " + std::to_string(mIO) + " and ports " +
+ std::accumulate(std::begin(mPorts), std::end(mPorts), std::string{},
+ [](const std::string &ls, int rs) {
+ return ls + std::to_string(rs) + " ";
+ });
}
};
@@ -823,7 +828,7 @@
audio_config_base_t *mixerConfig,
const sp<DeviceDescriptorBase>& device,
uint32_t *latencyMs,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_attributes_t attributes);
// creates a special output that is duplicated to the two outputs passed as arguments. The duplication is performed by
// a special mixer thread in the AudioFlinger.
@@ -854,9 +859,10 @@
// misc control functions
//
- // set a stream volume for a particular output. For the same user setting, a given stream type can have different volumes
- // for each output (destination device) it is attached to.
- virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, audio_io_handle_t output, int delayMs = 0);
+ // set a stream volume for a particular output. For the same user setting, a given stream
+ // type can have different volumes for each output (destination device) it is attached to.
+ virtual status_t setStreamVolume(audio_stream_type_t stream, float volume, bool muted,
+ audio_io_handle_t output, int delayMs = 0);
/**
* Set a volume on port(s) for a particular output. For the same user setting, a volume
* group (and associated given port of the client's track) can have different volumes for
@@ -864,12 +870,13 @@
*
* @param ports to consider
* @param volume to set
+ * @param muted to set
* @param output to consider
* @param delayMs to use
* @return NO_ERROR if successful
*/
status_t setPortsVolume(const std::vector<audio_port_handle_t> &ports, float volume,
- audio_io_handle_t output, int delayMs = 0) override;
+ bool muted, audio_io_handle_t output, int delayMs = 0) override;
// function enabling to send proprietary informations directly from audio policy manager to audio hardware interface.
virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0);
diff --git a/services/audiopolicy/service/SpatializerPoseController.cpp b/services/audiopolicy/service/SpatializerPoseController.cpp
index 874bde4..368dde0 100644
--- a/services/audiopolicy/service/SpatializerPoseController.cpp
+++ b/services/audiopolicy/service/SpatializerPoseController.cpp
@@ -22,6 +22,7 @@
#define LOG_TAG "SpatializerPoseController"
//#define LOG_NDEBUG 0
+#include <audio_utils/mutex.h>
#include <cutils/properties.h>
#include <sensor/Sensor.h>
#include <media/MediaMetricsItem.h>
@@ -131,20 +132,22 @@
Pose3f headToStage;
std::optional<HeadTrackingMode> modeIfChanged;
{
- std::unique_lock lock(mMutex);
- if (maxUpdatePeriod.has_value()) {
- mCondVar.wait_for(lock, maxUpdatePeriod.value(),
- [this] { return mShouldExit || mShouldCalculate; });
- } else {
- mCondVar.wait(lock, [this] { return mShouldExit || mShouldCalculate; });
+ audio_utils::unique_lock ul(mMutex);
+ while (true) {
+ if (mShouldExit) {
+ ALOGV("Exiting thread");
+ return;
+ }
+ if (mShouldCalculate) {
+ std::tie(headToStage, modeIfChanged) = calculate_l();
+ break;
+ }
+ if (maxUpdatePeriod.has_value()) {
+ mCondVar.wait_for(ul, maxUpdatePeriod.value());
+ } else {
+ mCondVar.wait(ul);
+ }
}
- if (mShouldExit) {
- ALOGV("Exiting thread");
- return;
- }
-
- // Calculate.
- std::tie(headToStage, modeIfChanged) = calculate_l();
}
// Invoke the callbacks outside the lock.
@@ -173,7 +176,7 @@
SpatializerPoseController::~SpatializerPoseController() {
{
- std::unique_lock lock(mMutex);
+ std::lock_guard lock(mMutex);
mShouldExit = true;
mCondVar.notify_all();
}
@@ -278,8 +281,10 @@
}
void SpatializerPoseController::waitUntilCalculated() {
- std::unique_lock lock(mMutex);
- mCondVar.wait(lock, [this] { return mCalculated; });
+ audio_utils::unique_lock ul(mMutex);
+ while (!mCalculated) {
+ mCondVar.wait(ul);
+ }
}
std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>>
@@ -358,14 +363,15 @@
}
}
-std::string SpatializerPoseController::toString(unsigned level) const {
+std::string SpatializerPoseController::toString(unsigned level) const NO_THREAD_SAFETY_ANALYSIS {
std::string prefixSpace(level, ' ');
std::string ss = prefixSpace + "SpatializerPoseController:\n";
bool needUnlock = false;
prefixSpace += ' ';
auto now = std::chrono::steady_clock::now();
- if (!mMutex.try_lock_until(now + media::kSpatializerDumpSysTimeOutInSecond)) {
+ if (!audio_utils::std_mutex_timed_lock(mMutex, std::chrono::nanoseconds(
+ media::kSpatializerDumpSysTimeOutInSecond).count())) {
ss.append(prefixSpace).append("try_lock failed, dumpsys maybe INACCURATE!\n");
} else {
needUnlock = true;
diff --git a/services/audiopolicy/service/SpatializerPoseController.h b/services/audiopolicy/service/SpatializerPoseController.h
index 7fa4f86..9955cd8 100644
--- a/services/audiopolicy/service/SpatializerPoseController.h
+++ b/services/audiopolicy/service/SpatializerPoseController.h
@@ -118,34 +118,34 @@
std::string toString(unsigned level) const;
private:
- mutable std::timed_mutex mMutex;
+ mutable std::mutex mMutex;
Listener* const mListener;
const std::chrono::microseconds mSensorPeriod;
- std::unique_ptr<media::HeadTrackingProcessor> mProcessor;
- int32_t mHeadSensor = media::SensorPoseProvider::INVALID_HANDLE;
- int32_t mScreenSensor = media::SensorPoseProvider::INVALID_HANDLE;
- std::optional<media::HeadTrackingMode> mActualMode;
- std::condition_variable_any mCondVar;
- bool mShouldCalculate = true;
- bool mShouldExit = false;
- bool mCalculated = false;
+ std::unique_ptr<media::HeadTrackingProcessor> mProcessor GUARDED_BY(mMutex);
+ int32_t mHeadSensor GUARDED_BY(mMutex) = media::SensorPoseProvider::INVALID_HANDLE;
+ int32_t mScreenSensor GUARDED_BY(mMutex) = media::SensorPoseProvider::INVALID_HANDLE;
+ std::optional<media::HeadTrackingMode> mActualMode GUARDED_BY(mMutex);
+ std::condition_variable mCondVar GUARDED_BY(mMutex);
+ bool mShouldCalculate GUARDED_BY(mMutex) = true;
+ bool mShouldExit GUARDED_BY(mMutex) = false;
+ bool mCalculated GUARDED_BY(mMutex) = false;
- media::VectorRecorder mHeadSensorRecorder{
+ media::VectorRecorder mHeadSensorRecorder GUARDED_BY(mMutex) {
8 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */,
{ 3, 6, 7 } /* delimiterIdx */};
- media::VectorRecorder mHeadSensorDurableRecorder{
+ media::VectorRecorder mHeadSensorDurableRecorder GUARDED_BY(mMutex) {
8 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */,
{ 3, 6, 7 } /* delimiterIdx */};
- media::VectorRecorder mScreenSensorRecorder{
+ media::VectorRecorder mScreenSensorRecorder GUARDED_BY(mMutex) {
4 /* vectorSize */, std::chrono::seconds(1), 10 /* maxLogLine */,
{ 3 } /* delimiterIdx */};
- media::VectorRecorder mScreenSensorDurableRecorder{
+ media::VectorRecorder mScreenSensorDurableRecorder GUARDED_BY(mMutex) {
4 /* vectorSize */, std::chrono::minutes(1), 10 /* maxLogLine */,
{ 3 } /* delimiterIdx */};
// Next to last variable as releasing this stops the callbacks
- std::unique_ptr<media::SensorPoseProvider> mPoseProvider;
+ std::unique_ptr<media::SensorPoseProvider> mPoseProvider GUARDED_BY(mMutex);
// It's important that mThread is the last variable in this class
// since we starts mThread in initializer list
@@ -158,7 +158,8 @@
* Calculates the new outputs and updates internal state. Must be called with the lock held.
* Returns values that should be passed to the respective callbacks.
*/
- std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l();
+ std::tuple<media::Pose3f, std::optional<media::HeadTrackingMode>> calculate_l()
+ REQUIRES(mMutex);
};
} // namespace android
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index c600fb6..182dc61 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -29,7 +29,6 @@
"libbase",
"libbinder",
"libcutils",
- "libcutils",
"libhidlbase",
"liblog",
"libmedia_helper",
@@ -41,6 +40,7 @@
static_libs: [
"android.media.audiopolicy-aconfig-cc",
"audioclient-types-aidl-cpp",
+ "com.android.media.audio-aconfig-cc",
"com.android.media.audioserver-aconfig-cc",
"libaudiopolicycomponents",
"libflagtest",
@@ -53,7 +53,10 @@
"libaudiopolicymanager_interface_headers",
],
- srcs: ["audiopolicymanager_tests.cpp"],
+ srcs: [
+ "audiopolicymanager_tests.cpp",
+ "test_execution_tracer.cpp",
+ ],
data: [":audiopolicytest_configuration_files"],
diff --git a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
index 45643f7..79c25ab 100644
--- a/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyManagerTestClient.h
@@ -17,6 +17,7 @@
#include <map>
#include <set>
+#include <media/TypeConverter.h>
#include <system/audio.h>
#include <utils/Log.h>
#include <utils/String8.h>
@@ -37,11 +38,11 @@
status_t openOutput(audio_module_handle_t module,
audio_io_handle_t *output,
- audio_config_t * /*halConfig*/,
- audio_config_base_t * /*mixerConfig*/,
+ audio_config_t *halConfig,
+ audio_config_base_t *mixerConfig,
const sp<DeviceDescriptorBase>& /*device*/,
uint32_t * /*latencyMs*/,
- audio_output_flags_t /*flags*/,
+ audio_output_flags_t *flags,
audio_attributes_t /*attributes*/) override {
if (module >= mNextModuleHandle) {
ALOGE("%s: Module handle %d has not been allocated yet (next is %d)",
@@ -49,6 +50,13 @@
return BAD_VALUE;
}
*output = mNextIoHandle++;
+ mOpenedOutputs[*output] = *flags;
+ ALOGD("%s: opened output %d: HAL(%s %s %d) Mixer(%s %s %d) %s", __func__, *output,
+ audio_channel_out_mask_to_string(halConfig->channel_mask),
+ audio_format_to_string(halConfig->format), halConfig->sample_rate,
+ audio_channel_out_mask_to_string(mixerConfig->channel_mask),
+ audio_format_to_string(mixerConfig->format), mixerConfig->sample_rate,
+ android::toString(*flags).c_str());
return NO_ERROR;
}
@@ -58,6 +66,16 @@
return id;
}
+ status_t closeOutput(audio_io_handle_t output) override {
+ if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+ mOpenedOutputs.erase(iter);
+ return NO_ERROR;
+ } else {
+ ALOGE("%s: Unknown output %d", __func__, output);
+ return BAD_VALUE;
+ }
+ }
+
status_t openInput(audio_module_handle_t module,
audio_io_handle_t *input,
audio_config_t * /*config*/,
@@ -276,6 +294,13 @@
return mOpenInputCallsCount;
}
+ std::optional<audio_output_flags_t> getOpenOutputFlags(audio_io_handle_t output) const {
+ if (auto iter = mOpenedOutputs.find(output); iter != mOpenedOutputs.end()) {
+ return iter->second;
+ }
+ return std::nullopt;
+ }
+
private:
audio_module_handle_t mNextModuleHandle = AUDIO_MODULE_HANDLE_NONE + 1;
audio_io_handle_t mNextIoHandle = AUDIO_IO_HANDLE_NONE + 1;
@@ -292,6 +317,7 @@
std::set<audio_io_handle_t> mOpenedInputs;
size_t mOpenInputCallsCount = 0;
size_t mCloseInputCallsCount = 0;
+ std::map<audio_io_handle_t, audio_output_flags_t> mOpenedOutputs;
};
} // namespace android
diff --git a/services/audiopolicy/tests/AudioPolicyTestClient.h b/services/audiopolicy/tests/AudioPolicyTestClient.h
index 6f63721..5290da2 100644
--- a/services/audiopolicy/tests/AudioPolicyTestClient.h
+++ b/services/audiopolicy/tests/AudioPolicyTestClient.h
@@ -37,7 +37,7 @@
audio_config_base_t* /*mixerConfig*/,
const sp<DeviceDescriptorBase>& /*device*/,
uint32_t* /*latencyMs*/,
- audio_output_flags_t /*flags*/,
+ audio_output_flags_t* /*flags*/,
audio_attributes_t /*attributes*/) override { return NO_INIT; }
audio_io_handle_t openDuplicateOutput(audio_io_handle_t /*output1*/,
audio_io_handle_t /*output2*/) override {
@@ -56,11 +56,13 @@
status_t closeInput(audio_io_handle_t /*input*/) override { return NO_INIT; }
status_t setStreamVolume(audio_stream_type_t /*stream*/,
float /*volume*/,
+ bool /*muted*/,
audio_io_handle_t /*output*/,
int /*delayMs*/) override { return NO_INIT; }
- status_t setPortsVolume(const std::vector<audio_port_handle_t>& /*ports*/, float /*volume*/,
- audio_io_handle_t /*output*/, int /*delayMs*/) override { return NO_INIT; }
+ status_t setPortsVolume(const std::vector<audio_port_handle_t> & /*ports*/, float /*volume*/,
+ bool /*muted*/, audio_io_handle_t /*output*/,
+ int /*delayMs*/) override { return NO_INIT; }
void setParameters(audio_io_handle_t /*ioHandle*/,
const String8& /*keyValuePairs*/,
diff --git a/services/audiopolicy/tests/AudioPolicyTestManager.h b/services/audiopolicy/tests/AudioPolicyTestManager.h
index 34ceeab..e30882c 100644
--- a/services/audiopolicy/tests/AudioPolicyTestManager.h
+++ b/services/audiopolicy/tests/AudioPolicyTestManager.h
@@ -24,9 +24,11 @@
explicit AudioPolicyTestManager(AudioPolicyClientInterface *clientInterface)
: AudioPolicyTestManager(AudioPolicyConfig::createDefault(), clientInterface) {}
AudioPolicyTestManager(const sp<const AudioPolicyConfig>& config,
- AudioPolicyClientInterface *clientInterface)
+ AudioPolicyClientInterface *clientInterface,
+ std::string engineConfig = "")
: AudioPolicyManager(config,
- loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix()),
+ loadApmEngineLibraryAndCreateEngine(config->getEngineLibraryNameSuffix(),
+ engineConfig),
clientInterface) {}
using AudioPolicyManager::getConfig;
using AudioPolicyManager::initialize;
@@ -44,6 +46,7 @@
using AudioPolicyManager::setDeviceConnectionState;
using AudioPolicyManager::deviceToAudioPort;
using AudioPolicyManager::handleDeviceConfigChange;
+ using AudioPolicyManager::getInputProfile;
uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
HwModuleCollection getHwModules() const { return mHwModules; }
};
diff --git a/services/audiopolicy/tests/audiopolicymanager_tests.cpp b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
index 43b451f..d83a277 100644
--- a/services/audiopolicy/tests/audiopolicymanager_tests.cpp
+++ b/services/audiopolicy/tests/audiopolicymanager_tests.cpp
@@ -35,6 +35,7 @@
#include <media/AudioPolicy.h>
#include <media/PatchBuilder.h>
#include <media/RecordingActivityTracker.h>
+#include <media/TypeConverter.h>
#include <utils/Log.h>
#include <utils/Vector.h>
#include <cutils/multiuser.h>
@@ -43,6 +44,7 @@
#include "AudioPolicyManagerTestClient.h"
#include "AudioPolicyTestClient.h"
#include "AudioPolicyTestManager.h"
+#include "test_execution_tracer.h"
using namespace android;
using testing::UnorderedElementsAre;
@@ -175,6 +177,11 @@
};
class AudioPolicyManagerTest : public testing::Test {
+ public:
+ constexpr static uint32_t k384000SamplingRate = 384000;
+ constexpr static uint32_t k48000SamplingRate = 48000;
+ constexpr static uint32_t k96000SamplingRate = 96000;
+
protected:
void SetUp() override;
void TearDown() override;
@@ -191,7 +198,7 @@
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
audio_io_handle_t *output = nullptr,
audio_port_handle_t *portId = nullptr,
- audio_attributes_t attr = {},
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER,
audio_session_t session = AUDIO_SESSION_NONE,
int uid = 0,
bool* isBitPerfect = nullptr);
@@ -222,13 +229,16 @@
std::unique_ptr<AudioPolicyManagerTestClient> mClient;
std::unique_ptr<AudioPolicyTestManager> mManager;
- constexpr static const uint32_t k48000SamplingRate = 48000;
+ static const std::string sTestEngineConfig;
};
+const std::string AudioPolicyManagerTest::sTestEngineConfig =
+ base::GetExecutableDirectory() + "/engine/test_audio_policy_engine_configuration.xml";
+
void AudioPolicyManagerTest::SetUp() {
mClient.reset(getClient());
ASSERT_NO_FATAL_FAILURE(SetUpManagerConfig()); // Subclasses may want to customize the config.
- mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get()));
+ mManager.reset(new AudioPolicyTestManager(mConfig, mClient.get(), sTestEngineConfig));
ASSERT_EQ(NO_ERROR, mManager->initialize());
ASSERT_EQ(NO_ERROR, mManager->initCheck());
}
@@ -300,11 +310,13 @@
bool isSpatialized;
bool isBitPerfectInternal;
float volume;
+ bool muted;
AttributionSourceState attributionSource = createAttributionSourceState(uid);
ASSERT_EQ(OK, mManager->getOutputForAttr(
&attr, output, session, &stream, attributionSource, &config, &flags,
selectedDeviceId, portId, {}, &outputType, &isSpatialized,
- isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect, &volume));
+ isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect, &volume,
+ &muted));
ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
}
@@ -490,6 +502,9 @@
void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
// TODO: Consider using Serializer to load part of the config from a string.
ASSERT_NO_FATAL_FAILURE(AudioPolicyManagerTest::SetUpManagerConfig());
+ mConfig->getHwModules().getModuleFromName(
+ AUDIO_HARDWARE_MODULE_ID_PRIMARY)->setHalVersion(3, 0);
+
mMsdOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_BUS);
sp<AudioProfile> pcmOutputProfile = new AudioProfile(
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, k48000SamplingRate);
@@ -521,7 +536,7 @@
addOutputProfile(spdifOutputProfile);
}
- sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
+ sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 3 /*halVersionMajor*/);
HwModuleCollection modules = mConfig->getHwModules();
modules.add(msdModule);
mConfig->setHwModules(modules);
@@ -783,27 +798,27 @@
audio_config_base_t directConfig = AUDIO_CONFIG_BASE_INITIALIZER;
directConfig.format = AUDIO_FORMAT_DTS;
- directConfig.sample_rate = 48000;
+ directConfig.sample_rate = k48000SamplingRate;
directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_base_t nonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
- nonDirectConfig.sample_rate = 48000;
+ nonDirectConfig.sample_rate = k48000SamplingRate;
nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_base_t nonExistentConfig = AUDIO_CONFIG_BASE_INITIALIZER;
nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
- nonExistentConfig.sample_rate = 48000;
+ nonExistentConfig.sample_rate = k48000SamplingRate;
nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_base_t msdDirectConfig1 = AUDIO_CONFIG_BASE_INITIALIZER;
msdDirectConfig1.format = AUDIO_FORMAT_AC3;
- msdDirectConfig1.sample_rate = 48000;
+ msdDirectConfig1.sample_rate = k48000SamplingRate;
msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_base_t msdDirectConfig2 = AUDIO_CONFIG_BASE_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
- msdDirectConfig2.sample_rate = 48000;
+ msdDirectConfig2.sample_rate = k48000SamplingRate;
msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_base_t msdNonDirectConfig = AUDIO_CONFIG_BASE_INITIALIZER;
@@ -850,27 +865,27 @@
audio_config_t directConfig = AUDIO_CONFIG_INITIALIZER;
directConfig.format = AUDIO_FORMAT_DTS;
- directConfig.sample_rate = 48000;
+ directConfig.sample_rate = k48000SamplingRate;
directConfig.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_t nonDirectConfig = AUDIO_CONFIG_INITIALIZER;
nonDirectConfig.format = AUDIO_FORMAT_PCM_16_BIT;
- nonDirectConfig.sample_rate = 48000;
+ nonDirectConfig.sample_rate = k48000SamplingRate;
nonDirectConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_t nonExistentConfig = AUDIO_CONFIG_INITIALIZER;
nonExistentConfig.format = AUDIO_FORMAT_E_AC3;
- nonExistentConfig.sample_rate = 48000;
+ nonExistentConfig.sample_rate = k48000SamplingRate;
nonExistentConfig.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
audio_config_t msdDirectConfig1 = AUDIO_CONFIG_INITIALIZER;
msdDirectConfig1.format = AUDIO_FORMAT_AC3;
- msdDirectConfig1.sample_rate = 48000;
+ msdDirectConfig1.sample_rate = k48000SamplingRate;
msdDirectConfig1.channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
audio_config_t msdDirectConfig2 = AUDIO_CONFIG_INITIALIZER;
msdDirectConfig2.format = AUDIO_FORMAT_IEC60958;
- msdDirectConfig2.sample_rate = 48000;
+ msdDirectConfig2.sample_rate = k48000SamplingRate;
msdDirectConfig2.channel_mask = AUDIO_CHANNEL_INDEX_MASK_24;
audio_config_t msdNonDirectConfig = AUDIO_CONFIG_INITIALIZER;
@@ -1126,12 +1141,12 @@
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
AUDIO_SESSION_NONE, uid);
status_t status = mManager->startOutput(portId);
if (status == DEAD_OBJECT) {
getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
- 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
+ k48000SamplingRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
AUDIO_SESSION_NONE, uid);
status = mManager->startOutput(portId);
}
@@ -1172,9 +1187,9 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
AttributionSourceState attributionSource = createAttributionSourceState(/*uid=*/ 0);
audio_config_base_t requestedConfig = {
+ .sample_rate = k48000SamplingRate,
.channel_mask = AUDIO_CHANNEL_IN_STEREO,
.format = AUDIO_FORMAT_PCM_16_BIT,
- .sample_rate = 48000
};
audio_config_base_t config = requestedConfig;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -1234,6 +1249,33 @@
EXPECT_EQ(streamCountBefore, mClient->getOpenedInputsCount());
}
+TEST_F(AudioPolicyManagerTestWithConfigurationFile, UpdateConfigFromInexactProfile) {
+ const audio_format_t expectedFormat = AUDIO_FORMAT_PCM_16_BIT;
+ const uint32_t expectedSampleRate = 48000;
+ const audio_channel_mask_t expectedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+ const std::string expectedIOProfile = "primary input";
+
+ auto devices = mManager->getAvailableInputDevices();
+ sp<DeviceDescriptor> mic = nullptr;
+ for (auto device : devices) {
+ if (device->type() == AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ mic = device;
+ break;
+ }
+ }
+ EXPECT_NE(nullptr, mic);
+
+ audio_format_t requestedFormat = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t requestedSampleRate = 44100;
+ audio_channel_mask_t requestedChannelMask = AUDIO_CHANNEL_IN_STEREO;
+ auto profile = mManager->getInputProfile(
+ mic, requestedSampleRate, requestedFormat, requestedChannelMask, AUDIO_INPUT_FLAG_NONE);
+ EXPECT_EQ(expectedIOProfile, profile->getName());
+ EXPECT_EQ(expectedFormat, requestedFormat);
+ EXPECT_EQ(expectedSampleRate, requestedSampleRate);
+ EXPECT_EQ(expectedChannelMask, requestedChannelMask);
+}
+
class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void TearDown() override;
@@ -2067,6 +2109,7 @@
bool mIsSpatialized;
bool mIsBitPerfect;
float mVolume;
+ bool mMuted;
};
TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting, MmapPlaybackStreamMatchingLoopbackDapMixFails) {
@@ -2085,7 +2128,8 @@
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
- &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+ &mMuted));
}
TEST_P(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -2104,7 +2148,8 @@
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
- &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+ &mMuted));
}
TEST_F(AudioPolicyManagerTestMMapPlaybackRerouting,
@@ -2135,7 +2180,8 @@
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
- &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+ &mMuted));
ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
auto outputDesc = mManager->getOutputs().valueFor(mOutput);
ASSERT_NE(nullptr, outputDesc);
@@ -2151,7 +2197,8 @@
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
- &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+ &mMuted));
ASSERT_EQ(usbDevicePort.id, mSelectedDeviceId);
outputDesc = mManager->getOutputs().valueFor(mOutput);
ASSERT_NE(nullptr, outputDesc);
@@ -2180,7 +2227,8 @@
mManager->getOutputForAttr(&attr, &mOutput, AUDIO_SESSION_NONE, &mStream,
createAttributionSourceState(testUid), &audioConfig,
&outputFlags, &mSelectedDeviceId, &mPortId, {},
- &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume));
+ &mOutputType, &mIsSpatialized, &mIsBitPerfect, &mVolume,
+ &mMuted));
}
INSTANTIATE_TEST_SUITE_P(
@@ -2510,7 +2558,7 @@
audio_config_base_t * mixerConfig,
const sp<DeviceDescriptorBase>& device,
uint32_t * latencyMs,
- audio_output_flags_t flags,
+ audio_output_flags_t *flags,
audio_attributes_t attributes) override {
return mSimulateFailure ? BAD_VALUE :
AudioPolicyManagerTestClient::openOutput(
@@ -2532,8 +2580,29 @@
void setSimulateFailure(bool simulateFailure) { mSimulateFailure = simulateFailure; }
+ void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+ if (status != NO_ERROR) {
+ // simulate device connect status
+ mSimulateBroadcastDeviceStatus[device] = status;
+ } else {
+ // remove device connection fixed status
+ mSimulateBroadcastDeviceStatus.erase(device);
+ }
+ }
+
+ status_t setDeviceConnectedState(const struct audio_port_v7* port,
+ media::DeviceConnectedState state) override {
+ if (mSimulateBroadcastDeviceStatus.find(port->ext.device.type) !=
+ mSimulateBroadcastDeviceStatus.end()) {
+ // If a simulated status exists, return a status value
+ return mSimulateBroadcastDeviceStatus[port->ext.device.type];
+ }
+ return AudioPolicyManagerTestClient::setDeviceConnectedState(port, state);
+ }
+
private:
bool mSimulateFailure = false;
+ std::map<audio_devices_t, status_t> mSimulateBroadcastDeviceStatus;
};
} // namespace
@@ -2554,6 +2623,9 @@
void setSimulateOpenFailure(bool simulateFailure) {
mFullClient->setSimulateFailure(simulateFailure); }
+ void setSimulateBroadcastDeviceStatus(audio_devices_t device, status_t status) {
+ mFullClient->setSimulateBroadcastDeviceStatus(device, status); }
+
static const std::string sBluetoothConfig;
private:
@@ -2597,6 +2669,30 @@
}
}
+TEST_P(AudioPolicyManagerTestDeviceConnectionFailed, BroadcastDeviceFailure) {
+ const audio_devices_t type = std::get<0>(GetParam());
+ const std::string name = std::get<1>(GetParam());
+ const std::string address = std::get<2>(GetParam());
+ const audio_format_t format = std::get<3>(GetParam());
+
+ // simulate broadcastDeviceConnectionState return failure
+ setSimulateBroadcastDeviceStatus(type, INVALID_OPERATION);
+ ASSERT_EQ(INVALID_OPERATION, mManager->setDeviceConnectionState(
+ type, AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ address.c_str(), name.c_str(), format));
+
+ // if broadcast is fail, device should not be added to available devices list
+ if (audio_is_output_device(type)) {
+ auto availableDevices = mManager->getAvailableOutputDevices();
+ EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+ } else if (audio_is_input_device(type)) {
+ auto availableDevices = mManager->getAvailableInputDevices();
+ EXPECT_FALSE(availableDevices.containsDeviceWithType(type));
+ }
+
+ setSimulateBroadcastDeviceStatus(type, NO_ERROR);
+}
+
INSTANTIATE_TEST_CASE_P(
DeviceConnectionFailure,
AudioPolicyManagerTestDeviceConnectionFailed,
@@ -3181,6 +3277,259 @@
"low latency");
}
+class AudioPolicyManagerPhoneTest : public AudioPolicyManagerTestWithConfigurationFile {
+protected:
+ std::string getConfigFile() override { return sPhoneConfig; }
+ void testOutputMixPortSelectionForAttr(audio_output_flags_t flags, audio_format_t format,
+ int samplingRate, bool isMusic, const char* expectedMixPortName);
+ void testOutputMixPortSelectionForStream(
+ audio_stream_type_t stream, const char* expectedMixPortName);
+ void verifyMixPortNameAndFlags(audio_io_handle_t output, const char* expectedMixPortName);
+
+ static const std::string sPhoneConfig;
+ static const std::map<std::string, audio_output_flags_t> sMixPortFlags;
+};
+
+const std::string AudioPolicyManagerPhoneTest::sPhoneConfig =
+ AudioPolicyManagerPhoneTest::sExecutableDir + "test_phone_apm_configuration.xml";
+
+// Must be in sync with the contents of the sPhoneConfig file.
+const std::map<std::string, audio_output_flags_t> AudioPolicyManagerPhoneTest::sMixPortFlags = {
+ {"primary output",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_PRIMARY | AUDIO_OUTPUT_FLAG_FAST)},
+ {"direct", AUDIO_OUTPUT_FLAG_DIRECT},
+ {"deep buffer", AUDIO_OUTPUT_FLAG_DEEP_BUFFER},
+ {"compressed_offload",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING |
+ AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD)},
+ {"raw", (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_FAST)},
+ {"mmap_no_irq_out",
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT|AUDIO_OUTPUT_FLAG_MMAP_NOIRQ)},
+ {"voip_rx", AUDIO_OUTPUT_FLAG_VOIP_RX},
+};
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForAttr(
+ audio_output_flags_t flags, audio_format_t format, int samplingRate, bool isMusic,
+ const char* expectedMixPortName) {
+ audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
+ audio_io_handle_t output;
+ audio_port_handle_t portId;
+ audio_attributes_t attr = AUDIO_ATTRIBUTES_INITIALIZER;
+ if (isMusic) {
+ attr.content_type = AUDIO_CONTENT_TYPE_MUSIC;
+ attr.usage = AUDIO_USAGE_MEDIA;
+ }
+ getOutputForAttr(&selectedDeviceId, format, AUDIO_CHANNEL_OUT_STEREO, samplingRate, flags,
+ &output, &portId, attr);
+ EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+ mManager->releaseOutput(portId);
+}
+
+void AudioPolicyManagerPhoneTest::testOutputMixPortSelectionForStream(
+ audio_stream_type_t stream, const char* expectedMixPortName) {
+ audio_io_handle_t output = mManager->getOutput(stream);
+ EXPECT_NO_FATAL_FAILURE(verifyMixPortNameAndFlags(output, expectedMixPortName));
+}
+
+void AudioPolicyManagerPhoneTest::verifyMixPortNameAndFlags(audio_io_handle_t output,
+ const char* expectedMixPortName) {
+ ALOGI("%s: checking output %d", __func__, output);
+ sp<SwAudioOutputDescriptor> outDesc = mManager->getOutputs().valueFor(output);
+ ASSERT_NE(nullptr, outDesc.get());
+ audio_port_v7 port = {};
+ outDesc->toAudioPort(&port);
+ EXPECT_EQ(AUDIO_PORT_TYPE_MIX, port.type);
+ EXPECT_EQ(AUDIO_PORT_ROLE_SOURCE, port.role);
+ ASSERT_STREQ(expectedMixPortName, port.name);
+
+ auto iter = sMixPortFlags.find(port.name);
+ ASSERT_NE(iter, sMixPortFlags.end()) << "\"" << port.name << "\" is not in sMixPortFlags";
+ auto actualFlags = mClient->getOpenOutputFlags(output);
+ ASSERT_TRUE(actualFlags.has_value()) << "\"" << port.name << "\" was not opened via client";
+ EXPECT_EQ(*actualFlags, iter->second);
+}
+
+TEST_F(AudioPolicyManagerPhoneTest, InitSuccess) {
+ // SetUp must finish with no assertions.
+}
+
+enum {
+ MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER,
+ MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+ MIX_PORT_ATTR_FLAGS_PARAMETER,
+ MIX_PORT_ATTR_FORMAT_PARAMETER,
+ MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER,
+};
+using MixPortSelectionForAttr =
+ std::tuple<const char*, const char*, audio_output_flags_t, audio_format_t, int>;
+
+class AudioPolicyManagerOutputMixPortForAttrSelectionTest
+ : public AudioPolicyManagerPhoneTest,
+ public testing::WithParamInterface<MixPortSelectionForAttr> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ false /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_Music) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForAttr(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ true /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(
+ testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ false /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForAttrSelectionTest, SelectPortByFlags_DeepMedia_Music) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_ATTR_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(
+ testOutputMixPortSelectionForAttr(std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(GetParam()),
+ true /*isMusic*/,
+ std::get<MIX_PORT_ATTR_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(AudioPolicyManagerOutputMixPortForAttrSelection,
+ AudioPolicyManagerOutputMixPortForAttrSelectionTest,
+ ::testing::Values(
+ std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("primary output", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+ // Note: this goes to "direct" because 384000 > SAMPLE_RATE_HZ_MAX (192000)
+ std::make_tuple("direct", "deep buffer", AUDIO_OUTPUT_FLAG_NONE,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("primary output", nullptr, AUDIO_OUTPUT_FLAG_FAST,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k96000SamplingRate),
+ std::make_tuple("direct", nullptr, AUDIO_OUTPUT_FLAG_DIRECT,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("deep buffer", nullptr, AUDIO_OUTPUT_FLAG_DEEP_BUFFER,
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("compressed_offload", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD |
+ AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+ AUDIO_FORMAT_MP3, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("raw", nullptr,
+ AUDIO_OUTPUT_FLAG_RAW, AUDIO_FORMAT_PCM_32_BIT,
+ AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("mmap_no_irq_out", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k48000SamplingRate),
+ std::make_tuple("mmap_no_irq_out", nullptr,
+ (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_DIRECT |
+ AUDIO_OUTPUT_FLAG_MMAP_NOIRQ),
+ AUDIO_FORMAT_PCM_FLOAT, AudioPolicyManagerTest::k384000SamplingRate),
+ std::make_tuple("voip_rx", nullptr, AUDIO_OUTPUT_FLAG_VOIP_RX,
+ AUDIO_FORMAT_PCM_16_BIT, AudioPolicyManagerTest::k48000SamplingRate)),
+ [](const ::testing::TestParamInfo<MixPortSelectionForAttr>& info) {
+ static const std::string flagPrefix = "AUDIO_OUTPUT_FLAG_";
+ static const std::string formatPrefix = "AUDIO_FORMAT_";
+ std::string flags;
+ TypeConverter<OutputFlagTraits>::maskToString(
+ std::get<MIX_PORT_ATTR_FLAGS_PARAMETER>(info.param), flags, "__");
+ size_t index = 0;
+ while (true) {
+ index = flags.rfind(flagPrefix);
+ if (index == std::string::npos) break;
+ flags.erase(index, flagPrefix.length());
+ }
+ std::string format;
+ TypeConverter<FormatTraits>::toString(
+ std::get<MIX_PORT_ATTR_FORMAT_PARAMETER>(info.param), format);
+ if (size_t index = format.find(formatPrefix); index != std::string::npos) {
+ format.erase(index, formatPrefix.length());
+ }
+ return flags + "__" + format + "__" +
+ std::to_string(std::get<MIX_PORT_ATTR_SAMPLING_RATE_PARAMETER>(info.param));
+ }
+);
+
+
+enum {
+ MIX_PORT_STRM_EXPECTED_NAME_PARAMETER,
+ MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER,
+ MIX_PORT_STRM_STREAM_PARAMETER,
+};
+using MixPortSelectionForStream =
+ std::tuple<const char*, const char*, audio_stream_type_t>;
+
+class AudioPolicyManagerOutputMixPortForStreamSelectionTest
+ : public AudioPolicyManagerPhoneTest,
+ public testing::WithParamInterface<MixPortSelectionForStream> {
+};
+
+// There is no easy way to create a flat tuple from tuples via ::testing::Combine.
+// Instead, just run the same selection twice while altering the deep buffer for media setting.
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_NoDBFM) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(false);
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam())));
+}
+TEST_P(AudioPolicyManagerOutputMixPortForStreamSelectionTest, SelectPort_WithDBFM) {
+ mConfig->setUseDeepBufferForMediaOverrideForTests(true);
+ const char* fallbackName = std::get<MIX_PORT_STRM_EXPECTED_NAME_PARAMETER>(GetParam());
+ ASSERT_NO_FATAL_FAILURE(testOutputMixPortSelectionForStream(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(GetParam()),
+ std::get<MIX_PORT_STRM_EXPECTED_NAME_WITH_DBFM_PARAMETER>(
+ GetParam()) ?: fallbackName));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AudioPolicyManagerOutputMixPortForStreamSelection,
+ AudioPolicyManagerOutputMixPortForStreamSelectionTest,
+ ::testing::Values(std::make_tuple("primary output", nullptr, AUDIO_STREAM_DEFAULT),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_SYSTEM),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_RING),
+ std::make_tuple("primary output", "deep buffer", AUDIO_STREAM_MUSIC),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ALARM),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_NOTIFICATION),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_BLUETOOTH_SCO),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ENFORCED_AUDIBLE),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_DTMF),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_TTS),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ACCESSIBILITY),
+ std::make_tuple("primary output", nullptr, AUDIO_STREAM_ASSISTANT)),
+ [](const ::testing::TestParamInfo<MixPortSelectionForStream>& info) {
+ static const std::string streamPrefix = "AUDIO_STREAM_";
+ std::string stream;
+ TypeConverter<StreamTraits>::toString(
+ std::get<MIX_PORT_STRM_STREAM_PARAMETER>(info.param), stream);
+ if (size_t index = stream.find(streamPrefix); index != std::string::npos) {
+ stream.erase(index, streamPrefix.length());
+ }
+ return stream;
+ }
+);
+
class AudioPolicyManagerDynamicHwModulesTest : public AudioPolicyManagerTestWithConfigurationFile {
protected:
void SetUpManagerConfig() override;
@@ -3333,7 +3682,7 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
ASSERT_NE(nullptr, selectedDevice);
@@ -3354,7 +3703,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(preferredDevice, availableDevices.getDeviceFromId(selectedDeviceId));
// After clearing preferred device for capture preset, the selected device for input should be
@@ -3365,7 +3714,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3391,7 +3740,7 @@
audio_io_handle_t input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
auto selectedDevice = availableDevices.getDeviceFromId(selectedDeviceId);
ASSERT_NE(nullptr, selectedDevice);
@@ -3404,7 +3753,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1,
&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT,
- AUDIO_CHANNEL_IN_STEREO, 48000));
+ AUDIO_CHANNEL_IN_STEREO, k48000SamplingRate));
ASSERT_NE(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
// After clearing disabled device for capture preset, the selected device for input should be
@@ -3415,7 +3764,7 @@
input = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input, AUDIO_SESSION_NONE, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
ASSERT_EQ(selectedDevice, availableDevices.getDeviceFromId(selectedDeviceId));
ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(
@@ -3518,7 +3867,7 @@
// effect attached again
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &inputClientHandle, session, 1, &routedPortId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
// unregister effect should succeed since effect shall have been restore on the client session
ASSERT_EQ(NO_ERROR, mManager->unregisterEffect(effectId));
@@ -3535,7 +3884,7 @@
const audio_format_t mBitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
const audio_channel_mask_t mBitPerfectChannelMask = AUDIO_CHANNEL_OUT_STEREO;
- const uint32_t mBitPerfectSampleRate = 48000;
+ const uint32_t mBitPerfectSampleRate = k48000SamplingRate;
const uid_t mUid = 1234;
audio_port_handle_t mUsbPortId = AUDIO_PORT_HANDLE_NONE;
@@ -3637,11 +3986,12 @@
bool isSpatialized;
bool isBitPerfect;
float volume;
+ bool muted;
EXPECT_EQ(expected,
mManager->getOutputForAttr(&sMediaAttr, &mBitPerfectOutput, AUDIO_SESSION_NONE,
&stream, attributionSource, &config, &flags,
&mSelectedDeviceId, &mBitPerfectPortId, {}, &outputType,
- &isSpatialized, &isBitPerfect, &volume));
+ &isSpatialized, &isBitPerfect, &volume, &muted));
}
class AudioPolicyManagerTestBitPerfect : public AudioPolicyManagerTestBitPerfectBase {
@@ -3811,8 +4161,8 @@
ASSERT_NO_FATAL_FAILURE(startBitPerfectOutput());
audio_attributes_t attr = {
+ .content_type = AUDIO_CONTENT_TYPE_UNKNOWN,
.usage = GetParam(),
- .content_type = AUDIO_CONTENT_TYPE_UNKNOWN
};
audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
@@ -3853,14 +4203,14 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
audio_io_handle_t input2 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3881,7 +4231,7 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
@@ -3889,7 +4239,7 @@
attr.source = AUDIO_SOURCE_VOICE_RECOGNITION;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
EXPECT_EQ(0, mClient->getCloseInputCallsCount());
@@ -3910,7 +4260,7 @@
audio_io_handle_t input1 = AUDIO_PORT_HANDLE_NONE;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input1, TEST_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(1, mClient->getOpenInputCallsCount());
@@ -3918,9 +4268,15 @@
attr.source = AUDIO_SOURCE_CAMCORDER;
ASSERT_NO_FATAL_FAILURE(getInputForAttr(attr, &input2, OTHER_SESSION_ID, 1, &selectedDeviceId,
AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_STEREO,
- 48000));
+ k48000SamplingRate));
EXPECT_EQ(2, mClient->getOpenInputCallsCount());
EXPECT_EQ(1, mClient->getCloseInputCallsCount());
EXPECT_NE(input1, input2);
}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+ ::testing::UnitTest::GetInstance()->listeners().Append(new TestExecutionTracer());
+ return RUN_ALL_TESTS();
+}
diff --git a/services/audiopolicy/tests/resources/Android.bp b/services/audiopolicy/tests/resources/Android.bp
index 1c191f5..8e7a697 100644
--- a/services/audiopolicy/tests/resources/Android.bp
+++ b/services/audiopolicy/tests/resources/Android.bp
@@ -11,11 +11,16 @@
filegroup {
name: "audiopolicytest_configuration_files",
srcs: [
+ "engine/test_audio_policy_engine_configuration.xml",
+ "engine/test_audio_policy_engine_default_stream_volumes.xml",
+ "engine/test_audio_policy_engine_product_strategies.xml",
+ "engine/test_audio_policy_engine_stream_volumes.xml",
"test_audio_policy_configuration.xml",
"test_audio_policy_configuration_bluetooth.xml",
"test_audio_policy_primary_only_configuration.xml",
"test_car_ap_atmos_offload_configuration.xml",
"test_invalid_audio_policy_configuration.xml",
+ "test_phone_apm_configuration.xml",
"test_settop_box_surround_configuration.xml",
"test_tv_apm_configuration.xml",
],
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
new file mode 100644
index 0000000..dc2e7af
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_configuration.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<configuration version="1.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <xi:include href="test_audio_policy_engine_product_strategies.xml"/>
+ <xi:include href="test_audio_policy_engine_stream_volumes.xml"/>
+ <xi:include href="test_audio_policy_engine_default_stream_volumes.xml"/>
+
+</configuration>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
new file mode 100644
index 0000000..d184cb5
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_default_stream_volumes.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Default Volume Tables included by Audio Policy Configuration file -->
+<!-- Full Default Volume table for all device category -->
+<volumes>
+ <reference name="FULL_SCALE_VOLUME_CURVE">
+ <!-- Full Scale reference Volume Curve -->
+ <point>0,0</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="SILENT_VOLUME_CURVE">
+ <point>0,-9600</point>
+ <point>100,-9600</point>
+ </reference>
+ <reference name="DEFAULT_SYSTEM_VOLUME_CURVE">
+ <!-- Default System reference Volume Curve -->
+ <point>1,-2400</point>
+ <point>33,-1800</point>
+ <point>66,-1200</point>
+ <point>100,-600</point>
+ </reference>
+ <reference name="DEFAULT_MEDIA_VOLUME_CURVE">
+ <!-- Default Media reference Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE">
+ <!-- Default is Speaker Media Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE">
+ <!-- Default is Speaker System Volume Curve -->
+ <point>1,-4680</point>
+ <point>42,-2070</point>
+ <point>85,-540</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE">
+ <!--Default Volume Curve -->
+ <point>1,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE">
+ <!-- Default is Ext Media System Volume Curve -->
+ <point>1,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-2100</point>
+ <point>100,-1000</point>
+ </reference>
+ <reference name="DEFAULT_HEARING_AID_VOLUME_CURVE">
+ <!-- Default Hearing Aid Volume Curve -->
+ <point>1,-12700</point>
+ <point>20,-8000</point>
+ <point>60,-4000</point>
+ <point>100,0</point>
+ </reference>
+ <!-- **************************************************************** -->
+ <!-- Non-mutable default volume curves: -->
+ <!-- * first point is always for index 0 -->
+ <!-- * attenuation is small enough that stream can still be heard -->
+ <reference name="DEFAULT_NON_MUTABLE_VOLUME_CURVE">
+ <!-- Default non-mutable reference Volume Curve -->
+ <!-- based on DEFAULT_MEDIA_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE">
+ <!--Default non-mutable Volume Curve for headset -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE -->
+ <point>0,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE">
+ <!-- Default non-mutable Speaker Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE">
+ <!--Default non-mutable Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE -->
+ <point>0,-4950</point>
+ <point>33,-3350</point>
+ <point>66,-1700</point>
+ <point>100,0</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE">
+ <!-- Default non-mutable Ext Media System Volume Curve -->
+ <!-- based on DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE -->
+ <point>0,-5800</point>
+ <point>20,-4000</point>
+ <point>60,-2100</point>
+ <point>100,-1000</point>
+ </reference>
+ <reference name="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE">
+ <!-- Default non-mutable Hearing Aid Volume Curve -->
+ <!-- based on DEFAULT_HEARING_AID_VOLUME_CURVE -->
+ <point>0,-12700</point>
+ <point>20,-8000</point>
+ <point>60,-4000</point>
+ <point>100,0</point>
+ </reference>
+</volumes>
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
new file mode 100644
index 0000000..58e7152
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_product_strategies.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<ProductStrategies>
+
+ <!-- "hidden strategies" like TTS, enforced audible:
+ Shall we expose them here or keep it hard coded -->
+
+ <!-- Used to identify the volume of audio streams for enforced system sounds in certain
+ countries (e.g. camera in Japan)
+ This strategy will only have higher priority than phone if force for system is set to
+ enforced. -->
+
+ <ProductStrategy name="STRATEGY_PHONE">
+ <AttributesGroup streamType="AUDIO_STREAM_VOICE_CALL" volumeGroup="voice_call">
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION"/> </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_BLUETOOTH_SCO" volumeGroup="bluetooth_sco">
+ <Attributes> <Flags value="AUDIO_FLAG_SCO"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_SONIFICATION">
+ <AttributesGroup streamType="AUDIO_STREAM_RING" volumeGroup="ring">
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE"/> </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_ALARM" volumeGroup="alarm">
+ <Attributes> <Usage value="AUDIO_USAGE_ALARM"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_ENFORCED_AUDIBLE">
+ <AttributesGroup streamType="AUDIO_STREAM_ENFORCED_AUDIBLE" volumeGroup="enforced_audible">
+ <Attributes> <Flags value="AUDIO_FLAG_AUDIBILITY_ENFORCED"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_ACCESSIBILITY">
+ <AttributesGroup streamType="AUDIO_STREAM_ACCESSIBILITY" volumeGroup="accessibility">
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_SONIFICATION_RESPECTFUL">
+ <AttributesGroup streamType="AUDIO_STREAM_NOTIFICATION" volumeGroup="notification">
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_NOTIFICATION_EVENT"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_MEDIA">
+ <AttributesGroup streamType="AUDIO_STREAM_ASSISTANT" volumeGroup="assistant">
+ <Attributes>
+ <ContentType value="AUDIO_CONTENT_TYPE_SPEECH"/>
+ <Usage value="AUDIO_USAGE_ASSISTANT"/>
+ </Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_MUSIC" volumeGroup="music">
+ <Attributes> <Usage value="AUDIO_USAGE_MEDIA"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_GAME"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANT"/> </Attributes>
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE"/> </Attributes>
+ <Attributes></Attributes>
+ </AttributesGroup>
+ <AttributesGroup streamType="AUDIO_STREAM_SYSTEM" volumeGroup="system">
+ <Attributes> <Usage value="AUDIO_USAGE_ASSISTANCE_SONIFICATION"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <ProductStrategy name="STRATEGY_DTMF">
+ <AttributesGroup streamType="AUDIO_STREAM_DTMF" volumeGroup="dtmf">
+ <Attributes> <Usage value="AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+ <!-- Used to identify the volume of audio streams exclusively transmitted through the speaker
+ (TTS) of the device -->
+ <ProductStrategy name="STRATEGY_TRANSMITTED_THROUGH_SPEAKER">
+ <AttributesGroup streamType="AUDIO_STREAM_TTS" volumeGroup="tts">
+ <Attributes> <Flags value="AUDIO_FLAG_BEACON"/> </Attributes>
+ </AttributesGroup>
+ </ProductStrategy>
+
+</ProductStrategies>
+
diff --git a/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
new file mode 100644
index 0000000..af517cf
--- /dev/null
+++ b/services/audiopolicy/tests/resources/engine/test_audio_policy_engine_stream_volumes.xml
@@ -0,0 +1,221 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Volume section defines a volume curve for a given use case and device category.
+It contains a list of points of this curve expressing the attenuation in Millibels for a given
+volume index from 0 to 100.
+<volume deviceCategory=””>
+<point>0,-9600</point>
+<point>100,0</point>
+</volume>
+-->
+
+<volumeGroups>
+ <volumeGroup>
+ <name>voice_call</name>
+ <indexMin>1</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-2700</point>
+ <point>33,-1800</point>
+ <point>66,-900</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>system</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-5100</point>
+ <point>57,-2800</point>
+ <point>71,-2500</point>
+ <point>85,-2300</point>
+ <point>100,-2100</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>ring</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>music</name>
+ <indexMin>0</indexMin>
+ <indexMax>25</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>alarm</name>
+ <indexMin>1</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_EXT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>notification</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_DEVICE_CATEGORY_EARPIECE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_DEVICE_CATEGORY_HEADSET_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>bluetooth_sco</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>0,-2400</point>
+ <point>33,-1600</point>
+ <point>66,-800</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE">
+ <point>0,-4200</point>
+ <point>33,-2800</point>
+ <point>66,-1400</point>
+ <point>100,0</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>enforced_audible</name>
+ <indexMin>0</indexMin>
+ <indexMax>7</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-3400</point>
+ <point>71,-2400</point>
+ <point>100,-2000</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>dtmf</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET">
+ <point>1,-3000</point>
+ <point>33,-2600</point>
+ <point>66,-2200</point>
+ <point>100,-1800</point>
+ </volume>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER">
+ <point>1,-4000</point>
+ <point>71,-2400</point>
+ <point>100,-1400</point>
+ </volume>
+ <!--volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/-->
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_SYSTEM_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_DEVICE_CATEGORY_EXT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>tts</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="FULL_SCALE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="SILENT_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="SILENT_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>accessibility</name>
+ <indexMin>1</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_NON_MUTABLE_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_NON_MUTABLE_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_NON_MUTABLE_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+ <volumeGroup>
+ <name>assistant</name>
+ <indexMin>0</indexMin>
+ <indexMax>15</indexMax>
+ <volume deviceCategory="DEVICE_CATEGORY_HEADSET" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_SPEAKER" ref="DEFAULT_DEVICE_CATEGORY_SPEAKER_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EARPIECE" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_EXT_MEDIA" ref="DEFAULT_MEDIA_VOLUME_CURVE"/>
+ <volume deviceCategory="DEVICE_CATEGORY_HEARING_AID" ref="DEFAULT_HEARING_AID_VOLUME_CURVE"/>
+ </volumeGroup>
+
+</volumeGroups>
+
diff --git a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
index 67e99f2..3c64898 100644
--- a/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
+++ b/services/audiopolicy/tests/resources/test_audio_policy_configuration.xml
@@ -66,6 +66,11 @@
channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
</mixPort>
<mixPort name="hifi_input" role="sink" />
+ <mixPort name="multiple_channels_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000"
+ channelMasks="AUDIO_CHANNEL_IN_5POINT1"/>
+ </mixPort>
</mixPorts>
<devicePorts>
<devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
@@ -114,6 +119,8 @@
sources="BUS Device In"/>
<route type="mix" sink="hifi_input"
sources="USB Device In" />
+ <route type="mix" sink="multiple_channels_input"
+ sources="Built-In Mic" />
</routes>
</module>
diff --git a/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
new file mode 100644
index 0000000..efe1400
--- /dev/null
+++ b/services/audiopolicy/tests/resources/test_phone_apm_configuration.xml
@@ -0,0 +1,279 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<audioPolicyConfiguration version="7.0" xmlns:xi="http://www.w3.org/2001/XInclude">
+ <globalConfiguration speaker_drc_enabled="false" call_screen_mode_supported="true" />
+ <modules>
+ <!-- Primary Audio HAL -->
+ <module name="primary" halVersion="2.0">
+ <attachedDevices>
+ <item>Speaker</item>
+ <item>Speaker Safe</item>
+ <item>Earpiece</item>
+ <item>Built-In Mic</item>
+ <item>Built-In Back Mic</item>
+ <item>Telephony Tx</item>
+ <item>Voice Call And Telephony Rx</item>
+ <item>Echo Ref In</item>
+ </attachedDevices>
+ <defaultOutputDevice>Speaker</defaultOutputDevice>
+ <mixPorts>
+ <mixPort name="primary output" role="source" flags="AUDIO_OUTPUT_FLAG_PRIMARY AUDIO_OUTPUT_FLAG_FAST"
+ recommendedMuteDurationMs="40">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="direct" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT"
+ recommendedMuteDurationMs="40">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="deep buffer" role="source" flags="AUDIO_OUTPUT_FLAG_DEEP_BUFFER">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="compressed_offload" role="source"
+ flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD AUDIO_OUTPUT_FLAG_NON_BLOCKING AUDIO_OUTPUT_FLAG_GAPLESS_OFFLOAD">
+ <profile name="" format="AUDIO_FORMAT_MP3"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_LC"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_HE_V1"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_AAC_HE_V2"
+ samplingRates="8000 16000 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO AUDIO_CHANNEL_OUT_MONO"/>
+ <profile name="" format="AUDIO_FORMAT_OPUS"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="haptic" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO_HAPTIC_AB" />
+ </mixPort>
+ <mixPort name="raw" role="source" flags="AUDIO_OUTPUT_FLAG_RAW AUDIO_OUTPUT_FLAG_FAST">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="mmap_no_irq_out" role="source" flags="AUDIO_OUTPUT_FLAG_DIRECT AUDIO_OUTPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_FLOAT"
+ samplingRates="48000 96000 384000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="immersive_out" role="source" flags="AUDIO_OUTPUT_FLAG_SPATIALIZER">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="incall playback" role="source"
+ flags="AUDIO_OUTPUT_FLAG_INCALL_MUSIC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+ </mixPort>
+ <mixPort name="voice call tx" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_OUT_STEREO" />
+ </mixPort>
+ <mixPort name="voip_rx" role="source"
+ flags="AUDIO_OUTPUT_FLAG_VOIP_RX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ <mixPort name="primary input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO AUDIO_CHANNEL_INDEX_MASK_3"/>
+ </mixPort>
+ <mixPort name="hotword input" role="sink" flags="AUDIO_INPUT_FLAG_HW_HOTWORD" maxActiveCount="0" >
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="8000 11025 12000 16000 22050 24000 32000 44100 48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="incall capture" role="sink" maxActiveCount="2" maxOpenCount="2">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voice call rx" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="voip_tx" role="sink"
+ flags="AUDIO_INPUT_FLAG_VOIP_TX">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_IN_MONO"/>
+ </mixPort>
+ <mixPort name="fast input" role="sink" flags="AUDIO_INPUT_FLAG_RAW AUDIO_INPUT_FLAG_FAST">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="mmap_no_irq_in" role="sink" flags="AUDIO_INPUT_FLAG_MMAP_NOIRQ">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_MONO AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ <mixPort name="hifi_playback" role="source" />
+ <mixPort name="hifi_input" role="sink" />
+ <mixPort name="echo_ref_input" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_32_BIT"
+ samplingRates="48000 96000"
+ channelMasks="AUDIO_CHANNEL_IN_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <!-- Output devices declaration, i.e. Sink DEVICE PORT -->
+ <devicePort tagName="Earpiece" type="AUDIO_DEVICE_OUT_EARPIECE" role="sink">
+ </devicePort>
+ <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">
+ </devicePort>
+ <devicePort tagName="Speaker Safe" type="AUDIO_DEVICE_OUT_SPEAKER_SAFE" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET" role="sink">
+ </devicePort>
+ <devicePort tagName="BT SCO Car Kit" type="AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Device Out" type="AUDIO_DEVICE_OUT_USB_DEVICE" role="sink">
+ </devicePort>
+ <devicePort tagName="USB Headset Out" type="AUDIO_DEVICE_OUT_USB_HEADSET" role="sink">
+ </devicePort>
+ <devicePort tagName="HDMI Out" type="AUDIO_DEVICE_OUT_HDMI" role="sink">
+ </devicePort>
+ <devicePort tagName="Telephony Tx" type="AUDIO_DEVICE_OUT_TELEPHONY_TX" role="sink">
+ </devicePort>
+ <!-- Input devices declaration, i.e. Source DEVICE PORT -->
+ <devicePort tagName="Built-In Mic" type="AUDIO_DEVICE_IN_BUILTIN_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="Built-In Back Mic" type="AUDIO_DEVICE_IN_BACK_MIC" role="source">
+ </devicePort>
+ <devicePort tagName="BT SCO Headset Mic" type="AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET" role="source">
+ </devicePort>
+ <devicePort tagName="BT A2DP Out" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Headphones" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT A2DP Speaker" type="AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER" role="sink"
+ encodedFormats="AUDIO_FORMAT_OPUS AUDIO_FORMAT_AAC AUDIO_FORMAT_SBC">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100 48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Headset" type="AUDIO_DEVICE_OUT_BLE_HEADSET" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Speaker" type="AUDIO_DEVICE_OUT_BLE_SPEAKER" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BT BLE Broadcast" type="AUDIO_DEVICE_OUT_BLE_BROADCAST" role="sink"
+ encodedFormats="AUDIO_FORMAT_LC3">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="48000 96000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ <devicePort tagName="BLE Headset Mic" type="AUDIO_DEVICE_IN_BLE_HEADSET" role="source">
+ </devicePort>
+ <devicePort tagName="USB Device In" type="AUDIO_DEVICE_IN_USB_DEVICE" role="source">
+ </devicePort>
+ <devicePort tagName="USB Headset In" type="AUDIO_DEVICE_IN_USB_HEADSET" role="source">
+ </devicePort>
+ <!-- AUDIO_DEVICE_IN_VOICE_CALL and AUDIO_DEVICE_IN_TELEPHONY_RX are in the same value -->
+ <devicePort tagName="Voice Call And Telephony Rx" type="AUDIO_DEVICE_IN_VOICE_CALL" role="source">
+ </devicePort>
+ <devicePort tagName="Echo Ref In" type="AUDIO_DEVICE_IN_ECHO_REFERENCE" role="source">
+ </devicePort>
+ </devicePorts>
+ <!-- route declaration, i.e. list all available sources for a given sink -->
+ <routes>
+ <route type="mix" sink="Speaker"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="Speaker Safe"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="Earpiece"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="BT A2DP Out"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT A2DP Headphones"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT A2DP Speaker"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Headset"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Speaker"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="BT BLE Broadcast"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out,immersive_out"/>
+ <route type="mix" sink="USB Device Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+ <route type="mix" sink="USB Headset Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,hifi_playback,compressed_offload,immersive_out"/>
+ <route type="mix" sink="HDMI Out"
+ sources="primary output,direct,deep buffer,haptic,raw,mmap_no_irq_out,voip_rx,compressed_offload"/>
+ <route type="mix" sink="BT SCO"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="BT SCO Headset"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="BT SCO Car Kit"
+ sources="primary output,direct,deep buffer,haptic,voip_rx,compressed_offload,raw,mmap_no_irq_out"/>
+ <route type="mix" sink="Telephony Tx" sources="incall playback,voice call tx" />
+ <route type="mix" sink="primary input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="hotword input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="incall capture" sources="Voice Call And Telephony Rx" />
+ <route type="mix" sink="voice call rx" sources="Voice Call And Telephony Rx" />
+ <route type="mix" sink="voip_tx"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="fast input"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="mmap_no_irq_in"
+ sources="Built-In Mic,Built-In Back Mic,USB Device In,USB Headset In,BT SCO Headset Mic,BLE Headset Mic"/>
+ <route type="mix" sink="hifi_input" sources="USB Device In,USB Headset In" />
+ <route type="mix" sink="echo_ref_input" sources="Echo Ref In"/>
+ </routes>
+ </module>
+ <!-- Usb Audio HAL -->
+ <module name="usbv2" halVersion="2.0">
+ <mixPorts>
+ <mixPort name="usb_accessory output" role="source">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </mixPort>
+ </mixPorts>
+ <devicePorts>
+ <devicePort tagName="USB Host Out" type="AUDIO_DEVICE_OUT_USB_ACCESSORY" role="sink">
+ <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
+ samplingRates="44100" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
+ </devicePort>
+ </devicePorts>
+ <routes>
+ <route type="mix" sink="USB Host Out"
+ sources="usb_accessory output"/>
+ </routes>
+ </module>
+ </modules>
+ <!-- End of Modules section -->
+</audioPolicyConfiguration>
diff --git a/services/audiopolicy/tests/test_execution_tracer.cpp b/services/audiopolicy/tests/test_execution_tracer.cpp
new file mode 100644
index 0000000..09de4a1
--- /dev/null
+++ b/services/audiopolicy/tests/test_execution_tracer.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "TestExecutionTracer"
+
+#include "test_execution_tracer.h"
+
+#include <android-base/logging.h>
+
+void TestExecutionTracer::OnTestStart(const ::testing::TestInfo& test_info) {
+ TraceTestState("Started", test_info);
+}
+
+void TestExecutionTracer::OnTestEnd(const ::testing::TestInfo& test_info) {
+ TraceTestState("Finished", test_info);
+}
+
+void TestExecutionTracer::OnTestPartResult(const ::testing::TestPartResult& result) {
+ if (result.failed()) {
+ LOG(ERROR) << result;
+ } else {
+ LOG(INFO) << result;
+ }
+}
+
+// static
+void TestExecutionTracer::TraceTestState(const std::string& state,
+ const ::testing::TestInfo& test_info) {
+ LOG(INFO) << state << " " << test_info.test_suite_name() << "::" << test_info.name();
+}
diff --git a/services/audiopolicy/tests/test_execution_tracer.h b/services/audiopolicy/tests/test_execution_tracer.h
new file mode 100644
index 0000000..9031aaf
--- /dev/null
+++ b/services/audiopolicy/tests/test_execution_tracer.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <gtest/gtest.h>
+
+class TestExecutionTracer : public ::testing::EmptyTestEventListener {
+ public:
+ void OnTestStart(const ::testing::TestInfo& test_info) override;
+ void OnTestEnd(const ::testing::TestInfo& test_info) override;
+ void OnTestPartResult(const ::testing::TestPartResult& result) override;
+
+ private:
+ static void TraceTestState(const std::string& state, const ::testing::TestInfo& test_info);
+};
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index a74b6d6..3f2a617 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -267,9 +267,21 @@
"liblog",
"libutils",
"libxml2",
- "camera_platform_flags_c_lib",
],
+ target: {
+ android: {
+ shared_libs: [
+ "camera_platform_flags_c_lib",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "camera_platform_flags_c_lib_for_test",
+ ],
+ },
+ },
+
include_dirs: [
"frameworks/av/camera/include",
"frameworks/av/camera/include/camera",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f94300e..fa5eb6f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -89,7 +89,6 @@
#include "utils/Utils.h"
namespace {
- const char* kPermissionServiceName = "permission";
const char* kActivityServiceName = "activity";
const char* kSensorPrivacyServiceName = "sensor_privacy";
const char* kAppopsServiceName = "appops";
@@ -828,10 +827,6 @@
hardware::camera2::impl::CameraMetadataNative* request) {
ATRACE_CALL();
- if (!flags::feature_combination_query()) {
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
- "Camera subsystem doesn't support this method!");
- }
if (!mInitialized) {
ALOGE("%s: Camera subsystem is not available", __FUNCTION__);
logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
@@ -891,10 +886,6 @@
/*out*/ bool* supported) {
ATRACE_CALL();
- if (!flags::feature_combination_query()) {
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
- "Camera subsystem doesn't support this method!");
- }
if (!mInitialized) {
ALOGE("%s: Camera HAL couldn't be initialized", __FUNCTION__);
logServiceError("Camera subsystem is not available", ERROR_DISCONNECTED);
@@ -924,8 +915,7 @@
cameraId.c_str());
}
- bool overrideForPerfClass = flags::calculate_perf_override_during_session_support() &&
- SessionConfigurationUtils::targetPerfClassPrimaryCamera(
+ bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
auto ret = isSessionConfigurationWithParametersSupportedUnsafe(cameraId,
@@ -1021,23 +1011,23 @@
bool overrideForPerfClass = SessionConfigurationUtils::targetPerfClassPrimaryCamera(
mPerfClassPrimaryCameraIds, cameraId, targetSdkVersion);
- if (flags::check_session_support_before_session_char()) {
- bool sessionConfigSupported;
- Status res = isSessionConfigurationWithParametersSupportedUnsafe(
- cameraId, sessionConfiguration, overrideForPerfClass, &sessionConfigSupported);
- if (!res.isOk()) {
- // isSessionConfigurationWithParametersSupportedUnsafe should log what went wrong and
- // report the correct Status to send to the client. Simply forward the error to
- // the client.
- outMetadata->clear();
- return res;
- }
- if (!sessionConfigSupported) {
- std::string msg = fmt::sprintf(
- "Session configuration not supported for camera device %s.", cameraId.c_str());
- outMetadata->clear();
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
- }
+
+ bool sessionConfigSupported;
+ Status res = isSessionConfigurationWithParametersSupportedUnsafe(
+ cameraId, sessionConfiguration, overrideForPerfClass, &sessionConfigSupported);
+ if (!res.isOk()) {
+ // isSessionConfigurationWithParametersSupportedUnsafe should log what went wrong and
+ // report the correct Status to send to the client. Simply forward the error to
+ // the client.
+ outMetadata->clear();
+ return res;
+ }
+
+ if (!sessionConfigSupported) {
+ std::string msg = fmt::sprintf("Session configuration not supported for camera device %s.",
+ cameraId.c_str());
+ outMetadata->clear();
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
status_t ret = mCameraProviderManager->getSessionCharacteristics(
@@ -1079,7 +1069,7 @@
}
}
- Status res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+ res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
if (flags::analytics_24q3()) {
mCameraServiceProxyWrapper->logSessionCharacteristicsQuery(cameraId,
getCallingUid(), sessionConfiguration, res);
@@ -1612,11 +1602,12 @@
Status ret = Status::ok();
sp<Client> tmp = nullptr;
- logConnectionAttempt(getCallingPid(), kServiceName, cameraIdStr, API_1);
+ int callingPid = getCallingPid();
+ logConnectionAttempt(callingPid, kServiceName, cameraIdStr, API_1);
if (!(ret = connectHelper<ICameraClient,Client>(
sp<ICameraClient>{nullptr}, cameraIdStr, cameraId,
- kServiceName, /*systemNativeClient*/ false, {}, uid, USE_CALLING_PID,
+ kServiceName, /*systemNativeClient*/ false, {}, uid, callingPid,
API_1, /*shimUpdateOnly*/ true, /*oomScoreOffset*/ 0,
/*targetSdkVersion*/ __ANDROID_API_FUTURE__,
/*rotationOverride*/hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT,
@@ -1690,7 +1681,7 @@
}
Status CameraService::validateConnectLocked(const std::string& cameraId,
- const std::string& clientName8, /*inout*/int& clientUid, /*inout*/int& clientPid) const {
+ const std::string& clientName8, int clientUid, int clientPid) const {
#ifdef __BRILLO__
UNUSED(clientName8);
@@ -1735,36 +1726,10 @@
}
Status CameraService::validateClientPermissionsLocked(const std::string& cameraId,
- const std::string& clientName, int& clientUid, int& clientPid) const {
+ const std::string& clientName, int clientUid, int clientPid) const {
int callingPid = getCallingPid();
int callingUid = getCallingUid();
- // Check if we can trust clientUid
- if (clientUid == USE_CALLING_UID) {
- clientUid = callingUid;
- } else if (!isTrustedCallingUid(callingUid)) {
- ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
- "(don't trust clientUid %d)", callingPid, callingUid, clientUid);
- return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
- "Untrusted caller (calling PID %d, UID %d) trying to "
- "forward camera access to camera %s for client %s (PID %d, UID %d)",
- callingPid, callingUid, cameraId.c_str(),
- clientName.c_str(), clientPid, clientUid);
- }
-
- // Check if we can trust clientPid
- if (clientPid == USE_CALLING_PID) {
- clientPid = callingPid;
- } else if (!isTrustedCallingUid(callingUid)) {
- ALOGE("CameraService::connect X (calling PID %d, calling UID %d) rejected "
- "(don't trust clientPid %d)", callingPid, callingUid, clientPid);
- return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
- "Untrusted caller (calling PID %d, UID %d) trying to "
- "forward camera access to camera %s for client %s (PID %d, UID %d)",
- callingPid, callingUid, cameraId.c_str(),
- clientName.c_str(), clientPid, clientUid);
- }
-
if (shouldRejectSystemCameraConnection(cameraId)) {
ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
cameraId.c_str());
@@ -2152,20 +2117,33 @@
std::string clientPackageNameMaybe = clientAttribution.packageName.value_or("");
bool isNonSystemNdk = clientPackageNameMaybe.size() == 0;
- std::string clientPackageName = resolvePackageName(clientAttribution.uid,
- clientPackageNameMaybe);
- logConnectionAttempt(clientAttribution.pid, clientPackageName, cameraIdStr, API_1);
+
+ AttributionSourceState resolvedClientAttribution(clientAttribution);
+ ret = resolveAttributionSource(resolvedClientAttribution, __FUNCTION__, cameraIdStr);
+ if (!ret.isOk()) {
+ logRejected(cameraIdStr, getCallingPid(),
+ clientAttribution.packageName.value_or("<unknown>"),
+ toStdString(ret.toString8()));
+ return ret;
+ }
+
+ const int clientPid = resolvedClientAttribution.pid;
+ const int clientUid = resolvedClientAttribution.uid;
+ const std::string& clientPackageName = *resolvedClientAttribution.packageName;
+
+ logConnectionAttempt(clientPid, clientPackageName, cameraIdStr, API_1);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, cameraIdStr, api1CameraId,
clientPackageName, /*systemNativeClient*/ false, {},
- clientAttribution.uid, clientAttribution.pid, API_1,
+ clientUid, clientPid, API_1,
/*shimUpdateOnly*/ false, /*oomScoreOffset*/ 0, targetSdkVersion,
rotationOverride, forceSlowJpegMode, cameraIdStr, isNonSystemNdk, /*out*/client);
if (!ret.isOk()) {
- logRejected(cameraIdStr, getCallingPid(), clientAttribution.packageName.value_or(""),
- toStdString(ret.toString8()));
+ logRejected(cameraIdStr, getCallingPid(),
+ clientAttribution.packageName.value_or("<unknown>"),
+ toStdString(ret.toString8()));
return ret;
}
@@ -2271,22 +2249,32 @@
std::string cameraId = cameraIdOptional.value();
bool isNonSystemNdk = clientPackageNameMaybe.size() == 0;
- std::string clientPackageName = resolvePackageName(clientAttribution.uid,
- clientPackageNameMaybe);
- logConnectionAttempt(clientAttribution.pid, clientPackageName, cameraId, API_2);
- if (oomScoreOffset < 0) {
- std::string msg =
- fmt::sprintf("Cannot increase the priority of a client %s pid %d for "
- "camera id %s", clientPackageName.c_str(), callingPid,
- cameraId.c_str());
- ALOGE("%s: %s", __FUNCTION__, msg.c_str());
- return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
+ AttributionSourceState resolvedClientAttribution(clientAttribution);
+ if (!flags::use_context_attribution_source()) {
+ resolvedClientAttribution.pid = USE_CALLING_PID;
+ }
+ ret = resolveAttributionSource(resolvedClientAttribution, __FUNCTION__, cameraId);
+ if (!ret.isOk()) {
+ logRejected(cameraId, getCallingPid(), clientAttribution.packageName.value_or(""),
+ toStdString(ret.toString8()));
+ return ret;
}
- userid_t clientUserId = multiuser_get_user_id(clientAttribution.uid);
- if (clientAttribution.uid == USE_CALLING_UID) {
- clientUserId = multiuser_get_user_id(callingUid);
+ const int clientPid = resolvedClientAttribution.pid;
+ const int clientUid = resolvedClientAttribution.uid;
+ const std::string& clientPackageName = *resolvedClientAttribution.packageName;
+ userid_t clientUserId = multiuser_get_user_id(resolvedClientAttribution.uid);
+
+ logConnectionAttempt(clientPid, clientPackageName, cameraId, API_2);
+
+ if (oomScoreOffset < 0) {
+ std::string msg = fmt::sprintf(
+ "Cannot increase the priority of a client %s pid %d for "
+ "camera id %s",
+ clientPackageName.c_str(), clientPid, cameraId.c_str());
+ ALOGE("%s: %s", __FUNCTION__, msg.c_str());
+ return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.c_str());
}
// Automotive privileged client AID_AUTOMOTIVE_EVS using exterior system camera for use cases
@@ -2299,25 +2287,24 @@
}
// enforce system camera permissions
- if (oomScoreOffset > 0
- && !hasPermissionsForSystemCamera(cameraId, callingPid,
- callingUid)
- && !isTrustedCallingUid(callingUid)) {
- std::string msg = fmt::sprintf("Cannot change the priority of a client %s pid %d for "
- "camera id %s without SYSTEM_CAMERA permissions",
- clientPackageName.c_str(), callingPid, cameraId.c_str());
+ if (oomScoreOffset > 0 && !hasPermissionsForSystemCamera(cameraId, clientPid, callingUid) &&
+ !isTrustedCallingUid(callingUid)) {
+ std::string msg = fmt::sprintf(
+ "Cannot change the priority of a client %s pid %d for "
+ "camera id %s without SYSTEM_CAMERA permissions",
+ clientPackageName.c_str(), clientPid, cameraId.c_str());
ALOGE("%s: %s", __FUNCTION__, msg.c_str());
return STATUS_ERROR(ERROR_PERMISSION_DENIED, msg.c_str());
}
- ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb,
- cameraId, /*api1CameraId*/-1, clientPackageName, systemNativeClient,
- clientAttribution.attributionTag, clientAttribution.uid, USE_CALLING_PID, API_2,
+ ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks, CameraDeviceClient>(
+ cameraCb, cameraId, /*api1CameraId*/ -1, clientPackageName, systemNativeClient,
+ resolvedClientAttribution.attributionTag, clientUid, clientPid, API_2,
/*shimUpdateOnly*/ false, oomScoreOffset, targetSdkVersion, rotationOverride,
- /*forceSlowJpegMode*/false, unresolvedCameraId, isNonSystemNdk, /*out*/client);
+ /*forceSlowJpegMode*/ false, unresolvedCameraId, isNonSystemNdk, /*out*/ client);
if (!ret.isOk()) {
- logRejected(cameraId, callingPid, clientPackageName, toStdString(ret.toString8()));
+ logRejected(cameraId, clientPid, clientPackageName, toStdString(ret.toString8()));
return ret;
}
@@ -2377,74 +2364,13 @@
return false;
}
-std::string CameraService::getPackageNameFromUid(int clientUid) const {
- std::string packageName("");
-
- sp<IPermissionController> permCtrl;
- if (flags::cache_permission_services()) {
- permCtrl = getPermissionController();
- } else {
- sp<IServiceManager> sm = defaultServiceManager();
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
- // Using deprecated function to preserve functionality until the
- // cache_permission_services flag is removed.
- sp<IBinder> binder = sm->getService(toString16(kPermissionServiceName));
-#pragma clang diagnostic pop
- if (binder == 0) {
- ALOGE("Cannot get permission service");
- permCtrl = nullptr;
- } else {
- permCtrl = interface_cast<IPermissionController>(binder);
- }
- }
-
- if (permCtrl == nullptr) {
- // Return empty package name and the further interaction
- // with camera will likely fail
- return packageName;
- }
-
- Vector<String16> packages;
-
- permCtrl->getPackagesForUid(clientUid, packages);
-
- if (packages.isEmpty()) {
- ALOGE("No packages for calling UID %d", clientUid);
- // Return empty package name and the further interaction
- // with camera will likely fail
- return packageName;
- }
-
- // Arbitrarily pick the first name in the list
- packageName = toStdString(packages[0]);
-
- return packageName;
-}
-
void CameraService::logConnectionAttempt(int clientPid, const std::string& clientPackageName,
- const std::string& cameraId, apiLevel effectiveApiLevel) const {
- int packagePid = (clientPid == USE_CALLING_PID) ?
- getCallingPid() : clientPid;
+ const std::string& cameraId,
+ apiLevel effectiveApiLevel) const {
ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) and "
- "Camera API version %d", packagePid, clientPackageName.c_str(), cameraId.c_str(),
- static_cast<int>(effectiveApiLevel));
-}
-
-std::string CameraService::resolvePackageName(int clientUid,
- const std::string& clientPackageNameMaybe) const {
- if (clientPackageNameMaybe.size() <= 0) {
- int packageUid = (clientUid == USE_CALLING_UID) ?
- getCallingUid() : clientUid;
- // NDK calls don't come with package names, but we need one for various cases.
- // Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
- // do exist. For all authentication cases, all packages under the same UID get the
- // same permissions, so picking any associated package name is sufficient. For some
- // other cases, this may give inaccurate names for clients in logs.
- return getPackageNameFromUid(packageUid);
- } else {
- return clientPackageNameMaybe;
- }
+ "Camera API version %d",
+ clientPid, clientPackageName.c_str(), cameraId.c_str(),
+ static_cast<int>(effectiveApiLevel));
}
template<class CALLBACK, class CLIENT>
@@ -2456,11 +2382,6 @@
const std::string& originalCameraId, bool isNonSystemNdk, /*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
- int packageUid = (clientUid == USE_CALLING_UID) ?
- getCallingUid() : clientUid;
- int packagePid = (clientPid == USE_CALLING_PID) ?
- getCallingPid() : clientPid;
-
nsecs_t openTimeNs = systemTime();
sp<CLIENT> client = nullptr;
@@ -2680,7 +2601,7 @@
if (flags::camera_privacy_allowlist()) {
// Set camera muting behavior.
isCameraPrivacyEnabled = this->isCameraPrivacyEnabled(
- toString16(client->getPackageName()), cameraId, packagePid, packageUid);
+ toString16(client->getPackageName()), cameraId, clientPid, clientUid);
} else {
isCameraPrivacyEnabled =
mSensorPrivacyPolicy->isCameraPrivacyEnabled();
@@ -4330,14 +4251,9 @@
// Notify app ops that the camera is not available
mOpsCallback = new OpsCallback(this);
- if (flags::watch_foreground_changes()) {
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
- toString16(mClientPackageName),
- AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
- } else {
- mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
- toString16(mClientPackageName), mOpsCallback);
- }
+ mAppOpsManager->startWatchingMode(AppOpsManager::OP_CAMERA,
+ toString16(mClientPackageName),
+ AppOpsManager::WATCH_FOREGROUND_CHANGES, mOpsCallback);
// Just check for camera acccess here on open - delay startOp until
// camera frames start streaming in startCameraStreamingOps
@@ -4520,19 +4436,10 @@
// (WAR for b/175320666)the AppOpsManager could return MODE_IGNORED. Do not treat such
// cases as error.
if (!mUidIsTrusted) {
- if (flags::watch_foreground_changes()) {
- if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
- setCameraMute(true);
- } else {
- block();
- }
+ if (isUidVisible && isCameraPrivacyEnabled && supportsCameraMute()) {
+ setCameraMute(true);
} else {
- if (isUidActive && isCameraPrivacyEnabled && supportsCameraMute()) {
- setCameraMute(true);
- } else if (!isUidActive
- || (isCameraPrivacyEnabled && !supportsCameraMute())) {
- block();
- }
+ block();
}
}
} else if (res == AppOpsManager::MODE_ALLOWED) {
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index d5c57cb..5eb2536 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -33,7 +33,6 @@
#include <binder/IServiceManager.h>
#include <binder/IActivityManager.h>
#include <binder/IAppOpsCallback.h>
-#include <binder/IPermissionController.h>
#include <binder/IUidObserver.h>
#include <hardware/camera.h>
#include <sensorprivacy/SensorPrivacyManager.h>
@@ -686,25 +685,6 @@
return activityManager;
}
- static const sp<IPermissionController>& getPermissionController() {
- static const char* kPermissionControllerService = "permission";
- static thread_local sp<IPermissionController> sPermissionController = nullptr;
-
- if (sPermissionController == nullptr ||
- !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
- if (binder == nullptr) {
- ALOGE("%s: Could not get permission service", __FUNCTION__);
- sPermissionController = nullptr;
- } else {
- sPermissionController = interface_cast<IPermissionController>(binder);
- }
- }
-
- return sPermissionController;
- }
-
/**
* Typesafe version of device status, containing both the HAL-layer and the service interface-
* layer values.
@@ -950,12 +930,10 @@
// If clientPid/clientUid are USE_CALLING_PID/USE_CALLING_UID, they will be overwritten with
// the calling pid/uid.
binder::Status validateConnectLocked(const std::string& cameraId, const std::string& clientName,
- /*inout*/int& clientUid, /*inout*/int& clientPid) const;
+ int clientUid, int clientPid) const;
binder::Status validateClientPermissionsLocked(const std::string& cameraId,
- const std::string& clientName, /*inout*/int& clientUid, /*inout*/int& clientPid) const;
+ const std::string& clientName, int clientUid, int clientPid) const;
- // If clientPackageNameMaybe is empty, attempts to resolve the package name.
- std::string resolvePackageName(int clientUid, const std::string& clientPackageNameMaybe) const;
void logConnectionAttempt(int clientPid, const std::string& clientPackageName,
const std::string& cameraId, apiLevel effectiveApiLevel) const;
@@ -995,15 +973,6 @@
// sorted in alpha-numeric order.
void filterAPI1SystemCameraLocked(const std::vector<std::string> &normalDeviceIds);
- // In some cases the calling code has no access to the package it runs under.
- // For example, NDK camera API.
- // In this case we will get the packages for the calling UID and pick the first one
- // for attributing the app op. This will work correctly for runtime permissions
- // as for legacy apps we will toggle the app op for all packages in the UID.
- // The caveat is that the operation may be attributed to the wrong package and
- // stats based on app ops may be slightly off.
- std::string getPackageNameFromUid(int clientUid) const;
-
// Single implementation shared between the various connect calls
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const std::string& cameraId,
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.cpp b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
index 1c1bd24..ad1a84f 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.cpp
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.cpp
@@ -17,11 +17,14 @@
#define LOG_TAG "CameraServiceWatchdog"
#include "CameraServiceWatchdog.h"
+#include "com_android_internal_camera_flags.h"
#include "android/set_abort_message.h"
#include "utils/CameraServiceProxyWrapper.h"
namespace android {
+namespace flags = com::android::internal::camera::flags;
+
bool CameraServiceWatchdog::threadLoop()
{
{
@@ -51,6 +54,12 @@
true /*deviceError*/);
// We use abort here so we can get a tombstone for better
// debugging.
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ for (pid_t pid : mProviderPids) {
+ kill(pid, SIGABRT);
+ }
+ }
+
abort();
}
}
diff --git a/services/camera/libcameraservice/CameraServiceWatchdog.h b/services/camera/libcameraservice/CameraServiceWatchdog.h
index 165dece..691a274 100644
--- a/services/camera/libcameraservice/CameraServiceWatchdog.h
+++ b/services/camera/libcameraservice/CameraServiceWatchdog.h
@@ -30,6 +30,7 @@
*/
#pragma once
#include <chrono>
+#include <set>
#include <thread>
#include <time.h>
#include <utils/Thread.h>
@@ -57,16 +58,17 @@
};
public:
- explicit CameraServiceWatchdog(const std::string &cameraId,
+
+ explicit CameraServiceWatchdog(const std::set<pid_t> &pids, const std::string &cameraId,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
- mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
+ mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(kMaxCycles),
mCycleLengthMs(kCycleLengthMs), mEnabled(true),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
- explicit CameraServiceWatchdog (const std::string &cameraId, size_t maxCycles,
- uint32_t cycleLengthMs, bool enabled,
+ explicit CameraServiceWatchdog (const std::set<pid_t> &pids, const std::string &cameraId,
+ size_t maxCycles, uint32_t cycleLengthMs, bool enabled,
std::shared_ptr<CameraServiceProxyWrapper> cameraServiceProxyWrapper) :
- mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
+ mProviderPids(pids), mCameraId(cameraId), mPause(true), mMaxCycles(maxCycles),
mCycleLengthMs(cycleLengthMs), mEnabled(enabled),
mCameraServiceProxyWrapper(cameraServiceProxyWrapper) {};
@@ -90,7 +92,8 @@
// Lock for mEnabled
mEnabledLock.lock();
sp<CameraServiceWatchdog> tempWatchdog = new CameraServiceWatchdog(
- mCameraId, cycles, cycleLength, mEnabled, mCameraServiceProxyWrapper);
+ mProviderPids, mCameraId, cycles, cycleLength, mEnabled,
+ mCameraServiceProxyWrapper);
mEnabledLock.unlock();
status_t status = tempWatchdog->run("CameraServiceWatchdog");
@@ -150,6 +153,7 @@
Mutex mWatchdogLock; // Lock for condition variable
Mutex mEnabledLock; // Lock for enabled status
Condition mWatchdogCondition; // Condition variable for stop/start
+ std::set<pid_t> mProviderPids; // Process ID set of camera providers
std::string mCameraId; // Camera Id the watchdog belongs to
bool mPause; // True if tid map is empty
uint32_t mMaxCycles; // Max cycles
diff --git a/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h b/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
index 86af36c..61b150d 100644
--- a/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/ExtensionMetadataTags.h
@@ -30,13 +30,4 @@
std::vector<camera_metadata_tag> extension_metadata_keys{
ANDROID_EXTENSION_STRENGTH,
ANDROID_EXTENSION_CURRENT_TYPE,
- ANDROID_EFV_PADDING_ZOOM_FACTOR,
- ANDROID_EFV_AUTO_ZOOM,
- ANDROID_EFV_MAX_PADDING_ZOOM_FACTOR,
- ANDROID_EFV_STABILIZATION_MODE,
- ANDROID_EFV_TRANSLATE_VIEWPORT,
- ANDROID_EFV_ROTATE_VIEWPORT,
- ANDROID_EFV_PADDING_REGION,
- ANDROID_EFV_AUTO_ZOOM_PADDING_REGION,
- ANDROID_EFV_TARGET_COORDINATES,
};
diff --git a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
index 0e1db5c..b07d8d5 100644
--- a/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
+++ b/services/camera/libcameraservice/aidl/VndkVersionMetadataTags.h
@@ -87,7 +87,6 @@
} },
{35, {
ANDROID_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE,
- ANDROID_EFV_PADDING_ZOOM_FACTOR_RANGE,
ANDROID_FLASH_SINGLE_STRENGTH_DEFAULT_LEVEL,
ANDROID_FLASH_SINGLE_STRENGTH_MAX_LEVEL,
ANDROID_FLASH_TORCH_STRENGTH_DEFAULT_LEVEL,
@@ -121,15 +120,6 @@
} },
{35, {
ANDROID_CONTROL_LOW_LIGHT_BOOST_STATE,
- ANDROID_EFV_AUTO_ZOOM,
- ANDROID_EFV_AUTO_ZOOM_PADDING_REGION,
- ANDROID_EFV_MAX_PADDING_ZOOM_FACTOR,
- ANDROID_EFV_PADDING_REGION,
- ANDROID_EFV_PADDING_ZOOM_FACTOR,
- ANDROID_EFV_ROTATE_VIEWPORT,
- ANDROID_EFV_STABILIZATION_MODE,
- ANDROID_EFV_TARGET_COORDINATES,
- ANDROID_EFV_TRANSLATE_VIEWPORT,
ANDROID_FLASH_STRENGTH_LEVEL,
ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION,
ANDROID_STATISTICS_LENS_INTRINSIC_SAMPLES,
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index d4953c1..0f1d0ff 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -142,8 +142,12 @@
mHasFocuser(false),
mInputBuffer(nullptr),
mProducer(nullptr),
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ mInputSurface(nullptr),
+#else
mInputProducer(nullptr),
mInputProducerSlot(-1),
+#endif
mBuffersToDetach(0) {
// Initialize buffer queue and frame list based on pipeline max depth.
size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
@@ -331,10 +335,17 @@
mInputStreamId = NO_STREAM;
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ if (nullptr != mInputSurface.get()) {
+ // The surface destructor calls disconnect
+ mInputSurface.clear();
+ }
+#else
if (nullptr != mInputProducer.get()) {
mInputProducer->disconnect(NATIVE_WINDOW_API_CPU);
mInputProducer.clear();
}
+#endif
return OK;
}
@@ -393,11 +404,19 @@
void ZslProcessor::doNotifyInputReleasedLocked() {
assert(nullptr != mInputBuffer.get());
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ assert(nullptr != mInputSurface.get());
+#else
assert(nullptr != mInputProducer.get());
+#endif
sp<GraphicBuffer> gb;
sp<Fence> fence;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ auto rc = mInputSurface->detachNextBuffer(&gb, &fence);
+#else
auto rc = mInputProducer->detachNextBuffer(&gb, &fence);
+#endif
if (NO_ERROR != rc) {
ALOGE("%s: Failed to detach buffer from input producer: %d",
__FUNCTION__, rc);
@@ -456,9 +475,15 @@
__FUNCTION__, (unsigned int) metadataIdx);
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ if (nullptr == mInputSurface.get()) {
+ res = client->getCameraDevice()->getInputSurface(
+ &mInputSurface);
+#else
if (nullptr == mInputProducer.get()) {
res = client->getCameraDevice()->getInputBufferProducer(
&mInputProducer);
+#endif
if (res != OK) {
ALOGE("%s: Camera %d: Unable to retrieve input producer: "
"%s (%d)", __FUNCTION__, client->getCameraId(),
@@ -466,9 +491,14 @@
return res;
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ res = mInputSurface->connect(NATIVE_WINDOW_API_CPU, new InputProducerListener(this),
+ false);
+#else
IGraphicBufferProducer::QueueBufferOutput output;
res = mInputProducer->connect(new InputProducerListener(this),
NATIVE_WINDOW_API_CPU, false, &output);
+#endif
if (res != OK) {
ALOGE("%s: Camera %d: Unable to connect to input producer: "
"%s (%d)", __FUNCTION__, client->getCameraId(),
@@ -629,19 +659,32 @@
}
BufferItem &item = mInputBuffer->getBufferItem();
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ auto rc = mInputSurface->attachBuffer(item.mGraphicBuffer->getNativeBuffer());
+#else
auto rc = mInputProducer->attachBuffer(&mInputProducerSlot,
item.mGraphicBuffer);
+#endif
if (OK != rc) {
ALOGE("%s: Failed to attach input ZSL buffer to producer: %d",
__FUNCTION__, rc);
return rc;
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ mInputSurface->setBuffersTimestamp(item.mTimestamp);
+ mInputSurface->setBuffersDataSpace(static_cast<ui::Dataspace>(item.mDataSpace));
+ mInputSurface->setCrop(&item.mCrop);
+ mInputSurface->setScalingMode(item.mScalingMode);
+ mInputSurface->setBuffersTransform(item.mTransform);
+ rc = mInputSurface->queueBuffer(item.mGraphicBuffer, item.mFence);
+#else
IGraphicBufferProducer::QueueBufferOutput output;
IGraphicBufferProducer::QueueBufferInput input(item.mTimestamp,
item.mIsAutoTimestamp, item.mDataSpace, item.mCrop,
item.mScalingMode, item.mTransform, item.mFence);
rc = mInputProducer->queueBuffer(mInputProducerSlot, input, &output);
+#endif
if (OK != rc) {
ALOGE("%s: Failed to queue ZSL buffer to producer: %d",
__FUNCTION__, rc);
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 3186233..a98160a 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -24,8 +24,9 @@
#include <utils/Condition.h>
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
-#include <gui/RingBufferConsumer.h>
+#include <gui/Flags.h>
#include <gui/IProducerListener.h>
+#include <gui/RingBufferConsumer.h>
#include <camera/CameraMetadata.h>
#include "api1/client2/FrameProcessor.h"
@@ -83,6 +84,20 @@
private:
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ class InputProducerListener : public SurfaceListener {
+ public:
+ InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
+ virtual void onBufferReleased() override;
+ virtual void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /* buffers */)
+ override {}
+ virtual void onBufferDetached(int /* slot */) override {}
+ virtual bool needsReleaseNotify() override { return true; }
+
+ private:
+ wp<ZslProcessor> mParent;
+ };
+#else
class InputProducerListener : public BnProducerListener {
public:
InputProducerListener(wp<ZslProcessor> parent) : mParent(parent) {}
@@ -92,6 +107,7 @@
private:
wp<ZslProcessor> mParent;
};
+#endif
static const nsecs_t kWaitDuration = 10000000; // 10 ms
nsecs_t mLatestClearedBufferTimestamp;
@@ -139,8 +155,13 @@
// Input buffer queued into HAL
sp<RingBufferConsumer::PinnedBufferItem> mInputBuffer;
sp<RingBufferConsumer> mProducer;
+
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ sp<Surface> mInputSurface;
+#else
sp<IGraphicBufferProducer> mInputProducer;
int mInputProducerSlot;
+#endif
Condition mBuffersToDetachSignal;
int mBuffersToDetach;
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index fcba9bc..f469aad 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -546,14 +546,14 @@
mRunningSessionStats.mVideoStabilizationMode = entry.data.u8[0];
}
- if (!mRunningSessionStats.mUsedUltraWide && flags::log_ultrawide_usage()) {
+ if (!mRunningSessionStats.mUsedUltraWide) {
entry = physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_ZOOM_RATIO);
if (entry.count == 1 && entry.data.f[0] < 1.0f ) {
mRunningSessionStats.mUsedUltraWide = true;
}
}
- if (!mRunningSessionStats.mUsedSettingsOverrideZoom && flags::log_zoom_override_usage()) {
+ if (!mRunningSessionStats.mUsedSettingsOverrideZoom) {
entry = physicalSettingsList.begin()->metadata.find(
ANDROID_CONTROL_SETTINGS_OVERRIDE);
if (entry.count == 1 && entry.data.i32[0] ==
@@ -1240,6 +1240,18 @@
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ sp<Surface> surface;
+ status_t err = mDevice->getInputSurface(&surface);
+ if (err != OK) {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Camera %s: Error getting input Surface: %s (%d)",
+ mCameraIdStr.c_str(), strerror(-err), err);
+ } else {
+ inputSurface->name = toString16("CameraInput");
+ inputSurface->graphicBufferProducer = surface->getIGraphicBufferProducer();
+ }
+#else
sp<IGraphicBufferProducer> producer;
status_t err = mDevice->getInputBufferProducer(&producer);
if (err != OK) {
@@ -1250,6 +1262,7 @@
inputSurface->name = toString16("CameraInput");
inputSurface->graphicBufferProducer = producer;
}
+#endif
return res;
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 352c6f8..18069fe 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -358,7 +358,7 @@
bool landscapeSensor = (orientation == 0 || orientation == 180);
if (((TClientBase::mRotationOverride ==
ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) && landscapeSensor) ||
- ((wm_flags::camera_compat_for_freeform() &&
+ ((wm_flags::enable_camera_compat_for_desktop_windowing() &&
TClientBase::mRotationOverride ==
ICameraService::ROTATION_OVERRIDE_ROTATION_ONLY)
&& !landscapeSensor)) {
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index aceb5c0..9c8f5ad 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -25,6 +25,7 @@
#include <utils/KeyedVector.h>
#include <utils/Timers.h>
#include <utils/List.h>
+#include <gui/Flags.h>
#include "hardware/camera2.h"
#include "camera/CameraMetadata.h"
@@ -305,9 +306,14 @@
*/
virtual void getOfflineStreamIds(std::vector<int> *offlineStreamIds) = 0;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ // get the surface of the input stream
+ virtual status_t getInputSurface(sp<Surface> *surface) = 0;
+#else
// get the buffer producer of the input stream
virtual status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) = 0;
+#endif
/**
* Create a metadata buffer with fields that the HAL device believes are
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 2440c37..a03d199 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -34,6 +34,7 @@
#include <inttypes.h>
#include <android_companion_virtualdevice_flags.h>
#include <android_companion_virtualdevice_build_flags.h>
+#include <android/binder_libbinder.h>
#include <android/binder_manager.h>
#include <android/hidl/manager/1.2/IServiceManager.h>
#include <hidl/ServiceManagement.h>
@@ -148,11 +149,7 @@
using aidl::android::hardware::camera::provider::ICameraProvider;
AIBinder* binder = nullptr;
- if (flags::lazy_aidl_wait_for_service()) {
- binder = AServiceManager_waitForService(serviceName.c_str());
- } else {
- binder = AServiceManager_checkService(serviceName.c_str());
- }
+ binder = AServiceManager_waitForService(serviceName.c_str());
if (binder == nullptr) {
ALOGE("%s: AIDL Camera provider HAL '%s' is not actually available, despite waiting "
@@ -470,10 +467,6 @@
status_t CameraProviderManager::getSessionCharacteristics(
const std::string& id, const SessionConfiguration& configuration, bool overrideForPerfClass,
int rotationOverride, CameraMetadata* sessionCharacteristics /*out*/) const {
- if (!flags::feature_combination_query()) {
- return INVALID_OPERATION;
- }
-
std::lock_guard<std::mutex> lock(mInterfaceMutex);
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) {
@@ -2119,14 +2112,8 @@
const std::string& providerName, const sp<ProviderInfo>& providerInfo) {
using aidl::android::hardware::camera::provider::ICameraProvider;
- std::shared_ptr<ICameraProvider> interface;
- if (flags::delay_lazy_hal_instantiation()) {
- // Only get remote instance if already running. Lazy Providers will be
- // woken up later.
- interface = mAidlServiceProxy->tryGetService(providerName);
- } else {
- interface = mAidlServiceProxy->getService(providerName);
- }
+ // Only get remote instance if already running. Lazy Providers will be woken up later.
+ std::shared_ptr<ICameraProvider> interface = mAidlServiceProxy->tryGetService(providerName);
if (interface == nullptr) {
ALOGW("%s: AIDL Camera provider HAL '%s' is not actually available", __FUNCTION__,
@@ -2135,7 +2122,19 @@
}
AidlProviderInfo *aidlProviderInfo = static_cast<AidlProviderInfo *>(providerInfo.get());
- return aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+ status_t res = aidlProviderInfo->initializeAidlProvider(interface, mDeviceState);
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ pid_t pid = 0;
+
+ if (AIBinder_toPlatformBinder(interface->asBinder().get())->getDebugPid(&pid) == OK
+ && res == OK) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+ mProviderPidMap[providerInfo->mProviderInstance] = pid;
+ }
+ }
+
+ return res;
}
status_t CameraProviderManager::tryToInitializeHidlProviderLocked(
@@ -2152,7 +2151,23 @@
}
HidlProviderInfo *hidlProviderInfo = static_cast<HidlProviderInfo *>(providerInfo.get());
- return hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+ status_t res = hidlProviderInfo->initializeHidlProvider(interface, mDeviceState);
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ pid_t pid = 0;
+
+ auto ret = interface->getDebugInfo([&pid](
+ const ::android::hidl::base::V1_0::DebugInfo& info) {
+ pid = info.pid;
+ });
+
+ if (ret.isOk() && res == OK) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+ mProviderPidMap[providerInfo->mProviderInstance] = pid;
+ }
+ }
+
+ return res;
}
status_t CameraProviderManager::addAidlProviderLocked(const std::string& newProvider) {
@@ -2163,14 +2178,11 @@
bool preexisting =
(mAidlProviderWithBinders.find(newProvider) != mAidlProviderWithBinders.end());
using aidl::android::hardware::camera::provider::ICameraProvider;
- std::string providerNameUsed =
- newProvider.substr(std::string(ICameraProvider::descriptor).size() + 1);
- if (flags::lazy_aidl_wait_for_service()) {
- // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
- // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
- // here.
- providerNameUsed = newProvider;
- }
+
+ // 'newProvider' has the fully qualified name of the provider service in case of AIDL.
+ // ProviderInfo::mProviderName also has the fully qualified name - so we just compare them
+ // here.
+ std::string providerNameUsed = newProvider;
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == providerNameUsed) {
@@ -2264,20 +2276,23 @@
ALOGW("%s: Camera provider HAL with name '%s' is not registered", __FUNCTION__,
provider.c_str());
} else {
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ {
+ std::lock_guard<std::mutex> pidLock(mProviderPidMapLock);
+ mProviderPidMap.erase(provider);
+ }
+ }
+
// Check if there are any newer camera instances from the same provider and try to
// initialize.
for (const auto& providerInfo : mProviders) {
if (providerInfo->mProviderName == removedProviderName) {
IPCTransport providerTransport = providerInfo->getIPCTransport();
- std::string removedAidlProviderName = getFullAidlProviderName(removedProviderName);
- if (flags::lazy_aidl_wait_for_service()) {
- removedAidlProviderName = removedProviderName;
- }
switch(providerTransport) {
case IPCTransport::HIDL:
return tryToInitializeHidlProviderLocked(removedProviderName, providerInfo);
case IPCTransport::AIDL:
- return tryToInitializeAidlProviderLocked(removedAidlProviderName,
+ return tryToInitializeAidlProviderLocked(removedProviderName,
providerInfo);
default:
ALOGE("%s Unsupported Transport %d", __FUNCTION__, eToI(providerTransport));
@@ -2443,7 +2458,7 @@
bool CameraProviderManager::ProviderInfo::isExternalLazyHAL() const {
std::string providerName = mProviderName;
- if (flags::lazy_aidl_wait_for_service() && getIPCTransport() == IPCTransport::AIDL) {
+ if (getIPCTransport() == IPCTransport::AIDL) {
using aidl::android::hardware::camera::provider::ICameraProvider;
providerName =
mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
@@ -2451,6 +2466,20 @@
return kEnableLazyHal && (providerName == kExternalProviderName);
}
+std::set<pid_t> CameraProviderManager::getProviderPids() {
+ std::set<pid_t> pids;
+
+ if (flags::enable_hal_abort_from_cameraservicewatchdog()) {
+ std::lock_guard<std::mutex> lock(mProviderPidMapLock);
+
+ std::transform(mProviderPidMap.begin(), mProviderPidMap.end(),
+ std::inserter(pids, pids.begin()),
+ [](std::pair<const std::string, pid_t>& entry) { return entry.second; });
+ }
+
+ return pids;
+}
+
status_t CameraProviderManager::ProviderInfo::dump(int fd, const Vector<String16>&) const {
dprintf(fd, "== Camera Provider HAL %s (v2.%d, %s) static info: %zu devices: ==\n",
mProviderInstance.c_str(),
@@ -2771,7 +2800,7 @@
hardware::CameraInfo *info) const {
if (info == nullptr) return BAD_VALUE;
- bool freeform_compat_enabled = wm_flags::camera_compat_for_freeform();
+ bool freeform_compat_enabled = wm_flags::enable_camera_compat_for_desktop_windowing();
if (!freeform_compat_enabled &&
rotationOverride > hardware::ICameraService::ROTATION_OVERRIDE_OVERRIDE_TO_PORTRAIT) {
ALOGW("Camera compat freeform flag disabled but rotation override is %d", rotationOverride);
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.h b/services/camera/libcameraservice/common/CameraProviderManager.h
index 4a64b44..b686a58 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.h
+++ b/services/camera/libcameraservice/common/CameraProviderManager.h
@@ -431,6 +431,11 @@
// LocalRegistrationCallback::onServiceRegistration
virtual void onServiceRegistration(const String16& name, const sp<IBinder> &binder) override;
+ /*
+ * Return list of provider pid
+ */
+ std::set<pid_t> getProviderPids();
+
/**
* Dump out information about available providers and devices
*/
@@ -914,6 +919,9 @@
// Provider names of AIDL providers with retrieved binders.
std::set<std::string> mAidlProviderWithBinders;
+ std::mutex mProviderPidMapLock;
+ std::map<std::string, pid_t> mProviderPidMap;
+
static const char* deviceStatusToString(
const hardware::camera::common::V1_0::CameraDeviceStatus&);
static const char* torchStatusToString(
diff --git a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
index e76b750..4bfe11d 100644
--- a/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/aidl/AidlProviderInfo.cpp
@@ -109,11 +109,8 @@
std::shared_ptr<ICameraProvider>& interface, int64_t currentDeviceState) {
using aidl::android::hardware::camera::provider::ICameraProvider;
- std::string parsedProviderName = mProviderName;
- if (flags::lazy_aidl_wait_for_service()) {
- parsedProviderName =
+ std::string parsedProviderName =
mProviderName.substr(std::string(ICameraProvider::descriptor).size() + 1);
- }
status_t res = parseProviderName(parsedProviderName, &mType, &mId);
if (res != OK) {
@@ -529,13 +526,11 @@
__FUNCTION__, strerror(-res), res);
return;
}
- if (flags::camera_manual_flash_strength_control()) {
- res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
- if (OK != res) {
- ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
+ res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
}
auto stat = addDynamicDepthTags();
@@ -622,12 +617,10 @@
mHasFlashUnit = false;
}
- if (flags::feature_combination_query()) {
- res = addSessionConfigQueryVersionTag();
- if (OK != res) {
- ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
+ res = addSessionConfigQueryVersionTag();
+ if (OK != res) {
+ ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
}
camera_metadata_entry entry =
@@ -684,13 +677,11 @@
__FUNCTION__, strerror(-res), res);
}
- if (flags::camera_manual_flash_strength_control()) {
- res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
- if (OK != res) {
- ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
+ res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
}
}
}
@@ -844,11 +835,7 @@
mVersion.get_minor());
return INVALID_OPERATION;
}
- if (flags::feature_combination_query()) {
- ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status);
- } else {
- return INVALID_OPERATION;
- }
+ ret = interface->isStreamCombinationWithSettingsSupported(streamConfiguration, status);
} else {
ret = interface->isStreamCombinationSupported(streamConfiguration, status);
}
@@ -887,10 +874,6 @@
return res;
}
- if (!flags::feature_combination_query()) {
- return INVALID_OPERATION;
- }
-
auto err = interface->constructDefaultRequestSettings(id, &request);
if (!err.isOk()) {
ALOGE("%s: Transaction error: %s", __FUNCTION__, err.getMessage());
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index 40800d9..6cedb04 100644
--- a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
+++ b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
@@ -616,13 +616,12 @@
__FUNCTION__, strerror(-res), res);
return;
}
- if (flags::camera_manual_flash_strength_control()) {
- res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
- if (OK != res) {
- ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
+
+ res = fixupManualFlashStrengthControlTags(mCameraCharacteristics);
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
}
auto stat = addDynamicDepthTags();
@@ -693,12 +692,10 @@
mHasFlashUnit = false;
}
- if (flags::feature_combination_query()) {
- res = addSessionConfigQueryVersionTag();
- if (OK != res) {
- ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- }
+ res = addSessionConfigQueryVersionTag();
+ if (OK != res) {
+ ALOGE("%s: Unable to add sessionConfigurationQueryVersion tag: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
}
camera_metadata_entry entry =
@@ -782,13 +779,11 @@
__FUNCTION__, strerror(-res), res);
}
- if (flags::camera_manual_flash_strength_control()) {
- res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
- if (OK != res) {
- ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return;
- }
+ res = fixupManualFlashStrengthControlTags(mPhysicalCameraCharacteristics[id]);
+ if (OK != res) {
+ ALOGE("%s: Unable to fix up manual flash strength control tags: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return;
}
}
}
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 11891e9..5721745 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -133,7 +133,7 @@
return mId;
}
-status_t Camera3Device::initializeCommonLocked() {
+status_t Camera3Device::initializeCommonLocked(sp<CameraProviderManager> manager) {
/** Start up status tracker thread */
mStatusTracker = new StatusTracker(this);
@@ -251,7 +251,8 @@
mInjectionMethods = createCamera3DeviceInjectionMethods(this);
/** Start watchdog thread */
- mCameraServiceWatchdog = new CameraServiceWatchdog(mId, mCameraServiceProxyWrapper);
+ mCameraServiceWatchdog = new CameraServiceWatchdog(
+ manager->getProviderPids(), mId, mCameraServiceProxyWrapper);
res = mCameraServiceWatchdog->run("CameraServiceWatchdog");
if (res != OK) {
SET_ERR_L("Unable to start camera service watchdog thread: %s (%d)",
@@ -1440,6 +1441,21 @@
return configureStreamsLocked(operatingMode, filteredParams);
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Device::getInputSurface(sp<Surface> *surface) {
+ ATRACE_CALL();
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ if (surface == NULL) {
+ return BAD_VALUE;
+ } else if (mInputStream == NULL) {
+ return INVALID_OPERATION;
+ }
+
+ return mInputStream->getInputSurface(surface);
+}
+#else
status_t Camera3Device::getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) {
ATRACE_CALL();
@@ -1454,6 +1470,7 @@
return mInputStream->getInputBufferProducer(producer);
}
+#endif
status_t Camera3Device::createDefaultRequest(camera_request_template_t templateId,
CameraMetadata *request) {
@@ -1631,7 +1648,7 @@
bool signalPipelineDrain = false;
if (!active &&
(mUseHalBufManager ||
- (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() != 0))) {
+ (mHalBufManagedStreamIds.size() != 0))) {
auto streamIds = mOutputStreams.getStreamIds();
if (mStatus == STATUS_ACTIVE) {
mRequestThread->signalPipelineDrain(streamIds);
@@ -1835,10 +1852,7 @@
mSessionStatsBuilder.stopCounter();
}
- // Calculate expected duration for flush with additional buffer time in ms for watchdog
- uint64_t maxExpectedDuration = ns2ms(getExpectedInFlightDuration() + kBaseGetBufferWait);
- status_t res = mCameraServiceWatchdog->WATCH_CUSTOM_TIMER(mRequestThread->flush(),
- maxExpectedDuration / kCycleLengthMs, kCycleLengthMs);
+ status_t res = mCameraServiceWatchdog->WATCH(mRequestThread->flush());
return res;
}
@@ -2584,25 +2598,23 @@
// It is possible that use hal buffer manager behavior was changed by the
// configureStreams call.
mUseHalBufManager = config.use_hal_buf_manager;
- if (flags::session_hal_buf_manager()) {
- bool prevSessionHalBufManager = (mHalBufManagedStreamIds.size() != 0);
- // It is possible that configureStreams() changed config.hal_buffer_managed_streams
- mHalBufManagedStreamIds = config.hal_buffer_managed_streams;
+ bool prevSessionHalBufManager = (mHalBufManagedStreamIds.size() != 0);
+ // It is possible that configureStreams() changed config.hal_buffer_managed_streams
+ mHalBufManagedStreamIds = config.hal_buffer_managed_streams;
- bool thisSessionHalBufManager = mHalBufManagedStreamIds.size() != 0;
+ bool thisSessionHalBufManager = mHalBufManagedStreamIds.size() != 0;
- if (prevSessionHalBufManager && !thisSessionHalBufManager) {
- mRequestBufferSM.deInit();
- } else if (!prevSessionHalBufManager && thisSessionHalBufManager) {
- res = mRequestBufferSM.initialize(mStatusTracker);
- if (res != OK) {
- SET_ERR_L("%s: Camera %s: RequestBuffer State machine couldn't be initialized!",
- __FUNCTION__, mId.c_str());
- return res;
- }
+ if (prevSessionHalBufManager && !thisSessionHalBufManager) {
+ mRequestBufferSM.deInit();
+ } else if (!prevSessionHalBufManager && thisSessionHalBufManager) {
+ res = mRequestBufferSM.initialize(mStatusTracker);
+ if (res != OK) {
+ SET_ERR_L("%s: Camera %s: RequestBuffer State machine couldn't be initialized!",
+ __FUNCTION__, mId.c_str());
+ return res;
}
- mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
}
+ mRequestThread->setHalBufferManagedStreams(mHalBufManagedStreamIds);
// Finish all stream configuration immediately.
// TODO: Try to relax this later back to lazy completion, which should be
@@ -3007,8 +3019,7 @@
}
bool Camera3Device::HalInterface::isHalBufferManagedStream(int32_t streamId) const {
- return (mUseHalBufManager || (flags::session_hal_buf_manager() &&
- contains(mHalBufManagedStreamIds, streamId)));
+ return (mUseHalBufManager || contains(mHalBufManagedStreamIds, streamId));
}
status_t Camera3Device::HalInterface::popInflightBuffer(
@@ -4170,8 +4181,7 @@
}
}
bool passSurfaceMap =
- mUseHalBufManager ||
- (flags::session_hal_buf_manager() && containsHalBufferManagedStream);
+ mUseHalBufManager || containsHalBufferManagedStream;
auto expectedDurationInfo = calculateExpectedDurationRange(settings);
res = parent->registerInFlight(halRequest->frame_number,
totalNumBuffers, captureRequest->mResultExtras,
@@ -4287,7 +4297,7 @@
void Camera3Device::RequestThread::signalPipelineDrain(const std::vector<int>& streamIds) {
if (!mUseHalBufManager &&
- (flags::session_hal_buf_manager() && mHalBufManagedStreamIds.size() == 0)) {
+ (mHalBufManagedStreamIds.size() == 0)) {
ALOGE("%s called for camera device not supporting HAL buffer management", __FUNCTION__);
return;
}
@@ -4445,8 +4455,7 @@
Camera3Stream *stream = Camera3Stream::cast((*outputBuffers)[i].stream);
int32_t streamId = stream->getId();
bool skipBufferForStream =
- mUseHalBufManager || (flags::session_hal_buf_manager() &&
- contains(mHalBufManagedStreamIds, streamId));
+ mUseHalBufManager || (contains(mHalBufManagedStreamIds, streamId));
if (skipBufferForStream) {
// No output buffer can be returned when using HAL buffer manager for its stream
continue;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index e5ccbae..3c45c1a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -31,6 +31,7 @@
#include <utils/Timers.h>
#include <camera/CaptureResult.h>
+#include <gui/Flags.h>
#include "CameraServiceWatchdog.h"
#include <aidl/android/hardware/camera/device/CameraBlob.h>
@@ -197,8 +198,12 @@
status_t configureStreams(const CameraMetadata& sessionParams,
int operatingMode =
camera_stream_configuration_mode_t::CAMERA_STREAM_CONFIGURATION_NORMAL_MODE) override;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ status_t getInputSurface(sp<Surface> *surface) override;
+#else
status_t getInputBufferProducer(
sp<IGraphicBufferProducer> *producer) override;
+#endif
void getOfflineStreamIds(std::vector<int> *offlineStreamIds) override;
@@ -726,7 +731,7 @@
*
* Must be called with mLock and mInterfaceLock held.
*/
- status_t initializeCommonLocked();
+ status_t initializeCommonLocked(sp<CameraProviderManager> manager);
/**
* Update capture request list so that each batch size honors the batch_size_max report from
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index f9b6037..999f563 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -182,6 +182,21 @@
/*output*/false, /*transform*/ -1);
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3InputStream::getInputSurfaceLocked(sp<Surface> *surface) {
+ ATRACE_CALL();
+
+ if (surface == NULL) {
+ return BAD_VALUE;
+ } else if (mSurface == NULL) {
+ ALOGE("%s: No input stream is configured", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ *surface = mSurface;
+ return OK;
+}
+#else
status_t Camera3InputStream::getInputBufferProducerLocked(
sp<IGraphicBufferProducer> *producer) {
ATRACE_CALL();
@@ -196,6 +211,7 @@
*producer = mProducer;
return OK;
}
+#endif
status_t Camera3InputStream::disconnectLocked() {
@@ -284,7 +300,12 @@
mConsumer->setName(String8::format("Camera3-InputStream-%d", mId));
mConsumer->setMaxAcquiredBufferCount(mTotalBufferCount);
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ mSurface = mConsumer->getSurface();
+#else
mProducer = mConsumer->getSurface()->getIGraphicBufferProducer();
+#endif // WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+
#else
mConsumer = new BufferItemConsumer(consumer, mUsage,
mTotalBufferCount);
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.h b/services/camera/libcameraservice/device3/Camera3InputStream.h
index a99c364..b1603e5 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.h
@@ -18,6 +18,7 @@
#define ANDROID_SERVERS_CAMERA3_INPUT_STREAM_H
#include <utils/RefBase.h>
+#include <gui/Flags.h>
#include <gui/Surface.h>
#include <gui/BufferItemConsumer.h>
@@ -50,7 +51,11 @@
private:
sp<BufferItemConsumer> mConsumer;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ sp<Surface> mSurface;
+#else
sp<IGraphicBufferProducer> mProducer;
+#endif
Vector<BufferItem> mBuffersInFlight;
static const std::string FAKE_ID;
@@ -75,8 +80,12 @@
virtual status_t getInputBufferLocked(camera_stream_buffer *buffer, Size *size);
virtual status_t returnInputBufferLocked(
const camera_stream_buffer &buffer);
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ virtual status_t getInputSurfaceLocked(sp<Surface> *surface);
+#else
virtual status_t getInputBufferProducerLocked(
sp<IGraphicBufferProducer> *producer);
+#endif
virtual status_t disconnectLocked();
virtual status_t configureQueueLocked();
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 04867b9..83c8a38 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -687,11 +687,7 @@
}
}
- if (flags::surface_ipc()) {
- res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
- } else {
- res = native_window_set_buffer_count(mConsumer.get(), mTotalBufferCount);
- }
+ res = mConsumer->setMaxDequeuedBufferCount(mTotalBufferCount - maxConsumerBuffers);
if (res != OK) {
ALOGE("%s: Unable to set buffer count for stream %d",
__FUNCTION__, mId);
@@ -1035,7 +1031,7 @@
status_t Camera3OutputStream::getEndpointUsageForSurface(uint64_t *usage,
const sp<Surface>& surface) {
bool internalConsumer = (mConsumer.get() != nullptr) && (mConsumer == surface);
- if (mConsumerUsageCachedValue.has_value() && flags::surface_ipc() && internalConsumer) {
+ if (mConsumerUsageCachedValue.has_value() && internalConsumer) {
*usage = mConsumerUsageCachedValue.value();
return OK;
}
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
index 31707ec..62226e1 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.cpp
@@ -894,8 +894,7 @@
if (outputBuffers[i].buffer == nullptr) {
if (!useHalBufManager &&
- !(flags::session_hal_buf_manager() &&
- contains(halBufferManagedStreams, streamId))) {
+ !contains(halBufferManagedStreams, streamId)) {
// With HAL buffer management API, HAL sometimes will have to return buffers that
// has not got a output buffer handle filled yet. This is though illegal if HAL
// buffer management API is not being used.
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
index aca7a67..2d75d03 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtilsTemplated.h
@@ -212,8 +212,7 @@
bool noBufferReturned = false;
buffer_handle_t *buffer = nullptr;
if (states.useHalBufManager ||
- (flags::session_hal_buf_manager() &&
- contains(states.halBufManagedStreamIds, bSrc.streamId))) {
+ contains(states.halBufManagedStreamIds, bSrc.streamId)) {
// This is suspicious most of the time but can be correct during flush where HAL
// has to return capture result before a buffer is requested
if (bSrc.bufferId == BUFFER_ID_NO_BUFFER) {
@@ -303,8 +302,7 @@
for (const auto& buf : buffers) {
if (!states.useHalBufManager &&
- !(flags::session_hal_buf_manager() &&
- contains(states.halBufManagedStreamIds, buf.streamId))) {
+ !contains(states.halBufManagedStreamIds, buf.streamId)) {
ALOGE("%s: Camera %s does not support HAL buffer management for stream id %d",
__FUNCTION__, states.cameraId.c_str(), buf.streamId);
return;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 4934203..ae76e60 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -29,6 +29,9 @@
#include "ui/GraphicBufferMapper.h"
#include <cutils/properties.h>
+#include <com_android_internal_camera_flags.h>
+
+namespace flags = com::android::internal::camera::flags;
namespace android {
@@ -388,6 +391,10 @@
mOldDataSpace == camera_stream::data_space &&
mOldFormat == camera_stream::format) {
mState = STATE_CONFIGURED;
+ if (flags::enable_stream_reconfiguration_for_unchanged_streams()
+ && streamReconfigured != nullptr) {
+ *streamReconfigured = true;
+ }
return OK;
}
@@ -864,12 +871,21 @@
return res;
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Stream::getInputSurface(sp<Surface> *surface) {
+ ATRACE_CALL();
+ Mutex::Autolock l(mLock);
+
+ return getInputSurfaceLocked(surface);
+}
+#else
status_t Camera3Stream::getInputBufferProducer(sp<IGraphicBufferProducer> *producer) {
ATRACE_CALL();
Mutex::Autolock l(mLock);
return getInputBufferProducerLocked(producer);
}
+#endif
void Camera3Stream::fireBufferRequestForFrameNumber(uint64_t frameNumber,
const CameraMetadata& settings) {
@@ -983,10 +999,17 @@
ALOGE("%s: This type of stream does not support input", __FUNCTION__);
return INVALID_OPERATION;
}
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+status_t Camera3Stream::getInputSurfaceLocked(sp<Surface>*) {
+ ALOGE("%s: This type of stream does not support input", __FUNCTION__);
+ return INVALID_OPERATION;
+}
+#else
status_t Camera3Stream::getInputBufferProducerLocked(sp<IGraphicBufferProducer>*) {
ALOGE("%s: This type of stream does not support input", __FUNCTION__);
return INVALID_OPERATION;
}
+#endif
void Camera3Stream::addBufferListener(
wp<Camera3StreamBufferListener> listener) {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index ccd1044..1519ada 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA3_STREAM_H
#define ANDROID_SERVERS_CAMERA3_STREAM_H
+#include <gui/Flags.h>
#include <gui/Surface.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
@@ -382,9 +383,13 @@
*/
status_t returnInputBuffer(const camera_stream_buffer &buffer);
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ status_t getInputSurface(sp<Surface> *producer);
+#else
// get the buffer producer of the input buffer queue.
// only apply to input streams.
status_t getInputBufferProducer(sp<IGraphicBufferProducer> *producer);
+#endif
/**
* Whether any of the stream's buffers are currently in use by the HAL,
@@ -534,8 +539,12 @@
virtual status_t returnInputBufferLocked(
const camera_stream_buffer &buffer);
virtual bool hasOutstandingBuffersLocked() const = 0;
+#if WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
+ virtual status_t getInputSurfaceLocked(sp<Surface> *surface);
+#else
// Get the buffer producer of the input buffer queue. Only apply to input streams.
virtual status_t getInputBufferProducerLocked(sp<IGraphicBufferProducer> *producer);
+#endif
// Can return -ENOTCONN when we are already disconnected (not an error)
virtual status_t disconnectLocked() = 0;
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 4df8193..0786622 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H
#define ANDROID_SERVERS_CAMERA3_STREAM_INTERFACE_H
+#include <gui/Flags.h>
#include <utils/RefBase.h>
#include <camera/camera2/OutputConfiguration.h>
@@ -435,12 +436,14 @@
*/
virtual status_t returnInputBuffer(const camera_stream_buffer &buffer) = 0;
+#if !WB_CAMERA3_AND_PROCESSORS_WITH_DEPENDENCIES
/**
* Get the buffer producer of the input buffer queue.
*
* This method only applies to input streams.
*/
virtual status_t getInputBufferProducer(sp<IGraphicBufferProducer> *producer) = 0;
+#endif
/**
* Whether any of the stream's buffers are currently in use by the HAL,
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
index 77c037a..7090545 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.cpp
@@ -14,32 +14,39 @@
* limitations under the License.
*/
-#include <inttypes.h>
-
#define LOG_TAG "Camera3StreamSplitter"
#define ATRACE_TAG ATRACE_TAG_CAMERA
//#define LOG_NDEBUG 0
+#include <binder/ProcessState.h>
#include <camera/StringUtils.h>
#include <com_android_graphics_libgui_flags.h>
#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/IGraphicBufferConsumer.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/Surface.h>
-
+#include <system/window.h>
#include <ui/GraphicBuffer.h>
-
-#include <binder/ProcessState.h>
-
#include <utils/Trace.h>
#include <cutils/atomic.h>
+#include <inttypes.h>
+#include <algorithm>
+#include <cstdint>
+#include <memory>
#include "Camera3Stream.h"
+#include "Flags.h"
#include "Camera3StreamSplitter.h"
+// We're relying on a large number of yet-to-be-fully-launched flag dependencies
+// here. So instead of flagging each one, we flag the entire implementation to
+// improve legibility.
+#if USE_NEW_STREAM_SPLITTER
+
namespace android {
status_t Camera3StreamSplitter::connect(const std::unordered_map<size_t, sp<Surface>> &surfaces,
@@ -55,7 +62,7 @@
Mutex::Autolock lock(mMutex);
status_t res = OK;
- if (mOutputs.size() > 0 || mConsumer != nullptr) {
+ if (mOutputSurfaces.size() > 0 || mBufferItemConsumer != nullptr) {
SP_LOGE("%s: already connected", __FUNCTION__);
return BAD_VALUE;
}
@@ -82,43 +89,43 @@
}
}
-#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- // Create BufferQueue for input
- BufferQueue::createBufferQueue(&mProducer, &mConsumer);
-#endif // !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
-
// Allocate 1 extra buffer to handle the case where all buffers are detached
// from input, and attached to the outputs. In this case, the input queue's
// dequeueBuffer can still allocate 1 extra buffer before being blocked by
// the output's attachBuffer().
mMaxConsumerBuffers++;
+
#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mBufferItemConsumer = new BufferItemConsumer(consumerUsage, mMaxConsumerBuffers);
+ mBufferItemConsumer = sp<BufferItemConsumer>::make(consumerUsage, mMaxConsumerBuffers);
+ mSurface = mBufferItemConsumer->getSurface();
#else
- mBufferItemConsumer = new BufferItemConsumer(mConsumer, consumerUsage, mMaxConsumerBuffers);
+ // Create BufferQueue for input
+ sp<IGraphicBufferProducer> bqProducer;
+ sp<IGraphicBufferConsumer> bqConsumer;
+ BufferQueue::createBufferQueue(&bqProducer, &bqConsumer);
+
+ mBufferItemConsumer = new BufferItemConsumer(bqConsumer, consumerUsage, mMaxConsumerBuffers);
+ mSurface = new Surface(bqProducer);
#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
+
if (mBufferItemConsumer == nullptr) {
return NO_MEMORY;
}
-#if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mProducer = mBufferItemConsumer->getSurface()->getIGraphicBufferProducer();
- mConsumer = mBufferItemConsumer->getIGraphicBufferConsumer();
-#endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
- mConsumer->setConsumerName(toString8(mConsumerName));
+ mBufferItemConsumer->setName(toString8(mConsumerName));
- *consumer = new Surface(mProducer);
+ *consumer = mSurface;
if (*consumer == nullptr) {
return NO_MEMORY;
}
- res = mProducer->setAsyncMode(true);
+ res = mSurface->setAsyncMode(true);
if (res != OK) {
SP_LOGE("%s: Failed to enable input queue async mode: %s(%d)", __FUNCTION__,
strerror(-res), res);
return res;
}
- res = mConsumer->consumerConnect(this, /* controlledByApp */ false);
+ mBufferItemConsumer->setFrameAvailableListener(this);
mWidth = width;
mHeight = height;
@@ -139,25 +146,19 @@
ATRACE_CALL();
Mutex::Autolock lock(mMutex);
- for (auto& notifier : mNotifiers) {
- sp<IGraphicBufferProducer> producer = notifier.first;
- sp<OutputListener> listener = notifier.second;
- IInterface::asBinder(producer)->unlinkToDeath(listener);
- }
mNotifiers.clear();
- for (auto& output : mOutputs) {
+ for (auto& output : mOutputSurfaces) {
if (output.second != nullptr) {
output.second->disconnect(NATIVE_WINDOW_API_CAMERA);
}
}
- mOutputs.clear();
mOutputSurfaces.clear();
- mOutputSlots.clear();
+ mHeldBuffers.clear();
mConsumerBufferCount.clear();
- if (mConsumer.get() != nullptr) {
- mConsumer->consumerDisconnect();
+ if (mBufferItemConsumer != nullptr) {
+ mBufferItemConsumer->abandon();
}
if (mBuffers.size() > 0) {
@@ -189,7 +190,7 @@
}
if (mMaxConsumerBuffers > mAcquiredInputBuffers) {
- res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+ res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
}
return res;
@@ -207,7 +208,7 @@
return BAD_VALUE;
}
- if (mOutputs[surfaceId] != nullptr) {
+ if (mOutputSurfaces[surfaceId] != nullptr) {
SP_LOGE("%s: surfaceId: %u already taken!", __FUNCTION__, (unsigned) surfaceId);
return BAD_VALUE;
}
@@ -226,11 +227,9 @@
return res;
}
- sp<IGraphicBufferProducer> gbp = outputQueue->getIGraphicBufferProducer();
// Connect to the buffer producer
- sp<OutputListener> listener(new OutputListener(this, gbp));
- IInterface::asBinder(gbp)->linkToDeath(listener);
- res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener);
+ sp<OutputListener> listener = sp<OutputListener>::make(this, outputQueue);
+ res = outputQueue->connect(NATIVE_WINDOW_API_CAMERA, listener, /* reportBufferRemoval */ false);
if (res != NO_ERROR) {
SP_LOGE("addOutput: failed to connect (%d)", res);
return res;
@@ -272,22 +271,21 @@
outputQueue->setDequeueTimeout(timeout);
}
- res = gbp->allowAllocation(false);
+ res = outputQueue->allowAllocation(false);
if (res != OK) {
SP_LOGE("%s: Failed to turn off allocation for outputQueue", __FUNCTION__);
return res;
}
// Add new entry into mOutputs
- mOutputs[surfaceId] = gbp;
mOutputSurfaces[surfaceId] = outputQueue;
mConsumerBufferCount[surfaceId] = maxConsumerBuffers;
if (mConsumerBufferCount[surfaceId] > mMaxHalBuffers) {
SP_LOGW("%s: Consumer buffer count %zu larger than max. Hal buffers: %zu", __FUNCTION__,
mConsumerBufferCount[surfaceId], mMaxHalBuffers);
}
- mNotifiers[gbp] = listener;
- mOutputSlots[gbp] = std::make_unique<OutputSlots>(totalBufferCount);
+ mNotifiers[outputQueue] = listener;
+ mHeldBuffers[outputQueue] = std::make_unique<HeldBuffers>(totalBufferCount);
mMaxConsumerBuffers += maxConsumerBuffers;
return NO_ERROR;
@@ -304,7 +302,7 @@
}
if (mAcquiredInputBuffers < mMaxConsumerBuffers) {
- res = mConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
+ res = mBufferItemConsumer->setMaxAcquiredBufferCount(mMaxConsumerBuffers);
if (res != OK) {
SP_LOGE("%s: setMaxAcquiredBufferCount failed %d", __FUNCTION__, res);
return res;
@@ -315,70 +313,54 @@
}
status_t Camera3StreamSplitter::removeOutputLocked(size_t surfaceId) {
- if (mOutputs[surfaceId] == nullptr) {
+ if (mOutputSurfaces[surfaceId] == nullptr) {
SP_LOGE("%s: output surface is not present!", __FUNCTION__);
return BAD_VALUE;
}
- sp<IGraphicBufferProducer> gbp = mOutputs[surfaceId];
+ sp<Surface> surface = mOutputSurfaces[surfaceId];
//Search and decrement the ref. count of any buffers that are
//still attached to the removed surface.
std::vector<uint64_t> pendingBufferIds;
- auto& outputSlots = *mOutputSlots[gbp];
- for (size_t i = 0; i < outputSlots.size(); i++) {
- if (outputSlots[i] != nullptr) {
- pendingBufferIds.push_back(outputSlots[i]->getId());
- auto rc = gbp->detachBuffer(i);
- if (rc != NO_ERROR) {
- //Buffers that fail to detach here will be scheduled for detach in the
- //input buffer queue and the rest of the registered outputs instead.
- //This will help ensure that camera stops accessing buffers that still
- //can get referenced by the disconnected output.
- mDetachedBuffers.emplace(outputSlots[i]->getId());
- }
+
+ // TODO: can we simplify this to just use the tracker?
+ for (const auto& buffer : (*mHeldBuffers[surface])) {
+ pendingBufferIds.push_back(buffer->getId());
+ auto rc = surface->detachBuffer(buffer);
+ if (rc != NO_ERROR) {
+ // Buffers that fail to detach here will be scheduled for detach in the
+ // input buffer queue and the rest of the registered outputs instead.
+ // This will help ensure that camera stops accessing buffers that still
+ // can get referenced by the disconnected output.
+ mDetachedBuffers.emplace(buffer->getId());
}
}
- mOutputs[surfaceId] = nullptr;
mOutputSurfaces[surfaceId] = nullptr;
- mOutputSlots[gbp] = nullptr;
+ mHeldBuffers[surface] = nullptr;
for (const auto &id : pendingBufferIds) {
decrementBufRefCountLocked(id, surfaceId);
}
- auto res = IInterface::asBinder(gbp)->unlinkToDeath(mNotifiers[gbp]);
- if (res != OK) {
- SP_LOGE("%s: Failed to unlink producer death listener: %d ", __FUNCTION__, res);
- return res;
- }
-
- res = gbp->disconnect(NATIVE_WINDOW_API_CAMERA);
+ status_t res = surface->disconnect(NATIVE_WINDOW_API_CAMERA);
if (res != OK) {
SP_LOGE("%s: Unable disconnect from producer interface: %d ", __FUNCTION__, res);
return res;
}
- mNotifiers[gbp] = nullptr;
+ mNotifiers[surface] = nullptr;
mMaxConsumerBuffers -= mConsumerBufferCount[surfaceId];
mConsumerBufferCount[surfaceId] = 0;
return res;
}
-status_t Camera3StreamSplitter::outputBufferLocked(const sp<IGraphicBufferProducer>& output,
+status_t Camera3StreamSplitter::outputBufferLocked(const sp<Surface>& output,
const BufferItem& bufferItem, size_t surfaceId) {
ATRACE_CALL();
status_t res;
- IGraphicBufferProducer::QueueBufferInput queueInput(
- bufferItem.mTimestamp, bufferItem.mIsAutoTimestamp,
- bufferItem.mDataSpace, bufferItem.mCrop,
- static_cast<int32_t>(bufferItem.mScalingMode),
- bufferItem.mTransform, bufferItem.mFence);
-
- IGraphicBufferProducer::QueueBufferOutput queueOutput;
uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
const BufferTracker& tracker = *(mBuffers[bufferId]);
- int slot = getSlotForOutputLocked(output, tracker.getBuffer());
if (mOutputSurfaces[surfaceId] != nullptr) {
sp<ANativeWindow> anw = mOutputSurfaces[surfaceId];
@@ -388,19 +370,26 @@
SP_LOGE("%s: Invalid surface id: %zu!", __FUNCTION__, surfaceId);
}
+ output->setBuffersTimestamp(bufferItem.mTimestamp);
+ output->setBuffersDataSpace(static_cast<ui::Dataspace>(bufferItem.mDataSpace));
+ output->setCrop(&bufferItem.mCrop);
+ output->setScalingMode(bufferItem.mScalingMode);
+ output->setBuffersTransform(bufferItem.mTransform);
+
// In case the output BufferQueue has its own lock, if we hold splitter lock while calling
// queueBuffer (which will try to acquire the output lock), the output could be holding its
// own lock calling releaseBuffer (which will try to acquire the splitter lock), running into
// circular lock situation.
mMutex.unlock();
- res = output->queueBuffer(slot, queueInput, &queueOutput);
+ SurfaceQueueBufferOutput queueBufferOutput;
+ res = output->queueBuffer(bufferItem.mGraphicBuffer, bufferItem.mFence, &queueBufferOutput);
mMutex.lock();
- SP_LOGV("%s: Queuing buffer to buffer queue %p slot %d returns %d",
- __FUNCTION__, output.get(), slot, res);
- //During buffer queue 'mMutex' is not held which makes the removal of
- //"output" possible. Check whether this is the case and return.
- if (mOutputSlots[output] == nullptr) {
+ SP_LOGV("%s: Queuing buffer to buffer queue %p bufferId %" PRIu64 " returns %d", __FUNCTION__,
+ output.get(), bufferId, res);
+ // During buffer queue 'mMutex' is not held which makes the removal of
+ // "output" possible. Check whether this is the case and return.
+ if (mOutputSurfaces[surfaceId] == nullptr) {
return res;
}
if (res != OK) {
@@ -418,7 +407,7 @@
// If the queued buffer replaces a pending buffer in the async
// queue, no onBufferReleased is called by the buffer queue.
// Proactively trigger the callback to avoid buffer loss.
- if (queueOutput.bufferReplaced) {
+ if (queueBufferOutput.bufferReplaced) {
onBufferReplacedLocked(output, surfaceId);
}
@@ -456,52 +445,32 @@
auto tracker = std::make_unique<BufferTracker>(gb, surface_ids);
for (auto& surface_id : surface_ids) {
- sp<IGraphicBufferProducer>& gbp = mOutputs[surface_id];
- if (gbp.get() == nullptr) {
+ sp<Surface>& surface = mOutputSurfaces[surface_id];
+ if (surface.get() == nullptr) {
//Output surface got likely removed by client.
continue;
}
- int slot = getSlotForOutputLocked(gbp, gb);
- if (slot != BufferItem::INVALID_BUFFER_SLOT) {
- //Buffer is already attached to this output surface.
- continue;
- }
+
//Temporarly Unlock the mutex when trying to attachBuffer to the output
//queue, because attachBuffer could block in case of a slow consumer. If
//we block while holding the lock, onFrameAvailable and onBufferReleased
//will block as well because they need to acquire the same lock.
mMutex.unlock();
- res = gbp->attachBuffer(&slot, gb);
+ res = surface->attachBuffer(anb);
mMutex.lock();
if (res != OK) {
- SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)",
- __FUNCTION__, gbp.get(), strerror(-res), res);
+ SP_LOGE("%s: Cannot attachBuffer from GraphicBufferProducer %p: %s (%d)", __FUNCTION__,
+ surface.get(), strerror(-res), res);
// TODO: might need to detach/cleanup the already attached buffers before return?
return res;
}
- if ((slot < 0) || (slot > BufferQueue::NUM_BUFFER_SLOTS)) {
- SP_LOGE("%s: Slot received %d either bigger than expected maximum %d or negative!",
- __FUNCTION__, slot, BufferQueue::NUM_BUFFER_SLOTS);
- return BAD_VALUE;
- }
//During buffer attach 'mMutex' is not held which makes the removal of
//"gbp" possible. Check whether this is the case and continue.
- if (mOutputSlots[gbp] == nullptr) {
+ if (mHeldBuffers[surface] == nullptr) {
continue;
}
- auto& outputSlots = *mOutputSlots[gbp];
- if (static_cast<size_t> (slot + 1) > outputSlots.size()) {
- outputSlots.resize(slot + 1);
- }
- if (outputSlots[slot] != nullptr) {
- // If the buffer is attached to a slot which already contains a buffer,
- // the previous buffer will be removed from the output queue. Decrement
- // the reference count accordingly.
- decrementBufRefCountLocked(outputSlots[slot]->getId(), surface_id);
- }
- SP_LOGV("%s: Attached buffer %p to slot %d on output %p.",__FUNCTION__, gb.get(),
- slot, gbp.get());
- outputSlots[slot] = gb;
+ mHeldBuffers[surface]->insert(gb);
+ SP_LOGV("%s: Attached buffer %p on output %p.", __FUNCTION__, gb.get(), surface.get());
}
mBuffers[bufferId] = std::move(tracker);
@@ -515,25 +484,14 @@
// Acquire and detach the buffer from the input
BufferItem bufferItem;
- status_t res = mConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
+ status_t res = mBufferItemConsumer->acquireBuffer(&bufferItem, /* presentWhen */ 0);
if (res != NO_ERROR) {
SP_LOGE("%s: Acquiring buffer from input failed (%d)", __FUNCTION__, res);
mOnFrameAvailableRes.store(res);
return;
}
- uint64_t bufferId;
- if (bufferItem.mGraphicBuffer != nullptr) {
- mInputSlots[bufferItem.mSlot] = bufferItem;
- } else if (bufferItem.mAcquireCalled) {
- bufferItem.mGraphicBuffer = mInputSlots[bufferItem.mSlot].mGraphicBuffer;
- mInputSlots[bufferItem.mSlot].mFrameNumber = bufferItem.mFrameNumber;
- } else {
- SP_LOGE("%s: Invalid input graphic buffer!", __FUNCTION__);
- mOnFrameAvailableRes.store(BAD_VALUE);
- return;
- }
- bufferId = bufferItem.mGraphicBuffer->getId();
+ uint64_t bufferId = bufferItem.mGraphicBuffer->getId();
if (mBuffers.find(bufferId) == mBuffers.end()) {
SP_LOGE("%s: Acquired buffer doesn't exist in attached buffer map",
@@ -556,13 +514,12 @@
SP_LOGV("%s: BufferTracker for buffer %" PRId64 ", number of requests %zu",
__FUNCTION__, bufferItem.mGraphicBuffer->getId(), tracker.requestedSurfaces().size());
for (const auto id : tracker.requestedSurfaces()) {
-
- if (mOutputs[id] == nullptr) {
+ if (mOutputSurfaces[id] == nullptr) {
//Output surface got likely removed by client.
continue;
}
- res = outputBufferLocked(mOutputs[id], bufferItem, id);
+ res = outputBufferLocked(mOutputSurfaces[id], bufferItem, id);
if (res != OK) {
SP_LOGE("%s: outputBufferLocked failed %d", __FUNCTION__, res);
mOnFrameAvailableRes.store(res);
@@ -601,26 +558,11 @@
mBuffers.erase(id);
uint64_t bufferId = tracker_ptr->getBuffer()->getId();
- int consumerSlot = -1;
- uint64_t frameNumber;
- auto inputSlot = mInputSlots.begin();
- for (; inputSlot != mInputSlots.end(); inputSlot++) {
- if (inputSlot->second.mGraphicBuffer->getId() == bufferId) {
- consumerSlot = inputSlot->second.mSlot;
- frameNumber = inputSlot->second.mFrameNumber;
- break;
- }
- }
- if (consumerSlot == -1) {
- SP_LOGE("%s: Buffer missing inside input slots!", __FUNCTION__);
- return;
- }
auto detachBuffer = mDetachedBuffers.find(bufferId);
bool detach = (detachBuffer != mDetachedBuffers.end());
if (detach) {
mDetachedBuffers.erase(detachBuffer);
- mInputSlots.erase(inputSlot);
}
// Temporarily unlock mutex to avoid circular lock:
// 1. This function holds splitter lock, calls releaseBuffer which triggers
@@ -629,15 +571,14 @@
// 2. Camera3SharedOutputStream::getBufferLocked calls
// attachBufferToOutputs, which holds the stream lock, and waits for the
// splitter lock.
- sp<IGraphicBufferConsumer> consumer(mConsumer);
mMutex.unlock();
int res = NO_ERROR;
- if (consumer != nullptr) {
+ if (mBufferItemConsumer != nullptr) {
if (detach) {
- res = consumer->detachBuffer(consumerSlot);
+ res = mBufferItemConsumer->detachBuffer(tracker_ptr->getBuffer());
} else {
- res = consumer->releaseBuffer(consumerSlot, frameNumber,
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, tracker_ptr->getMergedFence());
+ res = mBufferItemConsumer->releaseBuffer(tracker_ptr->getBuffer(),
+ tracker_ptr->getMergedFence());
}
} else {
SP_LOGE("%s: consumer has become null!", __FUNCTION__);
@@ -659,23 +600,25 @@
}
}
-void Camera3StreamSplitter::onBufferReleasedByOutput(
- const sp<IGraphicBufferProducer>& from) {
+void Camera3StreamSplitter::onBufferReleasedByOutput(const sp<Surface>& from) {
ATRACE_CALL();
- sp<Fence> fence;
- int slot = BufferItem::INVALID_BUFFER_SLOT;
- auto res = from->dequeueBuffer(&slot, &fence, mWidth, mHeight, mFormat, mProducerUsage,
- nullptr, nullptr);
+ from->setBuffersDimensions(mWidth, mHeight);
+ from->setBuffersFormat(mFormat);
+ from->setUsage(mProducerUsage);
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ auto res = from->dequeueBuffer(&buffer, &fence);
Mutex::Autolock lock(mMutex);
- handleOutputDequeueStatusLocked(res, slot);
+ handleOutputDequeueStatusLocked(res, buffer);
if (res != OK) {
return;
}
size_t surfaceId = 0;
bool found = false;
- for (const auto& it : mOutputs) {
+ for (const auto& it : mOutputSurfaces) {
if (it.second == from) {
found = true;
surfaceId = it.first;
@@ -687,36 +630,29 @@
return;
}
- returnOutputBufferLocked(fence, from, surfaceId, slot);
+ returnOutputBufferLocked(fence, from, surfaceId, buffer);
}
-void Camera3StreamSplitter::onBufferReplacedLocked(
- const sp<IGraphicBufferProducer>& from, size_t surfaceId) {
+void Camera3StreamSplitter::onBufferReplacedLocked(const sp<Surface>& from, size_t surfaceId) {
ATRACE_CALL();
- sp<Fence> fence;
- int slot = BufferItem::INVALID_BUFFER_SLOT;
- auto res = from->dequeueBuffer(&slot, &fence, mWidth, mHeight, mFormat, mProducerUsage,
- nullptr, nullptr);
- handleOutputDequeueStatusLocked(res, slot);
+ from->setBuffersDimensions(mWidth, mHeight);
+ from->setBuffersFormat(mFormat);
+ from->setUsage(mProducerUsage);
+
+ sp<GraphicBuffer> buffer;
+ sp<Fence> fence;
+ auto res = from->dequeueBuffer(&buffer, &fence);
+ handleOutputDequeueStatusLocked(res, buffer);
if (res != OK) {
return;
}
- returnOutputBufferLocked(fence, from, surfaceId, slot);
+ returnOutputBufferLocked(fence, from, surfaceId, buffer);
}
void Camera3StreamSplitter::returnOutputBufferLocked(const sp<Fence>& fence,
- const sp<IGraphicBufferProducer>& from, size_t surfaceId, int slot) {
- sp<GraphicBuffer> buffer;
-
- if (mOutputSlots[from] == nullptr) {
- //Output surface got likely removed by client.
- return;
- }
-
- auto outputSlots = *mOutputSlots[from];
- buffer = outputSlots[slot];
+ const sp<Surface>& from, size_t surfaceId, const sp<GraphicBuffer>& buffer) {
BufferTracker& tracker = *(mBuffers[buffer->getId()]);
// Merge the release fence of the incoming buffer so that the fence we send
// back to the input includes all of the outputs' fences
@@ -727,9 +663,16 @@
auto detachBuffer = mDetachedBuffers.find(buffer->getId());
bool detach = (detachBuffer != mDetachedBuffers.end());
if (detach) {
- auto res = from->detachBuffer(slot);
+ auto res = from->detachBuffer(buffer);
if (res == NO_ERROR) {
- outputSlots[slot] = nullptr;
+ if (mHeldBuffers.contains(from)) {
+ mHeldBuffers[from]->erase(buffer);
+ } else {
+ uint64_t surfaceId = 0;
+ from->getUniqueId(&surfaceId);
+ SP_LOGW("%s: buffer %" PRIu64 " not found in held buffers of surface %" PRIu64,
+ __FUNCTION__, buffer->getId(), surfaceId);
+ }
} else {
SP_LOGE("%s: detach buffer from output failed (%d)", __FUNCTION__, res);
}
@@ -739,22 +682,17 @@
decrementBufRefCountLocked(buffer->getId(), surfaceId);
}
-void Camera3StreamSplitter::handleOutputDequeueStatusLocked(status_t res, int slot) {
+void Camera3StreamSplitter::handleOutputDequeueStatusLocked(status_t res,
+ const sp<GraphicBuffer>& buffer) {
if (res == NO_INIT) {
// If we just discovered that this output has been abandoned, note that,
// but we can't do anything else, since buffer is invalid
onAbandonedLocked();
- } else if (res == IGraphicBufferProducer::BUFFER_NEEDS_REALLOCATION) {
- SP_LOGE("%s: Producer needs to re-allocate buffer!", __FUNCTION__);
- SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
- } else if (res == IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
- SP_LOGE("%s: All slot->buffer mapping should be released!", __FUNCTION__);
- SP_LOGE("%s: This should not happen with buffer allocation disabled!", __FUNCTION__);
} else if (res == NO_MEMORY) {
SP_LOGE("%s: No free buffers", __FUNCTION__);
} else if (res == WOULD_BLOCK) {
SP_LOGE("%s: Dequeue call will block", __FUNCTION__);
- } else if (res != OK || (slot == BufferItem::INVALID_BUFFER_SLOT)) {
+ } else if (res != OK || buffer == nullptr) {
SP_LOGE("%s: dequeue buffer from output failed (%d)", __FUNCTION__, res);
}
}
@@ -773,36 +711,20 @@
SP_LOGV("One of my outputs has abandoned me");
}
-int Camera3StreamSplitter::getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
- const sp<GraphicBuffer>& gb) {
- auto& outputSlots = *mOutputSlots[gbp];
-
- for (size_t i = 0; i < outputSlots.size(); i++) {
- if (outputSlots[i] == gb) {
- return (int)i;
- }
- }
-
- SP_LOGV("%s: Cannot find slot for gb %p on output %p", __FUNCTION__, gb.get(),
- gbp.get());
- return BufferItem::INVALID_BUFFER_SLOT;
-}
-
-Camera3StreamSplitter::OutputListener::OutputListener(
- wp<Camera3StreamSplitter> splitter,
- wp<IGraphicBufferProducer> output)
- : mSplitter(splitter), mOutput(output) {}
+Camera3StreamSplitter::OutputListener::OutputListener(wp<Camera3StreamSplitter> splitter,
+ wp<Surface> output)
+ : mSplitter(splitter), mOutput(output) {}
void Camera3StreamSplitter::OutputListener::onBufferReleased() {
ATRACE_CALL();
sp<Camera3StreamSplitter> splitter = mSplitter.promote();
- sp<IGraphicBufferProducer> output = mOutput.promote();
+ sp<Surface> output = mOutput.promote();
if (splitter != nullptr && output != nullptr) {
splitter->onBufferReleasedByOutput(output);
}
}
-void Camera3StreamSplitter::OutputListener::binderDied(const wp<IBinder>& /* who */) {
+void Camera3StreamSplitter::OutputListener::onRemoteDied() {
sp<Camera3StreamSplitter> splitter = mSplitter.promote();
if (splitter != nullptr) {
Mutex::Autolock lock(splitter->mMutex);
@@ -833,3 +755,5 @@
}
} // namespace android
+
+#endif // USE_NEW_STREAM_SPLITTER
\ No newline at end of file
diff --git a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
index 43f12fb..0440e08 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamSplitter.h
@@ -14,22 +14,25 @@
* limitations under the License.
*/
-#ifndef ANDROID_SERVERS_STREAMSPLITTER_H
-#define ANDROID_SERVERS_STREAMSPLITTER_H
+#pragma once
+#include <memory>
#include <unordered_set>
#include <camera/CameraMetadata.h>
-#include <gui/IConsumerListener.h>
-#include <gui/Surface.h>
#include <gui/BufferItemConsumer.h>
+#include <gui/Surface.h>
#include <utils/Condition.h>
#include <utils/Mutex.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
+#include "Flags.h"
+
+#if USE_NEW_STREAM_SPLITTER // trying to do this for each change would be a huge hassle.
+
#define SP_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
#define SP_LOGI(x, ...) ALOGI("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
#define SP_LOGW(x, ...) ALOGW("[%s] " x, mConsumerName.c_str(), ##__VA_ARGS__)
@@ -38,8 +41,6 @@
namespace android {
class GraphicBuffer;
-class IGraphicBufferConsumer;
-class IGraphicBufferProducer;
// Camera3StreamSplitter is an autonomous class that manages one input BufferQueue
// and multiple output BufferQueues. By using the buffer attach and detach logic
@@ -47,9 +48,8 @@
// BufferQueue, where each buffer queued to the input is available to be
// acquired by each of the outputs, and is able to be dequeued by the input
// again only once all of the outputs have released it.
-class Camera3StreamSplitter : public BnConsumerListener {
-public:
-
+class Camera3StreamSplitter : public BufferItemConsumer::FrameAvailableListener {
+ public:
// Constructor
Camera3StreamSplitter(bool useHalBufManager = false);
@@ -67,7 +67,7 @@
//
// A return value other than NO_ERROR means that an error has occurred and
// outputQueue has not been added to the splitter. BAD_VALUE is returned if
- // outputQueue is NULL. See IGraphicBufferProducer::connect for explanations
+ // outputQueue is NULL. See Surface::connect for explanations
// of other error codes.
status_t addOutput(size_t surfaceId, const sp<Surface>& outputQueue);
@@ -97,7 +97,7 @@
void setHalBufferManager(bool enabled);
private:
- // From IConsumerListener
+ // From BufferItemConsumer::FrameAvailableListener
//
// During this callback, we store some tracking information, detach the
// buffer from the input, and attach it to each of the outputs. This call
@@ -106,23 +106,13 @@
// input.
void onFrameAvailable(const BufferItem& item) override;
- // From IConsumerListener
+ // From BufferItemConsumer::FrameAvailableListener
//
// Similar to onFrameAvailable, but buffer item is indeed replacing a buffer
// in the buffer queue. This can happen when buffer queue is in droppable
// mode.
void onFrameReplaced(const BufferItem& item) override;
- // From IConsumerListener
- // We don't care about released buffers because we detach each buffer as
- // soon as we acquire it. See the comment for onBufferReleased below for
- // some clarifying notes about the name.
- void onBuffersReleased() override {}
-
- // From IConsumerListener
- // We don't care about sideband streams, since we won't be splitting them
- void onSidebandStreamChanged() override {}
-
// This is the implementation of the onBufferReleased callback from
// IProducerListener. It gets called from an OutputListener (see below), and
// 'from' is which producer interface from which the callback was received.
@@ -132,10 +122,10 @@
// last output releasing the buffer, and if so, release it to the input.
// If we release the buffer to the input, we allow a blocked
// onFrameAvailable call to proceed.
- void onBufferReleasedByOutput(const sp<IGraphicBufferProducer>& from);
+ void onBufferReleasedByOutput(const sp<Surface>& from);
// Called by outputBufferLocked when a buffer in the async buffer queue got replaced.
- void onBufferReplacedLocked(const sp<IGraphicBufferProducer>& from, size_t surfaceId);
+ void onBufferReplacedLocked(const sp<Surface>& from, size_t surfaceId);
// When this is called, the splitter disconnects from (i.e., abandons) its
// input queue and signals any waiting onFrameAvailable calls to wake up.
@@ -149,35 +139,32 @@
void decrementBufRefCountLocked(uint64_t id, size_t surfaceId);
// Check for and handle any output surface dequeue errors.
- void handleOutputDequeueStatusLocked(status_t res, int slot);
+ void handleOutputDequeueStatusLocked(status_t res, const sp<GraphicBuffer>& buffer);
// Handles released output surface buffers.
- void returnOutputBufferLocked(const sp<Fence>& fence, const sp<IGraphicBufferProducer>& from,
- size_t surfaceId, int slot);
+ void returnOutputBufferLocked(const sp<Fence>& fence, const sp<Surface>& from, size_t surfaceId,
+ const sp<GraphicBuffer>& buffer);
// This is a thin wrapper class that lets us determine which BufferQueue
// the IProducerListener::onBufferReleased callback is associated with. We
// create one of these per output BufferQueue, and then pass the producer
// into onBufferReleasedByOutput above.
- class OutputListener : public SurfaceListener,
- public IBinder::DeathRecipient {
- public:
- OutputListener(wp<Camera3StreamSplitter> splitter,
- wp<IGraphicBufferProducer> output);
+ class OutputListener : public SurfaceListener {
+ public:
+ OutputListener(wp<Camera3StreamSplitter> splitter, wp<Surface> output);
virtual ~OutputListener() = default;
- // From IProducerListener
+ // From SurfaceListener
void onBufferReleased() override;
bool needsReleaseNotify() override { return true; };
- void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>& /*buffers*/) override {};
+ void onBuffersDiscarded(const std::vector<sp<GraphicBuffer>>&) override {}
void onBufferDetached(int /*slot*/) override {}
- // From IBinder::DeathRecipient
- void binderDied(const wp<IBinder>& who) override;
+ void onRemoteDied() override;
private:
wp<Camera3StreamSplitter> mSplitter;
- wp<IGraphicBufferProducer> mOutput;
+ wp<Surface> mOutput;
};
class BufferTracker {
@@ -198,7 +185,6 @@
const std::vector<size_t> requestedSurfaces() const { return mRequestedSurfaces; }
private:
-
// Disallow copying
BufferTracker(const BufferTracker& other);
BufferTracker& operator=(const BufferTracker& other);
@@ -223,16 +209,12 @@
// Send a buffer to particular output, and increment the reference count
// of the buffer. If this output is abandoned, the buffer's reference count
// won't be incremented.
- status_t outputBufferLocked(const sp<IGraphicBufferProducer>& output,
- const BufferItem& bufferItem, size_t surfaceId);
+ status_t outputBufferLocked(const sp<Surface>& output, const BufferItem& bufferItem,
+ size_t surfaceId);
// Get unique name for the buffer queue consumer
std::string getUniqueConsumerName();
- // Helper function to get the BufferQueue slot where a particular buffer is attached to.
- int getSlotForOutputLocked(const sp<IGraphicBufferProducer>& gbp,
- const sp<GraphicBuffer>& gb);
-
// Sum of max consumer buffers for all outputs
size_t mMaxConsumerBuffers = 0;
size_t mMaxHalBuffers = 0;
@@ -249,17 +231,9 @@
Mutex mMutex;
- sp<IGraphicBufferProducer> mProducer;
- sp<IGraphicBufferConsumer> mConsumer;
sp<BufferItemConsumer> mBufferItemConsumer;
sp<Surface> mSurface;
- //Map graphic buffer ids -> buffer items
- std::unordered_map<uint64_t, BufferItem> mInputSlots;
-
- //Map surface ids -> gbp outputs
- std::unordered_map<int, sp<IGraphicBufferProducer> > mOutputs;
-
//Map surface ids -> gbp outputs
std::unordered_map<int, sp<Surface>> mOutputSurfaces;
@@ -271,18 +245,22 @@
// buffer, but also contain merged release fences).
std::unordered_map<uint64_t, std::unique_ptr<BufferTracker> > mBuffers;
- struct GBPHash {
- std::size_t operator()(const sp<IGraphicBufferProducer>& producer) const {
- return std::hash<IGraphicBufferProducer *>{}(producer.get());
+ struct SurfaceHash {
+ std::size_t operator()(const sp<Surface>& producer) const {
+ return std::hash<Surface*>{}(producer.get());
}
};
- std::unordered_map<sp<IGraphicBufferProducer>, sp<OutputListener>,
- GBPHash> mNotifiers;
+ struct BufferHash {
+ std::size_t operator()(const sp<GraphicBuffer>& buffer) const {
+ return std::hash<GraphicBuffer*>{}(buffer.get());
+ }
+ };
- typedef std::vector<sp<GraphicBuffer>> OutputSlots;
- std::unordered_map<sp<IGraphicBufferProducer>, std::unique_ptr<OutputSlots>,
- GBPHash> mOutputSlots;
+ std::unordered_map<sp<Surface>, sp<OutputListener>, SurfaceHash> mNotifiers;
+
+ typedef std::unordered_set<sp<GraphicBuffer>, BufferHash> HeldBuffers;
+ std::unordered_map<sp<Surface>, std::unique_ptr<HeldBuffers>, SurfaceHash> mHeldBuffers;
//A set of buffers that could potentially stay in some of the outputs after removal
//and therefore should be detached from the input queue.
@@ -301,4 +279,4 @@
} // namespace android
-#endif
+#endif // USE_NEW_STREAM_SPLITTER
diff --git a/services/camera/libcameraservice/device3/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 9a3f433..9a4e9e3 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -43,9 +43,7 @@
kResultPointsToCorrectNoClamp.begin(),
kResultPointsToCorrectNoClamp.end());
mRemappedKeys.insert(ANDROID_DISTORTION_CORRECTION_MODE);
- if (flags::concert_mode()) {
- mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
- }
+ mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
}
bool DistortionMapper::isDistortionSupported(const CameraMetadata &deviceInfo) {
diff --git a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
index 8bb22a9..1ea077c 100644
--- a/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
+++ b/services/camera/libcameraservice/device3/RotateAndCropMapper.cpp
@@ -37,9 +37,7 @@
mRemappedKeys.insert(ANDROID_SCALER_ROTATE_AND_CROP);
mRemappedKeys.insert(ANDROID_SCALER_CROP_REGION);
- if (flags::concert_mode()) {
- mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
- }
+ mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
}
bool RotateAndCropMapper::isNeeded(const CameraMetadata* deviceInfo) {
diff --git a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
index 1f52e9b..2016284 100644
--- a/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
+++ b/services/camera/libcameraservice/device3/ZoomRatioMapper.cpp
@@ -38,9 +38,7 @@
kResultPointsToCorrectNoClamp.end());
mRemappedKeys.insert(ANDROID_CONTROL_ZOOM_RATIO);
- if (flags::concert_mode()) {
- mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
- }
+ mRemappedKeys.insert(ANDROID_LOGICAL_MULTI_CAMERA_ACTIVE_PHYSICAL_SENSOR_CROP_REGION);
}
status_t ZoomRatioMapper::initZoomRatioInTemplate(CameraMetadata *request) {
diff --git a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
index 57297bc..e52e9a2 100644
--- a/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/aidl/AidlCamera3Device.cpp
@@ -349,7 +349,7 @@
readoutSupported.data.u8[0] == ANDROID_SENSOR_READOUT_TIMESTAMP_HARDWARE;
}
- return initializeCommonLocked();
+ return initializeCommonLocked(manager);
}
::ndk::ScopedAStatus AidlCamera3Device::AidlCameraDeviceCallbacks::processCaptureResult(
@@ -918,12 +918,6 @@
camera3::camera_stream_t *src = config->streams[i];
Camera3Stream* cam3stream = Camera3Stream::cast(src);
- // For stream configurations with multi res streams, hal buffer manager has to be used.
- if (!flags::session_hal_buf_manager() && cam3stream->getHalStreamGroupId() != -1 &&
- src->stream_type != CAMERA_STREAM_INPUT) {
- mUseHalBufManager = true;
- config->use_hal_buf_manager = true;
- }
cam3stream->setBufferFreedListener(this);
int streamId = cam3stream->getId();
StreamType streamType;
@@ -1002,8 +996,7 @@
err.getMessage());
return AidlProviderInfo::mapToStatusT(err);
}
- if (flags::session_hal_buf_manager() && interfaceVersion >= AIDL_DEVICE_SESSION_V3
- && mSupportSessionHalBufManager) {
+ if (interfaceVersion >= AIDL_DEVICE_SESSION_V3 && mSupportSessionHalBufManager) {
err = mAidlSession->configureStreamsV2(requestedConfiguration, &configureStreamsRet);
finalConfiguration = std::move(configureStreamsRet.halStreams);
} else {
@@ -1015,18 +1008,16 @@
return AidlProviderInfo::mapToStatusT(err);
}
- if (flags::session_hal_buf_manager()) {
- std::set<int32_t> halBufferManagedStreamIds;
- for (const auto &halStream: finalConfiguration) {
- if ((interfaceVersion >= AIDL_DEVICE_SESSION_V3 &&
- mSupportSessionHalBufManager && halStream.enableHalBufferManager)
- || mUseHalBufManager) {
- halBufferManagedStreamIds.insert(halStream.id);
- }
+ std::set<int32_t> halBufferManagedStreamIds;
+ for (const auto &halStream: finalConfiguration) {
+ if ((interfaceVersion >= AIDL_DEVICE_SESSION_V3 &&
+ mSupportSessionHalBufManager && halStream.enableHalBufferManager)
+ || mUseHalBufManager) {
+ halBufferManagedStreamIds.insert(halStream.id);
}
- mHalBufManagedStreamIds = std::move(halBufferManagedStreamIds);
- config->hal_buffer_managed_streams = mHalBufManagedStreamIds;
}
+ mHalBufManagedStreamIds = std::move(halBufferManagedStreamIds);
+ config->hal_buffer_managed_streams = mHalBufManagedStreamIds;
// And convert output stream configuration from AIDL
for (size_t i = 0; i < config->num_streams; i++) {
camera3::camera_stream_t *dst = config->streams[i];
@@ -1096,10 +1087,8 @@
}
dstStream->setUsage(
mapProducerToFrameworkUsage(src.producerUsage));
- if (flags::session_hal_buf_manager()) {
- dstStream->setHalBufferManager(
- contains(config->hal_buffer_managed_streams, streamId));
- }
+ dstStream->setHalBufferManager(
+ contains(config->hal_buffer_managed_streams, streamId));
}
dst->max_buffers = src.maxBuffers;
}
diff --git a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
index 09299e6..6986d3c 100644
--- a/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
+++ b/services/camera/libcameraservice/device3/hidl/HidlCamera3Device.cpp
@@ -303,7 +303,7 @@
}
mNeedFixupMonochromeTags = (isMonochrome && deviceVersion < CAMERA_DEVICE_API_VERSION_3_5);
- return initializeCommonLocked();
+ return initializeCommonLocked(manager);
}
hardware::Return<void> HidlCamera3Device::requestStreamBuffers(
@@ -929,7 +929,7 @@
switch (src->stream_type) {
case CAMERA_STREAM_OUTPUT:
streamType = StreamType::OUTPUT;
- if (flags::session_hal_buf_manager() && mUseHalBufManager) {
+ if (mUseHalBufManager) {
mHalBufManagedStreamIds.insert(streamId);
}
break;
diff --git a/services/camera/libcameraservice/tests/Android.bp b/services/camera/libcameraservice/tests/Android.bp
index bbc10dc..837bf6d 100644
--- a/services/camera/libcameraservice/tests/Android.bp
+++ b/services/camera/libcameraservice/tests/Android.bp
@@ -44,13 +44,25 @@
"libjpeg",
"liblog",
"libutils",
- "camera_platform_flags_c_lib",
],
static_libs: [
"libgmock",
],
+ target: {
+ android: {
+ shared_libs: [
+ "camera_platform_flags_c_lib",
+ ],
+ },
+ host: {
+ shared_libs: [
+ "camera_platform_flags_c_lib_for_test",
+ ],
+ },
+ },
+
cflags: [
"-Wall",
"-Wextra",
diff --git a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
index 939126c..56cacef 100644
--- a/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
+++ b/services/camera/libcameraservice/tests/CameraProviderManagerTest.cpp
@@ -445,10 +445,6 @@
virtual std::shared_ptr<aidl::android::hardware::camera::provider::ICameraProvider>
getService(const std::string& serviceName) override {
- if (!flags::delay_lazy_hal_instantiation()) {
- return mTestAidlCameraProvider;
- }
-
// If no provider has been given, fail; in reality, getService would
// block for HALs that don't start correctly, so we should never use
// getService when we don't have a valid HAL running
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
index 93b440b..37903e1 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "AttributionAndPermissionUtils"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+
#include "AttributionAndPermissionUtils.h"
#include <binder/AppOpsManager.h>
@@ -25,8 +28,12 @@
#include "CameraService.h"
#include <binder/IPCThreadState.h>
-#include <hwbinder/IPCThreadState.h>
#include <binderthreadstate/CallerUtils.h>
+#include <hwbinder/IPCThreadState.h>
+
+namespace {
+static const std::string kPermissionServiceName = "permission";
+} // namespace
namespace android {
@@ -35,8 +42,7 @@
const std::string AttributionAndPermissionUtils::sDumpPermission("android.permission.DUMP");
const std::string AttributionAndPermissionUtils::sManageCameraPermission(
"android.permission.MANAGE_CAMERA");
-const std::string AttributionAndPermissionUtils::sCameraPermission(
- "android.permission.CAMERA");
+const std::string AttributionAndPermissionUtils::sCameraPermission("android.permission.CAMERA");
const std::string AttributionAndPermissionUtils::sSystemCameraPermission(
"android.permission.SYSTEM_CAMERA");
const std::string AttributionAndPermissionUtils::sCameraHeadlessSystemUserPermission(
@@ -50,14 +56,14 @@
const std::string AttributionAndPermissionUtils::sCameraInjectExternalCameraPermission(
"android.permission.CAMERA_INJECT_EXTERNAL_CAMERA");
-int AttributionAndPermissionUtils::getCallingUid() {
+int AttributionAndPermissionUtils::getCallingUid() const {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingUid();
}
return IPCThreadState::self()->getCallingUid();
}
-int AttributionAndPermissionUtils::getCallingPid() {
+int AttributionAndPermissionUtils::getCallingPid() const {
if (getCurrentServingCall() == BinderCallType::HWBINDER) {
return hardware::IPCThreadState::self()->getCallingPid();
}
@@ -80,47 +86,38 @@
return;
}
-bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(const std::string &cameraId,
- const AttributionSourceState &attributionSource) {
- if (isAutomotivePrivilegedClient(attributionSource.uid)) {
- // If cameraId is empty, then it means that this check is not used for the
- // purpose of accessing a specific camera, hence grant permission just
- // based on uid to the automotive privileged client.
- if (cameraId.empty())
- return true;
-
- auto cameraService = mCameraService.promote();
- if (cameraService == nullptr) {
- ALOGE("%s: CameraService unavailable.", __FUNCTION__);
- return false;
- }
-
- // If this call is used for accessing a specific camera then cam_id must be provided.
- // In that case, only pre-grants the permission for accessing the exterior system only
- // camera.
- return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+binder::Status AttributionAndPermissionUtils::resolveAttributionSource(
+ /*inout*/ AttributionSourceState& resolvedAttributionSource, const std::string& methodName,
+ const std::optional<std::string>& cameraIdMaybe) {
+ // Check if we can trust clientUid
+ if (!resolveClientUid(resolvedAttributionSource.uid)) {
+ return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
+ methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
+ /* isPid= */ false);
}
- return false;
+ resolveAttributionPackage(resolvedAttributionSource);
+
+ if (!resolveClientPid(resolvedAttributionSource.pid)) {
+ return errorNotTrusted(resolvedAttributionSource.pid, resolvedAttributionSource.uid,
+ methodName, cameraIdMaybe, *resolvedAttributionSource.packageName,
+ /* isPid= */ true);
+ }
+
+ return binder::Status::ok();
}
-bool AttributionAndPermissionUtils::checkPermissionForPreflight(const std::string &cameraId,
- const std::string &permission, const AttributionSourceState &attributionSource,
- const std::string& message, int32_t attributedOpCode) {
+bool AttributionAndPermissionUtils::checkPermissionForPreflight(
+ const std::string& cameraId, const std::string& permission,
+ const AttributionSourceState& attributionSource, const std::string& message,
+ int32_t attributedOpCode) {
if (checkAutomotivePrivilegedClient(cameraId, attributionSource)) {
return true;
}
- if (!flags::cache_permission_services()) {
- PermissionChecker permissionChecker;
- return permissionChecker.checkPermissionForPreflight(
- toString16(permission), attributionSource, toString16(message),
- attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
- } else {
- return mPermissionChecker->checkPermissionForPreflight(
- toString16(permission), attributionSource, toString16(message),
- attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
- }
+ return mPermissionChecker->checkPermissionForPreflight(
+ toString16(permission), attributionSource, toString16(message),
+ attributedOpCode) != PermissionChecker::PERMISSION_HARD_DENIED;
}
// Can camera service trust the caller based on the calling UID?
@@ -153,8 +150,7 @@
bool AttributionAndPermissionUtils::isAutomotivePrivilegedClient(int32_t uid) {
// Returns false if this is not an automotive device type.
- if (!isAutomotiveDevice())
- return false;
+ if (!isAutomotiveDevice()) return false;
// Returns true if the uid is AID_AUTOMOTIVE_EVS which is a
// privileged client uid used for safety critical use cases such as
@@ -162,8 +158,35 @@
return uid == AID_AUTOMOTIVE_EVS;
}
-status_t AttributionAndPermissionUtils::getUidForPackage(const std::string &packageName,
- int userId, /*inout*/uid_t& uid, int err) {
+std::string AttributionAndPermissionUtils::getPackageNameFromUid(int clientUid) const {
+ std::string packageName("");
+
+ sp<IPermissionController> permCtrl = getPermissionController();
+ if (permCtrl == nullptr) {
+ // Return empty package name and the further interaction
+ // with camera will likely fail
+ return packageName;
+ }
+
+ Vector<String16> packages;
+
+ permCtrl->getPackagesForUid(clientUid, packages);
+
+ if (packages.isEmpty()) {
+ ALOGE("No packages for calling UID %d", clientUid);
+ // Return empty package name and the further interaction
+ // with camera will likely fail
+ return packageName;
+ }
+
+ // Arbitrarily pick the first name in the list
+ packageName = toStdString(packages[0]);
+
+ return packageName;
+}
+
+status_t AttributionAndPermissionUtils::getUidForPackage(const std::string& packageName, int userId,
+ /*inout*/ uid_t& uid, int err) {
PermissionController pc;
uid = pc.getPackageUid(toString16(packageName), 0);
if (uid <= 0) {
@@ -186,36 +209,147 @@
return (getCallingPid() == getpid());
}
-bool AttributionAndPermissionUtils::hasPermissionsForCamera(const std::string& cameraId,
- const AttributionSourceState& attributionSource) {
- return checkPermissionForPreflight(cameraId, sCameraPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
+bool AttributionAndPermissionUtils::hasPermissionsForCamera(
+ const std::string& cameraId, const AttributionSourceState& attributionSource) {
+ return checkPermissionForPreflight(cameraId, sCameraPermission, attributionSource,
+ std::string(), AppOpsManager::OP_NONE);
}
-bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(const std::string& cameraId,
- const AttributionSourceState& attributionSource, bool checkCameraPermissions) {
- bool systemCameraPermission = checkPermissionForPreflight(cameraId,
- sSystemCameraPermission, attributionSource, std::string(), AppOpsManager::OP_NONE);
- return systemCameraPermission && (!checkCameraPermissions
- || hasPermissionsForCamera(cameraId, attributionSource));
+bool AttributionAndPermissionUtils::hasPermissionsForSystemCamera(
+ const std::string& cameraId, const AttributionSourceState& attributionSource,
+ bool checkCameraPermissions) {
+ bool systemCameraPermission =
+ checkPermissionForPreflight(cameraId, sSystemCameraPermission, attributionSource,
+ std::string(), AppOpsManager::OP_NONE);
+ return systemCameraPermission &&
+ (!checkCameraPermissions || hasPermissionsForCamera(cameraId, attributionSource));
}
bool AttributionAndPermissionUtils::hasPermissionsForCameraHeadlessSystemUser(
const std::string& cameraId, const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(cameraId, sCameraHeadlessSystemUserPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
}
bool AttributionAndPermissionUtils::hasPermissionsForCameraPrivacyAllowlist(
const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(std::string(), sCameraPrivacyAllowlistPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
}
bool AttributionAndPermissionUtils::hasPermissionsForOpenCloseListener(
const AttributionSourceState& attributionSource) {
return checkPermissionForPreflight(std::string(), sCameraOpenCloseListenerPermission,
- attributionSource, std::string(), AppOpsManager::OP_NONE);
+ attributionSource, std::string(), AppOpsManager::OP_NONE);
+}
+
+bool AttributionAndPermissionUtils::checkAutomotivePrivilegedClient(
+ const std::string& cameraId, const AttributionSourceState& attributionSource) {
+ if (isAutomotivePrivilegedClient(attributionSource.uid)) {
+ // If cameraId is empty, then it means that this check is not used for the
+ // purpose of accessing a specific camera, hence grant permission just
+ // based on uid to the automotive privileged client.
+ if (cameraId.empty()) return true;
+
+ auto cameraService = mCameraService.promote();
+ if (cameraService == nullptr) {
+ ALOGE("%s: CameraService unavailable.", __FUNCTION__);
+ return false;
+ }
+
+ // If this call is used for accessing a specific camera then cam_id must be provided.
+ // In that case, only pre-grants the permission for accessing the exterior system only
+ // camera.
+ return cameraService->isAutomotiveExteriorSystemCamera(cameraId);
+ }
+
+ return false;
+}
+
+void AttributionAndPermissionUtils::resolveAttributionPackage(
+ AttributionSourceState& resolvedAttributionSource) {
+ if (resolvedAttributionSource.packageName.has_value() &&
+ resolvedAttributionSource.packageName->size() > 0) {
+ return;
+ }
+
+ // NDK calls don't come with package names, but we need one for various cases.
+ // Generally, there's a 1:1 mapping between UID and package name, but shared UIDs
+ // do exist. For all authentication cases, all packages under the same UID get the
+ // same permissions, so picking any associated package name is sufficient. For some
+ // other cases, this may give inaccurate names for clients in logs.
+ resolvedAttributionSource.packageName = getPackageNameFromUid(resolvedAttributionSource.uid);
+}
+
+// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
+bool AttributionAndPermissionUtils::resolveClientUid(/*inout*/ int& clientUid) {
+ int callingUid = getCallingUid();
+
+ bool validUid = true;
+ if (clientUid == hardware::ICameraService::USE_CALLING_UID) {
+ clientUid = callingUid;
+ } else {
+ validUid = isTrustedCallingUid(callingUid);
+ if (flags::use_context_attribution_source()) {
+ validUid = validUid || (clientUid == callingUid);
+ }
+ }
+
+ return validUid;
+}
+
+// TODO(362551824): Make USE_CALLING_UID more explicit with a scoped enum.
+bool AttributionAndPermissionUtils::resolveClientPid(/*inout*/ int& clientPid) {
+ int callingUid = getCallingUid();
+ int callingPid = getCallingPid();
+
+ bool validPid = true;
+ if (clientPid == hardware::ICameraService::USE_CALLING_PID) {
+ clientPid = callingPid;
+ } else {
+ validPid = isTrustedCallingUid(callingUid);
+ if (flags::use_context_attribution_source()) {
+ validPid = validPid || (clientPid == callingPid);
+ }
+ }
+
+ return validPid;
+}
+
+binder::Status AttributionAndPermissionUtils::errorNotTrusted(
+ int clientPid, int clientUid, const std::string& methodName,
+ const std::optional<std::string>& cameraIdMaybe, const std::string& clientName,
+ bool isPid) const {
+ int callingPid = getCallingPid();
+ int callingUid = getCallingUid();
+ ALOGE("CameraService::%s X (calling PID %d, calling UID %d) rejected "
+ "(don't trust %s %d)",
+ methodName.c_str(), callingPid, callingUid, isPid ? "clientPid" : "clientUid",
+ isPid ? clientPid : clientUid);
+ return STATUS_ERROR_FMT(hardware::ICameraService::ERROR_PERMISSION_DENIED,
+ "Untrusted caller (calling PID %d, UID %d) trying to "
+ "forward camera access to camera %s for client %s (PID %d, UID %d)",
+ getCallingPid(), getCallingUid(), cameraIdMaybe.value_or("N/A").c_str(),
+ clientName.c_str(), clientPid, clientUid);
+}
+
+const sp<IPermissionController>& AttributionAndPermissionUtils::getPermissionController() const {
+ static const char* kPermissionControllerService = "permission";
+ static thread_local sp<IPermissionController> sPermissionController = nullptr;
+
+ if (sPermissionController == nullptr ||
+ !IInterface::asBinder(sPermissionController)->isBinderAlive()) {
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IBinder> binder = sm->checkService(toString16(kPermissionControllerService));
+ if (binder == nullptr) {
+ ALOGE("%s: Could not get permission service", __FUNCTION__);
+ sPermissionController = nullptr;
+ } else {
+ sPermissionController = interface_cast<IPermissionController>(binder);
+ }
+ }
+
+ return sPermissionController;
}
} // namespace android
diff --git a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
index 4daab0f..22abccc 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.h
@@ -19,6 +19,7 @@
#include <android/content/AttributionSourceState.h>
#include <android/permission/PermissionChecker.h>
#include <binder/BinderService.h>
+#include <binder/IPermissionController.h>
#include <private/android_filesystem_config.h>
namespace android {
@@ -34,12 +35,10 @@
*/
class AttributionAndPermissionUtils {
public:
- AttributionAndPermissionUtils() { }
+ AttributionAndPermissionUtils() {}
virtual ~AttributionAndPermissionUtils() {}
- void setCameraService(wp<CameraService> cameraService) {
- mCameraService = cameraService;
- }
+ void setCameraService(wp<CameraService> cameraService) { mCameraService = cameraService; }
static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
AttributionSourceState attributionSource{};
@@ -49,19 +48,33 @@
}
static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
- int32_t deviceId) {
+ int32_t deviceId) {
AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid);
attributionSource.deviceId = deviceId;
return attributionSource;
}
// Utilities handling Binder calling identities (previously in CameraThreadState)
- virtual int getCallingUid();
- virtual int getCallingPid();
+ virtual int getCallingUid() const;
+ virtual int getCallingPid() const;
virtual int64_t clearCallingIdentity();
virtual void restoreCallingIdentity(int64_t token);
/**
+ * If flag::use_context_attribution_source() is enabled, check the calling attribution source
+ * and resolve its package name, or fill in the pid/uid/package name if necessary.
+ *
+ * @param resolvedAttributionSource The resolved attribution source.
+ * @param methodName The name of the method calling this function (for logging only).
+ * @param cameraIdMaybe The camera ID, if applicable.
+ * @return The status of the operation.
+ */
+ virtual binder::Status resolveAttributionSource(
+ /*inout*/ AttributionSourceState& resolvedAttributionSource,
+ const std::string& methodName,
+ const std::optional<std::string>& cameraIdMaybe = std::nullopt);
+
+ /**
* Pre-grants the permission if the attribution source uid is for an automotive
* privileged client. Otherwise uses system service permission checker to check
* for the appropriate permission. If this function is called for accessing a specific
@@ -70,9 +83,10 @@
* which is located outside of the vehicle body frame because camera located inside the vehicle
* cabin would need user permission.
*/
- virtual bool checkPermissionForPreflight(const std::string &cameraId,
- const std::string &permission, const AttributionSourceState& attributionSource,
- const std::string& message, int32_t attributedOpCode);
+ virtual bool checkPermissionForPreflight(const std::string& cameraId,
+ const std::string& permission,
+ const AttributionSourceState& attributionSource,
+ const std::string& message, int32_t attributedOpCode);
// Can camera service trust the caller based on the calling UID?
virtual bool isTrustedCallingUid(uid_t uid);
@@ -85,17 +99,27 @@
*/
virtual bool isAutomotivePrivilegedClient(int32_t uid);
- virtual status_t getUidForPackage(const std::string &packageName, int userId,
- /*inout*/uid_t& uid, int err);
+ // In some cases the calling code has no access to the package it runs under.
+ // For example, NDK camera API.
+ // In this case we will get the packages for the calling UID and pick the first one
+ // for attributing the app op. This will work correctly for runtime permissions
+ // as for legacy apps we will toggle the app op for all packages in the UID.
+ // The caveat is that the operation may be attributed to the wrong package and
+ // stats based on app ops may be slightly off.
+ virtual std::string getPackageNameFromUid(int clientUid) const;
+
+ virtual status_t getUidForPackage(const std::string& packageName, int userId,
+ /*inout*/ uid_t& uid, int err);
virtual bool isCallerCameraServerNotDelegating();
// Utils for checking specific permissions
virtual bool hasPermissionsForCamera(const std::string& cameraId,
- const AttributionSourceState& attributionSource);
+ const AttributionSourceState& attributionSource);
virtual bool hasPermissionsForSystemCamera(const std::string& cameraId,
- const AttributionSourceState& attributionSource, bool checkCameraPermissions = true);
- virtual bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId,
- const AttributionSourceState& attributionSource);
+ const AttributionSourceState& attributionSource,
+ bool checkCameraPermissions = true);
+ virtual bool hasPermissionsForCameraHeadlessSystemUser(
+ const std::string& cameraId, const AttributionSourceState& attributionSource);
virtual bool hasPermissionsForCameraPrivacyAllowlist(
const AttributionSourceState& attributionSource);
virtual bool hasPermissionsForOpenCloseListener(
@@ -114,10 +138,24 @@
protected:
wp<CameraService> mCameraService;
- bool checkAutomotivePrivilegedClient(const std::string &cameraId,
- const AttributionSourceState &attributionSource);
+ bool checkAutomotivePrivilegedClient(const std::string& cameraId,
+ const AttributionSourceState& attributionSource);
+
+ // If the package name is missing from the AttributionSource and a package name exists for the
+ // AttributionSource's uid, fills in the missing package name.
+ void resolveAttributionPackage(AttributionSourceState& resolvedAttributionSource);
+
+ virtual bool resolveClientUid(/*inout*/ int& clientUid);
+ virtual bool resolveClientPid(/*inout*/ int& clientPid);
+
+ virtual binder::Status errorNotTrusted(int clientPid, int clientUid,
+ const std::string& methodName,
+ const std::optional<std::string>& cameraIdMaybe,
+ const std::string& clientName, bool isPid) const;
private:
+ virtual const sp<IPermissionController>& getPermissionController() const;
+
std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
std::make_unique<permission::PermissionChecker>();
};
@@ -128,39 +166,36 @@
* in the encapsulating class's methods.
*/
class AttributionAndPermissionUtilsEncapsulator {
-protected:
+ protected:
std::shared_ptr<AttributionAndPermissionUtils> mAttributionAndPermissionUtils;
-public:
+ public:
AttributionAndPermissionUtilsEncapsulator(
- std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
- : mAttributionAndPermissionUtils(attributionAndPermissionUtils) { }
+ std::shared_ptr<AttributionAndPermissionUtils> attributionAndPermissionUtils)
+ : mAttributionAndPermissionUtils(attributionAndPermissionUtils) {}
static AttributionSourceState buildAttributionSource(int callingPid, int callingUid) {
return AttributionAndPermissionUtils::buildAttributionSource(callingPid, callingUid);
}
static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
- int32_t deviceId) {
- return AttributionAndPermissionUtils::buildAttributionSource(
- callingPid, callingUid, deviceId);
+ int32_t deviceId) {
+ return AttributionAndPermissionUtils::buildAttributionSource(callingPid, callingUid,
+ deviceId);
}
static AttributionSourceState buildAttributionSource(int callingPid, int callingUid,
- const std::string& packageName, int32_t deviceId) {
- AttributionSourceState attributionSource = buildAttributionSource(callingPid, callingUid,
- deviceId);
+ const std::string& packageName,
+ int32_t deviceId) {
+ AttributionSourceState attributionSource =
+ buildAttributionSource(callingPid, callingUid, deviceId);
attributionSource.packageName = packageName;
return attributionSource;
}
- int getCallingUid() const {
- return mAttributionAndPermissionUtils->getCallingUid();
- }
+ int getCallingUid() const { return mAttributionAndPermissionUtils->getCallingUid(); }
- int getCallingPid() const {
- return mAttributionAndPermissionUtils->getCallingPid();
- }
+ int getCallingPid() const { return mAttributionAndPermissionUtils->getCallingPid(); }
int64_t clearCallingIdentity() const {
return mAttributionAndPermissionUtils->clearCallingIdentity();
@@ -170,48 +205,52 @@
mAttributionAndPermissionUtils->restoreCallingIdentity(token);
}
+ binder::Status resolveAttributionSource(AttributionSourceState& resolvedAttributionSource,
+ const std::string& methodName,
+ const std::optional<std::string>& cameraIdMaybe) {
+ return mAttributionAndPermissionUtils->resolveAttributionSource(resolvedAttributionSource,
+ methodName, cameraIdMaybe);
+ }
+
// The word 'System' here does not refer to callers only on the system
// partition. They just need to have an android system uid.
- bool callerHasSystemUid() const {
- return (getCallingUid() < AID_APP_START);
- }
+ bool callerHasSystemUid() const { return (getCallingUid() < AID_APP_START); }
bool hasPermissionsForCamera(int callingPid, int callingUid, int32_t deviceId) const {
return hasPermissionsForCamera(std::string(), callingPid, callingUid, deviceId);
}
- bool hasPermissionsForCamera(int callingPid, int callingUid,
- const std::string& packageName, int32_t deviceId) const {
+ bool hasPermissionsForCamera(int callingPid, int callingUid, const std::string& packageName,
+ int32_t deviceId) const {
return hasPermissionsForCamera(std::string(), callingPid, callingUid, packageName,
- deviceId);
+ deviceId);
}
- bool hasPermissionsForCamera(const std::string& cameraId, int callingPid,
- int callingUid, int32_t deviceId) const {
- auto attributionSource = buildAttributionSource(callingPid, callingUid,
- deviceId);
+ bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
+ int32_t deviceId) const {
+ auto attributionSource = buildAttributionSource(callingPid, callingUid, deviceId);
return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
}
bool hasPermissionsForCamera(const std::string& cameraId, int callingPid, int callingUid,
- const std::string& packageName, int32_t deviceId) const {
- auto attributionSource = buildAttributionSource(callingPid, callingUid, packageName,
- deviceId);
+ const std::string& packageName, int32_t deviceId) const {
+ auto attributionSource =
+ buildAttributionSource(callingPid, callingUid, packageName, deviceId);
return mAttributionAndPermissionUtils->hasPermissionsForCamera(cameraId, attributionSource);
}
bool hasPermissionsForSystemCamera(const std::string& cameraId, int callingPid, int callingUid,
- bool checkCameraPermissions = true) const {
+ bool checkCameraPermissions = true) const {
auto attributionSource = buildAttributionSource(callingPid, callingUid);
return mAttributionAndPermissionUtils->hasPermissionsForSystemCamera(
- cameraId, attributionSource, checkCameraPermissions);
+ cameraId, attributionSource, checkCameraPermissions);
}
bool hasPermissionsForCameraHeadlessSystemUser(const std::string& cameraId, int callingPid,
- int callingUid) const {
+ int callingUid) const {
auto attributionSource = buildAttributionSource(callingPid, callingUid);
return mAttributionAndPermissionUtils->hasPermissionsForCameraHeadlessSystemUser(
- cameraId, attributionSource);
+ cameraId, attributionSource);
}
bool hasPermissionsForCameraPrivacyAllowlist(int callingPid, int callingUid) const {
@@ -226,9 +265,7 @@
attributionSource);
}
- bool isAutomotiveDevice() const {
- return mAttributionAndPermissionUtils->isAutomotiveDevice();
- }
+ bool isAutomotiveDevice() const { return mAttributionAndPermissionUtils->isAutomotiveDevice(); }
bool isAutomotivePrivilegedClient(int32_t uid) const {
return mAttributionAndPermissionUtils->isAutomotivePrivilegedClient(uid);
@@ -242,11 +279,15 @@
return mAttributionAndPermissionUtils->isHeadlessSystemUserMode();
}
- status_t getUidForPackage(const std::string &packageName, int userId,
- /*inout*/uid_t& uid, int err) const {
+ status_t getUidForPackage(const std::string& packageName, int userId,
+ /*inout*/ uid_t& uid, int err) const {
return mAttributionAndPermissionUtils->getUidForPackage(packageName, userId, uid, err);
}
+ std::string getPackageNameFromUid(int clientUid) const {
+ return mAttributionAndPermissionUtils->getPackageNameFromUid(clientUid);
+ }
+
bool isCallerCameraServerNotDelegating() const {
return mAttributionAndPermissionUtils->isCallerCameraServerNotDelegating();
}
@@ -254,4 +295,4 @@
} // namespace android
-#endif // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
+#endif // ANDROID_SERVERS_CAMERA_ATTRIBUTION_AND_PERMISSION_UTILS_H
diff --git a/services/camera/libcameraservice/utils/Utils.cpp b/services/camera/libcameraservice/utils/Utils.cpp
index 76517dc..5f61de5 100644
--- a/services/camera/libcameraservice/utils/Utils.cpp
+++ b/services/camera/libcameraservice/utils/Utils.cpp
@@ -25,44 +25,7 @@
namespace android {
-namespace flags = com::android::internal::camera::flags;
-
-namespace {
-constexpr const char* LEGACY_VNDK_VERSION_PROP = "ro.vndk.version";
-constexpr const char* BOARD_API_LEVEL_PROP = "ro.board.api_level";
-constexpr int MAX_VENDOR_API_LEVEL = 1000000;
-constexpr int FIRST_VNDK_VERSION = 202404;
-
-int legacyGetVNDKVersionFromProp(int defaultVersion) {
- if (!flags::use_ro_board_api_level_for_vndk_version()) {
- return base::GetIntProperty(LEGACY_VNDK_VERSION_PROP, defaultVersion);
- }
-
- int vndkVersion = base::GetIntProperty(BOARD_API_LEVEL_PROP, MAX_VENDOR_API_LEVEL);
-
- if (vndkVersion == MAX_VENDOR_API_LEVEL) {
- // Couldn't find property
- return defaultVersion;
- }
-
- if (vndkVersion < __ANDROID_API_V__) {
- // VNDK versions below V return the corresponding SDK version.
- return vndkVersion;
- }
-
- // VNDK for Android V and above are of the format YYYYMM starting with 202404 and is bumped
- // up once a year. So V would be 202404 and the next one would be 202504.
- // This is the same assumption as that made in system/core/init/property_service.cpp.
- vndkVersion = (vndkVersion - FIRST_VNDK_VERSION) / 100;
- return __ANDROID_API_V__ + vndkVersion;
-}
-} // anonymous namespace
-
int getVNDKVersionFromProp(int defaultVersion) {
- if (!flags::use_system_api_for_vndk_version()) {
- return legacyGetVNDKVersionFromProp(defaultVersion);
- }
-
int vendorApiLevel = AVendorSupport_getVendorApiLevel();
if (vendorApiLevel == 0) {
// Couldn't find vendor API level, return default
@@ -77,28 +40,26 @@
RunThreadWithRealtimePriority::RunThreadWithRealtimePriority(int tid)
: mTid(tid), mPreviousPolicy(sched_getscheduler(tid)) {
- if (flags::realtime_priority_bump()) {
- auto res = sched_getparam(mTid, &mPreviousParams);
- if (res != OK) {
- ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
- return;
- }
+ auto res = sched_getparam(mTid, &mPreviousParams);
+ if (res != OK) {
+ ALOGE("Can't retrieve thread scheduler parameters: %s (%d)", strerror(-res), res);
+ return;
+ }
- struct sched_param param = {0};
- param.sched_priority = kRequestThreadPriority;
+ struct sched_param param = {0};
+ param.sched_priority = kRequestThreadPriority;
- res = sched_setscheduler(mTid, SCHED_FIFO, ¶m);
- if (res != OK) {
- ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
- } else {
- ALOGD("Set real time priority for thread (tid %d)", mTid);
- mPolicyBumped = true;
- }
+ res = sched_setscheduler(mTid, SCHED_FIFO, ¶m);
+ if (res != OK) {
+ ALOGW("Can't set realtime priority for thread: %s (%d)", strerror(-res), res);
+ } else {
+ ALOGD("Set real time priority for thread (tid %d)", mTid);
+ mPolicyBumped = true;
}
}
RunThreadWithRealtimePriority::~RunThreadWithRealtimePriority() {
- if (mPolicyBumped && flags::realtime_priority_bump()) {
+ if (mPolicyBumped) {
auto res = sched_setscheduler(mTid, mPreviousPolicy, &mPreviousParams);
if (res != OK) {
ALOGE("Can't set regular priority for thread: %s (%d)", strerror(-res), res);
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index 7ece0cb..dd64daa 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -25,6 +25,7 @@
"libEGL",
"libGLESv2",
"libGLESv3",
+ "android.companion.virtualdevice.flags-aconfig-cc",
],
static_libs: [
"android.hardware.camera.common@1.0-helper",
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 40a96e4..becba90 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -14,9 +14,12 @@
* limitations under the License.
*/
+// #define LOG_NDEBUG 0
#define LOG_TAG "VirtualCameraRenderThread"
#include "VirtualCameraRenderThread.h"
+#include <android_companion_virtualdevice_flags.h>
+
#include <chrono>
#include <cstdint>
#include <cstring>
@@ -46,13 +49,11 @@
#include "android-base/thread_annotations.h"
#include "android/binder_auto_utils.h"
#include "android/hardware_buffer.h"
-#include "hardware/gralloc.h"
#include "system/camera_metadata.h"
#include "ui/GraphicBuffer.h"
#include "ui/Rect.h"
#include "util/EglFramebuffer.h"
#include "util/JpegUtil.h"
-#include "util/MetadataUtil.h"
#include "util/Util.h"
#include "utils/Errors.h"
@@ -91,6 +92,8 @@
using namespace std::chrono_literals;
+namespace flags = ::android::companion::virtualdevice::flags;
+
static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024; // 32 KiB
@@ -117,12 +120,12 @@
NotifyMsg createRequestErrorNotifyMsg(int frameNumber) {
NotifyMsg msg;
- msg.set<NotifyMsg::Tag::error>(ErrorMsg{
- .frameNumber = frameNumber,
- // errorStreamId needs to be set to -1 for ERROR_REQUEST
- // (not tied to specific stream).
- .errorStreamId = -1,
- .errorCode = ErrorCode::ERROR_REQUEST});
+ msg.set<NotifyMsg::Tag::error>(
+ ErrorMsg{.frameNumber = frameNumber,
+ // errorStreamId needs to be set to -1 for ERROR_REQUEST
+ // (not tied to specific stream).
+ .errorStreamId = -1,
+ .errorCode = ErrorCode::ERROR_REQUEST});
return msg;
}
@@ -413,29 +416,8 @@
std::memory_order_relaxed));
if (request.getRequestSettings().fpsRange) {
- const int maxFps =
- std::max(1, request.getRequestSettings().fpsRange->maxFps);
- const std::chrono::nanoseconds minFrameDuration(
- static_cast<uint64_t>(1e9 / maxFps));
- const std::chrono::nanoseconds frameDuration =
- timestamp - lastAcquisitionTimestamp;
- if (frameDuration < minFrameDuration) {
- // We're too fast for the configured maxFps, let's wait a bit.
- const std::chrono::nanoseconds sleepTime =
- minFrameDuration - frameDuration;
- ALOGV("Current frame duration would be %" PRIu64
- " ns corresponding to, "
- "sleeping for %" PRIu64
- " ns before updating texture to match maxFps %d",
- static_cast<uint64_t>(frameDuration.count()),
- static_cast<uint64_t>(sleepTime.count()), maxFps);
-
- std::this_thread::sleep_for(sleepTime);
- timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
- std::chrono::steady_clock::now().time_since_epoch());
- mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
- std::memory_order_relaxed);
- }
+ int maxFps = std::max(1, request.getRequestSettings().fpsRange->maxFps);
+ timestamp = throttleRendering(maxFps, lastAcquisitionTimestamp, timestamp);
}
// Calculate the maximal amount of time we can afford to wait for next frame.
@@ -463,6 +445,17 @@
}
// Acquire new (most recent) image from the Surface.
mEglSurfaceTexture->updateTexture();
+ std::chrono::nanoseconds captureTimestamp = timestamp;
+
+ if (flags::camera_timestamp_from_surface()) {
+ std::chrono::nanoseconds surfaceTimestamp =
+ getSurfaceTimestamp(elapsedDuration);
+ if (surfaceTimestamp.count() > 0) {
+ captureTimestamp = surfaceTimestamp;
+ }
+ ALOGV("%s captureTimestamp:%lld timestamp:%lld", __func__,
+ captureTimestamp.count(), timestamp.count());
+ }
CaptureResult captureResult;
captureResult.fmqResultSize = 0;
@@ -472,7 +465,7 @@
captureResult.inputBuffer.streamId = -1;
captureResult.physicalCameraMetadata.resize(0);
captureResult.result = createCaptureResultMetadata(
- timestamp, request.getRequestSettings(), mReportedSensorSize);
+ captureTimestamp, request.getRequestSettings(), mReportedSensorSize);
const std::vector<CaptureRequestBuffer>& buffers = request.getBuffers();
captureResult.outputBuffers.resize(buffers.size());
@@ -506,7 +499,7 @@
}
std::vector<NotifyMsg> notifyMsg{
- createShutterNotifyMsg(request.getFrameNumber(), timestamp)};
+ createShutterNotifyMsg(request.getFrameNumber(), captureTimestamp)};
for (const StreamBuffer& resBuffer : captureResult.outputBuffers) {
if (resBuffer.status != BufferStatus::OK) {
notifyMsg.push_back(createBufferErrorNotifyMsg(request.getFrameNumber(),
@@ -535,6 +528,52 @@
ALOGV("%s: Successfully called processCaptureResult", __func__);
}
+std::chrono::nanoseconds VirtualCameraRenderThread::throttleRendering(
+ int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+ std::chrono::nanoseconds timestamp) {
+ const std::chrono::nanoseconds minFrameDuration(
+ static_cast<uint64_t>(1e9 / maxFps));
+ const std::chrono::nanoseconds frameDuration =
+ timestamp - lastAcquisitionTimestamp;
+ if (frameDuration < minFrameDuration) {
+ // We're too fast for the configured maxFps, let's wait a bit.
+ const std::chrono::nanoseconds sleepTime = minFrameDuration - frameDuration;
+ ALOGV("Current frame duration would be %" PRIu64
+ " ns corresponding to, "
+ "sleeping for %" PRIu64
+ " ns before updating texture to match maxFps %d",
+ static_cast<uint64_t>(frameDuration.count()),
+ static_cast<uint64_t>(sleepTime.count()), maxFps);
+
+ std::this_thread::sleep_for(sleepTime);
+ timestamp = std::chrono::duration_cast<std::chrono::nanoseconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+ mLastAcquisitionTimestampNanoseconds.store(timestamp.count(),
+ std::memory_order_relaxed);
+ }
+ return timestamp;
+}
+
+std::chrono::nanoseconds VirtualCameraRenderThread::getSurfaceTimestamp(
+ std::chrono::nanoseconds timeSinceLastFrame) {
+ std::chrono::nanoseconds surfaceTimestamp = mEglSurfaceTexture->getTimestamp();
+ uint64_t lastSurfaceTimestamp = mLastSurfaceTimestampNanoseconds.load();
+ if (surfaceTimestamp.count() < 0 ||
+ surfaceTimestamp.count() == lastSurfaceTimestamp) {
+ if (lastSurfaceTimestamp > 0) {
+ // The timestamps were provided by the producer but we are
+ // repeating the last frame, so we increase the previous timestamp by
+ // the elapsed time sinced its capture, otherwise the camera framework
+ // will discard the frame.
+ surfaceTimestamp = std::chrono::nanoseconds(lastSurfaceTimestamp +
+ timeSinceLastFrame.count());
+ }
+ }
+ mLastSurfaceTimestampNanoseconds.store(surfaceTimestamp.count(),
+ std::memory_order_relaxed);
+ return surfaceTimestamp;
+}
+
void VirtualCameraRenderThread::flushCaptureRequest(
const ProcessCaptureRequestTask& request) {
CaptureResult captureResult;
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index aafed44..a35eea1 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -18,6 +18,7 @@
#define ANDROID_COMPANION_VIRTUALCAMERA_VIRTUALCAMERARENDERTHREAD_H
#include <atomic>
+#include <chrono>
#include <cstdint>
#include <deque>
#include <future>
@@ -188,6 +189,22 @@
EglFrameBuffer& framebuffer, sp<Fence> fence = nullptr,
std::optional<Rect> viewport = std::nullopt);
+ // Throttle the current thread to ensure that we are not rendering faster than
+ // the provided maxFps.
+ // maxFps: The maximum fps in the capture request
+ // lastAcquisitionTimestamp: timestamp of the previous frame
+ // timestamp: the current capture time
+ // Returns the time at which the capture has happened after throttling.
+ std::chrono::nanoseconds throttleRendering(
+ int maxFps, std::chrono::nanoseconds lastAcquisitionTimestamp,
+ std::chrono::nanoseconds timestamp);
+
+ // Fetch the timestamp of the latest buffer from the EGL Surface
+ // timeSinceLastFrame: The elapsed time since the last captured frame.
+ // Return 0 if no timestamp has been associated to this surface by the producer.
+ std::chrono::nanoseconds getSurfaceTimestamp(
+ std::chrono::nanoseconds timeSinceLastFrame);
+
// Camera callback
const std::shared_ptr<
::aidl::android::hardware::camera::device::ICameraDeviceCallback>
@@ -209,6 +226,7 @@
// Acquisition timestamp of last frame.
std::atomic<uint64_t> mLastAcquisitionTimestampNanoseconds;
+ std::atomic<uint64_t> mLastSurfaceTimestampNanoseconds;
// EGL helpers - constructed and accessed only from rendering thread.
std::unique_ptr<EglDisplayContext> mEglDisplayContext;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 98bf62a..be36ec4 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -15,6 +15,8 @@
*/
// #define LOG_NDEBUG 0
+#include <chrono>
+
#include "utils/Timers.h"
#define LOG_TAG "EglSurfaceTexture"
@@ -99,6 +101,10 @@
static_cast<nsecs_t>(timeout.count()));
}
+std::chrono::nanoseconds EglSurfaceTexture::getTimestamp() {
+ return std::chrono::nanoseconds(mGlConsumer->getTimestamp());
+}
+
GLuint EglSurfaceTexture::updateTexture() {
int previousFrameId;
int framesAdvance = 0;
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index a46af8f..c1f1169 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -82,6 +82,10 @@
// See SurfaceTexture.getTransformMatrix for more details.
std::array<float, 16> getTransformMatrix();
+ // Retrieves the timestamp associated with the texture image
+ // set by the most recent call to updateTexture.
+ std::chrono::nanoseconds getTimestamp();
+
private:
#if !COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ)
sp<IGraphicBufferProducer> mBufferProducer;
diff --git a/services/mediametrics/AudioAnalytics.cpp b/services/mediametrics/AudioAnalytics.cpp
index bd4ac38..c01d46e 100644
--- a/services/mediametrics/AudioAnalytics.cpp
+++ b/services/mediametrics/AudioAnalytics.cpp
@@ -555,22 +555,24 @@
}
std::pair<std::string, int32_t> AudioAnalytics::dump(
- int32_t lines, int64_t sinceNs, const char *prefix) const
+ bool details, int32_t lines, int64_t sinceNs, const char *prefix) const
{
std::stringstream ss;
int32_t ll = lines;
if (ll > 0) {
- auto [s, l] = mAnalyticsState->dump(ll, sinceNs, prefix);
+ auto [s, l] = mAnalyticsState->dump(details, ll, sinceNs, prefix);
ss << s;
ll -= l;
}
- if (ll > 0) {
+
+ // use details to dump prior state.
+ if (details && ll > 0) {
ss << "Prior audioserver state:\n";
--ll;
}
- if (ll > 0) {
- auto [s, l] = mPreviousAnalyticsState->dump(ll, sinceNs, prefix);
+ if (details && ll > 0) {
+ auto [s, l] = mPreviousAnalyticsState->dump(details, ll, sinceNs, prefix);
ss << s;
ll -= l;
}
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index f81db53..2ec4ac8 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -49,12 +49,9 @@
// (0 for either of these disables that threshold)
//
static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * NANOS_PER_SECOND;
-// 2019/6: average daily per device is currently 375-ish;
-// setting this to 2000 is large enough to catch most devices
-// we'll lose some data on very very media-active devices, but only for
-// the gms collection; statsd will have already covered those for us.
-// This also retains enough information to help with bugreports
-static constexpr size_t kMaxRecords = 2000;
+
+// Max records to keep in queue which dump out for bugreports.
+static constexpr size_t kMaxRecords = 2500;
// max we expire in a single call, to constrain how long we hold the
// mutex, which also constrains how long a client might wait.
@@ -92,16 +89,12 @@
/* static */
std::pair<std::string, int64_t>
MediaMetricsService::getSanitizedPackageNameAndVersionCode(uid_t uid) {
- // Meyer's singleton, initialized on first access.
- // mUidInfo is locked internally.
- static mediautils::UidInfo uidInfo;
-
- // get info.
- mediautils::UidInfo::Info info = uidInfo.getInfo(uid);
- if (useUidForPackage(info.package, info.installer)) {
+ const std::shared_ptr<const mediautils::UidInfo::Info> info =
+ mediautils::UidInfo::getInfo(uid);
+ if (useUidForPackage(info->package, info->installer)) {
return { std::to_string(uid), /* versionCode */ 0 };
} else {
- return { info.package, info.versionCode };
+ return { info->package, info->versionCode };
}
}
@@ -315,7 +308,8 @@
// TODO: maybe consider a better way of dumping audio analytics info.
const int32_t linesToDump = all ? INT32_MAX : 1000;
- auto [ dumpString, lines ] = mAudioAnalytics.dump(linesToDump, sinceNs, prefixptr);
+ auto [ dumpString, lines ] = mAudioAnalytics.dump(
+ all, linesToDump, sinceNs, prefixptr);
result << dumpString;
if (lines == linesToDump) {
result << "-- some lines may be truncated --\n";
diff --git a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
index c7468c7..572e969 100644
--- a/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
+++ b/services/mediametrics/fuzzer/mediametrics_aidl_fuzzer.cpp
@@ -22,6 +22,7 @@
using ::android::MediaMetricsService;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ signal(SIGPIPE, SIG_IGN);
auto service = sp<MediaMetricsService>::make();
fuzzService(service, FuzzedDataProvider(data, size));
return 0;
diff --git a/services/mediametrics/include/mediametricsservice/AnalyticsState.h b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
index 09c0b4c..1dabe5d 100644
--- a/services/mediametrics/include/mediametricsservice/AnalyticsState.h
+++ b/services/mediametrics/include/mediametricsservice/AnalyticsState.h
@@ -83,11 +83,12 @@
* different locks, so may not be 100% consistent with the last data
* delivered.
*
+ * \param details dumps the detailed internal state.
* \param lines the maximum number of lines in the string returned.
* \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
* \param prefix the desired key prefix to match (nullptr shows all)
*/
- std::pair<std::string, int32_t> dump(
+ std::pair<std::string, int32_t> dump(bool details,
int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const {
std::stringstream ss;
int32_t ll = lines;
@@ -96,7 +97,7 @@
ss << "TransactionLog: gc(" << mTransactionLog.getGarbageCollectionCount() << ")\n";
--ll;
}
- if (ll > 0) {
+ if (details && ll > 0) {
auto [s, l] = mTransactionLog.dump(ll, sinceNs, prefix);
ss << s;
ll -= l;
@@ -105,7 +106,7 @@
ss << "TimeMachine: gc(" << mTimeMachine.getGarbageCollectionCount() << ")\n";
--ll;
}
- if (ll > 0) {
+ if (details && ll > 0) {
auto [s, l] = mTimeMachine.dump(ll, sinceNs, prefix);
ss << s;
ll -= l;
diff --git a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
index f0a4ac8..57f55c1 100644
--- a/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
+++ b/services/mediametrics/include/mediametricsservice/AudioAnalytics.h
@@ -67,11 +67,12 @@
* different locks, so may not be 100% consistent with the last data
* delivered.
*
+ * \param details dumps the detailed internal state.
* \param lines the maximum number of lines in the string returned.
* \param sinceNs the nanoseconds since Unix epoch to start dump (0 shows all)
* \param prefix the desired key prefix to match (nullptr shows all)
*/
- std::pair<std::string, int32_t> dump(
+ std::pair<std::string, int32_t> dump(bool details,
int32_t lines = INT32_MAX, int64_t sinceNs = 0, const char *prefix = nullptr) const;
/**
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index 4a6aee4..a7684f4 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -850,14 +850,14 @@
// TODO: Verify contents of AudioAnalytics.
// Currently there is no getter API in AudioAnalytics besides dump.
- ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_EQ(10, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
// untrusted entities can add to an existing key
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
// Check that we have some info in the dump.
- ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_LT(9, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
}
TEST(mediametrics_tests, audio_analytics_permission2) {
@@ -888,14 +888,14 @@
// TODO: Verify contents of AudioAnalytics.
// Currently there is no getter API in AudioAnalytics besides dump.
- ASSERT_EQ(10, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_EQ(10, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item, true /* isTrusted */));
// untrusted entities can add to an existing key
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item2, false /* isTrusted */));
// Check that we have some info in the dump.
- ASSERT_LT(9, audioAnalytics.dump(1000).second /* lines */);
+ ASSERT_LT(9, audioAnalytics.dump(true /* details */, 1000).second /* lines */);
}
TEST(mediametrics_tests, audio_analytics_dump) {
@@ -922,13 +922,13 @@
ASSERT_EQ(NO_ERROR, audioAnalytics.submit(item3, true /* isTrusted */));
// find out how many lines we have.
- auto [string, lines] = audioAnalytics.dump(1000);
+ auto [string, lines] = audioAnalytics.dump(true /* details */, 1000);
ASSERT_EQ(lines, (int32_t) countNewlines(string.c_str()));
printf("AudioAnalytics: %s", string.c_str());
// ensure that dump operates over those lines.
for (int32_t ll = 0; ll < lines; ++ll) {
- auto [s, l] = audioAnalytics.dump(ll);
+ auto [s, l] = audioAnalytics.dump(true /* details */, ll);
ASSERT_EQ(ll, l);
ASSERT_EQ(ll, (int32_t) countNewlines(s.c_str()));
}
diff --git a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
index 6253df7..1cad482 100644
--- a/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
+++ b/services/mediaresourcemanager/fuzzer/resourcemanager_service_fuzzer.cpp
@@ -26,6 +26,7 @@
using ndk::SharedRefBase;
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ signal(SIGPIPE, SIG_IGN);
std::shared_ptr<ResourceManagerService> service = ResourceManagerService::Create();
fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
return 0;
diff --git a/services/tuner/TunerFilter.cpp b/services/tuner/TunerFilter.cpp
index 84a2b4e..e393c44 100644
--- a/services/tuner/TunerFilter.cpp
+++ b/services/tuner/TunerFilter.cpp
@@ -335,26 +335,40 @@
/////////////// FilterCallback ///////////////////////
::ndk::ScopedAStatus TunerFilter::FilterCallback::onFilterStatus(DemuxFilterStatus status) {
- Mutex::Autolock _l(mCallbackLock);
- if (mTunerFilterCallback != nullptr) {
- mTunerFilterCallback->onFilterStatus(status);
+ shared_ptr<ITunerFilterCallback> cb(nullptr);
+ {
+ Mutex::Autolock _l(mCallbackLock);
+ cb = mTunerFilterCallback;
+ }
+ if (cb != nullptr) {
+ cb->onFilterStatus(status);
}
return ::ndk::ScopedAStatus::ok();
}
::ndk::ScopedAStatus TunerFilter::FilterCallback::onFilterEvent(
const vector<DemuxFilterEvent>& events) {
- Mutex::Autolock _l(mCallbackLock);
- if (mTunerFilterCallback != nullptr) {
- mTunerFilterCallback->onFilterEvent(events);
+ shared_ptr<ITunerFilterCallback> cb(nullptr);
+ {
+ Mutex::Autolock _l(mCallbackLock);
+ cb = mTunerFilterCallback;
+ }
+ if (cb != nullptr) {
+ cb->onFilterEvent(events);
}
return ::ndk::ScopedAStatus::ok();
}
void TunerFilter::FilterCallback::sendSharedFilterStatus(int32_t status) {
- Mutex::Autolock _l(mCallbackLock);
- if (mTunerFilterCallback != nullptr && mOriginalCallback != nullptr) {
- mTunerFilterCallback->onFilterStatus(static_cast<DemuxFilterStatus>(status));
+ shared_ptr<ITunerFilterCallback> cb(nullptr);
+ shared_ptr<ITunerFilterCallback> orig_cb(nullptr);
+ {
+ Mutex::Autolock _l(mCallbackLock);
+ cb = mTunerFilterCallback;
+ orig_cb = mOriginalCallback;
+ }
+ if (cb != nullptr && orig_cb != nullptr) {
+ cb->onFilterStatus(static_cast<DemuxFilterStatus>(status));
}
}
diff --git a/services/tuner/TunerHelper.cpp b/services/tuner/TunerHelper.cpp
index a03386f..8357a9e 100644
--- a/services/tuner/TunerHelper.cpp
+++ b/services/tuner/TunerHelper.cpp
@@ -73,7 +73,7 @@
// TODO: update Demux, Descrambler.
void TunerHelper::updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
- const vector<int32_t>& lnbHandles) {
+ const vector<int64_t>& lnbHandles) {
::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
shared_ptr<ITunerResourceManager> tunerRM = ITunerResourceManager::fromBinder(binder);
if (tunerRM == nullptr) {
@@ -85,7 +85,7 @@
}
void TunerHelper::updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
const vector<TunerDemuxInfo>& demuxInfos,
- const vector<int32_t>& lnbHandles) {
+ const vector<int64_t>& lnbHandles) {
::ndk::SpAIBinder binder(AServiceManager_waitForService("tv_tuner_resource_mgr"));
shared_ptr<ITunerResourceManager> tunerRM = ITunerResourceManager::fromBinder(binder);
if (tunerRM == nullptr) {
@@ -101,13 +101,22 @@
}
// TODO: create a map between resource id and handles.
-int TunerHelper::getResourceIdFromHandle(int resourceHandle, int /*type*/) {
- return (resourceHandle & 0x00ff0000) >> 16;
+int TunerHelper::getResourceIdFromHandle(long resourceHandle, int /*type*/) {
+ return (int)((resourceHandle >> RESOURCE_ID_SHIFT) & RESOURCE_ID_MASK);
}
-int TunerHelper::getResourceHandleFromId(int id, int resourceType) {
+/**
+ * Generate resource handle for resourceType and id
+ * Resource Handle Allotment : 64 bits (long)
+ * 8 bits - resourceType
+ * 32 bits - id
+ * 24 bits - resourceRequestCount
+ */
+long TunerHelper::getResourceHandleFromId(int id, int resourceType) {
// TODO: build up randomly generated id to handle mapping
- return (resourceType & 0x000000ff) << 24 | (id << 16) | (sResourceRequestCount++ & 0xffff);
+ return static_cast<int64_t>(resourceType & RESOURCE_TYPE_MASK) << RESOURCE_TYPE_SHIFT |
+ static_cast<int64_t>(id & RESOURCE_ID_MASK) << RESOURCE_ID_SHIFT |
+ (sResourceRequestCount++ & RESOURCE_COUNT_MASK);
}
} // namespace tuner
diff --git a/services/tuner/TunerHelper.h b/services/tuner/TunerHelper.h
index 65a9b0b..74e1662 100644
--- a/services/tuner/TunerHelper.h
+++ b/services/tuner/TunerHelper.h
@@ -56,17 +56,23 @@
// TODO: update Demux, Descrambler.
static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
- const vector<int32_t>& lnbHandles);
+ const vector<int64_t>& lnbHandles);
static void updateTunerResources(const vector<TunerFrontendInfo>& feInfos,
const vector<TunerDemuxInfo>& demuxInfos,
- const vector<int32_t>& lnbHandles);
+ const vector<int64_t>& lnbHandles);
// TODO: create a map between resource id and handles.
- static int getResourceIdFromHandle(int resourceHandle, int type);
- static int getResourceHandleFromId(int id, int resourceType);
+ static int getResourceIdFromHandle(long resourceHandle, int type);
+ static long getResourceHandleFromId(int id, int resourceType);
private:
static int32_t sResourceRequestCount;
+
+ static constexpr uint32_t RESOURCE_ID_SHIFT = 24;
+ static constexpr uint32_t RESOURCE_TYPE_SHIFT = 56;
+ static constexpr uint32_t RESOURCE_COUNT_MASK = 0xffffff;
+ static constexpr uint32_t RESOURCE_ID_MASK = 0xffffffff;
+ static constexpr uint32_t RESOURCE_TYPE_MASK = 0xff;
};
} // namespace tuner
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
index 9a1e8bb..8cf84e2 100644
--- a/services/tuner/TunerService.cpp
+++ b/services/tuner/TunerService.cpp
@@ -82,7 +82,7 @@
return AServiceManager_addService(tunerService->asBinder().get(), getServiceName());
}
-::ndk::ScopedAStatus TunerService::openDemux(int32_t in_demuxHandle,
+::ndk::ScopedAStatus TunerService::openDemux(int64_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) {
ALOGV("openDemux");
shared_ptr<IDemux> demux;
@@ -116,7 +116,7 @@
}
}
-::ndk::ScopedAStatus TunerService::getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) {
+::ndk::ScopedAStatus TunerService::getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) {
if (mTunerVersion <= TUNER_HAL_VERSION_2_0) {
return ::ndk::ScopedAStatus::fromServiceSpecificError(
static_cast<int32_t>(Result::UNAVAILABLE));
@@ -169,7 +169,7 @@
return mTuner->getFrontendInfo(id, _aidl_return);
}
-::ndk::ScopedAStatus TunerService::openFrontend(int32_t frontendHandle,
+::ndk::ScopedAStatus TunerService::openFrontend(int64_t frontendHandle,
shared_ptr<ITunerFrontend>* _aidl_return) {
int id = TunerHelper::getResourceIdFromHandle(frontendHandle, FRONTEND);
shared_ptr<IFrontend> frontend;
@@ -181,7 +181,7 @@
return status;
}
-::ndk::ScopedAStatus TunerService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
+::ndk::ScopedAStatus TunerService::openLnb(int64_t lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
shared_ptr<ILnb> lnb;
int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB);
auto status = mTuner->openLnbById(id, &lnb);
@@ -204,7 +204,7 @@
return ::ndk::ScopedAStatus::ok();
}
-::ndk::ScopedAStatus TunerService::openDescrambler(int32_t /*descramblerHandle*/,
+::ndk::ScopedAStatus TunerService::openDescrambler(int64_t /*descramblerHandle*/,
shared_ptr<ITunerDescrambler>* _aidl_return) {
shared_ptr<IDescrambler> descrambler;
// int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER);
@@ -310,7 +310,7 @@
continue;
}
TunerFrontendInfo tunerFrontendInfo{
- .handle = TunerHelper::getResourceHandleFromId((int)ids[i], FRONTEND),
+ .handle = TunerHelper::getResourceHandleFromId(ids[i], FRONTEND),
.type = static_cast<int>(frontendInfo.type),
.exclusiveGroupId = frontendInfo.exclusiveGroupId,
};
@@ -336,18 +336,16 @@
for (int i = 0; i < ids.size(); i++) {
DemuxInfo demuxInfo;
mTuner->getDemuxInfo(ids[i], &demuxInfo);
- TunerDemuxInfo tunerDemuxInfo{
- .handle = TunerHelper::getResourceHandleFromId((int)ids[i], DEMUX),
- .filterTypes = static_cast<int>(demuxInfo.filterTypes)
- };
+ TunerDemuxInfo tunerDemuxInfo{.handle = TunerHelper::getResourceHandleFromId(ids[i], DEMUX),
+ .filterTypes = static_cast<int>(demuxInfo.filterTypes)};
infos.push_back(tunerDemuxInfo);
}
return infos;
}
-vector<int32_t> TunerService::getTRMLnbHandles() {
- vector<int32_t> lnbHandles;
+vector<int64_t> TunerService::getTRMLnbHandles() {
+ vector<int64_t> lnbHandles;
if (mTuner != nullptr) {
vector<int32_t> lnbIds;
auto res = mTuner->getLnbIds(&lnbIds);
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
index 190ccd4..07b414e 100644
--- a/services/tuner/TunerService.h
+++ b/services/tuner/TunerService.h
@@ -61,20 +61,20 @@
virtual ~TunerService();
::ndk::ScopedAStatus getFrontendIds(vector<int32_t>* out_ids) override;
- ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendHandle,
+ ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendId,
FrontendInfo* _aidl_return) override;
- ::ndk::ScopedAStatus openFrontend(int32_t in_frontendHandle,
+ ::ndk::ScopedAStatus openFrontend(int64_t in_frontendHandle,
shared_ptr<ITunerFrontend>* _aidl_return) override;
- ::ndk::ScopedAStatus openLnb(int32_t in_lnbHandle,
+ ::ndk::ScopedAStatus openLnb(int64_t in_lnbHandle,
shared_ptr<ITunerLnb>* _aidl_return) override;
::ndk::ScopedAStatus openLnbByName(const string& in_lnbName,
shared_ptr<ITunerLnb>* _aidl_return) override;
- ::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
+ ::ndk::ScopedAStatus openDemux(int64_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) override;
::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
- ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) override;
::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
- ::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
+ ::ndk::ScopedAStatus openDescrambler(int64_t in_descramblerHandle,
shared_ptr<ITunerDescrambler>* _aidl_return) override;
::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
@@ -94,7 +94,7 @@
void updateTunerResources();
vector<TunerFrontendInfo> getTRMFrontendInfos();
vector<TunerDemuxInfo> getTRMDemuxInfos();
- vector<int32_t> getTRMLnbHandles();
+ vector<int64_t> getTRMLnbHandles();
shared_ptr<ITuner> mTuner;
int mTunerVersion = TUNER_HAL_VERSION_UNKNOWN;
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
index 932133e..0d23817 100644
--- a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -54,7 +54,7 @@
* @param frontendHandle the handle of the frontend granted by TRM.
* @return the aidl interface of the frontend.
*/
- ITunerFrontend openFrontend(in int frontendHandle);
+ ITunerFrontend openFrontend(in long frontendHandle);
/**
* Open a new interface of ITunerLnb given a lnbHandle.
@@ -62,7 +62,7 @@
* @param lnbHandle the handle of the LNB granted by TRM.
* @return a newly created ITunerLnb interface.
*/
- ITunerLnb openLnb(in int lnbHandle);
+ ITunerLnb openLnb(in long lnbHandle);
/**
* Open a new interface of ITunerLnb given a LNB name.
@@ -75,7 +75,7 @@
/**
* Create a new instance of Demux.
*/
- ITunerDemux openDemux(in int demuxHandle);
+ ITunerDemux openDemux(in long demuxHandle);
/**
* Retrieve the supported filter main types
@@ -83,7 +83,7 @@
* @param demuxHandle the handle of the demux to query demux info for
* @return the demux info
*/
- DemuxInfo getDemuxInfo(in int demuxHandle);
+ DemuxInfo getDemuxInfo(in long demuxHandle);
/**
* Retrieve the list of demux info for all the demuxes on the system
@@ -104,7 +104,7 @@
* @param descramblerHandle the handle of the descrambler granted by TRM.
* @return a newly created ITunerDescrambler interface.
*/
- ITunerDescrambler openDescrambler(in int descramblerHandle);
+ ITunerDescrambler openDescrambler(in long descramblerHandle);
/**
* Get an integer that carries the Tuner HIDL version. The high 16 bits are the
diff --git a/services/tuner/hidl/TunerHidlService.cpp b/services/tuner/hidl/TunerHidlService.cpp
index 6bc36be..1b6b032 100644
--- a/services/tuner/hidl/TunerHidlService.cpp
+++ b/services/tuner/hidl/TunerHidlService.cpp
@@ -101,7 +101,7 @@
return AServiceManager_addService(tunerService->asBinder().get(), getServiceName());
}
-::ndk::ScopedAStatus TunerHidlService::openDemux(int32_t /* in_demuxHandle */,
+::ndk::ScopedAStatus TunerHidlService::openDemux(int64_t /* in_demuxHandle */,
shared_ptr<ITunerDemux>* _aidl_return) {
ALOGV("openDemux");
HidlResult res;
@@ -123,7 +123,7 @@
return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
}
-::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int32_t /* in_demuxHandle */,
+::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int64_t /* in_demuxHandle */,
DemuxInfo* /* _aidl_return */) {
ALOGE("getDemuxInfo is not supported");
return ::ndk::ScopedAStatus::fromServiceSpecificError(
@@ -195,7 +195,7 @@
return ::ndk::ScopedAStatus::ok();
}
-::ndk::ScopedAStatus TunerHidlService::openFrontend(int32_t frontendHandle,
+::ndk::ScopedAStatus TunerHidlService::openFrontend(int64_t frontendHandle,
shared_ptr<ITunerFrontend>* _aidl_return) {
HidlResult status;
sp<HidlIFrontend> frontend;
@@ -221,7 +221,8 @@
return ::ndk::ScopedAStatus::ok();
}
-::ndk::ScopedAStatus TunerHidlService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) {
+::ndk::ScopedAStatus TunerHidlService::openLnb(int64_t lnbHandle,
+ shared_ptr<ITunerLnb>* _aidl_return) {
HidlResult status;
sp<HidlILnb> lnb;
int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB);
@@ -256,7 +257,7 @@
}
::ndk::ScopedAStatus TunerHidlService::openDescrambler(
- int32_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) {
+ int64_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) {
HidlResult status;
sp<HidlIDescrambler> descrambler;
//int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER);
@@ -410,8 +411,8 @@
return infos;
}
-vector<int32_t> TunerHidlService::getTRMLnbHandles() {
- vector<int32_t> lnbHandles;
+vector<int64_t> TunerHidlService::getTRMLnbHandles() {
+ vector<int64_t> lnbHandles;
if (mTuner != nullptr) {
HidlResult res;
vector<HidlLnbId> lnbIds;
diff --git a/services/tuner/hidl/TunerHidlService.h b/services/tuner/hidl/TunerHidlService.h
index 526c5e6..1973a77 100644
--- a/services/tuner/hidl/TunerHidlService.h
+++ b/services/tuner/hidl/TunerHidlService.h
@@ -73,20 +73,19 @@
virtual ~TunerHidlService();
::ndk::ScopedAStatus getFrontendIds(vector<int32_t>* out_ids) override;
- ::ndk::ScopedAStatus getFrontendInfo(int32_t in_frontendHandle,
- FrontendInfo* _aidl_return) override;
- ::ndk::ScopedAStatus openFrontend(int32_t in_frontendHandle,
+ ::ndk::ScopedAStatus getFrontendInfo(int32_t in_id, FrontendInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus openFrontend(int64_t in_frontendHandle,
shared_ptr<ITunerFrontend>* _aidl_return) override;
- ::ndk::ScopedAStatus openLnb(int32_t in_lnbHandle,
+ ::ndk::ScopedAStatus openLnb(int64_t in_lnbHandle,
shared_ptr<ITunerLnb>* _aidl_return) override;
::ndk::ScopedAStatus openLnbByName(const std::string& in_lnbName,
shared_ptr<ITunerLnb>* _aidl_return) override;
- ::ndk::ScopedAStatus openDemux(int32_t in_demuxHandle,
+ ::ndk::ScopedAStatus openDemux(int64_t in_demuxHandle,
shared_ptr<ITunerDemux>* _aidl_return) override;
::ndk::ScopedAStatus getDemuxCaps(DemuxCapabilities* _aidl_return) override;
- ::ndk::ScopedAStatus getDemuxInfo(int32_t in_demuxHandle, DemuxInfo* _aidl_return) override;
+ ::ndk::ScopedAStatus getDemuxInfo(int64_t in_demuxHandle, DemuxInfo* _aidl_return) override;
::ndk::ScopedAStatus getDemuxInfoList(vector<DemuxInfo>* _aidl_return) override;
- ::ndk::ScopedAStatus openDescrambler(int32_t in_descramblerHandle,
+ ::ndk::ScopedAStatus openDescrambler(int64_t in_descramblerHandle,
shared_ptr<ITunerDescrambler>* _aidl_return) override;
::ndk::ScopedAStatus getTunerHalVersion(int32_t* _aidl_return) override;
::ndk::ScopedAStatus openSharedFilter(const string& in_filterToken,
@@ -106,7 +105,7 @@
private:
void updateTunerResources();
vector<TunerFrontendInfo> getTRMFrontendInfos();
- vector<int32_t> getTRMLnbHandles();
+ vector<int64_t> getTRMLnbHandles();
HidlResult getHidlFrontendIds(hidl_vec<HidlFrontendId>& ids);
HidlResult getHidlFrontendInfo(const int id, HidlFrontendInfo& info);
DemuxCapabilities getAidlDemuxCaps(const HidlDemuxCapabilities& caps);
diff --git a/tools/mainline_hook_partial.sh b/tools/mainline_hook_partial.sh
index 63ae4c0..978dc02 100755
--- a/tools/mainline_hook_partial.sh
+++ b/tools/mainline_hook_partial.sh
Binary files differ
diff --git a/tools/mainline_hook_project.sh b/tools/mainline_hook_project.sh
index d58143e..65f4073 100755
--- a/tools/mainline_hook_project.sh
+++ b/tools/mainline_hook_project.sh
@@ -16,8 +16,9 @@
# tunables
+# as of 2024/5, things are all on the same branch
DEV_BRANCH=main
-MAINLINE_BRANCH=udc-mainline-prod
+MAINLINE_BRANCH=main
###
RED=$(tput setaf 1)