diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index c6f5beed3e..ab96c8ee6b 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2287,12 +2287,11 @@ typedef enum acamera_metadata_tag {
*
When low light boost is enabled by setting the AE mode to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY', it can dynamically apply a low light
* boost when the light level threshold is exceeded.
- * This field is present in the CaptureResult when the AE mode is set to
- * 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'. Otherwise, the field is not present.
* This state indicates when low light boost is 'ACTIVE' and applied. Similarly, it can
* indicate when it is not being applied by returning 'INACTIVE'.
* This key will be absent from the CaptureResult if AE mode is not set to
* 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY.
+ * The default value will always be 'INACTIVE'.
*/
ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE = // byte (acamera_metadata_enum_android_control_low_light_boost_state_t)
ACAMERA_CONTROL_START + 59,
@@ -8311,11 +8310,8 @@ typedef enum acamera_metadata_enum_acamera_control_ae_mode {
* If the session configuration is not supported, the AE mode reported in the
* CaptureResult will be 'ON' instead of 'ON_LOW_LIGHT_BOOST_BRIGHTNESS_PRIORITY'.
* When this AE mode is enabled, the CaptureResult field
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be present and not null. Otherwise, the
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE field will not be present in the CaptureResult.
- * The application can observe the CaptureResult field
- * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE to determine when low light boost is 'ACTIVE' or
- * 'INACTIVE'.
+ * ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will indicate when low light boost is 'ACTIVE'
+ * or 'INACTIVE'. By default ACAMERA_CONTROL_LOW_LIGHT_BOOST_STATE will be 'INACTIVE'.
* The low light boost is 'ACTIVE' once the scene lighting condition is less than the
* upper bound lux value defined by ACAMERA_CONTROL_LOW_LIGHT_BOOST_INFO_LUMINANCE_RANGE.
* This mode will be 'INACTIVE' once the scene lighting condition is greater than the
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index e26290fc94..5a2ab27118 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -289,7 +289,7 @@ class Interpolator : public std::map {
std::string toString() const {
std::stringstream ss;
- ss << "Interpolator{mInterpolatorType=" << static_cast(mInterpolatorType);
+ ss << "Interpolator{mInterpolatorType=" << media::toString(mInterpolatorType);
ss << ", mFirstSlope=" << mFirstSlope;
ss << ", mLastSlope=" << mLastSlope;
ss << ", {";
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 6208db313e..26da3634c8 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -116,6 +116,16 @@ class VolumeShaper {
TYPE_SCALE,
};
+ static std::string toString(Type type) {
+ switch (type) {
+ case TYPE_ID: return "TYPE_ID";
+ case TYPE_SCALE: return "TYPE_SCALE";
+ default:
+ return std::string("Unknown Type: ")
+ .append(std::to_string(static_cast(type)));
+ }
+ }
+
// Must match with VolumeShaper.java in frameworks/base.
enum OptionFlag : int32_t {
OPTION_FLAG_NONE = 0,
@@ -125,6 +135,22 @@ class VolumeShaper {
OPTION_FLAG_ALL = (OPTION_FLAG_VOLUME_IN_DBFS | OPTION_FLAG_CLOCK_TIME),
};
+ static std::string toString(OptionFlag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list>{
+ {OPTION_FLAG_VOLUME_IN_DBFS, "OPTION_FLAG_VOLUME_IN_DBFS"},
+ {OPTION_FLAG_CLOCK_TIME, "OPTION_FLAG_CLOCK_TIME"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
// Bring from base class; must match with VolumeShaper.java in frameworks/base.
using InterpolatorType = Interpolator::InterpolatorType;
@@ -329,10 +355,10 @@ class VolumeShaper {
// Returns a string for debug printing.
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Configuration{mType=" << static_cast(mType);
+ ss << "VolumeShaper::Configuration{mType=" << toString(mType);
ss << ", mId=" << mId;
if (mType != TYPE_ID) {
- ss << ", mOptionFlags=" << static_cast(mOptionFlags);
+ ss << ", mOptionFlags=" << toString(mOptionFlags);
ss << ", mDurationMs=" << mDurationMs;
ss << ", " << Interpolator::toString().c_str();
}
@@ -414,6 +440,25 @@ class VolumeShaper {
| FLAG_CREATE_IF_NECESSARY),
};
+ static std::string toString(Flag flag) {
+ std::string s;
+ for (const auto& flagPair : std::initializer_list>{
+ {FLAG_REVERSE, "FLAG_REVERSE"},
+ {FLAG_TERMINATE, "FLAG_TERMINATE"},
+ {FLAG_JOIN, "FLAG_JOIN"},
+ {FLAG_DELAY, "FLAG_DELAY"},
+ {FLAG_CREATE_IF_NECESSARY, "FLAG_CREATE_IF_NECESSARY"},
+ }) {
+ if (flag & flagPair.first) {
+ if (!s.empty()) {
+ s.append("|");
+ }
+ s.append(flagPair.second);
+ }
+ }
+ return s;
+ }
+
Operation()
: Operation(FLAG_NONE, -1 /* replaceId */) {
}
@@ -508,7 +553,7 @@ class VolumeShaper {
std::string toString() const {
std::stringstream ss;
- ss << "VolumeShaper::Operation{mFlags=" << static_cast(mFlags) ;
+ ss << "VolumeShaper::Operation{mFlags=" << toString(mFlags);
ss << ", mReplaceId=" << mReplaceId;
ss << ", mXOffset=" << mXOffset;
ss << "}";
diff --git a/media/audio/aconfig/audio.aconfig b/media/audio/aconfig/audio.aconfig
index 4c3e25a428..c3ae59c880 100644
--- a/media/audio/aconfig/audio.aconfig
+++ b/media/audio/aconfig/audio.aconfig
@@ -59,6 +59,13 @@ flag {
bug: "307588546"
}
+flag {
+ name: "music_fx_edge_to_edge"
+ namespace: "media_audio"
+ description: "Enable Edge-to-edge feature for MusicFx and handle insets"
+ bug: "336204940"
+}
+
flag {
name: "port_to_piid_simplification"
namespace: "media_audio"
diff --git a/media/audio/aconfig/audioserver.aconfig b/media/audio/aconfig/audioserver.aconfig
index 94b60e2034..5e701688b6 100644
--- a/media/audio/aconfig/audioserver.aconfig
+++ b/media/audio/aconfig/audioserver.aconfig
@@ -14,6 +14,13 @@ flag {
bug: "294525897"
}
+flag {
+ name: "effect_chain_callback_improve"
+ namespace: "media_audio"
+ description: "Improve effect chain callback mutex logic."
+ bug: "342413767"
+}
+
flag {
name: "fdtostring_timeout_fix"
namespace: "media_audio"
diff --git a/media/audioaidlconversion/AidlConversionCppNdk.cpp b/media/audioaidlconversion/AidlConversionCppNdk.cpp
index 9a92f773d9..694be5ab7d 100644
--- a/media/audioaidlconversion/AidlConversionCppNdk.cpp
+++ b/media/audioaidlconversion/AidlConversionCppNdk.cpp
@@ -1069,13 +1069,6 @@ ::android::status_t aidl2legacy_AudioDevice_audio_device(
if (mac.size() != 6) return BAD_VALUE;
snprintf(addressBuffer, AUDIO_DEVICE_MAX_ADDRESS_LEN, "%02X:%02X:%02X:%02X:%02X:%02X",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
- // special case for anonymized mac address:
- // change anonymized bytes back from FD:FF:FF:FF to XX:XX:XX:XX
- std::string address(addressBuffer);
- if (address.compare(0, strlen("FD:FF:FF:FF"), "FD:FF:FF:FF") == 0) {
- address.replace(0, strlen("FD:FF:FF:FF"), "XX:XX:XX:XX");
- }
- strcpy(addressBuffer, address.c_str());
} break;
case Tag::ipv4: {
const std::vector& ipv4 = aidl.address.get();
@@ -1136,20 +1129,11 @@ legacy2aidl_audio_device_AudioDevice(
if (!legacyAddress.empty()) {
switch (suggestDeviceAddressTag(aidl.type)) {
case Tag::mac: {
- // special case for anonymized mac address:
- // change anonymized bytes so that they can be scanned as HEX bytes
- // Use '01' for LSB bits 0 and 1 as Bluetooth MAC addresses are never multicast
- // and universaly administered
- std::string address = legacyAddress;
- if (address.compare(0, strlen("XX:XX:XX:XX"), "XX:XX:XX:XX") == 0) {
- address.replace(0, strlen("XX:XX:XX:XX"), "FD:FF:FF:FF");
- }
-
std::vector mac(6);
- int status = sscanf(address.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
+ int status = sscanf(legacyAddress.c_str(), "%hhX:%hhX:%hhX:%hhX:%hhX:%hhX",
&mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]);
if (status != mac.size()) {
- ALOGE("%s: malformed MAC address: \"%s\"", __func__, address.c_str());
+ ALOGE("%s: malformed MAC address: \"%s\"", __func__, legacyAddress.c_str());
return unexpected(BAD_VALUE);
}
aidl.address = AudioDeviceAddress::make(std::move(mac));
diff --git a/media/codec2/hal/aidl/ComponentStore.cpp b/media/codec2/hal/aidl/ComponentStore.cpp
index ef4930842c..659ad83dc7 100644
--- a/media/codec2/hal/aidl/ComponentStore.cpp
+++ b/media/codec2/hal/aidl/ComponentStore.cpp
@@ -36,7 +36,7 @@
#include
#include
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
#include
#include
#include
@@ -51,7 +51,7 @@ namespace media {
namespace c2 {
namespace utils {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
using ::android::DefaultFilterPlugin;
using ::android::FilterWrapper;
#endif
@@ -144,7 +144,15 @@ ComponentStore::ComponentStore(const std::shared_ptr& store)
::android::SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
+ std::shared_ptr paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -173,8 +181,7 @@ c2_status_t ComponentStore::validateSupportedParams(
std::lock_guard lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -189,7 +196,7 @@ std::shared_ptr ComponentStore::getParameterCache() const {
return mParameterCache;
}
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
// static
std::shared_ptr ComponentStore::GetFilterWrapper() {
constexpr const char kPluginPath[] = "libc2filterplugin.so";
@@ -220,7 +227,7 @@ ScopedAStatus ComponentStore::createComponent(
mStore->createComponent(name, &c2component);
if (status == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
c2component = GetFilterWrapper()->maybeWrapComponent(c2component);
#endif
onInterfaceLoaded(c2component->intf());
@@ -254,7 +261,7 @@ ScopedAStatus ComponentStore::createInterface(
std::shared_ptr c2interface;
c2_status_t res = mStore->createInterface(name, &c2interface);
if (res == C2_OK) {
-#ifndef __ANDROID_APEX__
+#ifndef __ANDROID_APEX__ // Filters are not supported for APEX modules
c2interface = GetFilterWrapper()->maybeWrapInterface(c2interface);
#endif
onInterfaceLoaded(c2interface);
@@ -314,8 +321,7 @@ ScopedAStatus ComponentStore::getStructDescriptors(
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -368,6 +374,16 @@ ScopedAStatus ComponentStore::getConfigurable(
return ScopedAStatus::ok();
}
+std::shared_ptr ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr &reflector : mParamReflectors) {
+ std::shared_ptr desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
diff --git a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
index 0698b0f85c..077ebc6316 100644
--- a/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
+++ b/media/codec2/hal/aidl/include/codec2/aidl/ComponentStore.h
@@ -115,7 +115,7 @@ struct ComponentStore : public BnComponentStore {
c2_status_t mInit;
std::shared_ptr mStore;
- std::shared_ptr mParamReflector;
+ std::vector> mParamReflectors;
std::map> mStructDescriptors;
std::set mUnsupportedStructDescriptors;
@@ -132,6 +132,9 @@ struct ComponentStore : public BnComponentStore {
mutable std::mutex mComponentRosterMutex;
std::map mComponentRoster;
+ // describe from mParamReflectors
+ std::shared_ptr describe(const C2Param::CoreIndex &index);
+
// Called whenever Component is created.
void reportComponentBirth(Component* component);
// Called only from the destructor of Component.
diff --git a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
index 1c0d5b0b98..77230de3da 100644
--- a/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.0/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@ ComponentStore::ComponentStore(const std::shared_ptr& store)
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@ c2_status_t ComponentStore::validateSupportedParams(
std::lock_guard lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -307,8 +314,7 @@ Return ComponentStore::getStructDescriptors(
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -354,6 +360,16 @@ Return> ComponentStore::getConfigurable() {
return mConfigurable;
}
+std::shared_ptr ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr &reflector : mParamReflectors) {
+ std::shared_ptr desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
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 27e2a05f3a..56f1faa9fe 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
@@ -114,9 +114,12 @@ struct ComponentStore : public IComponentStore {
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr &intf);
+ // describe from mParamReflectors
+ std::shared_ptr describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr mStore;
- std::shared_ptr mParamReflector;
+ std::vector> mParamReflectors;
std::map> mStructDescriptors;
std::set mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
index d47abdd040..e672eea38a 100644
--- a/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.1/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@ ComponentStore::ComponentStore(const std::shared_ptr& store)
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@ c2_status_t ComponentStore::validateSupportedParams(
std::lock_guard lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -306,8 +313,7 @@ Return ComponentStore::getStructDescriptors(
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -389,6 +395,16 @@ Return ComponentStore::createComponent_1_1(
return Void();
}
+std::shared_ptr ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr &reflector : mParamReflectors) {
+ std::shared_ptr desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
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 f6daee74b5..cde7b4e00f 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
@@ -122,9 +122,12 @@ struct ComponentStore : public IComponentStore {
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr &intf);
+ // describe from mParamReflectors
+ std::shared_ptr describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr mStore;
- std::shared_ptr mParamReflector;
+ std::vector> mParamReflectors;
std::map> mStructDescriptors;
std::set mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
index 9fac5d5268..f918808b41 100644
--- a/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
+++ b/media/codec2/hal/hidl/1.2/utils/ComponentStore.cpp
@@ -139,7 +139,15 @@ ComponentStore::ComponentStore(const std::shared_ptr& store)
SetPreferredCodec2ComponentStore(store);
// Retrieve struct descriptors
- mParamReflector = mStore->getParamReflector();
+ mParamReflectors.push_back(mStore->getParamReflector());
+#ifndef __ANDROID_APEX__
+ std::shared_ptr paramReflector =
+ GetFilterWrapper()->getParamReflector();
+ if (paramReflector != nullptr) {
+ ALOGD("[%s] added param reflector from filter wrapper", mStore->getName().c_str());
+ mParamReflectors.push_back(paramReflector);
+ }
+#endif
// Retrieve supported parameters from store
using namespace std::placeholders;
@@ -168,8 +176,7 @@ c2_status_t ComponentStore::validateSupportedParams(
std::lock_guard lock(mStructDescriptorsMutex);
auto it = mStructDescriptors.find(coreIndex);
if (it == mStructDescriptors.end()) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
// All supported params must be described
res = C2_BAD_INDEX;
@@ -306,8 +313,7 @@ Return ComponentStore::getStructDescriptors(
if (item == mStructDescriptors.end()) {
// not in the cache, and not known to be unsupported, query local reflector
if (!mUnsupportedStructDescriptors.count(coreIndex)) {
- std::shared_ptr structDesc =
- mParamReflector->describe(coreIndex);
+ std::shared_ptr structDesc = describe(coreIndex);
if (!structDesc) {
mUnsupportedStructDescriptors.emplace(coreIndex);
} else {
@@ -425,6 +431,16 @@ Return ComponentStore::createComponent_1_2(
return Void();
}
+std::shared_ptr ComponentStore::describe(const C2Param::CoreIndex &index) {
+ for (const std::shared_ptr &reflector : mParamReflectors) {
+ std::shared_ptr desc = reflector->describe(index);
+ if (desc) {
+ return desc;
+ }
+ }
+ return nullptr;
+}
+
// Called from createComponent() after a successful creation of `component`.
void ComponentStore::reportComponentBirth(Component* component) {
ComponentStatus componentStatus;
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 e95a651756..4cd42d10b8 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
@@ -129,9 +129,12 @@ struct ComponentStore : public IComponentStore {
// Does bookkeeping for an interface that has been loaded.
void onInterfaceLoaded(const std::shared_ptr &intf);
+ // describe from mParamReflectors
+ std::shared_ptr describe(const C2Param::CoreIndex &index);
+
c2_status_t mInit;
std::shared_ptr mStore;
- std::shared_ptr mParamReflector;
+ std::vector> mParamReflectors;
std::map> mStructDescriptors;
std::set mUnsupportedStructDescriptors;
diff --git a/media/codec2/hal/plugin/FilterWrapper.cpp b/media/codec2/hal/plugin/FilterWrapper.cpp
index b92615034a..ab6e3eb43f 100644
--- a/media/codec2/hal/plugin/FilterWrapper.cpp
+++ b/media/codec2/hal/plugin/FilterWrapper.cpp
@@ -1012,4 +1012,11 @@ c2_status_t FilterWrapper::queryParamsForPreviousComponent(
return mPlugin->queryParamsForPreviousComponent(intf, params);
}
+std::shared_ptr FilterWrapper::getParamReflector() {
+ if (mInit != OK) {
+ return nullptr;
+ }
+ return mStore->getParamReflector();
+}
+
} // namespace android
diff --git a/media/codec2/hal/plugin/FilterWrapperStub.cpp b/media/codec2/hal/plugin/FilterWrapperStub.cpp
index 3fd54095ae..a21f6d0735 100644
--- a/media/codec2/hal/plugin/FilterWrapperStub.cpp
+++ b/media/codec2/hal/plugin/FilterWrapperStub.cpp
@@ -57,4 +57,8 @@ c2_status_t FilterWrapper::createBlockPool(
return CreateCodec2BlockPool(allocatorParam, component, pool);
}
+std::shared_ptr FilterWrapper::getParamReflector() {
+ return nullptr;
+}
+
} // namespace android
diff --git a/media/codec2/hal/plugin/internal/FilterWrapper.h b/media/codec2/hal/plugin/internal/FilterWrapper.h
index dcffb5cd30..c27901e4ff 100644
--- a/media/codec2/hal/plugin/internal/FilterWrapper.h
+++ b/media/codec2/hal/plugin/internal/FilterWrapper.h
@@ -104,6 +104,10 @@ class FilterWrapper : public std::enable_shared_from_this {
const std::shared_ptr &intf,
std::vector> *params);
+ /**
+ * Return the param reflector of the filter plugin store.
+ */
+ std::shared_ptr getParamReflector();
private:
status_t mInit;
std::unique_ptr mPlugin;
diff --git a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
index b5383ad584..47412b7868 100644
--- a/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
+++ b/media/codec2/hal/plugin/samples/SampleFilterPlugin.cpp
@@ -37,6 +37,19 @@ typedef C2StreamParam
C2StreamColorAspectsRequestInfo;
+// In practice the vendor parameters will be defined in a separate header file,
+// but for the purpose of this sample, we just define it here.
+
+// Vendor-specific type index for filters start from this value. 0x7000 is added to
+// avoid conflict with existing vendor type indices.
+constexpr uint32_t kTypeIndexFilterStart = C2Param::TYPE_INDEX_VENDOR_START + 0x7000;
+// Answer to the Ultimate Question of Life, the Universe, and Everything
+// (Reference to The Hitchhiker's Guide to the Galaxy by Douglas Adams)
+constexpr uint32_t kParamIndexVendorUltimateAnswer = kTypeIndexFilterStart + 0;
+typedef C2StreamParam
+ C2StreamVendorUltimateAnswerInfo;
+constexpr char C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER[] = "ultimate-answer";
+
namespace android {
using namespace std::literals::chrono_literals;
@@ -49,10 +62,9 @@ class SampleToneMappingFilter
static const std::string NAME;
static const FilterPlugin_V1::Descriptor DESCRIPTOR;
- explicit Interface(c2_node_id_t id)
+ Interface(c2_node_id_t id, const std::shared_ptr &reflector)
: mId(id),
- mReflector(std::make_shared()),
- mHelper(mReflector) {
+ mHelper(reflector) {
}
~Interface() override = default;
C2String getName() const override { return NAME; }
@@ -126,7 +138,6 @@ class SampleToneMappingFilter
}
private:
const c2_node_id_t mId;
- std::shared_ptr mReflector;
struct Helper : public C2InterfaceHelper {
explicit Helper(std::shared_ptr reflector)
: C2InterfaceHelper(reflector) {
@@ -265,6 +276,15 @@ class SampleToneMappingFilter
.withSetter(ColorAspectsRequestSetter)
.build());
+ addParameter(
+ DefineParam(mVendorUltimateAnswerInfo, C2_PARAMKEY_VENDOR_ULTIMATE_ANSWER)
+ .withDefault(new C2StreamVendorUltimateAnswerInfo::input(0u))
+ .withFields({
+ C2F(mVendorUltimateAnswerInfo, value).any(),
+ })
+ .withSetter(VendorUltimateAnswerSetter)
+ .build());
+
addParameter(
DefineParam(mOutputColorAspectInfo, C2_PARAMKEY_COLOR_ASPECTS)
.withDefault(new C2StreamColorAspectsInfo::output(0u))
@@ -336,6 +356,15 @@ class SampleToneMappingFilter
return C2R::Ok();
}
+ static C2R VendorUltimateAnswerSetter(
+ bool mayBlock,
+ C2P &me) {
+ (void)mayBlock;
+ ALOGI("Answer to the Ultimate Question of Life, the Universe, and Everything "
+ "set to %d", me.v.value);
+ return C2R::Ok();
+ }
+
std::shared_ptr mApiFeatures;
std::shared_ptr mName;
@@ -362,11 +391,13 @@ class SampleToneMappingFilter
std::shared_ptr mInputColorAspectInfo;
std::shared_ptr mOutputColorAspectInfo;
std::shared_ptr mColorAspectRequestInfo;
+
+ std::shared_ptr mVendorUltimateAnswerInfo;
} mHelper;
};
- explicit SampleToneMappingFilter(c2_node_id_t id)
- : mIntf(std::make_shared(id)) {
+ SampleToneMappingFilter(c2_node_id_t id, const std::shared_ptr &reflector)
+ : mIntf(std::make_shared(id, reflector)) {
}
~SampleToneMappingFilter() override {
if (mProcessingThread.joinable()) {
@@ -802,7 +833,10 @@ const std::string SampleToneMappingFilter::Interface::NAME = "c2.sample.tone-map
// static
const FilterPlugin_V1::Descriptor SampleToneMappingFilter::Interface::DESCRIPTOR = {
// controlParams
- { C2StreamColorAspectsRequestInfo::output::PARAM_TYPE },
+ {
+ C2StreamColorAspectsRequestInfo::output::PARAM_TYPE,
+ C2StreamVendorUltimateAnswerInfo::input::PARAM_TYPE,
+ },
// affectedParams
{
C2StreamHdrStaticInfo::output::PARAM_TYPE,
@@ -815,7 +849,7 @@ class SampleC2ComponentStore : public C2ComponentStore {
SampleC2ComponentStore()
: mReflector(std::make_shared()),
mIntf(mReflector),
- mFactories(CreateFactories()) {
+ mFactories(CreateFactories(mReflector)) {
}
~SampleC2ComponentStore() = default;
@@ -892,36 +926,46 @@ class SampleC2ComponentStore : public C2ComponentStore {
template
struct ComponentFactoryImpl : public ComponentFactory {
public:
- ComponentFactoryImpl(const std::shared_ptr &traits)
- : ComponentFactory(traits) {
+ ComponentFactoryImpl(
+ const std::shared_ptr &traits,
+ const std::shared_ptr &reflector)
+ : ComponentFactory(traits),
+ mReflector(reflector) {
}
~ComponentFactoryImpl() override = default;
c2_status_t createComponent(
c2_node_id_t id,
std::shared_ptr* const component) const override {
- *component = std::make_shared(id);
+ *component = std::make_shared(id, mReflector);
return C2_OK;
}
c2_status_t createInterface(
c2_node_id_t id,
std::shared_ptr* const interface) const override {
- *interface = std::make_shared(id);
+ *interface = std::make_shared(id, mReflector);
return C2_OK;
}
+ private:
+ std::shared_ptr mReflector;
};
template
- static void AddFactory(std::map> *factories) {
- std::shared_ptr intf{new typename T::Interface(0)};
+ static void AddFactory(
+ std::map> *factories,
+ const std::shared_ptr &reflector) {
+ std::shared_ptr intf{new typename T::Interface(0, reflector)};
std::shared_ptr traits(new (std::nothrow) C2Component::Traits);
CHECK(C2InterfaceUtils::FillTraitsFromInterface(traits.get(), intf))
<< "Failed to fill traits from interface";
- factories->emplace(traits->name, new ComponentFactoryImpl(traits));
+ factories->emplace(
+ traits->name,
+ new ComponentFactoryImpl(traits, reflector));
}
- static std::map> CreateFactories() {
+ static std::map> CreateFactories(
+ const std::shared_ptr &reflector) {
std::map> factories;
- AddFactory(&factories);
+ AddFactory(&factories, reflector);
return factories;
}
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 4ce95d80ea..33588257c4 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -3136,6 +3136,7 @@ VolumeShaper::Status AudioTrack::applyVolumeShaper(
const sp& configuration,
const sp& operation)
{
+ const int64_t beginNs = systemTime();
AutoMutex lock(mLock);
mVolumeHandler->setIdIfNecessary(configuration);
media::VolumeShaperConfiguration config;
@@ -3143,6 +3144,18 @@ VolumeShaper::Status AudioTrack::applyVolumeShaper(
media::VolumeShaperOperation op;
operation->writeToParcelable(&op);
VolumeShaper::Status status;
+
+ mediametrics::Defer defer([&] {
+ mediametrics::LogItem(mMetricsId)
+ .set(AMEDIAMETRICS_PROP_EVENT, AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER)
+ .set(AMEDIAMETRICS_PROP_EXECUTIONTIMENS, (int64_t)(systemTime() - beginNs))
+ .set(AMEDIAMETRICS_PROP_STATE, stateToString(mState))
+ .set(AMEDIAMETRICS_PROP_STATUS, (int32_t)status)
+ .set(AMEDIAMETRICS_PROP_TOSTRING, configuration->toString()
+ .append(" ")
+ .append(operation->toString()))
+ .record(); });
+
mAudioTrack->applyVolumeShaper(config, op, &status);
if (status == DEAD_OBJECT) {
diff --git a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
index 0be1d7e25c..7f55e48b21 100644
--- a/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
+++ b/media/libaudioclient/tests/audio_aidl_legacy_conversion_tests.cpp
@@ -483,28 +483,8 @@ INSTANTIATE_TEST_SUITE_P(
AudioDeviceAddress::make(
std::vector{1, 2}))));
-TEST(AnonymizedBluetoothAddressRoundTripTest, Legacy2Aidl2Legacy) {
- const std::vector sAnonymizedAidlAddress =
- std::vector{0xFD, 0xFF, 0xFF, 0xFF, 0xAB, 0xCD};
- const std::string sAnonymizedLegacyAddress = std::string("XX:XX:XX:XX:AB:CD");
- auto device = legacy2aidl_audio_device_AudioDevice(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP,
- sAnonymizedLegacyAddress);
- ASSERT_TRUE(device.ok());
- ASSERT_EQ(AudioDeviceAddress::Tag::mac, device.value().address.getTag());
- ASSERT_EQ(sAnonymizedAidlAddress, device.value().address.get());
-
- audio_devices_t legacyType;
- std::string legacyAddress;
- status_t status =
- aidl2legacy_AudioDevice_audio_device(device.value(), &legacyType, &legacyAddress);
- ASSERT_EQ(OK, status);
- EXPECT_EQ(legacyType, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP);
- EXPECT_EQ(sAnonymizedLegacyAddress, legacyAddress);
-}
-
class AudioFormatDescriptionRoundTripTest : public testing::TestWithParam {
};
-
TEST_P(AudioFormatDescriptionRoundTripTest, Aidl2Legacy2Aidl) {
const auto initial = GetParam();
auto conv = aidl2legacy_AudioFormatDescription_audio_format_t(initial);
diff --git a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
index 426ad15c86..e5373f36ba 100644
--- a/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
+++ b/media/libeffects/lvm/wrapper/Aidl/BundleTypes.h
@@ -65,10 +65,9 @@ constexpr inline std::array, MAX_NUM_PRESETS>
{5, 3, -1, 3, 5}}}; /* Rock Preset */
static const std::vector kEqPresets = {
- {-1, "Custom"}, {0, "Normal"}, {1, "Classical"}, {2, "Dance"},
- {3, "Flat"}, {4, "Folk"}, {5, "Heavy Metal"}, {6, "Hip Hop"},
- {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
-
+ {-1, "Custom"}, {0, "Normal"}, {1, "Classical"}, {2, "Dance"},
+ {3, "Flat"}, {4, "Folk"}, {5, "Heavy Metal"}, {6, "Hip Hop"},
+ {7, "Jazz"}, {8, "Pop"}, {9, "Rock"}};
const std::vector kEqRanges = {
MAKE_RANGE(Equalizer, preset, 0, MAX_NUM_PRESETS - 1),
diff --git a/media/libmediahelper/Android.bp b/media/libmediahelper/Android.bp
index 53cb1d254c..974ccf39d3 100644
--- a/media/libmediahelper/Android.bp
+++ b/media/libmediahelper/Android.bp
@@ -68,9 +68,6 @@ cc_defaults {
cc_library {
name: "libmedia_helper",
vendor_available: true,
- vndk: {
- enabled: true,
- },
defaults: ["libmedia_helper_defaults"],
min_sdk_version: "29",
}
@@ -78,10 +75,6 @@ cc_library {
cc_library {
name: "libmedia_helper_ext",
vendor: true,
- vndk: {
- enabled: true,
- extends: "libmedia_helper",
- },
defaults: ["libmedia_helper_defaults"],
host_supported: false,
cflags: [
diff --git a/media/libmediametrics/include/MediaMetricsConstants.h b/media/libmediametrics/include/MediaMetricsConstants.h
index 26aa3755d9..e60a6784eb 100644
--- a/media/libmediametrics/include/MediaMetricsConstants.h
+++ b/media/libmediametrics/include/MediaMetricsConstants.h
@@ -213,6 +213,7 @@
// format to transport packets.
// Raw byte streams are used if this
// is false.
+#define AMEDIAMETRICS_PROP_TOSTRING "toString" // string
#define AMEDIAMETRICS_PROP_TOTALINPUTBYTES "totalInputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_TOTALOUTPUTBYTES "totalOutputBytes" // int32 (MIDI)
#define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle
@@ -243,6 +244,7 @@
// Values are strings accepted for a given property.
// An event is a general description, which often is a function name.
+#define AMEDIAMETRICS_PROP_EVENT_VALUE_APPLYVOLUMESHAPER "applyVolumeShaper"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_BEGINAUDIOINTERVALGROUP "beginAudioIntervalGroup"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CLOSE "close"
#define AMEDIAMETRICS_PROP_EVENT_VALUE_CREATE "create"
diff --git a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
index 652b1eed3b..15265bffb1 100644
--- a/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
+++ b/media/libmediaplayerservice/fuzzer/mediaplayer_fuzzer.cpp
@@ -51,6 +51,69 @@ const char dumpFile[] = "OutputDumpFile";
enum DataSourceType { HTTP, FD, STREAM, FILETYPE, SOCKET, kMaxValue = SOCKET };
+constexpr audio_flags_mask_t kAudioFlagsMasks[] = {AUDIO_FLAG_NONE,
+ AUDIO_FLAG_AUDIBILITY_ENFORCED,
+ AUDIO_FLAG_SECURE,
+ AUDIO_FLAG_SCO,
+ AUDIO_FLAG_BEACON,
+ AUDIO_FLAG_HW_AV_SYNC,
+ AUDIO_FLAG_HW_HOTWORD,
+ AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY,
+ AUDIO_FLAG_BYPASS_MUTE,
+ AUDIO_FLAG_LOW_LATENCY,
+ AUDIO_FLAG_DEEP_BUFFER,
+ AUDIO_FLAG_NO_MEDIA_PROJECTION,
+ AUDIO_FLAG_MUTE_HAPTIC,
+ AUDIO_FLAG_NO_SYSTEM_CAPTURE,
+ AUDIO_FLAG_CAPTURE_PRIVATE,
+ AUDIO_FLAG_CONTENT_SPATIALIZED,
+ AUDIO_FLAG_NEVER_SPATIALIZE,
+ AUDIO_FLAG_CALL_REDIRECTION};
+
+constexpr audio_content_type_t kAudioContentTypes[] = {
+ AUDIO_CONTENT_TYPE_UNKNOWN, AUDIO_CONTENT_TYPE_SPEECH, AUDIO_CONTENT_TYPE_MUSIC,
+ AUDIO_CONTENT_TYPE_MOVIE, AUDIO_CONTENT_TYPE_SONIFICATION, AUDIO_CONTENT_TYPE_ULTRASOUND};
+
+constexpr audio_source_t kAudioSources[] = {AUDIO_SOURCE_INVALID,
+ AUDIO_SOURCE_DEFAULT,
+ AUDIO_SOURCE_MIC,
+ AUDIO_SOURCE_VOICE_UPLINK,
+ AUDIO_SOURCE_VOICE_DOWNLINK,
+ AUDIO_SOURCE_VOICE_CALL,
+ AUDIO_SOURCE_CAMCORDER,
+ AUDIO_SOURCE_VOICE_RECOGNITION,
+ AUDIO_SOURCE_VOICE_COMMUNICATION,
+ AUDIO_SOURCE_REMOTE_SUBMIX,
+ AUDIO_SOURCE_UNPROCESSED,
+ AUDIO_SOURCE_VOICE_PERFORMANCE,
+ AUDIO_SOURCE_ECHO_REFERENCE,
+ AUDIO_SOURCE_FM_TUNER,
+ AUDIO_SOURCE_HOTWORD,
+ AUDIO_SOURCE_ULTRASOUND};
+
+constexpr audio_usage_t kAudioUsages[] = {AUDIO_USAGE_UNKNOWN,
+ AUDIO_USAGE_MEDIA,
+ AUDIO_USAGE_VOICE_COMMUNICATION,
+ AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING,
+ AUDIO_USAGE_ALARM,
+ AUDIO_USAGE_NOTIFICATION,
+ AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT,
+ AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED,
+ AUDIO_USAGE_NOTIFICATION_EVENT,
+ AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY,
+ AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
+ AUDIO_USAGE_ASSISTANCE_SONIFICATION,
+ AUDIO_USAGE_GAME,
+ AUDIO_USAGE_VIRTUAL_SOURCE,
+ AUDIO_USAGE_ASSISTANT,
+ AUDIO_USAGE_CALL_ASSISTANT,
+ AUDIO_USAGE_EMERGENCY,
+ AUDIO_USAGE_SAFETY,
+ AUDIO_USAGE_VEHICLE_STATUS,
+ AUDIO_USAGE_ANNOUNCEMENT};
+
constexpr PixelFormat kPixelFormat[] = {
PIXEL_FORMAT_UNKNOWN, PIXEL_FORMAT_NONE, PIXEL_FORMAT_CUSTOM,
PIXEL_FORMAT_TRANSLUCENT, PIXEL_FORMAT_TRANSPARENT, PIXEL_FORMAT_OPAQUE,
@@ -354,7 +417,18 @@ void MediaPlayerServiceFuzzer::invokeMediaPlayer() {
[&]() { mMediaPlayer->attachAuxEffect(mFdp.ConsumeIntegral()); },
[&]() {
int32_t key = mFdp.PickValueInArray(kMediaParamKeys);
- request.writeInt32(mFdp.ConsumeIntegral());
+ request.writeInt32((audio_usage_t)mFdp.ConsumeIntegralInRange(
+ AUDIO_USAGE_UNKNOWN, AUDIO_USAGE_ANNOUNCEMENT) /* usage */);
+ request.writeInt32((audio_content_type_t)mFdp.ConsumeIntegralInRange(
+ AUDIO_CONTENT_TYPE_UNKNOWN,
+ AUDIO_CONTENT_TYPE_ULTRASOUND) /* content_type */);
+ request.writeInt32((audio_source_t)mFdp.ConsumeIntegralInRange(
+ AUDIO_SOURCE_INVALID, AUDIO_SOURCE_ULTRASOUND) /* source */);
+ request.writeInt32((audio_flags_mask_t)mFdp.ConsumeIntegralInRange(
+ AUDIO_FLAG_NONE, AUDIO_FLAG_CALL_REDIRECTION) /* flags */);
+ request.writeInt32(mFdp.ConsumeBool() /* hasFlattenedTag */);
+ request.writeString16(
+ String16((mFdp.ConsumeRandomLengthString()).c_str()) /* tags */);
request.setDataPosition(0);
mMediaPlayer->setParameter(key, request);
key = mFdp.PickValueInArray(kMediaParamKeys);
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index e01af70984..f562445a61 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -16,6 +16,7 @@ license {
"NOTICE",
],
}
+
cc_defaults {
name: "libstagefright_omx_defaults",
double_loadable: true,
@@ -61,9 +62,6 @@ cc_defaults {
cc_library_shared {
name: "libstagefright_omx",
vendor_available: true,
- vndk: {
- enabled: true,
- },
export_shared_lib_headers: [
"libmedia_omx",
@@ -106,57 +104,6 @@ cc_library_shared {
},
}
-cc_library_shared {
- name: "libstagefright_omx_ext",
- vendor: true,
- vndk: {
- enabled: true,
- extends: "libstagefright_omx",
- },
- defaults: ["libstagefright_omx_defaults"],
-
- export_shared_lib_headers: [
- "libmedia_omx",
- "libstagefright_foundation_ext",
- "libstagefright_xmlparser",
- "libutils",
- ],
-
- shared_libs: [
- "libbase",
- "libbinder",
- "libmedia_omx",
- "libutils",
- "liblog",
- "libui",
- "libcutils",
- "libstagefright_foundation_ext",
- "libstagefright_bufferqueue_helper",
- "libstagefright_xmlparser",
- "libdl",
- "libhidlbase",
- "libhidlmemory",
- "libvndksupport",
- "android.hardware.media.omx@1.0",
- "android.hardware.graphics.bufferqueue@1.0",
- ],
- cflags: [
- "-Werror",
- "-Wall",
- "-Wno-unused-parameter",
- "-Wno-documentation",
- "-D__ANDROID_VNDK_EXT__",
- ],
- sanitize: {
- misc_undefined: [
- "signed-integer-overflow",
- "unsigned-integer-overflow",
- ],
- cfi: true,
- },
-
-}
-
cc_library_shared {
name: "libstagefright_softomx",
vendor_available: true,
diff --git a/media/module/bufferpool/2.0/AccessorImpl.cpp b/media/module/bufferpool/2.0/AccessorImpl.cpp
index 202d8030a7..b9483bfc19 100644
--- a/media/module/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/module/bufferpool/2.0/AccessorImpl.cpp
@@ -17,6 +17,8 @@
#define LOG_TAG "BufferPoolAccessor2.0"
//#define LOG_NDEBUG 0
+#include
+
#include
#include
#include
@@ -147,7 +149,25 @@ static constexpr uint32_t kSeqIdVndkBit = 0;
#endif
static constexpr uint32_t kSeqIdMax = 0x7fffffff;
-uint32_t Accessor::Impl::sSeqId = time(nullptr) & kSeqIdMax;
+
+Accessor::Impl::ConnectionIdGenerator::ConnectionIdGenerator() {
+ mSeqId = static_cast(time(nullptr) & kSeqIdMax);
+ mPid = static_cast(getpid());
+}
+
+ConnectionId Accessor::Impl::ConnectionIdGenerator::getConnectionId() {
+ uint32_t seq;
+ {
+ std::lock_guard l(mLock);
+ seq = mSeqId;
+ if (mSeqId == kSeqIdMax) {
+ mSeqId = 0;
+ } else {
+ ++mSeqId;
+ }
+ }
+ return (int64_t)mPid << 32 | seq | kSeqIdVndkBit;
+}
Accessor::Impl::Impl(
const std::shared_ptr &allocator)
@@ -163,13 +183,14 @@ ResultStatus Accessor::Impl::connect(
uint32_t *pMsgId,
const StatusDescriptor** statusDescPtr,
const InvalidationDescriptor** invDescPtr) {
+ static ::android::base::NoDestructor sConIdGenerator;
sp newConnection = new Connection();
ResultStatus status = ResultStatus::CRITICAL_ERROR;
{
std::lock_guard lock(mBufferPool.mMutex);
if (newConnection) {
int32_t pid = getpid();
- ConnectionId id = (int64_t)pid << 32 | sSeqId | kSeqIdVndkBit;
+ ConnectionId id = sConIdGenerator->getConnectionId();
status = mBufferPool.mObserver.open(id, statusDescPtr);
if (status == ResultStatus::OK) {
newConnection->initialize(accessor, id);
@@ -179,11 +200,6 @@ ResultStatus Accessor::Impl::connect(
mBufferPool.mConnectionIds.insert(id);
mBufferPool.mInvalidationChannel.getDesc(invDescPtr);
mBufferPool.mInvalidation.onConnect(id, observer);
- if (sSeqId == kSeqIdMax) {
- sSeqId = 0;
- } else {
- ++sSeqId;
- }
}
}
diff --git a/media/module/bufferpool/2.0/AccessorImpl.h b/media/module/bufferpool/2.0/AccessorImpl.h
index 3d39941337..2366177135 100644
--- a/media/module/bufferpool/2.0/AccessorImpl.h
+++ b/media/module/bufferpool/2.0/AccessorImpl.h
@@ -77,7 +77,14 @@ class Accessor::Impl
private:
// ConnectionId = pid : (timestamp_created + seqId)
// in order to guarantee uniqueness for each connection
- static uint32_t sSeqId;
+ struct ConnectionIdGenerator {
+ int32_t mPid;
+ uint32_t mSeqId;
+ std::mutex mLock;
+
+ ConnectionIdGenerator();
+ ConnectionId getConnectionId();
+ };
const std::shared_ptr mAllocator;
diff --git a/media/module/bufferpool/2.0/Android.bp b/media/module/bufferpool/2.0/Android.bp
index bdab103311..c40603c0e2 100644
--- a/media/module/bufferpool/2.0/Android.bp
+++ b/media/module/bufferpool/2.0/Android.bp
@@ -21,6 +21,9 @@ cc_defaults {
export_include_dirs: [
"include",
],
+ header_libs: [
+ "libbase_headers",
+ ],
shared_libs: [
"libcutils",
"libfmq",
diff --git a/media/module/foundation/Android.bp b/media/module/foundation/Android.bp
index de670c8c5f..c5526dd34e 100644
--- a/media/module/foundation/Android.bp
+++ b/media/module/foundation/Android.bp
@@ -126,9 +126,6 @@ cc_defaults {
cc_library {
name: "libstagefright_foundation",
vendor_available: true,
- vndk: {
- enabled: true,
- },
defaults: ["libstagefright_foundation_defaults"],
min_sdk_version: "29",
apex_available: [
@@ -152,10 +149,6 @@ cc_library {
cc_library {
name: "libstagefright_foundation_ext",
vendor: true,
- vndk: {
- enabled: true,
- extends: "libstagefright_foundation",
- },
defaults: ["libstagefright_foundation_defaults"],
host_supported: false,
min_sdk_version: "29",
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 4b0192a22b..7bec8cf616 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -47,7 +47,6 @@ static const String16 sAndroidPermissionRecordAudio("android.permission.RECORD_A
static const String16 sModifyPhoneState("android.permission.MODIFY_PHONE_STATE");
static const String16 sModifyAudioRouting("android.permission.MODIFY_AUDIO_ROUTING");
static const String16 sCallAudioInterception("android.permission.CALL_AUDIO_INTERCEPTION");
-static const String16 sAndroidPermissionBluetoothConnect("android.permission.BLUETOOTH_CONNECT");
static String16 resolveCallingPackage(PermissionController& permissionController,
const std::optional opPackageName, uid_t uid) {
@@ -393,48 +392,6 @@ status_t checkIMemory(const sp& iMemory)
return NO_ERROR;
}
-/**
- * Determines if the MAC address in Bluetooth device descriptors returned by APIs of
- * a native audio service (audio flinger, audio policy) must be anonymized.
- * MAC addresses returned to system server or apps with BLUETOOTH_CONNECT permission
- * are not anonymized.
- *
- * @param attributionSource The attribution source of the calling app.
- * @param caller string identifying the caller for logging.
- * @return true if the MAC addresses must be anonymized, false otherwise.
- */
-bool mustAnonymizeBluetoothAddress(
- const AttributionSourceState& attributionSource, const String16& caller) {
- uid_t uid = VALUE_OR_FATAL(aidl2legacy_int32_t_uid_t(attributionSource.uid));
- if (isAudioServerOrSystemServerUid(uid)) {
- return false;
- }
- const std::optional resolvedAttributionSource =
- resolveAttributionSource(attributionSource, DEVICE_ID_DEFAULT);
- if (!resolvedAttributionSource.has_value()) {
- return true;
- }
- permission::PermissionChecker permissionChecker;
- return permissionChecker.checkPermissionForPreflightFromDatasource(
- sAndroidPermissionBluetoothConnect, resolvedAttributionSource.value(), caller,
- AppOpsManager::OP_BLUETOOTH_CONNECT)
- != permission::PermissionChecker::PERMISSION_GRANTED;
-}
-
-/**
- * Modifies the passed MAC address string in place for consumption by unprivileged clients.
- * the string is assumed to have a valid MAC address format.
- * the anonymzation must be kept in sync with toAnonymizedAddress() in BluetoothUtils.java
- *
- * @param address input/output the char string contining the MAC address to anonymize.
- */
-void anonymizeBluetoothAddress(char *address) {
- if (address == nullptr || strlen(address) != strlen("AA:BB:CC:DD:EE:FF")) {
- return;
- }
- memcpy(address, "XX:XX:XX:XX", strlen("XX:XX:XX:XX"));
-}
-
sp MediaPackageManager::retrievePackageManager() {
const sp sm = defaultServiceManager();
if (sm == nullptr) {
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 9c02cd41f5..e0fabfdb22 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -113,10 +113,6 @@ bool modifyPhoneStateAllowed(const AttributionSourceState& attributionSource);
bool bypassInterruptionPolicyAllowed(const AttributionSourceState& attributionSource);
bool callAudioInterceptionAllowed(const AttributionSourceState& attributionSource);
void purgePermissionCache();
-bool mustAnonymizeBluetoothAddress(
- const AttributionSourceState& attributionSource, const String16& caller);
-void anonymizeBluetoothAddress(char *address);
-
int32_t getOpForSource(audio_source_t source);
AttributionSourceState getCallingAttributionSource();
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index 82a43d2668..5985252b51 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -1596,19 +1596,6 @@ Status AudioPolicyService::isDirectOutputSupported(
return Status::ok();
}
-template
-void anonymizePortBluetoothAddress(Port *port) {
- if (port->type != AUDIO_PORT_TYPE_DEVICE) {
- return;
- }
- if (!(audio_is_a2dp_device(port->ext.device.type)
- || audio_is_ble_device(port->ext.device.type)
- || audio_is_bluetooth_sco_device(port->ext.device.type)
- || audio_is_hearing_aid_out_device(port->ext.device.type))) {
- return;
- }
- anonymizeBluetoothAddress(port->ext.device.address);
-}
Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
media::AudioPortType typeAidl, Int* count,
@@ -1627,27 +1614,14 @@ Status AudioPolicyService::listAudioPorts(media::AudioPortRole roleAidl,
std::unique_ptr ports(new audio_port_v7[num_ports]);
unsigned int generation;
- const AttributionSourceState attributionSource = getCallingAttributionSource();
- AutoCallerClear acc;
- {
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
- // AudioPolicyManager->listAudioPorts makes a deep copy of port structs into ports
- // so it is safe to access after releasing the mutex
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
- mAudioPolicyManager->listAudioPorts(
- role, type, &num_ports, ports.get(), &generation)));
- numPortsReq = std::min(numPortsReq, num_ports);
- }
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- for (size_t i = 0; i < numPortsReq; ++i) {
- anonymizePortBluetoothAddress(&ports[i]);
- }
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
}
-
+ AutoCallerClear acc;
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->listAudioPorts(role, type, &num_ports, ports.get(), &generation)));
+ numPortsReq = std::min(numPortsReq, num_ports);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(ports.get(), ports.get() + numPortsReq, std::back_inserter(*portsAidl),
legacy2aidl_audio_port_v7_AudioPortFw)));
@@ -1670,24 +1644,12 @@ Status AudioPolicyService::listDeclaredDevicePorts(media::AudioPortRole role,
Status AudioPolicyService::getAudioPort(int portId,
media::AudioPortFw* _aidl_return) {
audio_port_v7 port{ .id = portId };
-
- const AttributionSourceState attributionSource = getCallingAttributionSource();
- AutoCallerClear acc;
-
- {
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
- // AudioPolicyManager->getAudioPort makes a deep copy of the port struct into port
- // so it is safe to access after releasing the mutex
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
- }
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- anonymizePortBluetoothAddress(&port);
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
}
-
+ AutoCallerClear acc;
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(mAudioPolicyManager->getAudioPort(&port)));
*_aidl_return = VALUE_OR_RETURN_BINDER_STATUS(legacy2aidl_audio_port_v7_AudioPortFw(port));
return Status::ok();
}
@@ -1745,32 +1707,14 @@ Status AudioPolicyService::listAudioPatches(Int* count,
std::unique_ptr patches(new audio_patch[num_patches]);
unsigned int generation;
- const AttributionSourceState attributionSource = getCallingAttributionSource();
- AutoCallerClear acc;
-
- {
- audio_utils::lock_guard _l(mMutex);
- if (mAudioPolicyManager == NULL) {
- return binderStatusFromStatusT(NO_INIT);
- }
- // AudioPolicyManager->listAudioPatches makes a deep copy of patches structs into patches
- // so it is safe to access after releasing the mutex
- RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
- mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
- numPatchesReq = std::min(numPatchesReq, num_patches);
- }
-
- if (mustAnonymizeBluetoothAddress(attributionSource, String16(__func__))) {
- for (size_t i = 0; i < numPatchesReq; ++i) {
- for (size_t j = 0; j < patches[i].num_sources; ++j) {
- anonymizePortBluetoothAddress(&patches[i].sources[j]);
- }
- for (size_t j = 0; j < patches[i].num_sinks; ++j) {
- anonymizePortBluetoothAddress(&patches[i].sinks[j]);
- }
- }
+ audio_utils::lock_guard _l(mMutex);
+ if (mAudioPolicyManager == NULL) {
+ return binderStatusFromStatusT(NO_INIT);
}
-
+ AutoCallerClear acc;
+ RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
+ mAudioPolicyManager->listAudioPatches(&num_patches, patches.get(), &generation)));
+ numPatchesReq = std::min(numPatchesReq, num_patches);
RETURN_IF_BINDER_ERROR(binderStatusFromStatusT(
convertRange(patches.get(), patches.get() + numPatchesReq,
std::back_inserter(*patchesAidl), legacy2aidl_audio_patch_AudioPatchFw)));
diff --git a/services/camera/virtualcamera/Android.bp b/services/camera/virtualcamera/Android.bp
index fc186fba9e..41a3dbe7f1 100644
--- a/services/camera/virtualcamera/Android.bp
+++ b/services/camera/virtualcamera/Android.bp
@@ -95,4 +95,5 @@ cc_binary {
"libvirtualcamera_utils",
],
init_rc: ["virtual_camera.hal.rc"],
+ sdclang: false,
}
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.cc b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
index 9a5bd1e5f0..cd17517d2c 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.cc
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.cc
@@ -24,6 +24,7 @@
#include
#include
#include
+#include
#include
#include "Exif.h"
@@ -78,6 +79,15 @@ using ::android::hardware::camera::common::helper::ExifUtils;
namespace {
+// helper type for the visitor
+template
+struct overloaded : Ts... {
+ using Ts::operator()...;
+};
+// explicit deduction guide (not needed as of C++20)
+template
+overloaded(Ts...) -> overloaded;
+
using namespace std::chrono_literals;
static constexpr std::chrono::milliseconds kAcquireFenceTimeout = 500ms;
@@ -89,6 +99,8 @@ static constexpr uint8_t kPipelineDepth = 2;
static constexpr size_t kJpegThumbnailBufferSize = 32 * 1024; // 32 KiB
+static constexpr UpdateTextureTask kUpdateTextureTask;
+
CameraMetadata createCaptureResultMetadata(
const std::chrono::nanoseconds timestamp,
const RequestSettings& requestSettings,
@@ -287,6 +299,21 @@ std::chrono::nanoseconds getMaxFrameDuration(
static_cast(1e9 / VirtualCameraDevice::kMinFps));
}
+class FrameAvailableListenerProxy : public ConsumerBase::FrameAvailableListener {
+ public:
+ FrameAvailableListenerProxy(std::function callback)
+ : mOnFrameAvailableCallback(callback) {
+ }
+
+ virtual void onFrameAvailable(const BufferItem&) override {
+ ALOGV("%s: onFrameAvailable", __func__);
+ mOnFrameAvailableCallback();
+ }
+
+ private:
+ std::function mOnFrameAvailableCallback;
+};
+
} // namespace
CaptureRequestBuffer::CaptureRequestBuffer(int streamId, int bufferId,
@@ -345,9 +372,25 @@ const RequestSettings& ProcessCaptureRequestTask::getRequestSettings() const {
return mRequestSettings;
}
+void VirtualCameraRenderThread::requestTextureUpdate() {
+ std::lock_guard lock(mLock);
+ // If queue is not empty, we don't need to set the mTextureUpdateRequested
+ // flag, since the texture will be updated during ProcessCaptureRequestTask
+ // processing anyway.
+ if (mQueue.empty()) {
+ mTextureUpdateRequested = true;
+ mCondVar.notify_one();
+ }
+}
+
void VirtualCameraRenderThread::enqueueTask(
std::unique_ptr task) {
std::lock_guard lock(mLock);
+ // When enqueving process capture request task, clear the
+ // mTextureUpdateRequested flag. If this flag is set, the texture was not yet
+ // updated and it will be updated when processing ProcessCaptureRequestTask
+ // anyway.
+ mTextureUpdateRequested = false;
mQueue.emplace_back(std::move(task));
mCondVar.notify_one();
}
@@ -377,8 +420,7 @@ sp VirtualCameraRenderThread::getInputSurface() {
return mInputSurfaceFuture.get();
}
-std::unique_ptr
-VirtualCameraRenderThread::dequeueTask() {
+RenderThreadTask VirtualCameraRenderThread::dequeueTask() {
std::unique_lock lock(mLock);
// Clang's thread safety analysis doesn't perform alias analysis,
// so it doesn't support moveable std::unique_lock.
@@ -389,12 +431,20 @@ VirtualCameraRenderThread::dequeueTask() {
ScopedLockAssertion lockAssertion(mLock);
mCondVar.wait(lock, [this]() REQUIRES(mLock) {
- return mPendingExit || !mQueue.empty();
+ return mPendingExit || mTextureUpdateRequested || !mQueue.empty();
});
if (mPendingExit) {
- return nullptr;
+ // Render thread task with null task signals render thread to terminate.
+ return RenderThreadTask(nullptr);
+ }
+ if (mTextureUpdateRequested) {
+ // If mTextureUpdateRequested, it's guaranteed the queue is empty, return
+ // kUpdateTextureTask to signal we want render thread to update the texture
+ // (consume buffer from the queue).
+ mTextureUpdateRequested = false;
+ return RenderThreadTask(kUpdateTextureTask);
}
- std::unique_ptr task = std::move(mQueue.front());
+ RenderThreadTask task(std::move(mQueue.front()));
mQueue.pop_front();
return task;
}
@@ -409,11 +459,23 @@ void VirtualCameraRenderThread::threadLoop() {
EglTextureProgram::TextureFormat::RGBA);
mEglSurfaceTexture = std::make_unique(
mInputSurfaceSize.width, mInputSurfaceSize.height);
+ sp frameAvailableListener =
+ sp::make(
+ [this]() { requestTextureUpdate(); });
+ mEglSurfaceTexture->setFrameAvailableListener(frameAvailableListener);
mInputSurfacePromise.set_value(mEglSurfaceTexture->getSurface());
- while (std::unique_ptr task = dequeueTask()) {
- processCaptureRequest(*task);
+ while (RenderThreadTask task = dequeueTask()) {
+ std::visit(
+ overloaded{[this](const std::unique_ptr& t) {
+ processTask(*t);
+ },
+ [this](const UpdateTextureTask&) {
+ ALOGV("Idle update of the texture");
+ mEglSurfaceTexture->updateTexture();
+ }},
+ task);
}
// Destroy EGL utilities still on the render thread.
@@ -425,7 +487,7 @@ void VirtualCameraRenderThread::threadLoop() {
ALOGV("Render thread exiting");
}
-void VirtualCameraRenderThread::processCaptureRequest(
+void VirtualCameraRenderThread::processTask(
const ProcessCaptureRequestTask& request) {
std::chrono::nanoseconds timestamp =
std::chrono::duration_cast(
@@ -688,7 +750,7 @@ ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoBlobStreamBuffer(
return status;
}
- PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_READ_RARELY,
+ PlanesLockGuard planesLock(hwBuffer, AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
fence);
if (planesLock.getStatus() != OK) {
return cameraStatus(Status::INTERNAL_ERROR);
@@ -771,8 +833,8 @@ ndk::ScopedAStatus VirtualCameraRenderThread::renderIntoEglFramebuffer(
Rect viewportRect =
viewport.value_or(Rect(framebuffer.getWidth(), framebuffer.getHeight()));
- glViewport(viewportRect.leftTop().x, viewportRect.leftTop().y,
- viewportRect.getWidth(), viewportRect.getHeight());
+ glViewport(viewportRect.left, viewportRect.top, viewportRect.getWidth(),
+ viewportRect.getHeight());
sp textureBuffer = mEglSurfaceTexture->getCurrentBuffer();
if (textureBuffer == nullptr) {
diff --git a/services/camera/virtualcamera/VirtualCameraRenderThread.h b/services/camera/virtualcamera/VirtualCameraRenderThread.h
index b23c30c144..5a5966b635 100644
--- a/services/camera/virtualcamera/VirtualCameraRenderThread.h
+++ b/services/camera/virtualcamera/VirtualCameraRenderThread.h
@@ -23,6 +23,7 @@
#include
#include
#include
+#include
#include
#include "VirtualCameraDevice.h"
@@ -34,7 +35,6 @@
#include "util/EglFramebuffer.h"
#include "util/EglProgram.h"
#include "util/EglSurfaceTexture.h"
-#include "util/MetadataUtil.h"
#include "util/Util.h"
namespace android {
@@ -94,6 +94,24 @@ class ProcessCaptureRequestTask {
const RequestSettings mRequestSettings;
};
+struct UpdateTextureTask {};
+
+struct RenderThreadTask
+ : public std::variant,
+ UpdateTextureTask> {
+ // Allow implicit conversion to bool.
+ //
+ // Returns false, if the RenderThreadTask consist of null
+ // ProcessCaptureRequestTask, which signals that the thread should terminate.
+ operator bool() const {
+ const bool isExitSignal =
+ std::holds_alternative>(
+ *this) &&
+ std::get>(*this) == nullptr;
+ return !isExitSignal;
+ }
+};
+
// Wraps dedicated rendering thread and rendering business with corresponding
// input surface.
class VirtualCameraRenderThread {
@@ -120,6 +138,12 @@ class VirtualCameraRenderThread {
// Stop rendering thread.
void stop();
+ // Send request to render thread to update the texture.
+ // Currently queued buffers in the input surface will be consumed and the most
+ // recent buffer in the input surface will be attached to the texture), all
+ // other buffers will be returned to the buffer queue.
+ void requestTextureUpdate() EXCLUDES(mLock);
+
// Equeue capture task for processing on render thread.
void enqueueTask(std::unique_ptr task)
EXCLUDES(mLock);
@@ -131,13 +155,13 @@ class VirtualCameraRenderThread {
sp getInputSurface();
private:
- std::unique_ptr dequeueTask() EXCLUDES(mLock);
+ RenderThreadTask dequeueTask() EXCLUDES(mLock);
// Rendering thread entry point.
void threadLoop();
// Process single capture request task (always called on render thread).
- void processCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
+ void processTask(const ProcessCaptureRequestTask& captureRequestTask);
// Flush single capture request task returning the error status immediately.
void flushCaptureRequest(const ProcessCaptureRequestTask& captureRequestTask);
@@ -192,6 +216,7 @@ class VirtualCameraRenderThread {
std::mutex mLock;
std::deque> mQueue GUARDED_BY(mLock);
std::condition_variable mCondVar;
+ volatile bool mTextureUpdateRequested GUARDED_BY(mLock);
volatile bool mPendingExit GUARDED_BY(mLock);
// Acquisition timestamp of last frame.
diff --git a/services/camera/virtualcamera/VirtualCameraService.cc b/services/camera/virtualcamera/VirtualCameraService.cc
index 705af86ec0..7466089e89 100644
--- a/services/camera/virtualcamera/VirtualCameraService.cc
+++ b/services/camera/virtualcamera/VirtualCameraService.cc
@@ -76,6 +76,8 @@ Available commands:
--camera_id=(ID) - override numerical ID for test camera instance
--lens_facing=(front|back|external) - specifies lens facing for test camera instance
--input_fps=(fps) - specify input fps for test camera, valid values are from 1 to 1000
+ --sensor_orientation=(0|90|180|270) - Clockwise angle through which the output image
+ needs to be rotated to be upright on the device screen in its native orientation
* disable_test_camera
)";
constexpr char kCreateVirtualDevicePermission[] =
@@ -439,6 +441,31 @@ binder_status_t VirtualCameraService::enableTestCameraCmd(
}
}
+ std::optional sensorOrientation;
+ std::optional sensorOrientationInt;
+ it = options.find("sensor_orientation");
+ if (it != options.end()) {
+ sensorOrientationInt = parseInt(it->second);
+ switch (sensorOrientationInt.value_or(0)) {
+ case 0:
+ sensorOrientation = SensorOrientation::ORIENTATION_0;
+ break;
+ case 90:
+ sensorOrientation = SensorOrientation::ORIENTATION_90;
+ break;
+ case 180:
+ sensorOrientation = SensorOrientation::ORIENTATION_180;
+ break;
+ case 270:
+ sensorOrientation = SensorOrientation::ORIENTATION_270;
+ break;
+ default:
+ dprintf(err, "Invalid sensor rotation: %s\n, must be 0, 90, 180 or 270.",
+ it->second.c_str());
+ return STATUS_BAD_VALUE;
+ }
+ }
+
sp token = sp::make();
mTestCameraToken.set(AIBinder_fromPlatformBinder(token));
@@ -449,6 +476,8 @@ binder_status_t VirtualCameraService::enableTestCameraCmd(
Format::RGBA_8888,
.maxFps = kMaxFps});
configuration.lensFacing = lensFacing.value_or(LensFacing::EXTERNAL);
+ configuration.sensorOrientation =
+ sensorOrientation.value_or(SensorOrientation::ORIENTATION_0);
configuration.virtualCameraCallback =
ndk::SharedRefBase::make(
inputFps.value_or(kTestCameraDefaultInputFps));
diff --git a/services/camera/virtualcamera/VirtualCameraSessionContext.cc b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
index 284ad05b23..aab2d0dc88 100644
--- a/services/camera/virtualcamera/VirtualCameraSessionContext.cc
+++ b/services/camera/virtualcamera/VirtualCameraSessionContext.cc
@@ -129,7 +129,8 @@ std::optional VirtualCameraSessionContext::getStreamConfig(
streamId);
return std::optional();
}
- return {it->second->getStreamConfig()};
+ VirtualCameraStream& stream = *it->second;
+ return {stream.getStreamConfig()};
}
std::shared_ptr VirtualCameraSessionContext::fetchHardwareBuffer(
@@ -141,7 +142,8 @@ std::shared_ptr VirtualCameraSessionContext::fetchHardwareBuffe
streamId);
return nullptr;
}
- return it->second->getHardwareBuffer(bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getHardwareBuffer(bufferId);
}
std::shared_ptr
@@ -154,7 +156,8 @@ VirtualCameraSessionContext::fetchOrCreateEglFramebuffer(
streamId);
return nullptr;
}
- return it->second->getEglFrameBuffer(eglDisplay, bufferId);
+ VirtualCameraStream& stream = *it->second;
+ return stream.getEglFrameBuffer(eglDisplay, bufferId);
}
std::set VirtualCameraSessionContext::getStreamIds() const {
diff --git a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
index 752d3908c4..719f64d53b 100644
--- a/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
+++ b/services/camera/virtualcamera/tests/VirtualCameraServiceTest.cc
@@ -19,6 +19,7 @@
#include
#include
#include
+#include
#include
#include "VirtualCameraService.h"
@@ -191,6 +192,16 @@ class VirtualCameraServiceTest : public ::testing::Test {
return getLensFacing(metadata);
}
+ std::optional getCameraSensorOrienation(const std::string& id) {
+ std::shared_ptr camera = mCameraProvider->getCamera(id);
+ if (camera == nullptr) {
+ return std::nullopt;
+ }
+ CameraMetadata metadata;
+ camera->getCameraCharacteristics(&metadata);
+ return getSensorOrientation(metadata);
+ }
+
protected:
std::shared_ptr mCameraService;
std::shared_ptr mCameraProvider;
@@ -506,6 +517,24 @@ TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithInvalidInputFps) {
Eq(STATUS_BAD_VALUE));
}
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientation90) {
+ EXPECT_THAT(
+ execute_shell_command("enable_test_camera --sensor_orientation=90"),
+ Eq(NO_ERROR));
+
+ std::vector cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(90)));
+}
+
+TEST_F(VirtualCameraServiceTest, TestCameraShellCmdWithSensorOrientationNoArgs) {
+ EXPECT_THAT(execute_shell_command("enable_test_camera"), Eq(NO_ERROR));
+
+ std::vector cameraIds = getCameraIds();
+ ASSERT_THAT(cameraIds, SizeIs(1));
+ EXPECT_THAT(getCameraSensorOrienation(cameraIds[0]), Optional(Eq(0)));
+}
+
} // namespace
} // namespace virtualcamera
} // namespace companion
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.cc b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
index 7de5020f95..c81d36d2fb 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.cc
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.cc
@@ -64,6 +64,11 @@ sp EglSurfaceTexture::getCurrentBuffer() {
return mGlConsumer->getCurrentBuffer();
}
+void EglSurfaceTexture::setFrameAvailableListener(
+ const wp& listener) {
+ mGlConsumer->setFrameAvailableListener(listener);
+}
+
bool EglSurfaceTexture::waitForNextFrame(const std::chrono::nanoseconds timeout) {
return mSurface->waitForNextFrame(mGlConsumer->getFrameNumber(),
static_cast(timeout.count()));
diff --git a/services/camera/virtualcamera/util/EglSurfaceTexture.h b/services/camera/virtualcamera/util/EglSurfaceTexture.h
index b9c5126851..ac3cf7d352 100644
--- a/services/camera/virtualcamera/util/EglSurfaceTexture.h
+++ b/services/camera/virtualcamera/util/EglSurfaceTexture.h
@@ -21,6 +21,7 @@
#include
#include "GLES/gl.h"
+#include "gui/ConsumerBase.h"
#include "gui/Surface.h"
#include "utils/RefBase.h"
@@ -58,6 +59,9 @@ class EglSurfaceTexture {
// Returns false on timeout, true if new frame was received before timeout.
bool waitForNextFrame(std::chrono::nanoseconds timeout);
+ void setFrameAvailableListener(
+ const wp& listener);
+
// Update the texture with the most recent submitted buffer.
// Most be called on thread with EGL context.
//
diff --git a/services/camera/virtualcamera/util/MetadataUtil.cc b/services/camera/virtualcamera/util/MetadataUtil.cc
index 31a8776bfe..4889830a64 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.cc
+++ b/services/camera/virtualcamera/util/MetadataUtil.cc
@@ -961,6 +961,20 @@ std::optional getDeviceId(
return static_cast(entry.data.i32[0]);
}
+std::optional getSensorOrientation(
+ const aidl::android::hardware::camera::device::CameraMetadata& cameraMetadata) {
+ auto metadata =
+ reinterpret_cast(cameraMetadata.metadata.data());
+
+ camera_metadata_ro_entry_t entry;
+ if (find_camera_metadata_ro_entry(metadata, ANDROID_SENSOR_ORIENTATION,
+ &entry) != OK) {
+ return std::nullopt;
+ }
+
+ return static_cast(entry.data.i32[0]);
+}
+
} // namespace virtualcamera
} // namespace companion
} // namespace android
diff --git a/services/camera/virtualcamera/util/MetadataUtil.h b/services/camera/virtualcamera/util/MetadataUtil.h
index ca6f332cdb..22d3657a4a 100644
--- a/services/camera/virtualcamera/util/MetadataUtil.h
+++ b/services/camera/virtualcamera/util/MetadataUtil.h
@@ -488,6 +488,11 @@ getPrecaptureTrigger(
std::optional