]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
seq: user_client: add an API to create GSource
authorTakashi Sakamoto <o-takashi@sakamocchi.jp>
Wed, 1 Apr 2020 09:13:28 +0000 (18:13 +0900)
committer坂本 貴史 <o-takashi@sakamocchi.jp>
Fri, 3 Apr 2020 13:06:25 +0000 (22:06 +0900)
Signed-off-by: Takashi Sakamoto <o-takashi@sakamocchi.jp>
src/seq/alsaseq.map
src/seq/user-client.c
src/seq/user-client.h
tests/alsaseq-user-client

index 9b0f883202d8cc77d173a1792bd44937da75f09b..85998bb2802d6ccfbf5a0dfe833f16de2478892e 100644 (file)
@@ -43,6 +43,7 @@ ALSA_GOBJECT_0_0_0 {
     "alsaseq_user_client_set_pool";
     "alsaseq_user_client_get_pool";
     "alsaseq_user_client_schedule_event";
+    "alsaseq_user_client_create_source";
 
     "alsaseq_addr_get_type";
     "alsaseq_addr_new";
index 383643833fb6c99b1447c8504d97e5f6f36c60ed..e8c5367391996dc57c775d5c61a1bc3d3f12724c 100644 (file)
@@ -16,6 +16,14 @@ struct _ALSASeqUserClientPrivate {
 };
 G_DEFINE_TYPE_WITH_PRIVATE(ALSASeqUserClient, alsaseq_user_client, G_TYPE_OBJECT)
 
+typedef struct {
+    GSource src;
+    ALSASeqUserClient *self;
+    gpointer tag;
+    void *buf;
+    size_t buf_len;
+} UserClientSource;
+
 enum seq_user_client_prop_type {
     SEQ_USER_CLIENT_PROP_CLIENT_ID = 1,
     SEQ_USER_CLIENT_PROP_COUNT,
@@ -371,3 +379,101 @@ void alsaseq_user_client_schedule_event(ALSASeqUserClient *self,
     if (ptr != NULL)
         g_free(ptr);
 }
+
+static gboolean seq_user_client_check_src(GSource *gsrc)
+{
+    UserClientSource *src = (UserClientSource *)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 seq_user_client_dispatch_src(GSource *gsrc, GSourceFunc cb,
+                                             gpointer user_data)
+{
+    UserClientSource *src = (UserClientSource *)gsrc;
+    ALSASeqUserClient *self = src->self;
+    ALSASeqUserClientPrivate *priv;
+    GIOCondition condition;
+    int len;
+
+    priv = alsaseq_user_client_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;
+    }
+
+    // TODO: dispatch event.
+
+    // Just be sure to continue to process this source.
+    return G_SOURCE_CONTINUE;
+}
+
+static void seq_user_client_finalize_src(GSource *gsrc)
+{
+    UserClientSource *src = (UserClientSource *)gsrc;
+
+    g_free(src->buf);
+    g_object_unref(src->self);
+}
+
+/**
+ * alsaseq_user_client_create_source:
+ * @self: A #ALSASeqUserClient.
+ * @gsrc: (out): A #GSource to handle events from ALSA seq character device.
+ * @error: A #GError.
+ *
+ * Allocate GSource structure to handle events from ALSA seq character device.
+ */
+void alsaseq_user_client_create_source(ALSASeqUserClient *self,
+                                       GSource **gsrc, GError **error)
+{
+    static GSourceFuncs funcs = {
+            .check          = seq_user_client_check_src,
+            .dispatch       = seq_user_client_dispatch_src,
+            .finalize       = seq_user_client_finalize_src,
+    };
+    ALSASeqUserClientPrivate *priv;
+    UserClientSource *src;
+    void *buf;
+    long page_size = sysconf(_SC_PAGESIZE);
+
+    g_return_if_fail(ALSASEQ_IS_USER_CLIENT(self));
+    priv = alsaseq_user_client_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(*src));
+    src = (UserClientSource *)(*gsrc);
+
+    g_source_set_name(*gsrc, "ALSASeqUserClient");
+    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 8db8f8daf36110ec5dc25d2adb7534585200d37f..c3ba52472796b12c96915df76c04494f63877890 100644 (file)
@@ -85,6 +85,9 @@ void alsaseq_user_client_get_pool(ALSASeqUserClient *self,
 void alsaseq_user_client_schedule_event(ALSASeqUserClient *self,
                                         ALSASeqEvent *event, GError **error);
 
+void alsaseq_user_client_create_source(ALSASeqUserClient *self,
+                                       GSource **gsrc, GError **error);
+
 G_END_DECLS
 
 #endif
index f2c3b6743704970ebb136d05bb18f7c618bd2924..fd84fc2f6d5bc1059a455d43400ff3a6a2e51378 100644 (file)
@@ -24,6 +24,7 @@ methods = (
     'set_pool',
     'get_pool',
     'schedule_event',
+    'create_source',
 )
 signals = ()