summaryrefslogtreecommitdiff
path: root/src/qcam/qt_event_dispatcher.cpp
blob: 5ba451bf88cef6e82a0e3912c5e996b3794cd251 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * qt_event_dispatcher.cpp - qcam - Qt-based event dispatcher
 */

#include <iostream>

#include <QAbstractEventDispatcher>
#include <QCoreApplication>
#include <QSocketNotifier>
#include <QTimerEvent>

#include <libcamera/event_notifier.h>
#include <libcamera/timer.h>

#include "qt_event_dispatcher.h"

using namespace libcamera;

QtEventDispatcher::QtEventDispatcher()
{
}

QtEventDispatcher::~QtEventDispatcher()
{
	for (auto &it : notifiers_) {
		NotifierSet &set = it.second;
		delete set.read.qnotifier;
		delete set.write.qnotifier;
		delete set.exception.qnotifier;
	}
}

void QtEventDispatcher::registerEventNotifier(EventNotifier *notifier)
{
	NotifierSet &set = notifiers_[notifier->fd()];
	QSocketNotifier::Type qtype;
	void (QtEventDispatcher::*method)(int);
	NotifierPair *pair;

	switch (notifier->type()) {
	case EventNotifier::Read:
	default:
		qtype = QSocketNotifier::Read;
		method = &QtEventDispatcher::readNotifierActivated;
		pair = &set.read;
		break;

	case EventNotifier::Write:
		qtype = QSocketNotifier::Write;
		method = &QtEventDispatcher::writeNotifierActivated;
		pair = &set.write;
		break;

	case EventNotifier::Exception:
		qtype = QSocketNotifier::Exception;
		method = &QtEventDispatcher::exceptionNotifierActivated;
		pair = &set.exception;
		break;
	}

	QSocketNotifier *qnotifier = new QSocketNotifier(notifier->fd(), qtype);
	connect(qnotifier, &QSocketNotifier::activated, this, method);
	pair->notifier = notifier;
	pair->qnotifier = qnotifier;
}

void QtEventDispatcher::unregisterEventNotifier(EventNotifier *notifier)
{
	NotifierSet &set = notifiers_[notifier->fd()];
	NotifierPair *pair;

	switch (notifier->type()) {
	case EventNotifier::Read:
	default:
		pair = &set.read;
		break;

	case EventNotifier::Write:
		pair = &set.write;
		break;

	case EventNotifier::Exception:
		pair = &set.exception;
		break;
	}

	delete pair->qnotifier;
	pair->qnotifier = nullptr;
	pair->notifier = nullptr;
}

void QtEventDispatcher::readNotifierActivated(int socket)
{
	EventNotifier *notifier = notifiers_[socket].read.notifier;
	notifier->activated.emit(notifier);
}

void QtEventDispatcher::writeNotifierActivated(int socket)
{
	EventNotifier *notifier = notifiers_[socket].write.notifier;
	notifier->activated.emit(notifier);
}

void QtEventDispatcher::exceptionNotifierActivated(int socket)
{
	EventNotifier *notifier = notifiers_[socket].exception.notifier;
	notifier->activated.emit(notifier);
}

void QtEventDispatcher::registerTimer(Timer *timer)
{
	int timerId = startTimer(timer->interval());
	timers_[timerId] = timer;
	timerIds_[timer] = timerId;
}

void QtEventDispatcher::unregisterTimer(Timer *timer)
{
	auto it = timerIds_.find(timer);
	timers_.erase(it->second);
	killTimer(it->second);
	timerIds_.erase(it);
}

void QtEventDispatcher::timerEvent(QTimerEvent *event)
{
	auto it = timers_.find(event->timerId());
	timerIds_.erase(it->second);
	killTimer(it->first);
	timers_.erase(it);
}

void QtEventDispatcher::processEvents()
{
	std::cout << "QtEventDispatcher::processEvents() should not be called"
		  << std::endl;
}

