]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
ctl: card: add an API to create GSource for event dispatcher
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Mon, 18 Nov 2019 04:22:44 +0000 (13:22 +0900)
committerTakashi Sakamoto <o-takashi@sakamocchi.jp>
Thu, 12 Dec 2019 05:29:12 +0000 (14:29 +0900)
src/ctl/alsactl.map
src/ctl/card.c
src/ctl/card.h
tests/alsactl-card

index 967f757d4af6256032c0c56d8d8a8795f869600a..dfabb9a72bce52af6af777baef172de74a7d4f42 100644 (file)
@@ -24,6 +24,7 @@ ALSA_GOBJECT_0_0_0 {
     "alsactl_card_add_elems";
     "alsactl_card_replace_elems";
     "alsactl_card_remove_elems";
+    "alsactl_card_create_source";
 
     "alsactl_card_info_get_type";
 
index d1e106b68d1a46cfe457dd6717e140b76cee9637..0a6247dca09d3ec2fb8f32310f1aff99998d7a2a 100644 (file)
@@ -15,6 +15,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <sys/ioctl.h>
+#include <unistd.h>
 
 struct _ALSACtlCardPrivate {
     int fd;
@@ -22,6 +23,14 @@ struct _ALSACtlCardPrivate {
 };
 G_DEFINE_TYPE_WITH_PRIVATE(ALSACtlCard, alsactl_card, G_TYPE_OBJECT)
 
+typedef struct {
+    GSource src;
+    ALSACtlCard *self;
+    gpointer tag;
+    void *buf;
+    unsigned int buf_len;
+} CtlCardSource;
+
 enum ctl_card_prop_type {
     CTL_CARD_PROP_DEVNODE = 1,
     CTL_CARD_PROP_COUNT,
@@ -633,3 +642,118 @@ void alsactl_card_remove_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
     if (ioctl(priv->fd, SNDRV_CTL_IOCTL_ELEM_REMOVE, elem_id) < 0)
         generate_error(error, errno);
 }
+
+static gboolean ctl_card_prepare_src(GSource *src, gint *timeout)
+{
+    *timeout = 500;
+
+    // This source is not ready, let's poll(2).
+    return FALSE;
+}
+
+static gboolean ctl_card_check_src(GSource *gsrc)
+{
+    CtlCardSource *src = (CtlCardSource *)gsrc;
+    GIOCondition condition;
+
+    // Don't go to dispatch if nothing available. As an exception, return TRUE
+    // for POLLERR to call .dispatch for internal destruction.
+    condition = g_source_query_unix_fd(gsrc, src->tag);
+    return !!(condition & (G_IO_IN | G_IO_ERR));
+}
+
+static gboolean ctl_card_dispatch_src(GSource *gsrc, GSourceFunc cb,
+                                      gpointer user_data)
+{
+    CtlCardSource *src = (CtlCardSource *)gsrc;
+    ALSACtlCard *self = src->self;
+    ALSACtlCardPrivate *priv;
+    GIOCondition condition;
+    int len;
+    struct snd_ctl_event *ev;
+
+    priv = alsactl_card_get_instance_private(self);
+    if (priv->fd < 0)
+        return G_SOURCE_REMOVE;
+
+    condition = g_source_query_unix_fd(gsrc, src->tag);
+    if (condition & G_IO_ERR)
+        return G_SOURCE_REMOVE;
+
+    len = read(priv->fd, src->buf, src->buf_len);
+    if (len < 0) {
+        if (errno == EAGAIN)
+            return G_SOURCE_CONTINUE;
+
+        return G_SOURCE_REMOVE;
+    }
+
+    ev = src->buf;
+    while (len >= sizeof(*ev)) {
+        // TODO: handle the event.
+
+        len -= sizeof(*ev);
+       ++ev;
+    }
+
+    // Just be sure to continue to process this source.
+    return G_SOURCE_CONTINUE;
+}
+
+static void ctl_card_finalize_src(GSource *gsrc)
+{
+    CtlCardSource *src = (CtlCardSource *)gsrc;
+
+    g_free(src->buf);
+    g_object_unref(src->self);
+}
+
+/**
+ * alsactl_card_create_source:
+ * @self: A #ALSACtlCard.
+ * @gsrc: (out): A #GSource to handle events from ALSA control character device.
+ * @error: A #GError.
+ *
+ * Allocate GSource structure to handle events from ALSA control character
+ * device.
+ */
+void alsactl_card_create_source(ALSACtlCard *self, GSource **gsrc,
+                                GError **error)
+{
+    static GSourceFuncs funcs = {
+            .prepare        = ctl_card_prepare_src,
+            .check          = ctl_card_check_src,
+            .dispatch       = ctl_card_dispatch_src,
+            .finalize       = ctl_card_finalize_src,
+    };
+    ALSACtlCardPrivate *priv;
+    CtlCardSource *src;
+    long page_size = sysconf(_SC_PAGESIZE);
+    void *buf;
+
+    g_return_if_fail(ALSACTL_IS_CARD(self));
+    priv = alsactl_card_get_instance_private(self);
+
+    if (priv->fd < 0) {
+        generate_error(error, ENXIO);
+        return;
+    }
+
+    buf = g_try_malloc0(page_size);
+    if (buf == NULL) {
+        generate_error(error, ENOMEM);
+        return;
+    }
+
+    *gsrc = g_source_new(&funcs, sizeof(CtlCardSource));
+    src = (CtlCardSource *)(*gsrc);
+
+    g_source_set_name(*gsrc, "ALSACtlCard");
+    g_source_set_priority(*gsrc, G_PRIORITY_HIGH_IDLE);
+    g_source_set_can_recurse(*gsrc, TRUE);
+
+    src->self = g_object_ref(self);
+    src->tag = g_source_add_unix_fd(*gsrc, priv->fd, G_IO_IN);
+    src->buf = buf;
+    src->buf_len = page_size;
+}
index 570b8a151d691037d6c36526905c41d6a36c759f..f5ea98ad64c2f887c7ad832b4a26312b074ed604 100644 (file)
@@ -86,6 +86,9 @@ void alsactl_card_replace_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
 void alsactl_card_remove_elems(ALSACtlCard *self, const ALSACtlElemId *elem_id,
                                GError **error);
 
+void alsactl_card_create_source(ALSACtlCard *self, GSource **gsrc,
+                                GError **error);
+
 G_END_DECLS
 
 #endif
index fc68e234f7df98f90662366e6a38d70b8facfd01..a43fa9b60cf780877e768a621c4a8474197d22cd 100644 (file)
@@ -26,6 +26,7 @@ methods = (
     'add_elems',
     'replace_elems',
     'remove_elems',
+    'create_source',
 )
 signals = ()