~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/src/video/v4l2/video_device_monitor_impl.cpp

  • Committer: Package Import Robot
  • Author(s): Francois Marier, Francois Marier, Mark Purcell
  • Date: 2014-10-18 15:08:50 UTC
  • mfrom: (1.1.12)
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20141018150850-2exfk34ckb15pcwi
Tags: 1.4.1-0.1
[ Francois Marier ]
* Non-maintainer upload
* New upstream release (closes: #759576, #741130)
  - debian/rules +PJPROJECT_VERSION := 2.2.1
  - add upstream patch to fix broken TLS support
  - add patch to fix pjproject regression

[ Mark Purcell ]
* Build-Depends:
  - sflphone-daemon + libavformat-dev, libavcodec-dev, libswscale-dev,
  libavdevice-dev, libavutil-dev
  - sflphone-gnome + libclutter-gtk-1.0-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *  Copyright (C) 2009 Rémi Denis-Courmont
 
3
 *
 
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>
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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.
 
21
 *
 
22
 *  Additional permission under GNU GPL version 3 section 7:
 
23
 *
 
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.
 
32
 */
 
33
 
 
34
#include <algorithm>
 
35
#include <cerrno>
 
36
#include <cstdio>
 
37
#include <cstring>
 
38
#include <libudev.h>
 
39
#include <mutex>
 
40
#include <sstream>
 
41
#include <stdexcept> // for std::runtime_error
 
42
#include <string>
 
43
#include <thread>
 
44
#include <unistd.h>
 
45
#include <vector>
 
46
 
 
47
#include "../video_device_monitor.h"
 
48
#include "config/yamlemitter.h"
 
49
#include "config/yamlnode.h"
 
50
#include "logger.h"
 
51
#include "noncopyable.h"
 
52
 
 
53
extern "C" {
 
54
#include <fcntl.h>
 
55
#include <sys/stat.h>
 
56
#include <sys/types.h>
 
57
}
 
58
 
 
59
namespace sfl_video {
 
60
 
 
61
using std::vector;
 
62
using std::string;
 
63
 
 
64
class VideoDeviceMonitorImpl {
 
65
    public:
 
66
        /*
 
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.
 
70
         *
 
71
         * This class should maybe inherit from VideoDeviceMonitor instead of
 
72
         * being its pImpl.
 
73
         */
 
74
        VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor);
 
75
        ~VideoDeviceMonitorImpl();
 
76
 
 
77
        void start();
 
78
 
 
79
    private:
 
80
        NON_COPYABLE(VideoDeviceMonitorImpl);
 
81
 
 
82
        VideoDeviceMonitor* monitor_;
 
83
 
 
84
        void run();
 
85
        std::thread thread_;
 
86
        mutable std::mutex mutex_;
 
87
 
 
88
        udev *udev_;
 
89
        udev_monitor *udev_mon_;
 
90
        bool probing_;
 
91
};
 
92
 
 
93
static int is_v4l2(struct udev_device *dev)
 
94
{
 
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");
 
98
}
 
99
 
 
100
VideoDeviceMonitorImpl::VideoDeviceMonitorImpl(VideoDeviceMonitor* monitor) :
 
101
    monitor_(monitor),
 
102
    thread_(), mutex_(),
 
103
    udev_(0), udev_mon_(0),
 
104
    probing_(false)
 
105
{
 
106
    udev_list_entry *devlist;
 
107
    udev_enumerate *devenum;
 
108
 
 
109
    udev_ = udev_new();
 
110
    if (!udev_)
 
111
        goto udev_failed;
 
112
 
 
113
    udev_mon_ = udev_monitor_new_from_netlink(udev_, "udev");
 
114
    if (!udev_mon_)
 
115
        goto udev_failed;
 
116
    if (udev_monitor_filter_add_match_subsystem_devtype(udev_mon_, "video4linux", NULL))
 
117
        goto udev_failed;
 
118
 
 
119
    /* Enumerate existing devices */
 
120
    devenum = udev_enumerate_new(udev_);
 
121
    if (devenum == NULL)
 
122
        goto udev_failed;
 
123
    if (udev_enumerate_add_match_subsystem(devenum, "video4linux")) {
 
124
        udev_enumerate_unref(devenum);
 
125
        goto udev_failed;
 
126
    }
 
127
 
 
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);
 
138
 
 
139
        if (is_v4l2(dev)) {
 
140
            const char *devpath = udev_device_get_devnode(dev);
 
141
            if (devpath) {
 
142
                try {
 
143
                    monitor_->addDevice(string(devpath));
 
144
                } catch (const std::runtime_error &e) {
 
145
                    ERROR("%s", e.what());
 
146
                }
 
147
            }
 
148
        }
 
149
        udev_device_unref(dev);
 
150
    }
 
