Merge "EffectBundle: update lvm control parameters with AIDL parameters" into main
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/camera_platform.aconfig b/camera/camera_platform.aconfig
index 821a4c4..ec36335 100644
--- a/camera/camera_platform.aconfig
+++ b/camera/camera_platform.aconfig
@@ -35,20 +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: "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"
@@ -71,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"
@@ -86,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"
@@ -124,16 +96,6 @@
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: "single_thread_executor_naming"
description: "Set the device executor thread name."
bug: "359709863"
@@ -144,54 +106,6 @@
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"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
-}
-
-flag {
- namespace: "camera_platform"
name: "analytics_24q3"
description: "Miscellaneous camera platform metrics for 24Q3"
bug: "332557570"
@@ -199,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"
@@ -256,3 +150,17 @@
purpose: PURPOSE_BUGFIX
}
}
+
+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"
+}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 1b5402f..1817490 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;
@@ -11573,7 +11571,6 @@
-
__END_DECLS
#endif /* _NDK_CAMERA_METADATA_TAGS_H */
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 2bf53f9..ed1522b 100644
--- a/media/aconfig/codec_fwk.aconfig
+++ b/media/aconfig/codec_fwk.aconfig
@@ -13,6 +13,16 @@
}
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"
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/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/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 356bf72..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;
@@ -240,11 +247,9 @@
// param reflectors. Currently filters work on video domain only,
// and the MultiAccessUnitHelper is only enabled on audio domain;
// thus we pass the component's param reflector, which is mParamReflectors[0].
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ 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 f09e232..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);
@@ -231,12 +239,9 @@
}
}
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
-
+ 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 009a326..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);
@@ -230,13 +238,10 @@
break;
}
}
-
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ 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 89f71a9..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);
@@ -231,11 +239,9 @@
}
}
if (!isComponentSupportsLargeAudioFrame) {
- std::shared_ptr<C2ReflectorHelper> multiAccessReflector(new C2ReflectorHelper());
multiAccessUnitIntf = std::make_shared<MultiAccessUnitInterface>(
c2interface,
- multiAccessReflector);
- mParamReflectors.push_back(multiAccessReflector);
+ 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/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/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index b1517bb..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",
],
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 e723926..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,6 +1315,7 @@
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 || mStreamType == AUDIO_STREAM_BLUETOOTH_SCO) {
@@ -1329,13 +1324,12 @@
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/IAudioPolicyService.aidl b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
index 7f5e8e2..b4f879a 100644
--- a/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
+++ b/media/libaudioclient/aidl/android/media/IAudioPolicyService.aidl
@@ -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,
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/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..d65701a 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;
}
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/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/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/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 8b50359..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);
@@ -4497,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;
}
@@ -4578,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;
}
@@ -5946,7 +5961,7 @@
}
updateHdrMetrics(false /* isConfig */);
- }
+}
void MediaCodec::extractCSD(const sp<AMessage> &format) {
mCSD.clear();
@@ -6025,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;
@@ -6071,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;
@@ -6129,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();
}
@@ -6481,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();
@@ -6497,6 +6518,7 @@
sp<AMessage> msg = mLeftover.front();
mLeftover.pop_front();
msg->setSize("index", index);
+ ALOGV("handleLeftover(%zu)", index);
return onQueueInputBuffer(msg);
}
@@ -6565,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();
@@ -6677,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..d916fd1 100644
--- a/media/mediaserver/Android.bp
+++ b/media/mediaserver/Android.bp
@@ -54,6 +54,8 @@
mediaserver_cc_binary {
name: "mediaserver",
+ defaults: ["libcodec2_hal_selection"],
+
srcs: ["main_mediaserver.cpp"],
shared_libs: [
@@ -61,6 +63,7 @@
"libicu",
"libfmq",
"libbinder",
+ "libbinder_ndk",
"libhidlbase",
"liblog",
"libmediaplayerservice",
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/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/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/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/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 1049d5e..8f9ee86 100644
--- a/media/tests/benchmark/MediaBenchmarkTest/Android.bp
+++ b/media/tests/benchmark/MediaBenchmarkTest/Android.bp
@@ -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 0315ac9..e13f8f7 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -41,6 +41,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 +119,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 +142,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 +160,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) {
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 b365648..2631469 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -92,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);
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 d94862a..4c7087e 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
@@ -899,6 +901,17 @@
BUFLOG_RESET;
+ if (media::psh_utils::AudioPowerManager::enabled()) {
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.display.id", value, "Unknown build");
+ std::string build(value);
+ build.append("\n");
+ write(fd, build.c_str(), build.size());
+ const std::string powerLog =
+ media::psh_utils::AudioPowerManager::getAudioPowerManager().toString();
+ write(fd, powerLog.c_str(), powerLog.size());
+ }
+
if (locked) {
mutex().unlock();
}
@@ -1054,6 +1067,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;
@@ -2327,6 +2341,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)
{
}
@@ -3022,7 +3039,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);
@@ -3057,7 +3074,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);
@@ -3066,22 +3083,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,
@@ -3145,7 +3162,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) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 7c58c96..50fd48c 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -38,6 +38,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>
@@ -336,7 +337,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()) {
@@ -499,6 +500,7 @@
const pid_t mPid;
const uid_t mUid;
const sp<media::IAudioFlingerClient> mAudioFlingerClient;
+ const std::unique_ptr<media::psh_utils::Token> mClientToken;
};
// --- MediaLogNotifier ---
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..abb8f2f 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
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index 02d4fc2..d0b96de 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) {
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 406b832..9c8a51c 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -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>
@@ -1218,6 +1219,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());
}
@@ -1243,6 +1248,7 @@
}
mWakeLockToken.clear();
}
+ mThreadToken.reset();
}
void ThreadBase::getPowerManager_l() {
@@ -4059,7 +4065,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) {
@@ -4084,8 +4096,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();
@@ -5266,7 +5276,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;
@@ -5325,8 +5338,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.
@@ -5406,7 +5422,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;
}
@@ -5439,7 +5458,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;
}
@@ -6335,7 +6357,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) {
@@ -7294,11 +7319,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 {
@@ -8308,8 +8336,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();
@@ -8343,8 +8373,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);
@@ -8977,7 +9010,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
@@ -11603,6 +11640,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);
@@ -11619,6 +11657,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..bf37238 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>
@@ -622,7 +623,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 +727,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
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..a692773 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)
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/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index e849bb4..edcb805 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -478,7 +478,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.
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 3c296e7..835fad2 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -412,7 +412,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 794c7c0..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>
@@ -141,6 +141,12 @@
void setDefault();
+ void setUseDeepBufferForMediaOverrideForTests(bool useDeepBufferForMedia)
+ {
+ mUseDeepBufferForMediaOverride = useDeepBufferForMedia;
+ }
+ bool useDeepBufferForMedia() const;
+
private:
friend class sp<AudioPolicyConfig>;
@@ -158,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/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 848051c..2c41de4 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -656,7 +656,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 +686,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 +704,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 +722,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 abeaaf8..f5e135e 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>
@@ -344,4 +345,9 @@
{AUDIO_FORMAT_AC4, {}}};
}
+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/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 1b53428..c1c4a28 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 &&
@@ -1572,6 +1594,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 +1677,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 +1709,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 +1754,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 +2406,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 +2424,9 @@
__func__);
mpClientInterface->invalidateTracks(clientsToInvalidate);
}
+ for (const auto& output : outputsToResetDevice) {
+ resetOutputDevice(output, 0 /*delayMs*/, nullptr /*patchHandle*/);
+ }
}
}
}
@@ -4374,8 +4414,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 +4424,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 +4538,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 +4872,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 +6162,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 +6232,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 +6246,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 +6784,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());
@@ -8101,9 +8159,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 +8221,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 +8261,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
@@ -8464,9 +8540,11 @@
}
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;
@@ -8828,6 +8906,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;
@@ -8962,7 +9042,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;
@@ -9000,7 +9080,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;
@@ -9008,11 +9088,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);
@@ -9063,6 +9143,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
@@ -9126,6 +9213,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..9ad2ea5 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -1109,8 +1109,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 +1366,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..363dfa7 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;
}
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 2f7d722..24ab6a1 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -88,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,
@@ -902,13 +906,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);
@@ -928,13 +932,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();
@@ -1020,8 +1028,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);
@@ -1050,7 +1060,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));
}
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 74cfdbe..7b7275e 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) \
@@ -1216,9 +1220,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;
}
}
}
@@ -1802,6 +1807,7 @@
++numTimesBecameEmpty;
}
mLastCommand = command;
+ status_t createAudioPatchStatus;
switch (command->mCommand) {
case SET_VOLUME: {
@@ -1869,10 +1875,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;
@@ -2041,8 +2048,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;
@@ -2602,7 +2629,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;
}
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d74bc07..c47b5e9 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -823,7 +823,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.
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/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..9ddfd6c 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 {
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 79fa157..39f9b8a 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>
@@ -176,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;
@@ -192,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);
@@ -223,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());
}
@@ -491,6 +500,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);
@@ -522,7 +534,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);
@@ -784,27 +796,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;
@@ -851,27 +863,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;
@@ -1127,12 +1139,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);
}
@@ -1173,9 +1185,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;
@@ -1235,6 +1247,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;
@@ -2511,7 +2550,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(
@@ -2533,8 +2572,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
@@ -2555,6 +2615,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:
@@ -2598,6 +2661,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,
@@ -3182,6 +3269,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;
@@ -3334,7 +3674,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);
@@ -3355,7 +3695,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
@@ -3366,7 +3706,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(
@@ -3392,7 +3732,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);
@@ -3405,7 +3745,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
@@ -3416,7 +3756,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(
@@ -3519,7 +3859,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));
@@ -3536,7 +3876,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;
@@ -3812,8 +4152,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;
@@ -3854,14 +4194,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());
@@ -3882,7 +4222,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());
@@ -3890,7 +4230,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());
@@ -3911,7 +4251,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());
@@ -3919,7 +4259,7 @@
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());
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/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 eb8708e..6a5d5e0 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";
@@ -916,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,
@@ -1013,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(
@@ -1071,7 +1069,7 @@
}
}
- Status res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
+ res = filterSensitiveMetadataIfNeeded(cameraId, outMetadata);
if (flags::analytics_24q3()) {
mCameraServiceProxyWrapper->logSessionCharacteristicsQuery(cameraId,
getCallingUid(), sessionConfiguration, res);
@@ -2387,51 +2385,6 @@
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) ?
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 0ac391d..80bd783 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.
@@ -997,15 +977,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 8c44e35..f469aad 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -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 5c0e2c6..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();
@@ -682,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;
}
}
}
diff --git a/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp b/services/camera/libcameraservice/common/hidl/HidlProviderInfo.cpp
index c394d43..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();
@@ -780,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/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 72f8c4b..6c16317 100644
--- a/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
+++ b/services/camera/libcameraservice/utils/AttributionAndPermissionUtils.cpp
@@ -28,6 +28,10 @@
#include <hwbinder/IPCThreadState.h>
#include <binderthreadstate/CallerUtils.h>
+namespace {
+ static const std::string kPermissionServiceName = "permission";
+} // namespace anonymous
+
namespace android {
namespace flags = com::android::internal::camera::flags;
@@ -138,16 +142,9 @@
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?
@@ -189,6 +186,33 @@
return uid == AID_AUTOMOTIVE_EVS;
}
+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;
@@ -245,4 +269,23 @@
attributionSource, std::string(), AppOpsManager::OP_NONE);
}
+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 a23fba7..8bfe6d8 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 {
@@ -88,6 +89,15 @@
*/
virtual bool isAutomotivePrivilegedClient(int32_t uid);
+ // 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();
@@ -121,6 +131,8 @@
const AttributionSourceState &attributionSource);
private:
+ virtual const sp<IPermissionController>& getPermissionController() const;
+
std::unique_ptr<permission::PermissionChecker> mPermissionChecker =
std::make_unique<permission::PermissionChecker>();
};
@@ -258,6 +270,10 @@
return mAttributionAndPermissionUtils->getUidForPackage(packageName, userId, uid, err);
}
+ std::string getPackageNameFromUid(int clientUid) const {
+ return mAttributionAndPermissionUtils->getPackageNameFromUid(clientUid);
+ }
+
bool isCallerCameraServerNotDelegating() const {
return mAttributionAndPermissionUtils->isCallerCameraServerNotDelegating();
}
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/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 1309626..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.
@@ -311,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));
}
}