input-plugin: new plugin to control activation/deactivation of 'sphinx-speech'
authorJanos Kovacs <jankovac503@gmail.com>
Thu, 6 Jun 2013 13:45:20 +0000 (16:45 +0300)
committerKrisztian Litkey <krisztian.litkey@intel.com>
Thu, 6 Jun 2013 13:58:28 +0000 (16:58 +0300)
src/Makefile.am
src/plugins/input-handler/input-plugin.c [new file with mode: 0644]

index d890112..311a393 100644 (file)
@@ -192,7 +192,21 @@ plugin_simple_voice_la_LDFLAGS =                           \
 
 plugin_simple_voice_la_LIBADD  =
 
+# input plugin
+plugin_LTLIBRARIES += plugin-input-handler.la
 
+plugin_input_handler_la_SOURCES =                              \
+               plugins/input-handler/input-plugin.c
+
+plugin_input_handler_la_CFLAGS  =                              \
+               $(AM_CFLAGS)
+
+plugin_input_handler_la_LDFLAGS =                              \
+               $(UDEV_CFLAGS)                                  \
+               -module -avoid-version
+
+plugin_input_handler_la_LIBADD  =                              \
+               $(UDEV_LIBS)
 
 # cleanup
 clean-local::
diff --git a/src/plugins/input-handler/input-plugin.c b/src/plugins/input-handler/input-plugin.c
new file mode 100644 (file)
index 0000000..ac37d98
--- /dev/null
@@ -0,0 +1,360 @@
+/*
+ * Copyright (c) 2012, 2013, Intel Corporation
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *   * Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *   * Neither the name of Intel Corporation nor the names of its contributors
+ *     may be used to endorse or promote products derived from this software
+ *     without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <linux/input.h>
+#include <libudev.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <pulse/mainloop.h>
+#include <pulse/mainloop-api.h>
+
+#include <murphy/common/debug.h>
+
+#include "src/daemon/plugin.h"
+#include "src/daemon/context.h"
+#include "src/daemon/recognizer.h"
+
+#define PLUGIN_NAME    "input-handler"
+#define PLUGIN_DESCR   "For activating/deactivating voice recognition"
+#define PLUGIN_AUTHORS "Janos Kovacs <janos.kovacs@intel.com>"
+#define PLUGIN_VERSION "0.0.1"
+
+
+typedef struct context_s  context_t;
+typedef struct input_s    input_t;
+
+struct context_s {
+    srs_plugin_t *plugin;
+    struct udev *udev;
+    size_t nkbd;
+    input_t *kbds;
+    uint16_t key;
+    uint32_t state;
+};
+
+struct input_s {
+    const char *path;
+    const char *id;
+    int fd;
+    pa_io_event *paev;
+};
+
+static void input_event_cb(pa_mainloop_api *, pa_io_event *, int,
+                           pa_io_event_flags_t, void *);
+static void scan_devices(context_t *);
+static void handle_device(context_t *, struct udev_device *);
+static int add_input(context_t *, const char *, size_t *, input_t **);
+static int remove_input(context_t *, const char *, size_t *, input_t **);
+
+
+static int create_input(srs_plugin_t *plugin)
+{
+    context_t *ctx;
+    struct udev *udev;
+
+    mrp_log_info("creating input plugin");
+
+    if ((ctx = mrp_allocz(sizeof(context_t))) && (udev = udev_new())) {
+        ctx->plugin = plugin;
+        ctx->udev = udev;
+
+        plugin->plugin_data = ctx;
+
+        return TRUE;
+    }
+
+    return FALSE;
+}
+
+
+static int config_input(srs_plugin_t *plugin, srs_cfg_t *settings)
+{
+    context_t *ctx = (context_t *)plugin->plugin_data;
+
+    mrp_log_info("configuring input plugin");
+
+    ctx->key = KEY_PAUSE;
+
+    return TRUE;
+}
+
+
+static int start_input(srs_plugin_t *plugin)
+{
+    context_t *ctx = (context_t *)plugin->plugin_data;
+
+    mrp_log_info("starting input plugin");
+
+    if (ctx->key) {
+        scan_devices(ctx);
+    }
+
+    return TRUE;
+}
+
+
+static void stop_input(srs_plugin_t *plugin)
+{
+    context_t *ctx = (context_t *)plugin->plugin_data;
+
+    mrp_log_info("stopping input plugin");
+
+    if (ctx) {
+        udev_unref(ctx->udev);
+
+        while (ctx->nkbd > 0)
+            remove_input(ctx, ctx->kbds->path, &ctx->nkbd, &ctx->kbds);
+        mrp_free(ctx->kbds);
+
+        ctx->nkbd = 0;
+        ctx->kbds = NULL;
+    }
+
+    return;
+}
+
+
+static void destroy_input(srs_plugin_t *plugin)
+{
+    context_t *ctx = (context_t *)plugin->plugin_data;
+    size_t i;
+
+    mrp_log_info("destroying input plugin");
+
+    if (ctx) {
+        mrp_free(ctx);
+    }
+}
+
+static void input_event_cb(pa_mainloop_api *ea,
+                           pa_io_event *ioev,
+                           int fd,
+                           pa_io_event_flags_t events,
+                           void *userdata)
+{
+    context_t *ctx = (void *)userdata;
+    srs_plugin_t *plugin;
+    srs_context_t *srs;
+    struct input_event inpev;
+    int rd;
+
+    MRP_UNUSED(ea);
+    MRP_UNUSED(ioev);
+    MRP_UNUSED(events);
+
+    if (ctx && (plugin = ctx->plugin) && (srs = plugin->srs)) {
+        for (;;) {
+            if ((rd = read(fd, &inpev, sizeof(inpev))) != sizeof(inpev)) {
+                if (rd < 0 && errno == EINTR)
+                    continue;
+                else {
+                    mrp_debug("input plugin: failed to read input event");
+                    return;
+                }
+            }
+
+            if (inpev.type == EV_KEY && inpev.value == 1) {
+                if (inpev.code == ctx->key) {
+                    if ((ctx->state ^= 1))
+                        srs_activate_srec(srs, "sphinx-speech");
+                    else
+                        srs_deactivate_srec(srs, "sphinx-speech");
+                }
+            }
+
+            return;
+       } /* for ;; */
+    }
+}
+
+
+static void scan_devices(context_t *ctx)
+{
+    struct udev *udev;
+    struct udev_enumerate *enm;
+    struct udev_list_entry *list, *entry;
+    struct udev_device *dev;
+    const char *syspath;
+
+    if (!ctx || !(udev = ctx->udev))
+        return;
+
+    enm = udev_enumerate_new(udev);
+
+    udev_enumerate_add_match_subsystem(enm, "input");
+    udev_enumerate_scan_devices(enm);
+    list = udev_enumerate_get_list_entry(enm);
+
+    udev_list_entry_foreach(entry, list) {
+        syspath = udev_list_entry_get_name(entry);
+        if ((dev = udev_device_new_from_syspath(udev, syspath))) {
+            handle_device(ctx, dev);
+            udev_device_unref(dev);
+        }
+    }
+
+    udev_enumerate_unref(enm);
+}
+
+static void handle_device(context_t *ctx, struct udev_device *dev)
+{
+    const char *path;
+    const char *kbd;
+    const char *key;
+    int fd;
+
+    if ((path = udev_device_get_property_value(dev, "DEVNAME"))) {
+        key = udev_device_get_property_value(dev, "ID_INPUT_KEY");
+        kbd = udev_device_get_property_value(dev, "ID_INPUT_KEYBOARD");
+
+        if (key) {
+        }
+
+        if (kbd && ctx->key) {
+            add_input(ctx, path, &ctx->nkbd, &ctx->kbds);
+        }
+    }
+}
+
+static int add_input(context_t *ctx,
+                     const char *path,
+                     size_t *pninput,
+                     input_t **pinputs)
+{
+    static pa_io_event_flags_t flags = PA_IO_EVENT_INPUT;
+
+    srs_plugin_t *plugin = ctx->plugin;
+    srs_context_t *srs = plugin->srs;
+    pa_mainloop_api *mlapi = pa_mainloop_get_api(srs->pa);
+    char id[512];
+    size_t idx;
+    input_t *inp;
+    size_t size;
+    int fd;
+
+    if (!mlapi || !path || (fd = open(path, O_RDONLY)) < 0)
+        return -1;
+
+    if (ioctl(fd, EVIOCGNAME(sizeof(id)), id) < 0) {
+        close(fd);
+        return -1;
+    }
+
+    idx = *pninput;
+    size = sizeof(input_t) * (idx + 1);
+
+    if (!(*pinputs = mrp_realloc(*pinputs, size))) {
+        *pninput = 0;
+        return -1;
+    }
+
+    *pninput = idx + 1;
+    inp = *pinputs + idx;
+
+    inp->path = mrp_strdup(path);
+    inp->id = mrp_strdup(id);
+    inp->fd = fd;
+    inp->paev = mlapi->io_new(mlapi, fd, flags, input_event_cb, ctx);
+
+    if (!inp->path || !inp->id || !inp->paev) {
+        mrp_free((void *)inp->path);
+        mrp_free((void *)inp->id);
+        if (inp->paev)
+            mlapi->io_free(inp->paev);
+        close(inp->fd);
+        *pninput = idx;
+        return -1;
+    }
+
+    mrp_log_info("input plugin: added event source '%s'", id);
+
+    return 0;
+}
+
+static int remove_input(context_t *ctx,
+                        const char *path,
+                        size_t *pninput,
+                        input_t **pinputs)
+{
+    srs_plugin_t *plugin = ctx->plugin;
+    srs_context_t *srs = plugin->srs;
+    pa_mainloop_api *mlapi = pa_mainloop_get_api(srs->pa);
+    input_t *inp, *inputs;
+    size_t i, ninput, size;
+
+    if (!mlapi || !path)
+        return -1;
+
+    inputs = *pinputs;
+    ninput = *pninput;
+
+    for (i = 0;  i < ninput;  i++) {
+        inp = inputs + i;
+
+        if (!strcmp(path, inp->path)) {
+            if (inp->paev)
+                mlapi->io_free(inp->paev);
+            if (inp->fd >= 0)
+                close(inp->fd);
+            mrp_free((void *)inp->path);
+            mrp_free((void *)inp->id);
+
+            size = (ninput - (i + 1)) * sizeof(input_t);
+
+            if (size > 0)
+                memmove(inp + 1, inp, size);
+
+            *pninput = ninput - 1;
+
+            return 0;
+        }
+    }
+
+    return -1;
+}
+
+SRS_DECLARE_PLUGIN(PLUGIN_NAME, PLUGIN_DESCR, PLUGIN_AUTHORS, PLUGIN_VERSION,
+                   create_input, config_input, start_input, stop_input,
+                   destroy_input)
+
+
+/*
+ * Local Variables:
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ *
+ */