151
    udev_enumerate_unref(devenum);
 
152
 
 
153
    return;
 
154
 
 
155
udev_failed:
 
156
 
 
157
    ERROR("udev enumeration failed");
 
158
 
 
159
    if (udev_mon_)
 
160
        udev_monitor_unref(udev_mon_);
 
161
    if (udev_)
 
162
        udev_unref(udev_);
 
163
    udev_mon_ = NULL;
 
164
    udev_ = NULL;
 
165
 
 
166
    /* fallback : go through /dev/video* */
 
167
    for (int idx = 0;; ++idx) {
 
168
        std::stringstream ss;
 
169
        ss << "/dev/video" << idx;
 
170
        try {
 
171
            monitor_->addDevice(ss.str());
 
172
        } catch (const std::runtime_error &e) {
 
173
            ERROR("%s", e.what());
 
174
            return;
 
175
        }
 
176
    }
 
177
}
 
178
 
 
179
void VideoDeviceMonitorImpl::start()
 
180
{
 
181
    probing_ = true;
 
182
    thread_ = std::thread(&VideoDeviceMonitorImpl::run, this);
 
183
}
 
184
 
 
185
VideoDeviceMonitorImpl::~VideoDeviceMonitorImpl()
 
186
{
 
187
    probing_ = false;
 
188
    if (thread_.joinable())
 
189
        thread_.join();
 
190
    if (udev_mon_)
 
191
        udev_monitor_unref(udev_mon_);
 
192
    if (udev_)
 
193
        udev_unref(udev_);
 
194
}
 
195
 
 
196
void VideoDeviceMonitorImpl::run()
 
197
{
 
198
    if (!udev_mon_) {
 
199
        probing_ = false;
 
200
        return;
 
201
    }
 
202
 
 
203
    const int udev_fd = udev_monitor_get_fd(udev_mon_);
 
204
    while (probing_) {
 
205
        timeval timeout = {0 /* sec */, 500000 /* usec */};
 
206
        fd_set set;
 
207
        FD_ZERO(&set);
 
208
        FD_SET(udev_fd, &set);
 
209
 
 
210
        int ret = select(udev_fd + 1, &set, NULL, NULL, &timeout);
 
211
        switch (ret) {
 
212
            case 0:
 
213
                break;
 
214
            case 1:
 
215
                {
 
216
                    udev_device *dev = udev_monitor_receive_device(udev_mon_);
 
217
                    if (!is_v4l2(dev)) {
 
218
                        udev_device_unref(dev);
 
219
                        break;
 
220
                    }
 
221
 
 
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);
 
226
                        try {
 
227
                            monitor_->addDevice(node);
 
228
                        } catch (const std::runtime_error &e) {
 
229
                            ERROR("%s", e.what());
 
230
                        }
 
231
                    } else if (!strcmp(action, "remove")) {
 
232
                        DEBUG("udev: removing %s", node);
 
233
                        monitor_->removeDevice(string(node));
 
234
                    }
 
235
                    udev_device_unref(dev);
 
236
                    break;
 
237
                }
 
238
 
 
239
            case -1:
 
240
                if (errno == EAGAIN)
 
241
                    continue;
 
242
                ERROR("udev monitoring thread: select failed (%m)");
 
243
                probing_ = false;
 
244
                return;
 
245
 
 
246
            default:
 
247
                ERROR("select() returned %d (%m)", ret);
 
248
                probing_ = false;
 
249
                return;
 
250
        }
 
251
    }
 
252
}
 
253
 
 
254
VideoDeviceMonitor::VideoDeviceMonitor() :
 
255
    preferences_(), devices_(),
 
256
    monitorImpl_(new VideoDeviceMonitorImpl(this))
 
257
{
 
258
    monitorImpl_->start();
 
259
}
 
260
 
 
261
VideoDeviceMonitor::~VideoDeviceMonitor()
 
262
{}
 
263
 
 
264
} // namespace sfl_video