From 3a9ba29562427e1754082f2ccc1095a775e0c348 Mon Sep 17 00:00:00 2001 From: Takashi Sakamoto Date: Wed, 1 Apr 2020 18:13:28 +0900 Subject: [PATCH] seq: user_client: emit 'handle_event' signal Signed-off-by: Takashi Sakamoto --- src/seq/user-client.c | 60 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/src/seq/user-client.c b/src/seq/user-client.c index 2471e7f..7aaad93 100644 --- a/src/seq/user-client.c +++ b/src/seq/user-client.c @@ -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 @@ -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); -- 2.47.3