{"id":363,"url":"https://patchwork.libcamera.org/api/patches/363/?format=json","web_url":"https://patchwork.libcamera.org/patch/363/","project":{"id":1,"url":"https://patchwork.libcamera.org/api/projects/1/?format=json","name":"libcamera","link_name":"libcamera","list_id":"libcamera_core","list_email":"libcamera-devel@lists.libcamera.org","web_url":"","scm_url":"","webscm_url":""},"msgid":"<20190124101651.9993-9-laurent.pinchart@ideasonboard.com>","date":"2019-01-24T10:16:49","name":"[libcamera-devel,08/10] libcamera: pipeline_handler: Add camera disconnection support","commit_ref":null,"pull_url":null,"state":"accepted","archived":false,"hash":"65817a194f7b4c5b33274c13faa02a8031cd34e7","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/?format=json","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"delegate":null,"mbox":"https://patchwork.libcamera.org/patch/363/mbox/","series":[{"id":125,"url":"https://patchwork.libcamera.org/api/series/125/?format=json","web_url":"https://patchwork.libcamera.org/project/libcamera/list/?series=125","date":"2019-01-24T10:16:41","name":"Hotplug support and object lifetime management","version":1,"mbox":"https://patchwork.libcamera.org/series/125/mbox/"}],"comments":"https://patchwork.libcamera.org/api/patches/363/comments/","check":"pending","checks":"https://patchwork.libcamera.org/api/patches/363/checks/","tags":{},"headers":{"Return-Path":"<laurent.pinchart@ideasonboard.com>","Received":["from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id C513B60CA4\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tThu, 24 Jan 2019 11:16:59 +0100 (CET)","from pendragon.bb.dnainternet.fi\n\t(dfj612yhrgyx302h3jwwy-3.rev.dnainternet.fi\n\t[IPv6:2001:14ba:21f5:5b00:ce28:277f:58d7:3ca4])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 5946C2F6;\n\tThu, 24 Jan 2019 11:16:59 +0100 (CET)"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1548325019;\n\tbh=aQGQ8RhvH7WMn6uwvrDcTO+ad1MMOuufb7zWhDXlJyk=;\n\th=From:To:Cc:Subject:Date:In-Reply-To:References:From;\n\tb=wne1UQNDzU9EQdXJgXQDJyqCkdjFEGqeam7r0zwkDPYcfhW7qJMQxQeZoUsG3RnD1\n\tx/luYYFF9m/+TJBhqyTLloDzo/SLZEvHADwhhK2pLzT7rbWoqoC0UFz1Kwz/8hqp07\n\tVi25xAYhOzzHSI0LAE4cNCQCgiiaf+J9vXyvbfgI=","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"libcamera-devel@lists.libcamera.org","Date":"Thu, 24 Jan 2019 12:16:49 +0200","Message-Id":"<20190124101651.9993-9-laurent.pinchart@ideasonboard.com>","X-Mailer":"git-send-email 2.19.2","In-Reply-To":"<20190124101651.9993-1-laurent.pinchart@ideasonboard.com>","References":"<20190124101651.9993-1-laurent.pinchart@ideasonboard.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Subject":"[libcamera-devel] [PATCH 08/10] libcamera: pipeline_handler: Add\n\tcamera disconnection support","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.23","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","X-List-Received-Date":"Thu, 24 Jan 2019 10:17:01 -0000"},"content":"From: Niklas Söderlund <niklas.soderlund@ragnatech.se>\n\nPipeline handlers are responsible for creating camera instances, but\nalso for destroying them when devices are unplugged. As camera objects\nare reference-counted this isn't a straightforward operation and\ninvolves the camera manager and camera object itself. Add two helper\nmethods in the PipelineHandler base class to register a camera and to\nregister a media device with the pipeline handler.\n\nWhen registering a camera, the registerCamera() helper method will add\nit to the camera manager. When registering a media device, the\nregisterMediaDevice() helper method will listen to device disconnection\nevents, and disconnect all cameras created by the pipeline handler as a\nresponse.\n\nUnder the hood the PipelineHandler class needs to keep track of\nregistered cameras in order to handle disconnection. They can't be\nstored as shared pointers as this would create a circular dependency\n(the Camera class owns a shared pointer to the pipeline handler). Store\nthem as weak pointers instead. This is safe as a reference to the camera\nis stored in the camera manager, and doesn't get removed until the\ncamera is unregistered from the manager by the PipelineHandler.\n\nSigned-off-by: Niklas Söderlund <niklas.soderlund@ragnatech.se>\nSigned-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n---\n src/libcamera/include/pipeline_handler.h | 10 ++++\n src/libcamera/pipeline/ipu3/ipu3.cpp     |  3 +-\n src/libcamera/pipeline/uvcvideo.cpp      |  3 +-\n src/libcamera/pipeline/vimc.cpp          |  3 +-\n src/libcamera/pipeline_handler.cpp       | 71 ++++++++++++++++++++++++\n 5 files changed, 84 insertions(+), 6 deletions(-)","diff":"diff --git a/src/libcamera/include/pipeline_handler.h b/src/libcamera/include/pipeline_handler.h\nindex e1d6369eb0c4..804cce4807ee 100644\n--- a/src/libcamera/include/pipeline_handler.h\n+++ b/src/libcamera/include/pipeline_handler.h\n@@ -16,6 +16,7 @@ namespace libcamera {\n \n class CameraManager;\n class DeviceEnumerator;\n+class MediaDevice;\n \n class PipelineHandler : public std::enable_shared_from_this<PipelineHandler>\n {\n@@ -27,6 +28,15 @@ public:\n \n protected:\n \tCameraManager *manager_;\n+\n+\tvoid registerCamera(std::shared_ptr<Camera> camera);\n+\tvoid hotplugMediaDevice(MediaDevice *media);\n+\n+private:\n+\tvirtual void disconnect();\n+\tvoid mediaDeviceDisconnected(MediaDevice *media);\n+\n+\tstd::vector<std::weak_ptr<Camera>> cameras_;\n };\n \n class PipelineHandlerFactory\ndiff --git a/src/libcamera/pipeline/ipu3/ipu3.cpp b/src/libcamera/pipeline/ipu3/ipu3.cpp\nindex 9831f74fe53f..3161e71420ed 100644\n--- a/src/libcamera/pipeline/ipu3/ipu3.cpp\n+++ b/src/libcamera/pipeline/ipu3/ipu3.cpp\n@@ -9,7 +9,6 @@\n #include <vector>\n \n #include <libcamera/camera.h>\n-#include <libcamera/camera_manager.h>\n \n #include \"device_enumerator.h\"\n #include \"log.h\"\n@@ -169,7 +168,7 @@ void PipelineHandlerIPU3::registerCameras()\n \n \t\tstd::string cameraName = sensor->name() + \" \" + std::to_string(id);\n \t\tstd::shared_ptr<Camera> camera = Camera::create(this, cameraName);\n-\t\tmanager_->addCamera(std::move(camera));\n+\t\tregisterCamera(std::move(camera));\n \n \t\tLOG(IPU3, Info)\n \t\t\t<< \"Registered Camera[\" << numCameras << \"] \\\"\"\ndiff --git a/src/libcamera/pipeline/uvcvideo.cpp b/src/libcamera/pipeline/uvcvideo.cpp\nindex 73bad6714bb4..c8f1bf553bfe 100644\n--- a/src/libcamera/pipeline/uvcvideo.cpp\n+++ b/src/libcamera/pipeline/uvcvideo.cpp\n@@ -6,7 +6,6 @@\n  */\n \n #include <libcamera/camera.h>\n-#include <libcamera/camera_manager.h>\n \n #include \"device_enumerator.h\"\n #include \"media_device.h\"\n@@ -49,7 +48,7 @@ bool PipelineHandlerUVC::match(DeviceEnumerator *enumerator)\n \tdev_->acquire();\n \n \tstd::shared_ptr<Camera> camera = Camera::create(this, dev_->model());\n-\tmanager_->addCamera(std::move(camera));\n+\tregisterCamera(std::move(camera));\n \n \treturn true;\n }\ndiff --git a/src/libcamera/pipeline/vimc.cpp b/src/libcamera/pipeline/vimc.cpp\nindex 521b20d3a120..b714a07688e9 100644\n--- a/src/libcamera/pipeline/vimc.cpp\n+++ b/src/libcamera/pipeline/vimc.cpp\n@@ -6,7 +6,6 @@\n  */\n \n #include <libcamera/camera.h>\n-#include <libcamera/camera_manager.h>\n \n #include \"device_enumerator.h\"\n #include \"media_device.h\"\n@@ -58,7 +57,7 @@ bool PipeHandlerVimc::match(DeviceEnumerator *enumerator)\n \tdev_->acquire();\n \n \tstd::shared_ptr<Camera> camera = Camera::create(this, \"Dummy VIMC Camera\");\n-\tmanager_->addCamera(std::move(camera));\n+\tregisterCamera(std::move(camera));\n \n \treturn true;\n }\ndiff --git a/src/libcamera/pipeline_handler.cpp b/src/libcamera/pipeline_handler.cpp\nindex 3850ea8fadb5..f0aa2f8022c2 100644\n--- a/src/libcamera/pipeline_handler.cpp\n+++ b/src/libcamera/pipeline_handler.cpp\n@@ -5,7 +5,11 @@\n  * pipeline_handler.cpp - Pipeline handler infrastructure\n  */\n \n+#include <libcamera/camera.h>\n+#include <libcamera/camera_manager.h>\n+\n #include \"log.h\"\n+#include \"media_device.h\"\n #include \"pipeline_handler.h\"\n \n /**\n@@ -97,6 +101,73 @@ PipelineHandler::~PipelineHandler()\n  * constant for the whole lifetime of the pipeline handler.\n  */\n \n+/**\n+ * \\brief Register a camera to the camera manager and pipeline handler\n+ * \\param[in] camera The camera to be added\n+ *\n+ * This function is called by pipeline handlers to register the cameras they\n+ * handle with the camera manager.\n+ */\n+void PipelineHandler::registerCamera(std::shared_ptr<Camera> camera)\n+{\n+\tcameras_.push_back(camera);\n+\tmanager_->addCamera(std::move(camera));\n+}\n+\n+/**\n+ * \\brief Handle hotplugging of a media device\n+ * \\param[in] media The media device\n+ *\n+ * This function enables hotplug handling, and especially hot-unplug handling,\n+ * of the \\a media device. It shall be called by pipeline handlers for all the\n+ * media devices that can be disconnected.\n+ *\n+ * When a media device passed to this function is later unplugged, the pipeline\n+ * handler gets notified and automatically disconnects all the cameras it has\n+ * registered without requiring any manual intervention.\n+ */\n+void PipelineHandler::hotplugMediaDevice(MediaDevice *media)\n+{\n+\tmedia->disconnected.connect(this, &PipelineHandler::mediaDeviceDisconnected);\n+}\n+\n+/**\n+ * \\brief Device disconnection handler\n+ *\n+ * This virtual function is called to notify the pipeline handler that the\n+ * device it handles has been disconnected. It notifies all cameras created by\n+ * the pipeline handler that they have been disconnected, and unregisters them\n+ * from the camera manager.\n+ *\n+ * The function can be overloaded by pipeline handlers to perform custom\n+ * operations at disconnection time. Any overloaded version shall call the\n+ * PipelineHandler::disconnect() base function for proper hot-unplug operation.\n+ */\n+void PipelineHandler::disconnect()\n+{\n+\tfor (std::weak_ptr<Camera> ptr : cameras_) {\n+\t\tstd::shared_ptr<Camera> camera = ptr.lock();\n+\t\tif (!camera)\n+\t\t\tcontinue;\n+\n+\t\tcamera->disconnect();\n+\t\tmanager_->removeCamera(camera.get());\n+\t}\n+\n+\tcameras_.clear();\n+}\n+\n+/**\n+ * \\brief Slot for the MediaDevice disconnected signal\n+ */\n+void PipelineHandler::mediaDeviceDisconnected(MediaDevice *media)\n+{\n+\tif (cameras_.empty())\n+\t\treturn;\n+\n+\tdisconnect();\n+}\n+\n /**\n  * \\class PipelineHandlerFactory\n  * \\brief Registration of PipelineHandler classes and creation of instances\n","prefixes":["libcamera-devel","08/10"]}