2
* Copyright (C) 2009 Rémi Denis-Courmont
4
* Copyright (C) 2004-2014 Savoir-Faire Linux Inc.
5
* Author: Rafaël Carré <rafael.carre@savoirfairelinux.com>
6
* Author: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License as published by
10
* the Free Software Foundation; either version 3 of the License, or
11
* (at your option) any later version.
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
* GNU General Public License for more details.
18
* You should have received a copy of the GNU General Public License
19
* along with this program; if not, write to the Free Software
20
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
* Additional permission under GNU GPL version 3 section 7:
24
* If you modify this program, or any covered work, by linking or
25
* combining it with the OpenSSL project's OpenSSL library (or a
26
* modified version of that library), containing parts covered by the
27
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
28
* grants you additional permission to convey the resulting work.
29
* Corresponding Source for a non-source form of such a combination
30
* shall include the source code for the parts of OpenSSL used as well
31
* as that of the covered work.
41
#include <stdexcept> // for std::runtime_error
47
#include "../video_device_monitor.h"
48
#include "config/yamlemitter.h"
49
#include "config/yamlnode.h"
51
#include "noncopyable.h"
56
#include <sys/types.h>
64
class VideoDeviceMonitorImpl {
67
* This is the only restriction to the pImpl design:
68
* as the Linux implementation has a thread, it needs a way to notify
69
* devices addition and deletion.
71
* This class should maybe inherit from VideoDeviceMonitor instead of
74
VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor);
75
~VideoDeviceMonitorImpl();
80
NON_COPYABLE(VideoDeviceMonitorImpl);
82
VideoDeviceMonitor* monitor_;
86
mutable std::mutex mutex_;
89
udev_monitor *udev_mon_;
93
static int is_v4l2(struct udev_device *dev)
95
const char *version = udev_device_get_property_value(dev, "ID_V4L_VERSION");
96
/* we do not support video4linux 1 */
97
return version and strcmp(version, "1");
100
VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor) :
103
udev_(0), udev_mon_(0),
106
udev_list_entry *devlist;
107
udev_enumerate *devenum;
113
udev_mon_ = udev_monitor_new_from_netlink(udev_, "udev");
116
if (udev_monitor_filter_add_match_subsystem_devtype(udev_mon_, "video4linux", NULL))
119
/* Enumerate existing devices */
120
devenum = udev_enumerate_new(udev_);
123
if (udev_enumerate_add_match_subsystem(devenum, "video4linux")) {
124
udev_enumerate_unref(devenum);
128
udev_monitor_enable_receiving(udev_mon_);
129
/* Note that we enumerate _after_ monitoring is enabled so that we do not
130
* loose device events occuring while we are enumerating. We could still
131
* loose events if the Netlink socket receive buffer overflows. */
132
udev_enumerate_scan_devices(devenum);
133
devlist = udev_enumerate_get_list_entry(devenum);
134
struct udev_list_entry *deventry;
135
udev_list_entry_foreach(deventry, devlist) {
136
const char *path = udev_list_entry_get_name(deventry);
137
struct udev_device *dev = udev_device_new_from_syspath(udev_, path);
140
const char *devpath = udev_device_get_devnode(dev);
143
monitor_->addDevice(string(devpath));
144
} catch (const std::runtime_error &e) {
145
ERROR("%s", e.what());
149
udev_device_unref(dev);
151
udev_enumerate_unref(devenum);
157
ERROR("udev enumeration failed");
160
udev_monitor_unref(udev_mon_);
166
/* fallback : go through /dev/video* */
167
for (int idx = 0;; ++idx) {
168
std::stringstream ss;
169
ss << "/dev/video" << idx;
171
monitor_->addDevice(ss.str());
172
} catch (const std::runtime_error &e) {
173
ERROR("%s", e.what());
179
void VideoDeviceMonitorImpl::start()
182
thread_ = std::thread(&VideoDeviceMonitorImpl::run, this);
185
VideoDeviceMonitorImpl::~VideoDeviceMonitorImpl()
188
if (thread_.joinable())
191
udev_monitor_unref(udev_mon_);
196
void VideoDeviceMonitorImpl::run()
203
const int udev_fd = udev_monitor_get_fd(udev_mon_);
205
timeval timeout = {0 /* sec */, 500000 /* usec */};
208
FD_SET(udev_fd, &set);
210
int ret = select(udev_fd + 1, &set, NULL, NULL, &timeout);
216
udev_device *dev = udev_monitor_receive_device(udev_mon_);
218
udev_device_unref(dev);
222
const char *node = udev_device_get_devnode(dev);
223
const char *action = udev_device_get_action(dev);
224
if (!strcmp(action, "add")) {
225
DEBUG("udev: adding %s", node);
227
monitor_->addDevice(node);
228
} catch (const std::runtime_error &e) {
229
ERROR("%s", e.what());
231
} else if (!strcmp(action, "remove")) {
232
DEBUG("udev: removing %s", node);
233
monitor_->removeDevice(string(node));
235
udev_device_unref(dev);
242
ERROR("udev monitoring thread: select failed (%m)");
247
ERROR("select() returned %d (%m)", ret);
254
VideoDeviceMonitor::VideoDeviceMonitor() :
255
preferences_(), devices_(),
256
monitorImpl_(new VideoDeviceMonitorImpl(this))
258
monitorImpl_->start();
261
VideoDeviceMonitor::~VideoDeviceMonitor()
264
} // namespace sfl_video