ICameraService: Add methods to query concurrent streaming camera support.
- getConcurrentStreamingCameraIds() :
returns a list of combinations of camera ids that may stream
concurrently.
- isConcurrentSessionConfigurationSupported() :
queries whether camera devices can support the
corresponding given session configurations concurrently.
Bug: 77960042
Test: GCA (sanity)
Test: CTS
Change-Id: Iba237118ccf145695a500a2c406713e416e66011
Signed-off-by: Jayant Chowdhary <jchowdhary@google.com>
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 1401ba7..b20774a 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -37,6 +37,7 @@
#include <android-base/logging.h>
#include <cutils/properties.h>
#include <hwbinder/IPCThreadState.h>
+#include <utils/SessionConfigurationUtils.h>
#include <utils/Trace.h>
#include "api2/HeicCompositeStream.h"
@@ -47,6 +48,8 @@
using namespace ::android::hardware::camera;
using namespace ::android::hardware::camera::common::V1_0;
using std::literals::chrono_literals::operator""s;
+using hardware::camera2::utils::CameraIdAndSessionConfiguration;
+using hardware::camera::provider::V2_6::CameraIdAndStreamCombination;
namespace {
const bool kEnableLazyHal(property_get_bool("ro.camera.enableLazyHal", false));
@@ -267,7 +270,6 @@
const hardware::camera::device::V3_4::StreamConfiguration &configuration,
bool *status /*out*/) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) {
return NAME_NOT_FOUND;
@@ -1083,10 +1085,8 @@
return OK;
}
-bool CameraProviderManager::isLogicalCamera(const std::string& id,
+bool CameraProviderManager::isLogicalCameraLocked(const std::string& id,
std::vector<std::string>* physicalCameraIds) {
- std::lock_guard<std::mutex> lock(mInterfaceMutex);
-
auto deviceInfo = findDeviceInfoLocked(id);
if (deviceInfo == nullptr) return false;
@@ -1096,6 +1096,12 @@
return deviceInfo->mIsLogicalCamera;
}
+bool CameraProviderManager::isLogicalCamera(const std::string& id,
+ std::vector<std::string>* physicalCameraIds) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ return isLogicalCameraLocked(id, physicalCameraIds);
+}
+
status_t CameraProviderManager::getSystemCameraKind(const std::string& id,
SystemCameraKind *kind) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
@@ -1261,11 +1267,27 @@
mProviderName.c_str(), interface->isRemote());
// Determine minor version
- auto castResult = provider::V2_5::ICameraProvider::castFrom(interface);
- if (castResult.isOk()) {
- mMinorVersion = 5;
- } else {
- mMinorVersion = 4;
+ mMinorVersion = 4;
+ auto cast2_6 = provider::V2_6::ICameraProvider::castFrom(interface);
+ sp<provider::V2_6::ICameraProvider> interface2_6 = nullptr;
+ if (cast2_6.isOk()) {
+ interface2_6 = cast2_6;
+ if (interface2_6 != nullptr) {
+ mMinorVersion = 6;
+ }
+ }
+ // We need to check again since cast2_6.isOk() succeeds even if the provider
+ // version isn't actually 2.6.
+ if (interface2_6 == nullptr){
+ auto cast2_5 =
+ provider::V2_5::ICameraProvider::castFrom(interface);
+ sp<provider::V2_5::ICameraProvider> interface2_5 = nullptr;
+ if (cast2_5.isOk()) {
+ interface2_5 = cast2_5;
+ if (interface != nullptr) {
+ mMinorVersion = 5;
+ }
+ }
}
hardware::Return<bool> linked = interface->linkToDeath(this, /*cookie*/ mId);
@@ -1328,6 +1350,34 @@
return mapToStatusT(status);
}
+ // Get list of concurrent streaming camera device combinations
+ if (mMinorVersion >= 6) {
+ hardware::Return<void> ret = interface2_6->getConcurrentStreamingCameraIds([&status, this](
+ Status concurrentIdStatus, // TODO: Move all instances of hidl_string to 'using'
+ const hardware::hidl_vec<hardware::hidl_vec<hardware::hidl_string>>&
+ cameraDeviceIdCombinations) {
+ status = concurrentIdStatus;
+ if (status == Status::OK) {
+ for (auto& combination : cameraDeviceIdCombinations) {
+ std::unordered_set<std::string> deviceIds;
+ for (auto &cameraDeviceId : combination) {
+ deviceIds.insert(cameraDeviceId.c_str());
+ }
+ mConcurrentCameraIdCombinations.push_back(std::move(deviceIds));
+ }
+ } });
+ if (!ret.isOk()) {
+ ALOGE("%s: Transaction error in getting camera ID list from provider '%s': %s",
+ __FUNCTION__, mProviderName.c_str(), linked.description().c_str());
+ return DEAD_OBJECT;
+ }
+ if (status != Status::OK) {
+ ALOGE("%s: Unable to query for camera devices from provider '%s'",
+ __FUNCTION__, mProviderName.c_str());
+ return mapToStatusT(status);
+ }
+ }
+
ret = interface->isSetTorchModeSupported(
[this](auto status, bool supported) {
if (status == Status::OK) {
@@ -1780,6 +1830,55 @@
return OK;
}
+status_t CameraProviderManager::ProviderInfo::isConcurrentSessionConfigurationSupported(
+ const hardware::hidl_vec<CameraIdAndStreamCombination> &halCameraIdsAndStreamCombinations,
+ bool *isSupported) {
+ status_t res = OK;
+ if (mMinorVersion >= 6) {
+ // Check if the provider is currently active - not going to start it up for this notification
+ auto interface = mSavedInterface != nullptr ? mSavedInterface : mActiveInterface.promote();
+ if (interface == nullptr) {
+ // TODO: This might be some other problem
+ return INVALID_OPERATION;
+ }
+ auto castResult = provider::V2_6::ICameraProvider::castFrom(interface);
+ if (castResult.isOk()) {
+ sp<provider::V2_6::ICameraProvider> interface_2_6 = castResult;
+ if (interface_2_6 != nullptr) {
+ Status callStatus;
+ auto cb =
+ [&isSupported, &callStatus](Status s, bool supported) {
+ callStatus = s;
+ *isSupported = supported; };
+
+ auto ret = interface_2_6->isConcurrentStreamCombinationSupported(
+ halCameraIdsAndStreamCombinations, cb);
+ if (ret.isOk()) {
+ switch (callStatus) {
+ case Status::OK:
+ // Expected case, do nothing.
+ res = OK;
+ break;
+ case Status::METHOD_NOT_SUPPORTED:
+ res = INVALID_OPERATION;
+ break;
+ default:
+ ALOGE("%s: Session configuration query failed: %d", __FUNCTION__,
+ callStatus);
+ res = UNKNOWN_ERROR;
+ }
+ } else {
+ ALOGE("%s: Unexpected binder error: %s", __FUNCTION__, ret.description().c_str());
+ res = UNKNOWN_ERROR;
+ }
+ return res;
+ }
+ }
+ }
+ // unsupported operation
+ return INVALID_OPERATION;
+}
+
template<class DeviceInfoT>
std::unique_ptr<CameraProviderManager::ProviderInfo::DeviceInfo>
CameraProviderManager::ProviderInfo::initializeDeviceInfo(
@@ -2642,6 +2741,125 @@
return OK;
}
+// Expects to have mInterfaceMutex locked
+std::vector<std::unordered_set<std::string>>
+CameraProviderManager::getConcurrentStreamingCameraIds() const {
+ std::vector<std::unordered_set<std::string>> deviceIdCombinations;
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ for (auto &provider : mProviders) {
+ for (auto &combinations : provider->mConcurrentCameraIdCombinations) {
+ deviceIdCombinations.push_back(combinations);
+ }
+ }
+ return deviceIdCombinations;
+}
+
+status_t CameraProviderManager::convertToHALStreamCombinationAndCameraIdsLocked(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ hardware::hidl_vec<CameraIdAndStreamCombination> *halCameraIdsAndStreamCombinations,
+ bool *earlyExit) {
+ binder::Status bStatus = binder::Status::ok();
+ std::vector<CameraIdAndStreamCombination> halCameraIdsAndStreamsV;
+ bool shouldExit = false;
+ status_t res = OK;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ hardware::camera::device::V3_4::StreamConfiguration streamConfiguration;
+ CameraMetadata deviceInfo;
+ res = getCameraCharacteristicsLocked(cameraIdAndSessionConfig.mCameraId, &deviceInfo);
+ if (res != OK) {
+ return res;
+ }
+ metadataGetter getMetadata =
+ [this](const String8 &id) {
+ CameraMetadata physicalDeviceInfo;
+ getCameraCharacteristicsLocked(id.string(), &physicalDeviceInfo);
+ return physicalDeviceInfo;
+ };
+ std::vector<std::string> physicalCameraIds;
+ isLogicalCameraLocked(cameraIdAndSessionConfig.mCameraId, &physicalCameraIds);
+ bStatus =
+ SessionConfigurationUtils::convertToHALStreamCombination(
+ cameraIdAndSessionConfig.mSessionConfiguration,
+ String8(cameraIdAndSessionConfig.mCameraId.c_str()), deviceInfo, getMetadata,
+ physicalCameraIds, streamConfiguration, &shouldExit);
+ if (!bStatus.isOk()) {
+ ALOGE("%s: convertToHALStreamCombination failed", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (shouldExit) {
+ *earlyExit = true;
+ return OK;
+ }
+ CameraIdAndStreamCombination halCameraIdAndStream;
+ halCameraIdAndStream.cameraId = cameraIdAndSessionConfig.mCameraId;
+ halCameraIdAndStream.streamConfiguration = streamConfiguration;
+ halCameraIdsAndStreamsV.push_back(halCameraIdAndStream);
+ }
+ *halCameraIdsAndStreamCombinations = halCameraIdsAndStreamsV;
+ return OK;
+}
+
+// Checks if the containing vector of sets has any set that contains all of the
+// camera ids in cameraIdsAndSessionConfigs.
+static bool checkIfSetContainsAll(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ const std::vector<std::unordered_set<std::string>> &containingSets) {
+ for (auto &containingSet : containingSets) {
+ bool didHaveAll = true;
+ for (auto &cameraIdAndSessionConfig : cameraIdsAndSessionConfigs) {
+ if (containingSet.find(cameraIdAndSessionConfig.mCameraId) == containingSet.end()) {
+ // a camera id doesn't belong to this set, keep looking in other
+ // sets
+ didHaveAll = false;
+ break;
+ }
+ }
+ if (didHaveAll) {
+ // found a set that has all camera ids, lets return;
+ return true;
+ }
+ }
+ return false;
+}
+
+status_t CameraProviderManager::isConcurrentSessionConfigurationSupported(
+ const std::vector<CameraIdAndSessionConfiguration> &cameraIdsAndSessionConfigs,
+ bool *isSupported) {
+ std::lock_guard<std::mutex> lock(mInterfaceMutex);
+ // Check if all the devices are a subset of devices advertised by the
+ // same provider through getConcurrentStreamingCameraIds()
+ // TODO: we should also do a findDeviceInfoLocked here ?
+ for (auto &provider : mProviders) {
+ if (checkIfSetContainsAll(cameraIdsAndSessionConfigs,
+ provider->mConcurrentCameraIdCombinations)) {
+ // For each camera device in cameraIdsAndSessionConfigs collect
+ // the streamConfigs and create the HAL
+ // CameraIdAndStreamCombination, exit early if needed
+ hardware::hidl_vec<CameraIdAndStreamCombination> halCameraIdsAndStreamCombinations;
+ bool knowUnsupported = false;
+ status_t res = convertToHALStreamCombinationAndCameraIdsLocked(
+ cameraIdsAndSessionConfigs, &halCameraIdsAndStreamCombinations,
+ &knowUnsupported);
+ if (res != OK) {
+ ALOGE("%s unable to convert session configurations provided to HAL stream"
+ "combinations", __FUNCTION__);
+ return res;
+ }
+ if (knowUnsupported) {
+ // We got to know the streams aren't valid before doing the HAL
+ // call itself.
+ *isSupported = false;
+ return OK;
+ }
+ return provider->isConcurrentSessionConfigurationSupported(
+ halCameraIdsAndStreamCombinations, isSupported);
+ }
+ }
+ *isSupported = false;
+ //The set of camera devices were not found
+ return INVALID_OPERATION;
+}
+
status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
CameraMetadata* characteristics) const {
auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});