From patchwork Mon Aug 17 20:26:40 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 9336 Return-Path: X-Original-To: parsemail@patchwork.libcamera.org Delivered-To: parsemail@patchwork.libcamera.org Received: from lancelot.ideasonboard.com (lancelot.ideasonboard.com [92.243.16.209]) by patchwork.libcamera.org (Postfix) with ESMTPS id 378D6BD87C for ; Mon, 17 Aug 2020 20:26:46 +0000 (UTC) Received: from lancelot.ideasonboard.com (localhost [IPv6:::1]) by lancelot.ideasonboard.com (Postfix) with ESMTP id DD5A361AEF; Mon, 17 Aug 2020 22:26:45 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="HFdTLvng"; dkim-atps=neutral Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id F2FBD61AC0 for ; Mon, 17 Aug 2020 22:26:41 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=uajain.com; h=from:subject:in-reply-to:references:mime-version:to:cc: content-transfer-encoding:content-type; s=s1; bh=yiHFIpZQ4kL+dL6weigacL2kbn4cA/MFi6/Usily6/U=; b=HFdTLvngPllYZl/Yw2DwArTltxsN/PjdQY2/59FDspXr6TopAbF8YEl/jBdKkg05TwCK w0i9DYfCM4879d/V9ugEdQVofs9sZX6jlOUqq5ARkw060xq8HqKhKKEaOU8S+pnRLEba8H FkgLmHWl6i+H8Yse/RWxd7zRaJEz+ge/w= Received: by filterdrecv-p3iad2-5c98798b7-shmb5 with SMTP id filterdrecv-p3iad2-5c98798b7-shmb5-18-5F3AE800-6E 2020-08-17 20:26:40.882614427 +0000 UTC m=+359831.957013569 Received: from mail.uajain.com (unknown) by ismtpd0008p1maa1.sendgrid.net (SG) with ESMTP id 85Lhv3GpRk6n0ciau08yBQ for ; Mon, 17 Aug 2020 20:26:40.078 +0000 (UTC) From: Umang Jain Date: Mon, 17 Aug 2020 20:26:40 +0000 (UTC) Message-Id: <20200817202629.4277-6-email@uajain.com> In-Reply-To: <20200817202629.4277-1-email@uajain.com> References: <20200817202629.4277-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPcZj5z9XHfwy1Ge6f/0y1LYwCA/v9XUm1JqRF7ylVeh12n0FwBW8t59CcHJhPITUZXGGGQgUqnsqxj5v/XY65EzXbreL7hK/T92NfH2u0fNm0haQKhw+/XWpW9t8Dqvtln933X7hTQVJuuGGIxxCDhYr+kt0hpLcQVsLlUKj8JSnHX9zVnqGmLm6g+AH9TvPfVcBDra35Xbbr7xiA0TowW4g== To: libcamera-devel@lists.libcamera.org Subject: [libcamera-devel] [PATCH v3 5/5] android: camera_hal_manager: Support camera hotplug X-BeenThere: libcamera-devel@lists.libcamera.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: libcamera-devel-bounces@lists.libcamera.org Sender: "libcamera-devel" Extend the support for camera hotplug from libcamera's CameraManager to CameraHalManager. Use camera module callbacks to let the framework know about the hotplug events and change the status of cameras being being hotplugged or unplugged via camera_device_status_change(). Introduce a map camerasMap_ which book-keeps all cameras seen in the past by the CameraHalManager. If the camera is seen for the first time, a new id is assigned to it. If the camera has been seen before by the manager, it's old id is reused. IDs for internal cameras start with '0' and for external cameras, they start with '1000'. Note, for the current implementation, we assume all UVC cameras are external cameras. Also, acess to camerasMap_ and cameras_ are protected by a mutex. Signed-off-by: Umang Jain --- src/android/camera_hal_manager.cpp | 174 +++++++++++++++++++++++++---- src/android/camera_hal_manager.h | 18 +++ 2 files changed, 170 insertions(+), 22 deletions(-) diff --git a/src/android/camera_hal_manager.cpp b/src/android/camera_hal_manager.cpp index 3a744af..e851185 100644 --- a/src/android/camera_hal_manager.cpp +++ b/src/android/camera_hal_manager.cpp @@ -8,6 +8,7 @@ #include "camera_hal_manager.h" #include +#include #include "libcamera/internal/log.h" @@ -35,6 +36,7 @@ CameraHalManager::CameraHalManager() CameraHalManager::~CameraHalManager() { cameras_.clear(); + camerasMap_.clear(); if (cameraManager_) { cameraManager_->stop(); @@ -47,6 +49,13 @@ int CameraHalManager::init() { cameraManager_ = new CameraManager(); + /* Support camera hotplug. */ + cameraManager_->cameraAdded.connect(this, &CameraHalManager::cameraAdded); + cameraManager_->cameraRemoved.connect(this, &CameraHalManager::cameraRemoved); + + internalCameras_ = 0; + externalCameras_ = 1000; + int ret = cameraManager_->start(); if (ret) { LOG(HAL, Error) << "Failed to start camera manager: " @@ -56,35 +65,22 @@ int CameraHalManager::init() return ret; } - /* - * For each Camera registered in the system, a CameraDevice - * gets created here to wraps a libcamera Camera instance. - * - * \todo Support camera hotplug. - */ - unsigned int index = 0; - for (auto &cam : cameraManager_->cameras()) { - std::shared_ptr camera = CameraDevice::create(index, cam); - ret = camera->initialize(); - if (ret) - continue; - - cameras_.emplace_back(std::move(camera)); - ++index; - } - return 0; } CameraDevice *CameraHalManager::open(unsigned int id, const hw_module_t *hardwareModule) { - if (id >= numCameras()) { + MutexLocker locker(mutex_); + + auto iter = cameraIterFromId(id); + if (iter == cameras_.end()) { LOG(HAL, Error) << "Invalid camera id '" << id << "'"; return nullptr; } - CameraDevice *camera = cameras_[id].get(); + CameraDevice *camera = iter->get(); + if (camera->open(hardwareModule)) return nullptr; @@ -93,9 +89,114 @@ CameraDevice *CameraHalManager::open(unsigned int id, return camera; } +void CameraHalManager::cameraAdded(std::shared_ptr cam) +{ + unsigned int id; + bool isCameraExternal = false; + bool isCameraNew = false; + + MutexLocker locker(mutex_); + + /* + * 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 and the camera is marked as CAMERA_DEVICE_STATUS_PRESENT + * subsequently. + * + * IDs starts from '0' for internal cameras and '1000' for external + * cameras. + */ + auto iter = camerasMap_.find(cam->id()); + if (iter != camerasMap_.end()) { + id = iter->second; + } else { + isCameraNew = true; + + /* + * Now check if this is an external camera and assign + * its id accordingly. + */ + const ControlList &properties = cam->properties(); + if (properties.contains(properties::Location) && + properties.get(properties::Location) == + properties::CameraLocationExternal) { + isCameraExternal = true; + id = externalCameras_; + } else { + id = internalCameras_; + } + } + + /* + * For each Camera registered in the system, a CameraDevice + * gets created here to wraps a libcamera Camera instance. + */ + std::shared_ptr camera = CameraDevice::create(id, std::move(cam)); + int ret = camera->initialize(); + if (ret) { + LOG(HAL, Error) << "Failed to initialize camera: " << cam->id(); + return; + } + + if (isCameraNew) { + camerasMap_.emplace(cam->id(), id); + + if (isCameraExternal) + externalCameras_++; + else + internalCameras_++; + } + + 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."; +} + +void CameraHalManager::cameraRemoved(std::shared_ptr cam) +{ + MutexLocker locker(mutex_); + + auto iter = cameraIterFromCamera(cam.get()); + if (iter == cameras_.end()) + return; + + unsigned int id = (*iter)->id(); + 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 it's absence before deleting it's + * reference here. + */ + cameras_.erase(iter); + + LOG(HAL, Debug) << "Camera ID: " << id << " removed successfully."; +} + +CameraHalManager::cameraDeviceIter CameraHalManager::cameraIterFromId(unsigned int id) +{ + return std::find_if(cameras_.begin(), cameras_.end(), + [id](std::shared_ptr &camera) { + return camera->id() == id; + }); +} + +CameraHalManager::cameraDeviceIter CameraHalManager::cameraIterFromCamera(Camera *cam) +{ + return std::find_if(cameras_.begin(), cameras_.end(), + [cam](std::shared_ptr &camera) { + return cam == camera->camera(); + }); +} + unsigned int CameraHalManager::numCameras() const { - return cameraManager_->cameras().size(); + return internalCameras_; } int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) @@ -103,12 +204,15 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) if (!info) return -EINVAL; - if (id >= numCameras()) { + MutexLocker locker(mutex_); + + auto iter = cameraIterFromId(id); + if (iter == cameras_.end()) { LOG(HAL, Error) << "Invalid camera id '" << id << "'"; return -EINVAL; } - CameraDevice *camera = cameras_[id].get(); + CameraDevice *camera = iter->get(); info->facing = camera->facing(); info->orientation = camera->orientation(); @@ -124,4 +228,30 @@ int CameraHalManager::getCameraInfo(unsigned int id, struct camera_info *info) 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 enabled. Iterate any 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 (auto &cam : cameraManager_->cameras()) { + auto iter = camerasMap_.find(cam->id()); + if (iter == camerasMap_.end()) + continue; + + unsigned int id = iter->second; + const ControlList &properties = cam->properties(); + if (properties.contains(properties::Location) && + properties.get(properties::Location) & + properties::CameraLocationExternal) { + callbacks_->camera_device_status_change(callbacks_, id, + CAMERA_DEVICE_STATUS_PRESENT); + } + } } diff --git a/src/android/camera_hal_manager.h b/src/android/camera_hal_manager.h index 3e34d63..f8adade 100644 --- a/src/android/camera_hal_manager.h +++ b/src/android/camera_hal_manager.h @@ -7,6 +7,8 @@ #ifndef __ANDROID_CAMERA_MANAGER_H__ #define __ANDROID_CAMERA_MANAGER_H__ +#include +#include #include #include @@ -18,12 +20,17 @@ class CameraDevice; +using Mutex = std::mutex; +using MutexLocker = std::unique_lock; + class CameraHalManager { public: CameraHalManager(); ~CameraHalManager(); + using cameraDeviceIter = std::vector>::iterator; + int init(); CameraDevice *open(unsigned int id, const hw_module_t *module); @@ -33,10 +40,21 @@ public: void setCallbacks(const camera_module_callbacks_t *callbacks); private: + void cameraAdded(std::shared_ptr cam); + void cameraRemoved(std::shared_ptr cam); + + cameraDeviceIter cameraIterFromId(unsigned int id); + cameraDeviceIter cameraIterFromCamera(libcamera::Camera *cam); + libcamera::CameraManager *cameraManager_; const camera_module_callbacks_t *callbacks_; std::vector> cameras_; + std::map camerasMap_; + Mutex mutex_; + + unsigned int internalCameras_; + unsigned int externalCameras_; }; #endif /* __ANDROID_CAMERA_MANAGER_H__ */