summaryrefslogtreecommitdiff
path: root/src/android/camera_hal_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/camera_hal_manager.cpp')
-rw-r--r--src/android/camera_hal_manager.cpp264
1 files changed, 220 insertions, 44 deletions
diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp
index 5bd3bdba..7500c749 100644
--- a/src/android/camera_hal_manager.cpp
+++ b/src/android/camera_hal_manager.cpp
@@ -2,20 +2,21 @@
/*
* Copyright (C) 2019, Google Inc.
*
- * camera_hal_manager.cpp - libcamera Android Camera Manager
+ * libcamera Android Camera Manager
*/
#include "camera_hal_manager.h"
-#include <libcamera/camera.h>
+#include <libcamera/base/log.h>
-#include "log.h"
+#include <libcamera/camera.h>
+#include <libcamera/property_ids.h>
#include "camera_device.h"
using namespace libcamera;
-LOG_DECLARE_CATEGORY(HAL);
+LOG_DECLARE_CATEGORY(HAL)
/*
* \class CameraHalManager
@@ -28,71 +29,224 @@ LOG_DECLARE_CATEGORY(HAL);
*/
CameraHalManager::CameraHalManager()
- : cameraManager_(nullptr)
+ : cameraManager_(nullptr), callbacks_(nullptr), numInternalCameras_(0),
+ nextExternalCameraId_(firstExternalCameraId_)
{
}
-CameraHalManager::~CameraHalManager()
-{
- cameras_.clear();
+/* CameraManager calls stop() in the destructor. */
+CameraHalManager::~CameraHalManager() = default;
- if (cameraManager_) {
- cameraManager_->stop();
- delete cameraManager_;
- cameraManager_ = nullptr;
- }
+/* static */
+CameraHalManager *CameraHalManager::instance()
+{
+ static CameraHalManager *cameraHalManager = new CameraHalManager;
+ return cameraHalManager;
}
int CameraHalManager::init()
{
- cameraManager_ = new CameraManager();
+ cameraManager_ = std::make_unique<CameraManager>();
+
+ /*
+ * If the configuration file is not available the HAL only supports
+ * external cameras. If it exists but it's not valid then error out.
+ */
+ if (halConfig_.exists() && !halConfig_.isValid()) {
+ LOG(HAL, Error) << "HAL configuration file is not valid";
+ return -EINVAL;
+ }
+
+ /* Support camera hotplug. */
+ cameraManager_->cameraAdded.connect(this, &CameraHalManager::cameraAdded);
+ cameraManager_->cameraRemoved.connect(this, &CameraHalManager::cameraRemoved);
int ret = cameraManager_->start();
if (ret) {
LOG(HAL, Error) << "Failed to start camera manager: "
<< strerror(-ret);
- delete cameraManager_;
- cameraManager_ = nullptr;
+ cameraManager_.reset();
return ret;
}
+ return 0;
+}
+
+std::tuple<CameraDevice *, int>
+CameraHalManager::open(unsigned int id, const hw_module_t *hardwareModule)
+{
+ MutexLocker locker(mutex_);
+
+ if (!callbacks_) {
+ LOG(HAL, Error) << "Can't open camera before callbacks are set";
+ return { nullptr, -ENODEV };
+ }
+
+ CameraDevice *camera = cameraDeviceFromHalId(id);
+ if (!camera) {
+ LOG(HAL, Error) << "Invalid camera id '" << id << "'";
+ return { nullptr, -ENODEV };
+ }
+
+ int ret = camera->open(hardwareModule);
+ if (ret)
+ return { nullptr, ret };
+
+ LOG(HAL, Info) << "Open camera '" << id << "'";
+
+ return { camera, 0 };
+}
+
+void CameraHalManager::cameraAdded(std::shared_ptr<Camera> cam)
+{
+ unsigned int id;
+ bool isCameraExternal = false;
+ bool isCameraNew = false;
+
+ MutexLocker locker(mutex_);
+
/*
- * For each Camera registered in the system, a CameraDevice
- * gets created here to wraps a libcamera Camera instance.
+ * Each camera is assigned a unique integer ID when it is seen for the
+ * first time. If the camera has been seen before, the previous ID is
+ * re-used.
*
- * \todo Support camera hotplug.
+ * IDs starts from '0' for internal cameras and '1000' for external
+ * cameras.
*/
- unsigned int index = 0;
- for (auto &cam : cameraManager_->cameras()) {
- CameraDevice *camera = new CameraDevice(index, cam);
- cameras_.emplace_back(camera);
+ auto iter = cameraIdsMap_.find(cam->id());
+ if (iter != cameraIdsMap_.end()) {
+ id = iter->second;
+ if (id >= firstExternalCameraId_)
+ isCameraExternal = true;
+ } else {
+ isCameraNew = true;
- ++index;
+ /*
+ * Now check if this is an external camera and assign
+ * its id accordingly.
+ */
+ if (cameraLocation(cam.get()) == properties::CameraLocationExternal) {
+ isCameraExternal = true;
+ id = nextExternalCameraId_;
+ } else {
+ id = numInternalCameras_;
+ }
}
- return 0;
+ /*
+ * The configuration file must be valid, and contain a corresponding
+ * entry for internal cameras. External cameras can be initialized
+ * without configuration file.
+ */
+ if (!isCameraExternal && !halConfig_.exists()) {
+ LOG(HAL, Error)
+ << "HAL configuration file is mandatory for internal cameras."
+ << " Camera " << cam->id() << " failed to load";
+ return;
+ }
+
+ const CameraConfigData *cameraConfigData = halConfig_.cameraConfigData(cam->id());
+
+ /*
+ * Some cameras whose location is reported by libcamera as external may
+ * actually be internal to the device. This is common with UVC cameras
+ * that are integrated in a laptop. In that case the real location
+ * should be specified in the configuration file.
+ *
+ * If the camera location is external and a configuration entry exists
+ * for it, override its location.
+ */
+ if (isCameraNew && isCameraExternal) {
+ if (cameraConfigData && cameraConfigData->facing != -1) {
+ isCameraExternal = false;
+ id = numInternalCameras_;
+ }
+ }
+
+ if (!isCameraExternal && !cameraConfigData) {
+ LOG(HAL, Error)
+ << "HAL configuration entry for internal camera "
+ << cam->id() << " is missing";
+ return;
+ }
+
+ /* Create a CameraDevice instance to wrap the libcamera Camera. */
+ std::unique_ptr<CameraDevice> camera = CameraDevice::create(id, cam);
+
+ int ret = camera->initialize(cameraConfigData);
+ if (ret) {
+ LOG(HAL, Error) << "Failed to initialize camera: " << cam->id();
+ return;
+ }
+
+ if (isCameraNew) {
+ cameraIdsMap_.emplace(cam->id(), id);
+
+ if (isCameraExternal)
+ nextExternalCameraId_++;
+ else
+ numInternalCameras_++;
+ }
+
+ cameras_.emplace_back(std::move(camera));
+
+ if (callbacks_)
+ callbacks_->camera_device_status_change(callbacks_, id,
+ CAMERA_DEVICE_STATUS_PRESENT);
+
+ LOG(HAL, Debug) << "Camera ID: " << id << " added successfully.";
}
-CameraDevice *CameraHalManager::open(unsigned int id,
- const hw_module_t *hardwareModule)
+void CameraHalManager::cameraRemoved(std::shared_ptr<Camera> cam)
{
- if (id >= numCameras()) {
- LOG(HAL, Error) << "Invalid camera id '" << id << "'";
- return nullptr;
- }
+ MutexLocker locker(mutex_);
- CameraDevice *camera = cameras_[id].get();
- if (camera->open(hardwareModule))
- return nullptr;
+ auto iter = std::find_if(cameras_.begin(), cameras_.end(),
+ [&cam](const std::unique_ptr<CameraDevice> &camera) {
+ return cam == camera->camera();
+ });
+ if (iter == cameras_.end())
+ return;
- LOG(HAL, Info) << "Open camera '" << id << "'";
+ /*
+ * CAMERA_DEVICE_STATUS_NOT_PRESENT should be set for external cameras
+ * only.
+ */
+ unsigned int id = (*iter)->id();
+ if (id >= firstExternalCameraId_)
+ callbacks_->camera_device_status_change(callbacks_, id,
+ CAMERA_DEVICE_STATUS_NOT_PRESENT);
+
+ /*
+ * \todo Check if the camera is already open and running.
+ * Inform the framework about its absence before deleting its
+ * reference here.
+ */
+ cameras_.erase(iter);
+
+ LOG(HAL, Debug) << "Camera ID: " << id << " removed successfully.";
+}
+
+int32_t CameraHalManager::cameraLocation(const Camera *cam)
+{
+ return cam->properties().get(properties::Location).value_or(-1);
+}
- return camera;
+CameraDevice *CameraHalManager::cameraDeviceFromHalId(unsigned int id)
+{
+ auto iter = std::find_if(cameras_.begin(), cameras_.end(),
+ [id](const std::unique_ptr<CameraDevice> &camera) {
+ return camera->id() == id;
+ });
+ if (iter == cameras_.end())
+ return nullptr;
+
+ return iter->get();
}
unsigned int CameraHalManager::numCameras() const
{
- return cameraManager_->cameras().size();
+ return numInternalCameras_;
}
int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)
@@ -100,17 +254,17 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)
if (!info)
return -EINVAL;
- if (id >= numCameras()) {
+ MutexLocker locker(mutex_);
+
+ CameraDevice *camera = cameraDeviceFromHalId(id);
+ if (!camera) {
LOG(HAL, Error) << "Invalid camera id '" << id << "'";
return -EINVAL;
}
- CameraDevice *camera = cameras_[id].get();
-
- /* \todo Get these info dynamically inspecting the camera module. */
- info->facing = id ? CAMERA_FACING_FRONT : CAMERA_FACING_BACK;
- info->orientation = 0;
- info->device_version = 0;
+ info->facing = camera->facing();
+ info->orientation = camera->orientation();
+ info->device_version = CAMERA_DEVICE_API_VERSION_3_3;
info->resource_cost = 0;
info->static_camera_characteristics = camera->getStaticMetadata();
info->conflicting_devices = nullptr;
@@ -118,3 +272,25 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info)
return 0;
}
+
+void CameraHalManager::setCallbacks(const camera_module_callbacks_t *callbacks)
+{
+ callbacks_ = callbacks;
+
+ MutexLocker locker(mutex_);
+
+ /*
+ * Some external cameras may have been identified before the callbacks_
+ * were set. Iterate all existing external cameras and mark them as
+ * CAMERA_DEVICE_STATUS_PRESENT explicitly.
+ *
+ * Internal cameras are already assumed to be present at module load
+ * time by the Android framework.
+ */
+ for (const std::unique_ptr<CameraDevice> &camera : cameras_) {
+ unsigned int id = camera->id();
+ if (id >= firstExternalCameraId_)
+ callbacks_->camera_device_status_change(callbacks_, id,
+ CAMERA_DEVICE_STATUS_PRESENT);
+ }
+}