2 * Copyright (c) 2012, 2013, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/types.h>
32 #include <linux/input.h>
41 #include <pulse/mainloop.h>
42 #include <pulse/mainloop-api.h>
44 #include <murphy/common/debug.h>
46 #include "srs/daemon/plugin.h"
47 #include "srs/daemon/context.h"
48 #include "srs/daemon/recognizer.h"
50 #define PLUGIN_NAME "input-handler"
51 #define PLUGIN_DESCR "For activating/deactivating voice recognition"
52 #define PLUGIN_AUTHORS "Janos Kovacs <janos.kovacs@intel.com>"
53 #define PLUGIN_VERSION "0.0.1"
56 typedef struct context_s context_t;
57 typedef struct input_s input_t;
75 static void input_event_cb(pa_mainloop_api *, pa_io_event *, int,
76 pa_io_event_flags_t, void *);
77 static void scan_devices(context_t *);
78 static void handle_device(context_t *, struct udev_device *);
79 static int add_input(context_t *, const char *, size_t *, input_t **);
80 static int remove_input(context_t *, const char *, size_t *, input_t **);
83 static int create_input(srs_plugin_t *plugin)
88 mrp_log_info("creating input plugin");
90 if ((ctx = mrp_allocz(sizeof(context_t))) && (udev = udev_new())) {
94 plugin->plugin_data = ctx;
103 static int config_input(srs_plugin_t *plugin, srs_cfg_t *settings)
105 context_t *ctx = (context_t *)plugin->plugin_data;
107 MRP_UNUSED(settings);
109 mrp_log_info("configuring input plugin");
111 ctx->key = KEY_PAUSE;
117 static int start_input(srs_plugin_t *plugin)
119 context_t *ctx = (context_t *)plugin->plugin_data;
121 mrp_log_info("starting input plugin");
131 static void stop_input(srs_plugin_t *plugin)
133 context_t *ctx = (context_t *)plugin->plugin_data;
135 mrp_log_info("stopping input plugin");
138 udev_unref(ctx->udev);
140 while (ctx->nkbd > 0)
141 remove_input(ctx, ctx->kbds->path, &ctx->nkbd, &ctx->kbds);
152 static void destroy_input(srs_plugin_t *plugin)
154 context_t *ctx = (context_t *)plugin->plugin_data;
156 mrp_log_info("destroying input plugin");
163 static void input_event_cb(pa_mainloop_api *ea,
166 pa_io_event_flags_t events,
169 context_t *ctx = (void *)userdata;
170 srs_plugin_t *plugin;
172 struct input_event inpev;
179 if (ctx && (plugin = ctx->plugin) && (srs = plugin->srs)) {
181 if ((rd = read(fd, &inpev, sizeof(inpev))) != sizeof(inpev)) {
182 if (rd < 0 && errno == EINTR)
185 mrp_debug("input plugin: failed to read input event");
190 if (inpev.type == EV_KEY && inpev.value == 1) {
191 if (inpev.code == ctx->key) {
192 if ((ctx->state ^= 1))
193 srs_activate_srec(srs, "sphinx-speech");
195 srs_deactivate_srec(srs, "sphinx-speech");
205 static void scan_devices(context_t *ctx)
208 struct udev_enumerate *enm;
209 struct udev_list_entry *list, *entry;
210 struct udev_device *dev;
213 if (!ctx || !(udev = ctx->udev))
216 enm = udev_enumerate_new(udev);
218 udev_enumerate_add_match_subsystem(enm, "input");
219 udev_enumerate_scan_devices(enm);
220 list = udev_enumerate_get_list_entry(enm);
222 udev_list_entry_foreach(entry, list) {
223 syspath = udev_list_entry_get_name(entry);
224 if ((dev = udev_device_new_from_syspath(udev, syspath))) {
225 handle_device(ctx, dev);
226 udev_device_unref(dev);
230 udev_enumerate_unref(enm);
233 static void handle_device(context_t *ctx, struct udev_device *dev)
239 if ((path = udev_device_get_property_value(dev, "DEVNAME"))) {
240 key = udev_device_get_property_value(dev, "ID_INPUT_KEY");
241 kbd = udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
246 if (kbd && ctx->key) {
247 add_input(ctx, path, &ctx->nkbd, &ctx->kbds);
252 static int add_input(context_t *ctx,
257 static pa_io_event_flags_t flags = PA_IO_EVENT_INPUT;
259 srs_plugin_t *plugin = ctx->plugin;
260 srs_context_t *srs = plugin->srs;
261 pa_mainloop_api *mlapi = srs->pa;
268 if (!mlapi || !path || (fd = open(path, O_RDONLY)) < 0)
271 if (ioctl(fd, EVIOCGNAME(sizeof(id)), id) < 0) {
277 size = sizeof(input_t) * (idx + 1);
279 if (!(*pinputs = mrp_realloc(*pinputs, size))) {
286 inp = *pinputs + idx;
288 inp->path = mrp_strdup(path);
289 inp->id = mrp_strdup(id);
291 inp->paev = mlapi->io_new(mlapi, fd, flags, input_event_cb, ctx);
293 if (!inp->path || !inp->id || !inp->paev) {
294 mrp_free((void *)inp->path);
295 mrp_free((void *)inp->id);
297 mlapi->io_free(inp->paev);
303 mrp_log_info("input plugin: added event source '%s'", id);
308 static int remove_input(context_t *ctx,
313 srs_plugin_t *plugin = ctx->plugin;
314 srs_context_t *srs = plugin->srs;
315 pa_mainloop_api *mlapi = srs->pa;
316 input_t *inp, *inputs;
317 size_t i, ninput, size;
325 for (i = 0; i < ninput; i++) {
328 if (!strcmp(path, inp->path)) {
330 mlapi->io_free(inp->paev);
333 mrp_free((void *)inp->path);
334 mrp_free((void *)inp->id);
336 size = (ninput - (i + 1)) * sizeof(input_t);
339 memmove(inp + 1, inp, size);
341 *pninput = ninput - 1;
350 SRS_DECLARE_PLUGIN(PLUGIN_NAME, PLUGIN_DESCR, PLUGIN_AUTHORS, PLUGIN_VERSION,
351 create_input, config_input, start_input, stop_input,
358 * indent-tabs-mode: nil