From patchwork Wed May 13 17:29:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 3788 X-Patchwork-Delegate: umang.jain@ideasonboard.com Return-Path: Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id BDAD7603DF for ; Wed, 13 May 2020 19:29:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="lixpZKdg"; dkim-atps=neutral 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=UvYCQMLtSlqyxjipAP34hYFQLE/aEzUVnGGAg2HHXJM=; b=lixpZKdgXtODfgXPBz9ubjrda9mwIqxKDn/LvUNvXGpQmtqdrtfEIUOJMJJOoMs8ey+5 r2yHalQV6QE2wYvBNAXNcFXTTPuFPS2Zlri95PcOIFN4gd36g7ABXVF2Iebay+zVuaWnz2 PSs292q5FGPqnlEJw6SutuZDjq9PjYmUI= Received: by filterdrecv-p3las1-cb48d7cc9-kxd8d with SMTP id filterdrecv-p3las1-cb48d7cc9-kxd8d-20-5EBC2E95-9 2020-05-13 17:29:57.526905451 +0000 UTC m=+4206145.711066577 Received: from mail.uajain.com (unknown) by ismtpd0007p1hnd1.sendgrid.net (SG) with ESMTP id HQRPfDjFSy6OogDvkxUFlg Wed, 13 May 2020 17:29:56.900 +0000 (UTC) From: Umang Jain Date: Wed, 13 May 2020 17:29:57 +0000 (UTC) Message-Id: <20200513172950.72685-2-email@uajain.com> In-Reply-To: <20200513172950.72685-1-email@uajain.com> References: <20200513172950.72685-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPcBLpXFhl3+P87RHKL8hWvbAoSNwQxsRzqeXhxRQRxuSi98fIkRX5KVdUyG6rC+ldV/q3cPnYJDJaQcRICEmtETcLIxNdVeM819TGq5t7q5fhdlbJX8huiFKd1beiPIV56ZLjRgjo8mXaCRy7XU2U4Q3hwcEeBosa/pZrd/EYv3T+vJ+auaGAL8c1qeasLRlWCV8mCAJ65ya3/KkrGEN0+dA== To: libcamera-devel Subject: [libcamera-devel] [PATCH v2 1/5] libcamera: camera_manager: Refactor device enumeration into separate function 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: , X-List-Received-Date: Wed, 13 May 2020 17:30:01 -0000 This commit introduces no functional changes. Split device enumeration code into a separate function, so that the function can be re-used for upcoming hotplug functionality in subsequent commits. Also, fixup correct tag for \todo. Signed-off-by: Umang Jain --- src/libcamera/camera_manager.cpp | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index fddf734..1579ad4 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -53,6 +53,7 @@ protected: private: int init(); + void enumerateDevices(); void cleanup(); CameraManager *cm_; @@ -121,11 +122,20 @@ int CameraManager::Private::init() return -ENODEV; /* - * TODO: Try to read handlers and order from configuration + * \todo Try to read handlers and order from configuration * file and only fallback on all handlers if there is no * configuration file. */ - std::vector &factories = PipelineHandlerFactory::factories(); + + enumerateDevices(); + + return 0; +} + +void CameraManager::Private::enumerateDevices() +{ + std::vector &factories = + PipelineHandlerFactory::factories(); for (PipelineHandlerFactory *factory : factories) { /* @@ -144,14 +154,12 @@ int CameraManager::Private::init() } } - /* TODO: register hot-plug callback here */ - - return 0; + /* \todo register hot-plug callback here */ } void CameraManager::Private::cleanup() { - /* TODO: unregister hot-plug callback here */ + /* \todo unregister hot-plug callback here */ /* * Release all references to cameras and pipeline handlers to ensure From patchwork Wed May 13 17:29:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 3790 X-Patchwork-Delegate: umang.jain@ideasonboard.com Return-Path: Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 3BB0360DFC for ; Wed, 13 May 2020 19:29:59 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="rnhcsiEQ"; dkim-atps=neutral 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=LDtxLbPplyDb22escqBemAmJKdBkt2XuDkj3m6ZFUBo=; b=rnhcsiEQMopSTbOtzxp3UmbJk8Tk6UIbnLKcMP8n0PUffrgeNad9NAwFnV7ajOZt6ZN+ nbGiVckSRtD9e7/nmenFM0QysIUPCX1lKr0kU19a3TYEK0XzyNf+s2lgdlWt41g9EjLfEI Onz1eWhYBN9H4POZEZKrr1Fzr9CjNZ1nA= Received: by filterdrecv-p3las1-cb48d7cc9-6ppgt with SMTP id filterdrecv-p3las1-cb48d7cc9-6ppgt-19-5EBC2E96-4 2020-05-13 17:29:58.430798336 +0000 UTC m=+4206148.422515078 Received: from mail.uajain.com (unknown) by ismtpd0008p1hnd1.sendgrid.net (SG) with ESMTP id UXtBw0nfQP-LDfU0mKMn6Q Wed, 13 May 2020 17:29:58.090 +0000 (UTC) From: Umang Jain Date: Wed, 13 May 2020 17:29:58 +0000 (UTC) Message-Id: <20200513172950.72685-3-email@uajain.com> In-Reply-To: <20200513172950.72685-1-email@uajain.com> References: <20200513172950.72685-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPclq38gSC/txiORZpK15NbTl7AhXvTDHCpy7PI7ewHqvpLN7lOwsSlZiy3BEDPP24epCBIsoYRSB9MsJoEnNgU1Ul4l1VtzvVcxrTgNs24778WyNEYrT6MZZ60YfTbHtMkxiMuF875F10o2ZOfn8woDj6WhB4DZj4z6J20gkBFtXZe8EEr2EHWf0eWpnM4TUXZ9F5j+XtJq7r5ToXH2RY/TQ== To: libcamera-devel Subject: [libcamera-devel] [PATCH v2 2/5] libcamera: device_enumerator: Emit a signal when a new device is hotplugged 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: , X-List-Received-Date: Wed, 13 May 2020 17:30:01 -0000 Emit a signal whenever is a new MediaDevice is added to the DeviceEnumerator. This will allow CameraManager to get notified about the new devices that have been hot-plugged. Signed-off-by: Umang Jain --- src/libcamera/camera_manager.cpp | 4 ++-- src/libcamera/device_enumerator.cpp | 12 ++++++++++++ src/libcamera/include/device_enumerator.h | 4 ++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index 1579ad4..a13cfe1 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -154,12 +154,12 @@ void CameraManager::Private::enumerateDevices() } } - /* \todo register hot-plug callback here */ + enumerator_->newDevicesFound.connect(this, &Private::enumerateDevices); } void CameraManager::Private::cleanup() { - /* \todo unregister hot-plug callback here */ + enumerator_->newDevicesFound.disconnect(this, &Private::enumerateDevices); /* * Release all references to cameras and pipeline handlers to ensure diff --git a/src/libcamera/device_enumerator.cpp b/src/libcamera/device_enumerator.cpp index dd17e3e..0492a86 100644 --- a/src/libcamera/device_enumerator.cpp +++ b/src/libcamera/device_enumerator.cpp @@ -227,6 +227,15 @@ std::unique_ptr DeviceEnumerator::createDevice(const std::string &d return media; } +/** +* \brief Notify of new media devices being found +* +* This signal is emitted when the device enumerator finds new media devices in +* the system. It may be emitted for every newly detected device, or once for +* multiple of devices, at the discretion of the device enumerator. Not all +* device enumerator types may support dynamic detection of new devices. +*/ + /** * \brief Add a media device to the enumerator * \param[in] media media device instance to add @@ -242,6 +251,9 @@ void DeviceEnumerator::addDevice(std::unique_ptr &&media) << "Added device " << media->deviceNode() << ": " << media->driver(); devices_.push_back(std::move(media)); + + /* \todo: To batch multiple additions, emit with a small delay here. */ + newDevicesFound.emit(); } /** diff --git a/src/libcamera/include/device_enumerator.h b/src/libcamera/include/device_enumerator.h index 433e357..cd4e846 100644 --- a/src/libcamera/include/device_enumerator.h +++ b/src/libcamera/include/device_enumerator.h @@ -13,6 +13,8 @@ #include +#include + namespace libcamera { class MediaDevice; @@ -43,6 +45,8 @@ public: std::shared_ptr search(const DeviceMatch &dm); + Signal<> newDevicesFound; + protected: std::unique_ptr createDevice(const std::string &deviceNode); void addDevice(std::unique_ptr &&media); From patchwork Wed May 13 17:29:59 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 3791 X-Patchwork-Delegate: umang.jain@ideasonboard.com Return-Path: Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 264F560DE6 for ; Wed, 13 May 2020 19:30:00 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="V0QaL3Eu"; dkim-atps=neutral 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=myHKDE1Oi/9sT1ZJw6qypPYkAFgznzgR4RInb2p4cBE=; b=V0QaL3EuQGrTy4g+XtFQWKBmyEhpSnmSPbQYJUtImecxg2p5ppZarjsf5tlsT+hVPp8v SjLbIYV6vD+LWffgMAfLtXNYSBA7spCUwuq6r07duanpCeSG3WwoxSCuVRMn5Pu6/RUzoN QA0THz6u/OUaHW+W4al2dak0BMfhZnwLg= Received: by filter0084p3las1.sendgrid.net with SMTP id filter0084p3las1-1974-5EBC2E97-A8 2020-05-13 17:29:59.468607979 +0000 UTC m=+2402891.606114937 Received: from mail.uajain.com (unknown) by ismtpd0007p1hnd1.sendgrid.net (SG) with ESMTP id Gkgx097gT6GynUsY8W18QQ Wed, 13 May 2020 17:29:59.102 +0000 (UTC) From: Umang Jain Date: Wed, 13 May 2020 17:29:59 +0000 (UTC) Message-Id: <20200513172950.72685-4-email@uajain.com> In-Reply-To: <20200513172950.72685-1-email@uajain.com> References: <20200513172950.72685-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPc1PzzgVzhjC45/EOdGbf2jl8Uv6lsWFJUNfuYgvUvwL2Veutc7YVJYIRWH04KiR/RM4E+KTHz/IT2aqxrkQ0NlM+vozLypV2eut18n+1jz+VLxS381CRLFTcE6+TfVG8j+mqjSm/a4yBZY1jyAFNnTXO5gEL7KXEhq7/rk3U30X9bQAD4xRg0LxSdWGAoX71O To: libcamera-devel Subject: [libcamera-devel] [PATCH v2 3/5] libcamera: camera_manager: Introduce signals when a camera is added/removed 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: , X-List-Received-Date: Wed, 13 May 2020 17:30:02 -0000 Emit 'cameraAdded' and 'cameraRemoved' from CameraManager to enable hotplug and hot-unplug support in appplications like QCam. Signed-off-by: Umang Jain --- include/libcamera/camera_manager.h | 6 +++++- src/libcamera/camera_manager.cpp | 34 +++++++++++++++++++++++++++--- src/libcamera/pipeline_handler.cpp | 2 +- 3 files changed, 37 insertions(+), 5 deletions(-) diff --git a/include/libcamera/camera_manager.h b/include/libcamera/camera_manager.h index 079f848..366fa07 100644 --- a/include/libcamera/camera_manager.h +++ b/include/libcamera/camera_manager.h @@ -13,6 +13,7 @@ #include #include +#include namespace libcamera { @@ -35,13 +36,16 @@ public: std::shared_ptr get(dev_t devnum); void addCamera(std::shared_ptr camera, dev_t devnum); - void removeCamera(Camera *camera); + void removeCamera(std::shared_ptr camera); static const std::string &version() { return version_; } void setEventDispatcher(std::unique_ptr dispatcher); EventDispatcher *eventDispatcher(); + Signal> cameraAdded; + Signal> cameraRemoved; + private: static const std::string version_; static CameraManager *self_; diff --git a/src/libcamera/camera_manager.cpp b/src/libcamera/camera_manager.cpp index a13cfe1..b9d2496 100644 --- a/src/libcamera/camera_manager.cpp +++ b/src/libcamera/camera_manager.cpp @@ -186,7 +186,7 @@ void CameraManager::Private::addCamera(std::shared_ptr &camera, } } - cameras_.push_back(std::move(camera)); + cameras_.push_back(camera); if (devnum) { unsigned int index = cameras_.size() - 1; @@ -376,6 +376,32 @@ std::shared_ptr CameraManager::get(dev_t devnum) return iter->second.lock(); } +/** + * \brief Notify of a new camera added to the system + * + * This signal is emitted when a new camera is detected and successfully handled + * by the camera manager. The notification occurs alike for cameras detected + * when the manager is started with start() or when new cameras are later + * connected to the system. When the signal is emitted the new camera is already + * available from the list of cameras(). + * + * The signal is emitted from the CameraManager thread. Applications shall + * minimize the time spent in the signal handler and shall in particular not + * perform any blocking operation. + */ + +/** + * \brief Notify of a new camera removed from the system + * + * This signal is emitted when a camera is removed from the system. When the + * signal is emitted the camera is not available from the list of cameras() + * anymore. + * + * The signal is emitted from the CameraManager thread. Applications shall + * minimize the time spent in the signal handler and shall in particular not + * perform any blocking operation. + */ + /** * \brief Add a camera to the camera manager * \param[in] camera The camera to be added @@ -395,6 +421,7 @@ void CameraManager::addCamera(std::shared_ptr camera, dev_t devnum) ASSERT(Thread::current() == p_.get()); p_->addCamera(camera, devnum); + cameraAdded.emit(camera); } /** @@ -407,11 +434,12 @@ void CameraManager::addCamera(std::shared_ptr camera, dev_t devnum) * * \context This function shall be called from the CameraManager thread. */ -void CameraManager::removeCamera(Camera *camera) +void CameraManager::removeCamera(std::shared_ptr camera) { ASSERT(Thread::current() == p_.get()); - p_->removeCamera(camera); + p_->removeCamera(camera.get()); + cameraRemoved.emit(camera); } /** diff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp index 254d341..a9187e1 100644 --- a/src/libcamera/pipeline_handler.cpp +++ b/src/libcamera/pipeline_handler.cpp @@ -555,7 +555,7 @@ void PipelineHandler::disconnect() continue; camera->disconnect(); - manager_->removeCamera(camera.get()); + manager_->removeCamera(camera); } cameras_.clear(); From patchwork Wed May 13 17:30:00 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 3792 X-Patchwork-Delegate: umang.jain@ideasonboard.com Return-Path: Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 8ED6660DFF for ; Wed, 13 May 2020 19:30:02 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="jTXSiAMJ"; dkim-atps=neutral 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=vQG8D4Rs2e+3VRzx4T+kw1iaoiDSgpaV3ULjJUAPrsI=; b=jTXSiAMJl4n/amseeBFMogLG+3AnaNoyM9jqq55o3j4msCf5XAk8IoMj5UikBL4/BybI w3G9U0qRuWGvwk5dkf6T/6wtUXgumd/MH17vJ4znK3IVMegOEiSMVk2XrAVmwPLkYpK+o/ jr82yQycDMFHiQMjuEJdMXPqNTri46ScI= Received: by filter0072p3las1.sendgrid.net with SMTP id filter0072p3las1-6642-5EBC2E98-17B 2020-05-13 17:30:00.930007584 +0000 UTC m=+2402884.819728798 Received: from mail.uajain.com (unknown) by ismtpd0001p1maa1.sendgrid.net (SG) with ESMTP id 3v7NZwMDTz2Lz20o5j-dDw Wed, 13 May 2020 17:30:00.181 +0000 (UTC) From: Umang Jain Date: Wed, 13 May 2020 17:30:00 +0000 (UTC) Message-Id: <20200513172950.72685-5-email@uajain.com> In-Reply-To: <20200513172950.72685-1-email@uajain.com> References: <20200513172950.72685-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPcROc560Os82e1tQwAlD2FoFmN5OulnnhnFwgFz4a1BpblVayaQjtPgzBnzvPCHP5XF8rSK9ay1hcdUKpmjYejxIF4TLI7ULNS7cSUuzXvBcoi6PaATAHiIHsntyR2+mlCOMVhtqruEhw7HTnKfAE9R7e0FSmjTx0aqURAAWvRtcXQxEplTgK1x63U11jfVaHv To: libcamera-devel Subject: [libcamera-devel] [PATCH v2 4/5] qcam: main_window: Introduce hotplug support 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: , X-List-Received-Date: Wed, 13 May 2020 17:30:04 -0000 Signed-off-by: Umang Jain --- src/qcam/main_window.cpp | 83 ++++++++++++++++++++++++++++++++++++++++ src/qcam/main_window.h | 6 +++ 2 files changed, 89 insertions(+) diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp index 7de0895..d595112 100644 --- a/src/qcam/main_window.cpp +++ b/src/qcam/main_window.cpp @@ -49,6 +49,43 @@ public: } }; +/** + * \brief Custom QEvent to signal hotplug or unplug + */ +class HotplugEvent : public QEvent +{ +public: + enum PLUGEVENT { + HOTPLUG, + UNPLUG + }; + + HotplugEvent(std::shared_ptr camera, PLUGEVENT event) + : QEvent(type()) + { + camera_ = camera; + plugEvent_ = event; + } + + ~HotplugEvent() + { + camera_.reset(); + } + + static Type type() + { + static int type = QEvent::registerEventType(); + return static_cast(type); + } + + PLUGEVENT getHotplugEvent() { return plugEvent_; } + Camera *getCamera() { return camera_.get(); } + +private: + std::shared_ptr camera_; + PLUGEVENT plugEvent_; +}; + MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) : saveRaw_(nullptr), options_(options), cm_(cm), allocator_(nullptr), isCapturing_(false), captureRaw_(false) @@ -71,6 +108,10 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options) setCentralWidget(viewfinder_); adjustSize(); + /* Hotplug/unplug support */ + cm_->cameraAdded.connect(this, &MainWindow::addNewCamera); + cm_->cameraRemoved.connect(this, &MainWindow::removeCamera); + /* Open the camera and start capture. */ ret = openCamera(); if (ret < 0) { @@ -95,6 +136,9 @@ bool MainWindow::event(QEvent *e) if (e->type() == CaptureEvent::type()) { processCapture(); return true; + } else if (e->type() == HotplugEvent::type()) { + processHotplug(static_cast(e)); + return true; } return QMainWindow::event(e); @@ -525,6 +569,45 @@ void MainWindow::stopCapture() setWindowTitle(title_); } +/* ----------------------------------------------------------------------------- + * Camera hotplugging support + */ + +void MainWindow::processHotplug(HotplugEvent *e) +{ + Camera *camera = e->getCamera(); + HotplugEvent::PLUGEVENT event = e->getHotplugEvent(); + + if (event == HotplugEvent::PLUGEVENT::HOTPLUG) { + cameraCombo_->addItem(QString::fromStdString(camera->name())); + } else if (event == HotplugEvent::PLUGEVENT::UNPLUG) { + int camIndex = cameraCombo_->findText(QString::fromStdString(camera->name())); + + /* Check if the currently-streaming camera is removed. */ + if (camera == camera_.get()) { + toggleCapture(false); + cameraCombo_->setCurrentIndex(0); + } + cameraCombo_->removeItem(camIndex); + } +} + +void MainWindow::addNewCamera(std::shared_ptr camera) +{ + qInfo() << "Adding new camera:" << camera->name().c_str(); + QCoreApplication::postEvent(this, + new HotplugEvent(std::move(camera), + HotplugEvent::PLUGEVENT::HOTPLUG)); +} + +void MainWindow::removeCamera(std::shared_ptr camera) +{ + qInfo() << "Removing camera:" << camera->name().c_str(); + QCoreApplication::postEvent(this, + new HotplugEvent(std::move(camera), + HotplugEvent::PLUGEVENT::UNPLUG)); +} + /* ----------------------------------------------------------------------------- * Image Save */ diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h index 59fa2d9..9108780 100644 --- a/src/qcam/main_window.h +++ b/src/qcam/main_window.h @@ -32,6 +32,8 @@ using namespace libcamera; class QAction; class QComboBox; +class HotplugEvent; + enum { OptCamera = 'c', OptHelp = 'h', @@ -87,8 +89,12 @@ private: int startCapture(); void stopCapture(); + void addNewCamera(std::shared_ptr camera); + void removeCamera(std::shared_ptr camera); + void requestComplete(Request *request); void processCapture(); + void processHotplug(HotplugEvent *e); void processViewfinder(FrameBuffer *buffer); /* UI elements */ From patchwork Wed May 13 17:30:01 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Umang Jain X-Patchwork-Id: 3793 Return-Path: Received: from o1.f.az.sendgrid.net (o1.f.az.sendgrid.net [208.117.55.132]) by lancelot.ideasonboard.com (Postfix) with ESMTPS id 48B6960E05 for ; Wed, 13 May 2020 19:30:03 +0200 (CEST) Authentication-Results: lancelot.ideasonboard.com; dkim=pass (1024-bit key; unprotected) header.d=uajain.com header.i=@uajain.com header.b="i9rVmTIY"; dkim-atps=neutral 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=n3tET7l5JBbSUk38m+eAP7HGUw7BhKcP/HWTY1KRbRE=; b=i9rVmTIYNQEnnIDBBV3dmlblHYW077K3q3Zrm+wI/mjkE8wOmk1P6jSVpcVyh2Wo+/oK soqMcqHaGHKPr97YfW+6rsX33MoHhh19yc4OAjf98zDBUwOLc/UdJZoI7VDLFgaFIh59Mo i5WcOJVUIQcO1Y/e8CXXOPnHEsv0WB2fw= Received: by filterdrecv-p3las1-cb48d7cc9-hbg9w with SMTP id filterdrecv-p3las1-cb48d7cc9-hbg9w-19-5EBC2E99-B 2020-05-13 17:30:01.716054493 +0000 UTC m=+4206155.129874852 Received: from mail.uajain.com (unknown) by ismtpd0008p1hnd1.sendgrid.net (SG) with ESMTP id 9w0Axt9xTMmt8wzQO4KqqA Wed, 13 May 2020 17:30:01.308 +0000 (UTC) From: Umang Jain Date: Wed, 13 May 2020 17:30:01 +0000 (UTC) Message-Id: <20200513172950.72685-6-email@uajain.com> In-Reply-To: <20200513172950.72685-1-email@uajain.com> References: <20200513172950.72685-1-email@uajain.com> Mime-Version: 1.0 X-SG-EID: 1Q40EQ7YGir8a9gjSIAdTjhngY657NMk9ckeo4dbHZDiOpywc/L3L9rFqlwE4KPcGYE5Iq+t2q0vZlJgodhIO78gONLK2nw2bcPFpm6NV+cHW8A0z64BTrWXbhN7KwVbmo9gzYkGAMrpkCSqX9SEJFEn0q4hz1yW4jm3L04HERlaysAtj3TWBVPlStnh/I+JfJovuDamrZZUZzonzIa4dqvR8M6VMnCHL9pDFVwcCU5bTkNE9Z9Uj/z820x24n9QS9nuUVdSBCSkZhjQOeV3vA== To: libcamera-devel Subject: [libcamera-devel] [PATCH v2 5/5] tests: Introduce hotplug hot-unplug unit test 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: , X-List-Received-Date: Wed, 13 May 2020 17:30:05 -0000 Signed-off-by: Umang Jain --- test/hotplug-cameras.cpp | 152 +++++++++++++++++++++++++++++++++++++++ test/meson.build | 1 + 2 files changed, 153 insertions(+) create mode 100644 test/hotplug-cameras.cpp diff --git a/test/hotplug-cameras.cpp b/test/hotplug-cameras.cpp new file mode 100644 index 0000000..cbf68af --- /dev/null +++ b/test/hotplug-cameras.cpp @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2020, Umang Jain + * + * hotplug-cameras.cpp - Emulate cameraAdded/cameraRemoved signals in CameraManager + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include "file.h" +#include "test.h" +#include "thread.h" + +using namespace std; +using namespace libcamera; + +class HotplugTest : public Test +{ +protected: + void cameraAddedHandler(std::shared_ptr cam) + { + cameraAddedPass_ = true; + } + + void cameraRemovedHandler(std::shared_ptr cam) + { + cameraRemovedPass_ = true; + } + + int init() + { + if (!File::exists("/sys/module/uvcvideo")) { + std::cout << "uvcvideo driver is not loaded, skipping" << std::endl; + return TestSkip; + } + + if (geteuid() != 0) { + std::cout << "This test requires root permissions, skipping" << std::endl; + return TestSkip; + } + + cm_ = new CameraManager(); + if (cm_->start()) { + std::cout << "Failed to start camera manager" << std::endl; + return TestFail; + } + + cameraAddedPass_ = false; + cameraRemovedPass_ = false; + + cm_->cameraAdded.connect(this, &HotplugTest::cameraAddedHandler); + cm_->cameraRemoved.connect(this, &HotplugTest::cameraRemovedHandler); + + uvc_toplevel_ = "/sys/module/uvcvideo/drivers/usb:uvcvideo/"; + + return 0; + } + + int run() + { + DIR *dir; + struct dirent *dirent, *dirent2; + std::string uvc_driver_dir; + bool uvc_driver_found = false; + + dir = opendir(uvc_toplevel_.c_str()); + /* Find a UVC device driver symlink, which we can bind/unbind */ + while ((dirent = readdir(dir)) != nullptr) { + if (dirent->d_type != DT_LNK) + continue; + + std::string child_dir = uvc_toplevel_ + dirent->d_name; + DIR *device_driver = opendir(child_dir.c_str()); + while ((dirent2 = readdir(device_driver)) != nullptr) { + if (strncmp(dirent2->d_name, "video4linux", 11) == 0) { + uvc_driver_dir = dirent->d_name; + uvc_driver_found = true; + break; + } + } + closedir(device_driver); + + if (uvc_driver_found) + break; + } + closedir(dir); + + /* If no UVC driver found, skip */ + if (!uvc_driver_found) + return TestSkip; + + /* Unbind a camera, process events */ + int fd1 = open("/sys/module/uvcvideo/drivers/usb:uvcvideo/unbind", O_WRONLY); + write(fd1, uvc_driver_dir.c_str(), uvc_driver_dir.size()); + close(fd1); + Timer timer; + timer.start(1000); + while (timer.isRunning()) + Thread::current()->eventDispatcher()->processEvents(); + + /* \todo: Fix this workaround of stopping and starting the camera-manager. + * We need to do this, so that cm_ release all references to the uvc media symlinks. + */ + cm_->stop(); + if (cm_->start()) { + std::cout << "Failed to restart camera-manager" << std::endl; + return TestFail; + } + + /* Bind the camera again, process events */ + int fd2 = open("/sys/module/uvcvideo/drivers/usb:uvcvideo/bind", O_WRONLY); + write(fd2, uvc_driver_dir.c_str(), uvc_driver_dir.size()); + close(fd2); + + timer.start(1000); + while (timer.isRunning()) + Thread::current()->eventDispatcher()->processEvents(); + + if (cameraAddedPass_ && cameraRemovedPass_) + return TestPass; + else + return TestFail; + } + + void cleanup() + { + cm_->stop(); + delete cm_; + } + +private: + CameraManager *cm_; + std::string uvc_toplevel_; + bool cameraRemovedPass_; + bool cameraAddedPass_; +}; + +TEST_REGISTER(HotplugTest) + diff --git a/test/meson.build b/test/meson.build index 5a45a85..383a7ea 100644 --- a/test/meson.build +++ b/test/meson.build @@ -29,6 +29,7 @@ internal_tests = [ ['file', 'file.cpp'], ['file-descriptor', 'file-descriptor.cpp'], ['message', 'message.cpp'], + ['hotplug-cameras', 'hotplug-cameras.cpp'], ['object', 'object.cpp'], ['object-invoke', 'object-invoke.cpp'], ['signal-threads', 'signal-threads.cpp'],