]> git.alsa-project.org Git - alsa-gobject.git/commitdiff
seq: user_client: emit 'handle_event' signal
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/user-client.c

index 2471e7f2a29edb61f21401c7e0d20e2b8693601c..7aaad9368d69be7e1dc9a80767b1feea3aeb3f86 100644 (file)
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: LGPL-3.0-or-later
 #include "user-client.h"
 #include "query.h"
+#include "event-fixed.h"
+#include "event-variable.h"
 #include "privates.h"
 
 #include <sys/types.h>
@@ -22,6 +24,8 @@ typedef struct {
     gpointer tag;
     void *buf;
     size_t buf_len;
+    ALSASeqEventFixed *ev_fixed;
+    ALSASeqEventVariable *ev_var;
 } UserClientSource;
 
 enum seq_user_client_prop_type {
@@ -421,6 +425,8 @@ static gboolean seq_user_client_dispatch_src(GSource *gsrc, GSourceFunc cb,
     ALSASeqUserClientPrivate *priv;
     GIOCondition condition;
     int len;
+    guint8 *buf;
+    struct snd_seq_event *event;
 
     priv = alsaseq_user_client_get_instance_private(self);
     if (priv->fd < 0)
@@ -438,7 +444,53 @@ static gboolean seq_user_client_dispatch_src(GSource *gsrc, GSourceFunc cb,
         return G_SOURCE_REMOVE;
     }
 
-    // TODO: dispatch event.
+    buf = src->buf;
+    while (len >= sizeof(*event)) {
+        struct snd_seq_event *data_ptr;
+        ALSASeqEvent *ev;
+
+        event = (struct snd_seq_event *)buf;
+
+        buf += sizeof(*event);
+        len -= sizeof(*event);
+
+        // For variable length of event.
+        switch (event->flags & SNDRV_SEQ_EVENT_LENGTH_MASK) {
+        case SNDRV_SEQ_EVENT_LENGTH_FIXED:
+            ev = ALSASEQ_EVENT(src->ev_fixed);
+            break;
+        case SNDRV_SEQ_EVENT_LENGTH_VARIABLE:
+        {
+            unsigned int length = event->data.ext.len;
+            unsigned int offset = (length + sizeof(*event) - 1) / sizeof(*event);
+
+            // MEMO: Although ALSA Sequencer core never truncate the event,
+            // let's skip it for safe.
+            if (length == 0 || len < offset)
+                break;
+
+            event->data.ext.ptr = buf;
+            buf += offset;
+            len -= offset;
+
+            ev = ALSASEQ_EVENT(src->ev_var);
+            break;
+        }
+        case SNDRV_SEQ_EVENT_LENGTH_VARUSR:
+            // Unsupported since it handles raw pointer which is difficult to
+            // be exposed by interfaces capable for g-i.
+        default:
+            continue;
+        }
+
+        // Copy event cell (= 28 bytes).
+        seq_event_refer_private(ev, &data_ptr);
+        *data_ptr = *event;
+
+        g_signal_emit(self,
+                    seq_user_client_sigs[SEQ_USER_CLIENT_SIG_TYPE_HANDLE_EVENT],
+                    0, ev);
+    }
 
     // Just be sure to continue to process this source.
     return G_SOURCE_CONTINUE;
@@ -448,6 +500,9 @@ static void seq_user_client_finalize_src(GSource *gsrc)
 {
     UserClientSource *src = (UserClientSource *)gsrc;
 
+    g_object_unref(src->ev_fixed);
+    g_object_unref(src->ev_var);
+
     g_free(src->buf);
     g_object_unref(src->self);
 }
@@ -490,6 +545,9 @@ void alsaseq_user_client_create_source(ALSASeqUserClient *self,
     *gsrc = g_source_new(&funcs, sizeof(*src));
     src = (UserClientSource *)(*gsrc);
 
+    src->ev_fixed = g_object_new(ALSASEQ_TYPE_EVENT_FIXED, NULL);
+    src->ev_var = g_object_new(ALSASEQ_TYPE_EVENT_VARIABLE, NULL);
+
     g_source_set_name(*gsrc, "ALSASeqUserClient");
     g_source_set_priority(*gsrc, G_PRIORITY_HIGH_IDLE);
     g_source_set_can_recurse(*gsrc, TRUE);