void QtEventDispatcher::interrupt()
{
	QCoreApplication::eventDispatcher()->interrupt();
}
pan class="hl kwa">if (!found) return false; } return true; } /** * \class DeviceEnumerator * \brief Enumerate, store and search media devices * * The DeviceEnumerator class is responsible for all interactions with the * operating system related to media devices. It enumerates all media devices * in the system, and for each device found creates an instance of the * MediaDevice class and stores it internally. The list of media devices can * then be searched using DeviceMatch search patterns. * * The enumerator also associates media device entities with device node paths. */ /** * \brief Create a new device enumerator matching the systems capabilities * * Depending on how the operating system handles device detection, hot-plug * notification and device node lookup, different device enumerator * implementations may be needed. This function creates the best enumerator for * the operating system based on the available resources. Not all different * enumerator types are guaranteed to support all features. * * \return A pointer to the newly created device enumerator on success, or * nullptr if an error occurs */ std::unique_ptr<DeviceEnumerator> DeviceEnumerator::create() { std::unique_ptr<DeviceEnumerator> enumerator; #ifdef HAVE_LIBUDEV enumerator = std::make_unique<DeviceEnumeratorUdev>(); if (!enumerator->init()) return enumerator; #endif /* * Either udev is not available or udev initialization failed. Fall back * on the sysfs enumerator. */ enumerator = std::make_unique<DeviceEnumeratorSysfs>(); if (!enumerator->init()) return enumerator; return nullptr; } DeviceEnumerator::~DeviceEnumerator() { for (const std::shared_ptr<MediaDevice> &media : devices_) { if (media->busy()) LOG(DeviceEnumerator, Error) << "Removing media device " << media->deviceNode() << " while still in use"; } } /** * \fn DeviceEnumerator::init() * \brief Initialize the enumerator * \return 0 on success or a negative error code otherwise * \retval -EBUSY the enumerator has already been initialized * \retval -ENODEV the enumerator can't enumerate devices */ /** * \fn DeviceEnumerator::enumerate() * \brief Enumerate all media devices in the system * * This function finds and add all media devices in the system to the * enumerator. It shall be implemented by all subclasses of DeviceEnumerator * using system-specific methods. * * Individual media devices that can't be properly enumerated shall be skipped * with a warning message logged, without returning an error. Only errors that * prevent enumeration altogether shall be fatal. * * \context This function is \threadbound. * * \return 0 on success or a negative error code otherwise */ /** * \brief Create a media device instance * \param[in] deviceNode path to the media device to create * * Create a media device for the \a deviceNode, open it, and populate its * media graph. The device enumerator shall then populate the media device by * associating device nodes with entities using MediaEntity::setDeviceNode(). * This process is specific to each device enumerator, and the device enumerator * shall ensure that device nodes are ready to be used (for instance, if * applicable, by waiting for device nodes to be created and access permissions * to be set by the system). Once done, it shall add the media device to the * system with addDevice(). * * \return Created media device instance on success, or nullptr otherwise */ std::unique_ptr<MediaDevice> DeviceEnumerator::createDevice(const std::string &deviceNode) { std::unique_ptr<MediaDevice> media = std::make_unique<MediaDevice>(deviceNode); int ret = media->populate(); if (ret < 0) { LOG(DeviceEnumerator, Info) << "Unable to populate media device " << deviceNode << " (" << strerror(-ret) << "), skipping"; return nullptr; } LOG(DeviceEnumerator, Debug) << "New media device \"" << media->driver() << "\" created from " << deviceNode; return media; } /** * \var DeviceEnumerator::devicesAdded * \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 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 * * Store the media device in the internal list for later matching with * pipeline handlers. \a media shall be created with createDevice() first. * This function shall be called after all members of the entities of the * media graph have been confirmed to be initialized. */ void DeviceEnumerator::addDevice(std::unique_ptr<MediaDevice> media) { LOG(DeviceEnumerator, Debug) << "Added device " << media->deviceNode() << ": " << media->driver(); devices_.push_back(std::move(media)); /* \todo To batch multiple additions, emit with a small delay here. */ devicesAdded.emit(); } /** * \brief Remove a media device from the enumerator * \param[in] deviceNode Path to the media device to remove * * Remove the media device identified by \a deviceNode previously added to the * enumerator with addDevice(). The media device's MediaDevice::disconnected * signal is emitted. */ void DeviceEnumerator::removeDevice(const std::string &deviceNode) { std::shared_ptr<MediaDevice> media; for (auto iter = devices_.begin(); iter != devices_.end(); ++iter) { if ((*iter)->deviceNode() == deviceNode) { media = std::move(*iter); devices_.erase(iter); break; } } if (!media) { LOG(DeviceEnumerator, Warning) << "Media device for node " << deviceNode << " not found"; return; } LOG(DeviceEnumerator, Debug) << "Media device for node " << deviceNode << " removed."; media->disconnected.emit(); } /** * \brief Search available media devices for a pattern match * \param[in] dm Search pattern * * Search in the enumerated media devices that are not already in use for a * match described in \a dm. If a match is found and the caller intends to use * it the caller is responsible for acquiring the MediaDevice object and * releasing it when done with it. * * \return pointer to the matching MediaDevice, or nullptr if no match is found */ std::shared_ptr<MediaDevice> DeviceEnumerator::search(const DeviceMatch &dm) { for (std::shared_ptr<MediaDevice> &media : devices_) { if (media->busy()) continue; if (dm.match(media.get())) { LOG(DeviceEnumerator, Debug) << "Successful match for media device \"" << media->driver() << "\""; return media; } } return nullptr; } } /* namespace libcamera */