From 8fac22afdb6a395a5be0cd4b2de2204a985df952 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Oct 2016 16:26:55 +0200 Subject: [PATCH] Work on main loop Make a main-loop object with associated helper functions to handle async methods. rtloop -> data_loop Handle async results a lot better. Remove REMOVE_MEM command. We don't need it. Handle stream memory updates better. --- pinos/client/connection.c | 15 +- pinos/client/connection.h | 9 - pinos/client/meson.build | 4 +- pinos/client/pinos.h | 2 +- pinos/client/stream.c | 39 +-- .../client/{mainloop.c => thread-mainloop.c} | 192 +++++------ pinos/client/thread-mainloop.h | 84 +++++ pinos/gst/gstpinosdeviceprovider.c | 22 +- pinos/gst/gstpinosdeviceprovider.h | 2 +- pinos/gst/gstpinossink.c | 52 +-- pinos/gst/gstpinossink.h | 2 +- pinos/gst/gstpinossrc.c | 74 ++--- pinos/gst/gstpinossrc.h | 2 +- pinos/server/client-node.c | 3 - pinos/server/daemon.c | 157 +++------ pinos/server/daemon.h | 8 +- pinos/server/{rt-loop.c => data-loop.c} | 110 +++--- pinos/server/data-loop.h | 71 ++++ pinos/server/link.c | 94 ++++-- pinos/server/link.h | 1 + pinos/server/main-loop.c | 313 ++++++++++++++++++ .../{client/mainloop.h => server/main-loop.h} | 53 +-- pinos/server/meson.build | 6 +- pinos/server/node.c | 111 +++---- pinos/server/rt-loop.h | 79 ----- spa/include/spa/node.h | 4 +- 26 files changed, 926 insertions(+), 583 deletions(-) rename pinos/client/{mainloop.c => thread-mainloop.c} (60%) create mode 100644 pinos/client/thread-mainloop.h rename pinos/server/{rt-loop.c => data-loop.c} (67%) create mode 100644 pinos/server/data-loop.h create mode 100644 pinos/server/main-loop.c rename pinos/{client/mainloop.h => server/main-loop.h} (59%) delete mode 100644 pinos/server/rt-loop.h diff --git a/pinos/client/connection.c b/pinos/client/connection.c index f6e46e3f7..e6254889d 100644 --- a/pinos/client/connection.c +++ b/pinos/client/connection.c @@ -421,7 +421,7 @@ refill_buffer (PinosConnection *conn, ConnectionBuffer *buf) buf->n_fds = (cmsg->cmsg_len - ((char *)CMSG_DATA (cmsg) - (char *)cmsg)) / sizeof (int); memcpy (buf->fds, CMSG_DATA (cmsg), buf->n_fds * sizeof (int)); } - PINOS_DEBUG_CONTROL ("connection %p: %d read %zd bytes and %d fds\n", conn, conn->fd, len, buf->n_fds); + PINOS_DEBUG_CONTROL ("connection %p: %d read %zd bytes and %d fds", conn, conn->fd, len, buf->n_fds); return TRUE; @@ -594,12 +594,6 @@ pinos_connection_parse_cmd (PinosConnection *conn, memcpy (command, conn->in.data, sizeof (PinosControlCmdAddMem)); break; - case PINOS_CONTROL_CMD_REMOVE_MEM: - if (conn->in.size < sizeof (PinosControlCmdRemoveMem)) - return FALSE; - memcpy (command, conn->in.data, sizeof (PinosControlCmdRemoveMem)); - break; - case PINOS_CONTROL_CMD_USE_BUFFERS: connection_parse_use_buffers (conn, command); break; @@ -748,11 +742,6 @@ pinos_connection_add_cmd (PinosConnection *conn, memcpy (p, command, sizeof (PinosControlCmdAddMem)); break; - case PINOS_CONTROL_CMD_REMOVE_MEM: - p = connection_add_cmd (conn, cmd, sizeof (PinosControlCmdRemoveMem)); - memcpy (p, command, sizeof (PinosControlCmdRemoveMem)); - break; - case PINOS_CONTROL_CMD_USE_BUFFERS: connection_add_use_buffers (conn, command); break; @@ -830,7 +819,7 @@ pinos_connection_flush (PinosConnection *conn) buf->buffer_size -= len; buf->n_fds = 0; - PINOS_DEBUG_CONTROL ("connection %p: %d written %zd bytes and %u fds\n", conn, conn->fd, len, buf->n_fds); + PINOS_DEBUG_CONTROL ("connection %p: %d written %zd bytes and %u fds", conn, conn->fd, len, buf->n_fds); return TRUE; diff --git a/pinos/client/connection.h b/pinos/client/connection.h index e76823f8d..165e58d9d 100644 --- a/pinos/client/connection.h +++ b/pinos/client/connection.h @@ -52,8 +52,6 @@ typedef enum { /* both */ PINOS_CONTROL_CMD_ADD_MEM = 64, - PINOS_CONTROL_CMD_REMOVE_MEM = 65, - PINOS_CONTROL_CMD_USE_BUFFERS = 66, PINOS_CONTROL_CMD_PROCESS_BUFFER = 67, @@ -146,13 +144,6 @@ typedef struct { size_t size; } PinosControlCmdAddMem; -/* PINOS_CONTROL_CMD_REMOVE_MEM */ -typedef struct { - SpaDirection direction; - uint32_t port_id; - uint32_t mem_id; -} PinosControlCmdRemoveMem; - typedef struct { uint32_t mem_id; off_t offset; diff --git a/pinos/client/meson.build b/pinos/client/meson.build index 5474e7ac0..dc12c9621 100644 --- a/pinos/client/meson.build +++ b/pinos/client/meson.build @@ -2,12 +2,12 @@ pinos_headers = [ 'context.h', 'format.h', 'introspect.h', - 'mainloop.h', 'pinos.h', 'properties.h', 'stream.h', 'ringbuffer.h', 'subscribe.h', + 'thread-mainloop.h', ] pinos_sources = [ @@ -15,13 +15,13 @@ pinos_sources = [ 'context.c', 'format.c', 'introspect.c', - 'mainloop.c', 'properties.c', 'serialize.c', 'stream.c', 'pinos.c', 'ringbuffer.c', 'subscribe.c', + 'thread-mainloop.c', gdbus_target, ] diff --git a/pinos/client/pinos.h b/pinos/client/pinos.h index e5157caf9..47d4a8ad4 100644 --- a/pinos/client/pinos.h +++ b/pinos/client/pinos.h @@ -25,7 +25,7 @@ extern const char g_log_domain_pinos[]; #include #include #include -#include +#include #include #include #include diff --git a/pinos/client/stream.c b/pinos/client/stream.c index d43c7747a..7f993c8df 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -992,7 +992,7 @@ parse_connection (PinosStream *stream) { PinosControlCmdAddMem p; int fd; - MemId mid; + MemId mid, *m; if (!pinos_connection_parse_cmd (conn, &p)) break; @@ -1001,27 +1001,25 @@ parse_connection (PinosStream *stream) if (fd == -1) break; - mid.id = p.mem_id; - mid.fd = fd; - mid.flags = p.flags; - mid.ptr = NULL; - mid.size = p.size; + m = find_mem (stream, p.mem_id); + if (m) { + g_debug ("update mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size); - g_debug ("add mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size); - g_array_append_val (priv->mem_ids, mid); - break; - } - case PINOS_CONTROL_CMD_REMOVE_MEM: - { - PinosControlCmdRemoveMem p; - MemId *mid; + m->id = p.mem_id; + m->fd = fd; + m->flags = p.flags; + m->ptr = NULL; + m->size = p.size; + } else { + mid.id = p.mem_id; + mid.fd = fd; + mid.flags = p.flags; + mid.ptr = NULL; + mid.size = p.size; - if (!pinos_connection_parse_cmd (conn, &p)) - break; - - g_debug ("stream %p: remove mem %d", stream, p.mem_id); - if ((mid = find_mem (stream, p.mem_id))) - mid->cleanup = true; + g_debug ("add mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size); + g_array_append_val (priv->mem_ids, mid); + } break; } case PINOS_CONTROL_CMD_USE_BUFFERS: @@ -1181,7 +1179,6 @@ parse_rtconnection (PinosStream *stream) case PINOS_CONTROL_CMD_SET_FORMAT: case PINOS_CONTROL_CMD_SET_PROPERTY: case PINOS_CONTROL_CMD_ADD_MEM: - case PINOS_CONTROL_CMD_REMOVE_MEM: case PINOS_CONTROL_CMD_USE_BUFFERS: case PINOS_CONTROL_CMD_NODE_COMMAND: g_warning ("got unexpected connection %d", cmd); diff --git a/pinos/client/mainloop.c b/pinos/client/thread-mainloop.c similarity index 60% rename from pinos/client/mainloop.c rename to pinos/client/thread-mainloop.c index 24d246f0d..c754d3962 100644 --- a/pinos/client/mainloop.c +++ b/pinos/client/thread-mainloop.c @@ -18,9 +18,9 @@ */ #include "pinos.h" -#include "mainloop.h" +#include "thread-mainloop.h" -struct _PinosMainLoopPrivate +struct _PinosThreadMainLoopPrivate { GMainContext *maincontext; GMainLoop *mainloop; @@ -38,10 +38,10 @@ struct _PinosMainLoopPrivate gint n_waiting_for_accept; }; -#define PINOS_MAIN_LOOP_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_MAIN_LOOP, PinosMainLoopPrivate)) +#define PINOS_THREAD_MAIN_LOOP_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopPrivate)) -G_DEFINE_TYPE (PinosMainLoop, pinos_main_loop, G_TYPE_OBJECT); +G_DEFINE_TYPE (PinosThreadMainLoop, pinos_thread_main_loop, G_TYPE_OBJECT); enum { @@ -52,13 +52,13 @@ enum }; static void -pinos_main_loop_get_property (GObject *_object, +pinos_thread_main_loop_get_property (GObject *_object, guint prop_id, GValue *value, GParamSpec *pspec) { - PinosMainLoop *loop = PINOS_MAIN_LOOP (_object); - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object); + PinosThreadMainLoopPrivate *priv = loop->priv; switch (prop_id) { case PROP_MAIN_CONTEXT: @@ -80,13 +80,13 @@ pinos_main_loop_get_property (GObject *_object, } static void -pinos_main_loop_set_property (GObject *_object, +pinos_thread_main_loop_set_property (GObject *_object, guint prop_id, const GValue *value, GParamSpec *pspec) { - PinosMainLoop *loop = PINOS_MAIN_LOOP (_object); - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object); + PinosThreadMainLoopPrivate *priv = loop->priv; switch (prop_id) { case PROP_MAIN_CONTEXT: @@ -104,22 +104,22 @@ pinos_main_loop_set_property (GObject *_object, } static void -pinos_main_loop_constructed (GObject * object) +pinos_thread_main_loop_constructed (GObject * object) { - PinosMainLoop *loop = PINOS_MAIN_LOOP (object); - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object); + PinosThreadMainLoopPrivate *priv = loop->priv; priv->mainloop = g_main_loop_new (priv->maincontext, FALSE); - g_debug ("mainloop %p: contructed %p %p", loop, priv->maincontext, priv->mainloop); + g_debug ("thread-mainloop %p: contructed %p %p", loop, priv->maincontext, priv->mainloop); - G_OBJECT_CLASS (pinos_main_loop_parent_class)->constructed (object); + G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->constructed (object); } static void -pinos_main_loop_finalize (GObject * object) +pinos_thread_main_loop_finalize (GObject * object) { - PinosMainLoop *loop = PINOS_MAIN_LOOP (object); - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object); + PinosThreadMainLoopPrivate *priv = loop->priv; if (priv->maincontext) g_main_context_unref (priv->maincontext); @@ -130,23 +130,23 @@ pinos_main_loop_finalize (GObject * object) g_cond_clear (&priv->cond); g_cond_clear (&priv->accept_cond); - G_OBJECT_CLASS (pinos_main_loop_parent_class)->finalize (object); + G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->finalize (object); } static void -pinos_main_loop_class_init (PinosMainLoopClass * klass) +pinos_thread_main_loop_class_init (PinosThreadMainLoopClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - g_type_class_add_private (klass, sizeof (PinosMainLoopPrivate)); + g_type_class_add_private (klass, sizeof (PinosThreadMainLoopPrivate)); - gobject_class->constructed = pinos_main_loop_constructed; - gobject_class->finalize = pinos_main_loop_finalize; - gobject_class->set_property = pinos_main_loop_set_property; - gobject_class->get_property = pinos_main_loop_get_property; + gobject_class->constructed = pinos_thread_main_loop_constructed; + gobject_class->finalize = pinos_thread_main_loop_finalize; + gobject_class->set_property = pinos_thread_main_loop_set_property; + gobject_class->get_property = pinos_thread_main_loop_get_property; /** - * PinosMainLoop:main-context + * PinosThreadMainLoop:main-context * * The GMainContext of the loop. */ @@ -160,7 +160,7 @@ pinos_main_loop_class_init (PinosMainLoopClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** - * PinosMainLoop:name + * PinosThreadMainLoop:name * * The name of the loop as specified at construction time. */ @@ -174,7 +174,7 @@ pinos_main_loop_class_init (PinosMainLoopClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** - * PinosMainLoop:main-loop + * PinosThreadMainLoop:main-loop * * The GMainLoop of the loop. */ @@ -189,9 +189,9 @@ pinos_main_loop_class_init (PinosMainLoopClass * klass) } static void -pinos_main_loop_init (PinosMainLoop * loop) +pinos_thread_main_loop_init (PinosThreadMainLoop * loop) { - PinosMainLoopPrivate *priv = loop->priv = PINOS_MAIN_LOOP_GET_PRIVATE (loop); + PinosThreadMainLoopPrivate *priv = loop->priv = PINOS_THREAD_MAIN_LOOP_GET_PRIVATE (loop); g_mutex_init (&priv->lock); g_cond_init (&priv->cond); @@ -199,21 +199,21 @@ pinos_main_loop_init (PinosMainLoop * loop) } /** - * pinos_main_loop_new: + * pinos_thread_main_loop_new: * @context: a #GMainContext * @name: a thread name * - * Make a new #PinosMainLoop that will run a mainloop on @context in + * Make a new #PinosThreadMainLoop that will run a mainloop on @context in * a thread with @name. * - * Returns: a #PinosMainLoop + * Returns: a #PinosThreadMainLoop */ -PinosMainLoop * -pinos_main_loop_new (GMainContext * context, const gchar *name) +PinosThreadMainLoop * +pinos_thread_main_loop_new (GMainContext * context, const gchar *name) { - PinosMainLoop *loop; + PinosThreadMainLoop *loop; - loop = g_object_new (PINOS_TYPE_MAIN_LOOP, + loop = g_object_new (PINOS_TYPE_THREAD_MAIN_LOOP, "main-context", context, "name", name, NULL); @@ -221,8 +221,8 @@ pinos_main_loop_new (GMainContext * context, const gchar *name) } /** - * pinos_main_loop_get_impl: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_get_impl: + * @loop: a #PinosThreadMainLoop * * Get the #GMainLoop used by @loop. * @@ -230,11 +230,11 @@ pinos_main_loop_new (GMainContext * context, const gchar *name) * @loop is valid. */ GMainLoop * -pinos_main_loop_get_impl (PinosMainLoop *loop) +pinos_thread_main_loop_get_impl (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), NULL); + g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), NULL); priv = loop->priv; @@ -247,8 +247,8 @@ static gint do_poll (GPollFD *ufds, guint nfsd, gint timeout_) { gint res; - PinosMainLoop *loop = g_private_get (&loop_key); - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoop *loop = g_private_get (&loop_key); + PinosThreadMainLoopPrivate *priv = loop->priv; g_mutex_unlock (&priv->lock); res = priv->poll_func (ufds, nfsd, timeout_); @@ -258,9 +258,9 @@ do_poll (GPollFD *ufds, guint nfsd, gint timeout_) } static gpointer -handle_mainloop (PinosMainLoop *loop) +handle_mainloop (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoopPrivate *priv = loop->priv; g_mutex_lock (&priv->lock); g_private_set (&loop_key, loop); @@ -269,9 +269,9 @@ handle_mainloop (PinosMainLoop *loop) g_main_context_set_poll_func (priv->maincontext, do_poll); g_main_context_push_thread_default (priv->maincontext); - g_debug ("mainloop %p: run mainloop %p context %p", loop, priv->mainloop, priv->maincontext); + g_debug ("thread-mainloop %p: run mainloop %p context %p", loop, priv->mainloop, priv->maincontext); g_main_loop_run (priv->mainloop); - g_debug ("mainloop %p: done", loop); + g_debug ("thread-mainloop %p: done", loop); g_main_context_pop_thread_default (priv->maincontext); g_main_context_set_poll_func (priv->maincontext, priv->poll_func); @@ -283,8 +283,8 @@ handle_mainloop (PinosMainLoop *loop) /** - * pinos_main_loop_start: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_start: + * @loop: a #PinosThreadMainLoop * @error: am optional #GError * * Start the thread to handle @loop. @@ -293,11 +293,11 @@ handle_mainloop (PinosMainLoop *loop) * and @error will contain more information. */ gboolean -pinos_main_loop_start (PinosMainLoop *loop, GError **error) +pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), FALSE); + g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE); priv = loop->priv; g_return_val_if_fail (priv->thread == NULL, FALSE); @@ -307,21 +307,21 @@ pinos_main_loop_start (PinosMainLoop *loop, GError **error) } /** - * pinos_main_loop_stop: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_stop: + * @loop: a #PinosThreadMainLoop * * Quit the main loop and stop its thread. */ void -pinos_main_loop_stop (PinosMainLoop *loop) +pinos_thread_main_loop_stop (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; g_return_if_fail (priv->thread != NULL); - g_return_if_fail (!pinos_main_loop_in_thread (loop)); + g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); g_mutex_lock (&priv->lock); g_main_loop_quit (priv->mainloop); @@ -332,54 +332,54 @@ pinos_main_loop_stop (PinosMainLoop *loop) } /** - * pinos_main_loop_lock: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_lock: + * @loop: a #PinosThreadMainLoop * * Lock the mutex associated with @loop. */ void -pinos_main_loop_lock (PinosMainLoop *loop) +pinos_thread_main_loop_lock (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; - g_return_if_fail (!pinos_main_loop_in_thread (loop)); + g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); g_mutex_lock (&priv->lock); } /** - * pinos_main_loop_unlock: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_unlock: + * @loop: a #PinosThreadMainLoop * * Unlock the mutex associated with @loop. */ void -pinos_main_loop_unlock (PinosMainLoop *loop) +pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; - g_return_if_fail (!pinos_main_loop_in_thread (loop)); + g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); g_mutex_unlock (&priv->lock); } /** - * pinos_main_loop_signal: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_signal: + * @loop: a #PinosThreadMainLoop * * Signal the main thread of @loop. If @wait_for_accept is %TRUE, - * this function waits until pinos_main_loop_accept() is called. + * this function waits until pinos_thread_main_loop_accept() is called. */ void -pinos_main_loop_signal (PinosMainLoop *loop, gboolean wait_for_accept) +pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_accept) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; if (priv->n_waiting > 0) @@ -394,19 +394,19 @@ pinos_main_loop_signal (PinosMainLoop *loop, gboolean wait_for_accept) } /** - * pinos_main_loop_wait: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_wait: + * @loop: a #PinosThreadMainLoop * - * Wait for the loop thread to call pinos_main_loop_signal(). + * Wait for the loop thread to call pinos_thread_main_loop_signal(). */ void -pinos_main_loop_wait (PinosMainLoop *loop) +pinos_thread_main_loop_wait (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; - g_return_if_fail (!pinos_main_loop_in_thread (loop)); + g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); priv->n_waiting ++; @@ -417,19 +417,19 @@ pinos_main_loop_wait (PinosMainLoop *loop) } /** - * pinos_main_loop_accept: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_accept: + * @loop: a #PinosThreadMainLoop * - * Signal the loop thread waiting for accept with pinos_main_loop_signal(). + * Signal the loop thread waiting for accept with pinos_thread_main_loop_signal(). */ void -pinos_main_loop_accept (PinosMainLoop *loop) +pinos_thread_main_loop_accept (PinosThreadMainLoop *loop) { - PinosMainLoopPrivate *priv; + PinosThreadMainLoopPrivate *priv; - g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); priv = loop->priv; - g_return_if_fail (!pinos_main_loop_in_thread (loop)); + g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); g_assert (priv->n_waiting_for_accept > 0); priv->n_waiting_for_accept--; @@ -438,17 +438,17 @@ pinos_main_loop_accept (PinosMainLoop *loop) } /** - * pinos_main_loop_in_thread: - * @loop: a #PinosMainLoop + * pinos_thread_main_loop_in_thread: + * @loop: a #PinosThreadMainLoop * * Check if we are inside the thread of @loop. * * Returns: %TRUE when called inside the thread of @loop. */ gboolean -pinos_main_loop_in_thread (PinosMainLoop *loop) +pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop) { - g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), FALSE); + g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE); return g_thread_self() == loop->priv->thread; } diff --git a/pinos/client/thread-mainloop.h b/pinos/client/thread-mainloop.h new file mode 100644 index 000000000..df8e8801e --- /dev/null +++ b/pinos/client/thread-mainloop.h @@ -0,0 +1,84 @@ +/* Pinos + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PINOS_THREAD_MAIN_LOOP_H__ +#define __PINOS_THREAD_MAIN_LOOP_H__ + +#include + +G_BEGIN_DECLS + +#define PINOS_TYPE_THREAD_MAIN_LOOP (pinos_thread_main_loop_get_type ()) +#define PINOS_IS_THREAD_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_THREAD_MAIN_LOOP)) +#define PINOS_IS_THREAD_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_THREAD_MAIN_LOOP)) +#define PINOS_THREAD_MAIN_LOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopClass)) +#define PINOS_THREAD_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoop)) +#define PINOS_THREAD_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopClass)) +#define PINOS_THREAD_MAIN_LOOP_CAST(obj) ((PinosThreadMainLoop*)(obj)) +#define PINOS_THREAD_MAIN_LOOP_CLASS_CAST(klass) ((PinosThreadMainLoopClass*)(klass)) + +typedef struct _PinosThreadMainLoop PinosThreadMainLoop; +typedef struct _PinosThreadMainLoopClass PinosThreadMainLoopClass; +typedef struct _PinosThreadMainLoopPrivate PinosThreadMainLoopPrivate; + + +/** + * PinosThreadMainLoop: + * + * Pinos main loop object class. + */ +struct _PinosThreadMainLoop { + GObject object; + + PinosThreadMainLoopPrivate *priv; +}; + +/** + * PinosThreadMainLoopClass: + * + * Pinos main loop object class. + */ +struct _PinosThreadMainLoopClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType pinos_thread_main_loop_get_type (void); + +PinosThreadMainLoop * pinos_thread_main_loop_new (GMainContext * context, + const gchar *name); + +GMainLoop * pinos_thread_main_loop_get_impl (PinosThreadMainLoop *loop); + +gboolean pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error); +void pinos_thread_main_loop_stop (PinosThreadMainLoop *loop); + +void pinos_thread_main_loop_lock (PinosThreadMainLoop *loop); +void pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop); + +void pinos_thread_main_loop_wait (PinosThreadMainLoop *loop); +void pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_accept); +void pinos_thread_main_loop_accept (PinosThreadMainLoop *loop); + +gboolean pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop); + + +G_END_DECLS + +#endif /* __PINOS_THREAD_MAIN_LOOP_H__ */ diff --git a/pinos/gst/gstpinosdeviceprovider.c b/pinos/gst/gstpinosdeviceprovider.c index 32ec0949c..2d3e105d0 100644 --- a/pinos/gst/gstpinosdeviceprovider.c +++ b/pinos/gst/gstpinosdeviceprovider.c @@ -451,7 +451,7 @@ context_state_notify (GObject *gobject, pinos_context_get_error (context)->message); break; } - pinos_main_loop_signal (self->loop, FALSE); + pinos_thread_main_loop_signal (self->loop, FALSE); } static gboolean @@ -465,23 +465,23 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) c = g_main_context_new (); - if (!(self->loop = pinos_main_loop_new (c, "pinos-device-monitor"))) { + if (!(self->loop = pinos_thread_main_loop_new (c, "pinos-device-monitor"))) { GST_ERROR_OBJECT (self, "Could not create pinos mainloop"); goto failed; } - if (!pinos_main_loop_start (self->loop, &error)) { + if (!pinos_thread_main_loop_start (self->loop, &error)) { GST_ERROR_OBJECT (self, "Could not start pinos mainloop: %s", error->message); g_clear_object (&self->loop); goto failed; } - pinos_main_loop_lock (self->loop); + pinos_thread_main_loop_lock (self->loop); if (!(self->context = pinos_context_new (c, self->client_name, NULL))) { GST_ERROR_OBJECT (self, "Failed to create context"); - pinos_main_loop_unlock (self->loop); - pinos_main_loop_stop (self->loop); + pinos_thread_main_loop_unlock (self->loop); + pinos_thread_main_loop_stop (self->loop); g_clear_object (&self->loop); goto failed; } @@ -515,7 +515,7 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) break; /* Wait until something happens */ - pinos_main_loop_wait (self->loop); + pinos_thread_main_loop_wait (self->loop); } GST_DEBUG_OBJECT (self, "connected"); pinos_context_get_daemon_info (self->context, @@ -524,7 +524,7 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) NULL, NULL, self); - pinos_main_loop_unlock (self->loop); + pinos_thread_main_loop_unlock (self->loop); g_main_context_unref (c); @@ -537,8 +537,8 @@ failed: } not_running: { - pinos_main_loop_unlock (self->loop); - pinos_main_loop_stop (self->loop); + pinos_thread_main_loop_unlock (self->loop); + pinos_thread_main_loop_stop (self->loop); g_clear_object (&self->context); g_clear_object (&self->loop); return TRUE; @@ -554,7 +554,7 @@ gst_pinos_device_provider_stop (GstDeviceProvider * provider) pinos_context_disconnect (self->context); } if (self->loop) { - pinos_main_loop_stop (self->loop); + pinos_thread_main_loop_stop (self->loop); } g_clear_object (&self->context); g_clear_object (&self->loop); diff --git a/pinos/gst/gstpinosdeviceprovider.h b/pinos/gst/gstpinosdeviceprovider.h index db0e771ee..49115389d 100644 --- a/pinos/gst/gstpinosdeviceprovider.h +++ b/pinos/gst/gstpinosdeviceprovider.h @@ -82,7 +82,7 @@ struct _GstPinosDeviceProvider { gchar *client_name; GMainContext *maincontext; - PinosMainLoop *loop; + PinosThreadMainLoop *loop; PinosContext *context; }; diff --git a/pinos/gst/gstpinossink.c b/pinos/gst/gstpinossink.c index 8e31ec0bf..9c8198036 100644 --- a/pinos/gst/gstpinossink.c +++ b/pinos/gst/gstpinossink.c @@ -415,7 +415,7 @@ on_add_buffer (GObject *gobject, gst_pinos_pool_add_buffer (pinossink->pool, buf); g_hash_table_insert (pinossink->buf_ids, GINT_TO_POINTER (id), buf); - pinos_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->loop, FALSE); } static void @@ -450,7 +450,7 @@ on_new_buffer (GObject *gobject, buf = g_hash_table_lookup (pinossink->buf_ids, GINT_TO_POINTER (id)); if (buf) { - pinos_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->loop, FALSE); } } @@ -479,7 +479,7 @@ on_stream_notify (GObject *gobject, pinos_stream_get_error (stream)->message), (NULL)); break; } - pinos_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->loop, FALSE); } static void @@ -528,7 +528,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) possible = gst_caps_to_format_all (caps); - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); state = pinos_stream_get_state (pinossink->stream); if (state == PINOS_STREAM_STATE_ERROR) @@ -556,7 +556,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->loop); } } res = TRUE; @@ -574,11 +574,11 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->loop); } } #endif - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); pinossink->negotiated = res; @@ -587,7 +587,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) start_error: { GST_ERROR ("could not start stream"); - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); g_ptr_array_unref (possible); return FALSE; } @@ -606,7 +606,7 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) if (!pinossink->negotiated) goto not_negotiated; - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); if (pinos_stream_get_state (pinossink->stream) != PINOS_STREAM_STATE_STREAMING) goto done; // goto streaming_error; @@ -639,7 +639,7 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) g_warning ("can't send buffer"); done: - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); return GST_FLOW_OK; @@ -649,7 +649,7 @@ not_negotiated: } //streaming_error: // { -// pinos_main_loop_unlock (pinossink->loop); +// pinos_thread_main_loop_unlock (pinossink->loop); // return GST_FLOW_ERROR; // } } @@ -683,7 +683,7 @@ gst_pinos_sink_start (GstBaseSink * basesink) props = NULL; } - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); pinossink->stream = pinos_stream_new (pinossink->ctx, pinossink->client_name, props); pinossink->pool->stream = pinossink->stream; g_signal_connect (pinossink->stream, "notify::state", (GCallback) on_stream_notify, pinossink); @@ -691,7 +691,7 @@ gst_pinos_sink_start (GstBaseSink * basesink) g_signal_connect (pinossink->stream, "add-buffer", (GCallback) on_add_buffer, pinossink); g_signal_connect (pinossink->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossink); g_signal_connect (pinossink->stream, "new-buffer", (GCallback) on_new_buffer, pinossink); - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); return TRUE; } @@ -701,14 +701,14 @@ gst_pinos_sink_stop (GstBaseSink * basesink) { GstPinosSink *pinossink = GST_PINOS_SINK (basesink); - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); if (pinossink->stream) { pinos_stream_stop (pinossink->stream); pinos_stream_disconnect (pinossink->stream); g_clear_object (&pinossink->stream); pinossink->pool->stream = NULL; } - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); pinossink->negotiated = FALSE; @@ -738,7 +738,7 @@ on_context_notify (GObject *gobject, pinos_context_get_error (pinossink->ctx)->message), (NULL)); break; } - pinos_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->loop, FALSE); } static gboolean @@ -749,11 +749,11 @@ gst_pinos_sink_open (GstPinosSink * pinossink) pinossink->context = g_main_context_new (); GST_DEBUG ("context %p", pinossink->context); - pinossink->loop = pinos_main_loop_new (pinossink->context, "pinos-sink-loop"); - if (!pinos_main_loop_start (pinossink->loop, &error)) + pinossink->loop = pinos_thread_main_loop_new (pinossink->context, "pinos-sink-loop"); + if (!pinos_thread_main_loop_start (pinossink->loop, &error)) goto mainloop_error; - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); pinossink->ctx = pinos_context_new (pinossink->context, g_get_application_name (), NULL); g_signal_connect (pinossink->ctx, "notify::state", (GCallback) on_context_notify, pinossink); @@ -768,9 +768,9 @@ gst_pinos_sink_open (GstPinosSink * pinossink) if (state == PINOS_CONTEXT_STATE_ERROR) goto connect_error; - pinos_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->loop); } - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); return TRUE; @@ -783,7 +783,7 @@ mainloop_error: } connect_error: { - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); return FALSE; } } @@ -791,7 +791,7 @@ connect_error: static gboolean gst_pinos_sink_close (GstPinosSink * pinossink) { - pinos_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->loop); if (pinossink->stream) { pinos_stream_disconnect (pinossink->stream); } @@ -807,12 +807,12 @@ gst_pinos_sink_close (GstPinosSink * pinossink) if (state == PINOS_CONTEXT_STATE_ERROR) break; - pinos_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->loop); } } - pinos_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->loop); - pinos_main_loop_stop (pinossink->loop); + pinos_thread_main_loop_stop (pinossink->loop); g_clear_object (&pinossink->loop); g_clear_object (&pinossink->stream); g_clear_object (&pinossink->ctx); diff --git a/pinos/gst/gstpinossink.h b/pinos/gst/gstpinossink.h index 4469c2061..59a23a208 100644 --- a/pinos/gst/gstpinossink.h +++ b/pinos/gst/gstpinossink.h @@ -78,7 +78,7 @@ struct _GstPinosSink { gboolean negotiated; GMainContext *context; - PinosMainLoop *loop; + PinosThreadMainLoop *loop; PinosContext *ctx; PinosStream *stream; GstAllocator *allocator; diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c index c54d170da..b033b5a07 100644 --- a/pinos/gst/gstpinossrc.c +++ b/pinos/gst/gstpinossrc.c @@ -479,7 +479,7 @@ on_new_buffer (GObject *gobject, } g_queue_push_tail (&pinossrc->queue, buf); - pinos_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->loop, FALSE); } return; } @@ -507,7 +507,7 @@ on_stream_notify (GObject *gobject, pinos_stream_get_error (pinossrc->stream)->message), (NULL)); break; } - pinos_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->loop, FALSE); } static void @@ -536,7 +536,7 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc) gboolean res; PinosProperties *props; - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); res = pinos_stream_start (pinossrc->stream); while (TRUE) { PinosStreamState state = pinos_stream_get_state (pinossrc->stream); @@ -547,26 +547,26 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->loop); } g_object_get (pinossrc->stream, "properties", &props, NULL); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); parse_stream_properties (pinossrc, props); pinos_properties_free (props); - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); pinossrc->started = TRUE; - pinos_main_loop_signal (pinossrc->loop, FALSE); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_unlock (pinossrc->loop); return res; start_error: { GST_DEBUG_OBJECT (pinossrc, "error starting stream"); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return FALSE; } } @@ -576,7 +576,7 @@ wait_negotiated (GstPinosSrc *this) { PinosStreamState state; - pinos_main_loop_lock (this->loop); + pinos_thread_main_loop_lock (this->loop); while (TRUE) { state = pinos_stream_get_state (this->stream); @@ -586,9 +586,9 @@ wait_negotiated (GstPinosSrc *this) if (this->started) break; - pinos_main_loop_wait (this->loop); + pinos_thread_main_loop_wait (this->loop); } - pinos_main_loop_unlock (this->loop); + pinos_thread_main_loop_unlock (this->loop); return state; } @@ -633,7 +633,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) possible = gst_caps_to_format_all (caps); /* first disconnect */ - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); if (pinos_stream_get_state (pinossrc->stream) != PINOS_STREAM_STATE_UNCONNECTED) { GST_DEBUG_OBJECT (basesrc, "disconnect capture"); pinos_stream_disconnect (pinossrc->stream); @@ -648,7 +648,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) goto connect_error; } - pinos_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->loop); } } @@ -669,9 +669,9 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) if (state == PINOS_STREAM_STATE_ERROR) goto connect_error; - pinos_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->loop); } - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); result = gst_pinos_src_stream_start (pinossrc); @@ -706,7 +706,7 @@ no_common_caps: } connect_error: { - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return FALSE; } } @@ -747,11 +747,11 @@ gst_pinos_src_unlock (GstBaseSrc * basesrc) { GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc); - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); GST_DEBUG_OBJECT (pinossrc, "setting flushing"); pinossrc->flushing = TRUE; - pinos_main_loop_signal (pinossrc->loop, FALSE); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_unlock (pinossrc->loop); return TRUE; } @@ -761,10 +761,10 @@ gst_pinos_src_unlock_stop (GstBaseSrc * basesrc) { GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc); - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); GST_DEBUG_OBJECT (pinossrc, "unsetting flushing"); pinossrc->flushing = FALSE; - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return TRUE; } @@ -850,7 +850,7 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (!pinossrc->negotiated) goto not_negotiated; - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); while (TRUE) { PinosStreamState state; @@ -868,9 +868,9 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (*buffer != NULL) break; - pinos_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->loop); } - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); if (pinossrc->is_live) base_time = GST_ELEMENT_CAST (psrc)->base_time; @@ -901,12 +901,12 @@ not_negotiated: } streaming_error: { - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return GST_FLOW_ERROR; } streaming_stopped: { - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return GST_FLOW_FLUSHING; } } @@ -931,9 +931,9 @@ gst_pinos_src_stop (GstBaseSrc * basesrc) pinossrc = GST_PINOS_SRC (basesrc); - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); clear_queue (pinossrc); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return TRUE; } @@ -959,7 +959,7 @@ on_context_notify (GObject *gobject, pinos_context_get_error (pinossrc->ctx)->message), (NULL)); break; } - pinos_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->loop, FALSE); } static gboolean @@ -985,11 +985,11 @@ gst_pinos_src_open (GstPinosSrc * pinossrc) pinossrc->context = g_main_context_new (); GST_DEBUG ("context %p", pinossrc->context); - pinossrc->loop = pinos_main_loop_new (pinossrc->context, "pinos-main-loop"); - if (!pinos_main_loop_start (pinossrc->loop, &error)) + pinossrc->loop = pinos_thread_main_loop_new (pinossrc->context, "pinos-main-loop"); + if (!pinos_thread_main_loop_start (pinossrc->loop, &error)) goto mainloop_failed; - pinos_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->loop); pinossrc->ctx = pinos_context_new (pinossrc->context, g_get_application_name (), NULL); g_signal_connect (pinossrc->ctx, "notify::state", (GCallback) on_context_notify, pinossrc); @@ -1004,7 +1004,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc) if (state == PINOS_CONTEXT_STATE_ERROR) goto connect_error; - pinos_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->loop); } if (pinossrc->properties) { @@ -1021,7 +1021,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc) g_signal_connect (pinossrc->stream, "remove-buffer", (GCallback) on_remove_buffer, pinossrc); g_signal_connect (pinossrc->stream, "new-buffer", (GCallback) on_new_buffer, pinossrc); pinossrc->clock = gst_pinos_clock_new (pinossrc->stream); - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return TRUE; @@ -1034,7 +1034,7 @@ mainloop_failed: } connect_error: { - pinos_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->loop); return FALSE; } } @@ -1042,7 +1042,7 @@ connect_error: static void gst_pinos_src_close (GstPinosSrc * pinossrc) { - pinos_main_loop_stop (pinossrc->loop); + pinos_thread_main_loop_stop (pinossrc->loop); g_clear_object (&pinossrc->loop); g_clear_object (&pinossrc->ctx); g_main_context_unref (pinossrc->context); diff --git a/pinos/gst/gstpinossrc.h b/pinos/gst/gstpinossrc.h index f4e40e7a4..01bc48e99 100644 --- a/pinos/gst/gstpinossrc.h +++ b/pinos/gst/gstpinossrc.h @@ -64,7 +64,7 @@ struct _GstPinosSrc { GstClockTime max_latency; GMainContext *context; - PinosMainLoop *loop; + PinosThreadMainLoop *loop; PinosContext *ctx; PinosStream *stream; GstAllocator *fd_allocator; diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 2d5cfbeb2..97ff7eec3 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -1111,8 +1111,6 @@ parse_connection (SpaProxy *this) case PINOS_CONTROL_CMD_ADD_MEM: break; - case PINOS_CONTROL_CMD_REMOVE_MEM: - break; case PINOS_CONTROL_CMD_USE_BUFFERS: break; @@ -1152,7 +1150,6 @@ parse_rtconnection (SpaProxy *this) case PINOS_CONTROL_CMD_SET_PROPERTY: case PINOS_CONTROL_CMD_NODE_COMMAND: case PINOS_CONTROL_CMD_ADD_MEM: - case PINOS_CONTROL_CMD_REMOVE_MEM: case PINOS_CONTROL_CMD_USE_BUFFERS: spa_log_error (this->log, "proxy %p: got unexpected connection %d\n", this, cmd); break; diff --git a/pinos/server/daemon.c b/pinos/server/daemon.c index f60b16734..bd72f80e4 100644 --- a/pinos/server/daemon.c +++ b/pinos/server/daemon.c @@ -33,7 +33,8 @@ #include "pinos/server/dbus-client-node.h" #include "pinos/server/client.h" #include "pinos/server/link.h" -#include "pinos/server/rt-loop.h" +#include "pinos/server/data-loop.h" +#include "pinos/server/main-loop.h" #include "pinos/dbus/org-pinos.h" @@ -52,7 +53,8 @@ struct _PinosDaemonPrivate GList *nodes; GHashTable *clients; - PinosRTLoop *loop; + PinosDataLoop *data_loop; + PinosMainLoop *main_loop; PinosProperties *properties; @@ -60,7 +62,6 @@ struct _PinosDaemonPrivate SpaSupport support[4]; SpaLog log; - SpaPoll main_loop; }; enum @@ -71,6 +72,7 @@ enum PROP_OBJECT_PATH, }; +static void try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this); static void handle_client_appeared (PinosClient *client, gpointer user_data) @@ -197,27 +199,30 @@ no_node: } } + static void on_node_remove_signal (PinosNode *node, - PinosDaemon *daemon) + PinosDaemon *this) { - g_debug ("daemon %p: node %p remove", daemon, node); + g_debug ("daemon %p: node %p remove", this, node); } static void on_link_input_unlinked (PinosLink *link, PinosPort *port, - PinosDaemon *daemon) + PinosDaemon *this) { - g_debug ("daemon %p: link %p: input unlinked", daemon, link); + g_debug ("daemon %p: link %p: input unlinked", this, link); } static void on_link_output_unlinked (PinosLink *link, PinosPort *port, - PinosDaemon *daemon) + PinosDaemon *this) { - g_debug ("daemon %p: link %p: output unlinked", daemon, link); + g_debug ("daemon %p: link %p: output unlinked", this, link); + + try_link_port (link->input->node, link->input, this); } static void @@ -245,6 +250,7 @@ on_link_state_notify (GObject *obj, case PINOS_LINK_STATE_UNLINKED: g_debug ("daemon %p: link %p: unlinked", daemon, link); +#if 0 g_set_error (&error, PINOS_ERROR, PINOS_ERROR_NODE_LINK, @@ -254,6 +260,7 @@ on_link_state_notify (GObject *obj, pinos_node_report_error (link->input->node, g_error_copy (error)); if (link->output && link->output->node) pinos_node_report_error (link->output->node, g_error_copy (error)); +#endif break; case PINOS_LINK_STATE_INIT: @@ -266,14 +273,13 @@ on_link_state_notify (GObject *obj, } static void -on_port_added (PinosNode *node, PinosPort *port, PinosDaemon *this) +try_link_port (PinosNode *node, PinosPort *port, PinosDaemon *this) { PinosClient *client; PinosProperties *props; const gchar *path; GError *error = NULL; PinosLink *link; - PinosDirection direction = port->direction; props = pinos_node_get_properties (node); if (props == NULL) @@ -285,16 +291,15 @@ on_port_added (PinosNode *node, PinosPort *port, PinosDaemon *this) PinosPort *target; target = pinos_daemon_find_port (this, - pinos_direction_reverse (direction), + port, path, NULL, - 0, NULL, &error); if (target == NULL) goto error; - if (direction == PINOS_DIRECTION_OUTPUT) + if (port->direction == PINOS_DIRECTION_OUTPUT) link = pinos_node_link (node, port, target, NULL, NULL, &error); else link = pinos_node_link (target->node, target, port, NULL, NULL, &error); @@ -306,10 +311,10 @@ on_port_added (PinosNode *node, PinosPort *port, PinosDaemon *this) if (client) pinos_client_add_object (client, G_OBJECT (link)); - g_signal_connect (target->node, "remove", (GCallback) on_node_remove_signal, daemon); - g_signal_connect (link, "input-unlinked", (GCallback) on_link_input_unlinked, daemon); - g_signal_connect (link, "output-unlinked", (GCallback) on_link_output_unlinked, daemon); - g_signal_connect (link, "notify::state", (GCallback) on_link_state_notify, daemon); + g_signal_connect (target->node, "remove", (GCallback) on_node_remove_signal, this); + g_signal_connect (link, "input-unlinked", (GCallback) on_link_input_unlinked, this); + g_signal_connect (link, "output-unlinked", (GCallback) on_link_output_unlinked, this); + g_signal_connect (link, "notify::state", (GCallback) on_link_state_notify, this); pinos_link_activate (link); g_object_unref (link); @@ -324,26 +329,32 @@ error: } static void -on_port_removed (PinosNode *node, PinosPort *port, PinosDaemon *daemon) +on_port_added (PinosNode *node, PinosPort *port, PinosDaemon *this) +{ + try_link_port (node, port, this); +} + +static void +on_port_removed (PinosNode *node, PinosPort *port, PinosDaemon *this) { } static void on_node_created (PinosNode *node, - PinosDaemon *daemon) + PinosDaemon *this) { GList *ports, *walk; ports = pinos_node_get_ports (node, PINOS_DIRECTION_INPUT); for (walk = ports; walk; walk = g_list_next (walk)) - on_port_added (node, walk->data, daemon); + on_port_added (node, walk->data, this); ports = pinos_node_get_ports (node, PINOS_DIRECTION_OUTPUT); for (walk = ports; walk; walk = g_list_next (walk)) - on_port_added (node, walk->data, daemon); + on_port_added (node, walk->data, this); - g_signal_connect (node, "port-added", (GCallback) on_port_added, daemon); - g_signal_connect (node, "port-removed", (GCallback) on_port_removed, daemon); + g_signal_connect (node, "port-added", (GCallback) on_port_added, this); + g_signal_connect (node, "port-removed", (GCallback) on_port_removed, this); } @@ -351,14 +362,14 @@ static void on_node_state_change (PinosNode *node, PinosNodeState old, PinosNodeState state, - PinosDaemon *daemon) + PinosDaemon *this) { - g_debug ("daemon %p: node %p state change %s -> %s", daemon, node, + g_debug ("daemon %p: node %p state change %s -> %s", this, node, pinos_node_state_as_string (old), pinos_node_state_as_string (state)); if (old == PINOS_NODE_STATE_CREATING && state == PINOS_NODE_STATE_SUSPENDED) - on_node_created (node, daemon); + on_node_created (node, this); } static void @@ -369,7 +380,7 @@ on_node_added (PinosDaemon *daemon, PinosNode *node) g_debug ("daemon %p: node %p added", daemon, node); - g_object_set (node, "rt-loop", priv->loop, NULL); + g_object_set (node, "data-loop", priv->data_loop, NULL); g_signal_connect (node, "state-change", (GCallback) on_node_state_change, daemon); @@ -727,6 +738,7 @@ pinos_daemon_remove_node (PinosDaemon *daemon, /** * pinos_daemon_find_port: * @daemon: a #PinosDaemon + * @other_port: a port to be compatible with * @name: a port name * @props: port properties * @format_filter: a format filter @@ -738,11 +750,10 @@ pinos_daemon_remove_node (PinosDaemon *daemon, */ PinosPort * pinos_daemon_find_port (PinosDaemon *daemon, - PinosDirection direction, + PinosPort *other_port, const gchar *name, PinosProperties *props, - unsigned int n_format_filters, - SpaFormat **format_filters, + GPtrArray *format_filters, GError **error) { PinosDaemonPrivate *priv; @@ -766,7 +777,7 @@ pinos_daemon_find_port (PinosDaemon *daemon, if (g_str_has_suffix (pinos_node_get_object_path (n), name)) { g_debug ("name \"%s\" matches node %p", name, n); - best = pinos_node_get_free_port (n, direction); + best = pinos_node_get_free_port (n, pinos_direction_reverse (other_port->direction)); if (best) break; } @@ -873,7 +884,7 @@ pinos_daemon_finalize (GObject * object) g_debug ("daemon %p: finalize", object); g_clear_object (&priv->server_manager); g_clear_object (&priv->iface); - g_clear_object (&priv->loop); + g_clear_object (&priv->data_loop); g_hash_table_unref (priv->clients); g_hash_table_unref (priv->node_factories); @@ -962,74 +973,6 @@ do_log (SpaLog *log, va_end (args); } -typedef struct { - PinosDaemonPrivate *priv; - SpaPollItem item; -} PollData; - -static gboolean -poll_event (GIOChannel *source, - GIOCondition condition, - gpointer user_data) -{ - PollData *data = user_data; - SpaPollNotifyData d; - - d.user_data = data->item.user_data; - d.fds = data->item.fds; - d.fds[0].revents = condition; - d.n_fds = data->item.n_fds; - data->item.after_cb (&d); - - return TRUE; -} - -static SpaResult -do_add_item (SpaPoll *poll, - SpaPollItem *item) -{ - PinosDaemonPrivate *priv = SPA_CONTAINER_OF (poll, PinosDaemonPrivate, main_loop); - GIOChannel *channel; - GSource *source; - PollData data; - - channel = g_io_channel_unix_new (item->fds[0].fd); - source = g_io_create_watch (channel, G_IO_IN); - g_io_channel_unref (channel); - - data.priv = priv; - data.item = *item; - - g_source_set_callback (source, (GSourceFunc) poll_event, g_slice_dup (PollData, &data) , NULL); - item->id = g_source_attach (source, g_main_context_get_thread_default ()); - g_source_unref (source); - - g_debug ("added main poll %d", item->id); - - return SPA_RESULT_OK; -} - -static SpaResult -do_update_item (SpaPoll *poll, - SpaPollItem *item) -{ - g_debug ("update main poll %d", item->id); - return SPA_RESULT_OK; -} - -static SpaResult -do_remove_item (SpaPoll *poll, - SpaPollItem *item) -{ - GSource *source; - - g_debug ("remove main poll %d", item->id); - source = g_main_context_find_source_by_id (g_main_context_get_thread_default (), item->id); - g_source_destroy (source); - - return SPA_RESULT_OK; -} - static void pinos_daemon_init (PinosDaemon * daemon) { @@ -1047,13 +990,9 @@ pinos_daemon_init (PinosDaemon * daemon) g_str_equal, g_free, g_object_unref); - priv->loop = pinos_rtloop_new(); + daemon->main_loop = pinos_main_loop_new(); - priv->main_loop.size = sizeof (SpaPoll); - priv->main_loop.info = NULL; - priv->main_loop.add_item = do_add_item; - priv->main_loop.update_item = do_update_item; - priv->main_loop.remove_item = do_remove_item; + priv->data_loop = pinos_data_loop_new(); priv->log.size = sizeof (SpaLog); priv->log.info = NULL; @@ -1069,9 +1008,9 @@ pinos_daemon_init (PinosDaemon * daemon) priv->support[1].uri = SPA_LOG_URI; priv->support[1].data = daemon->log; priv->support[2].uri = SPA_POLL__DataLoop; - priv->support[2].data = &priv->loop->poll; + priv->support[2].data = &priv->data_loop->poll; priv->support[3].uri = SPA_POLL__MainLoop; - priv->support[3].data = &priv->main_loop; + priv->support[3].data = &daemon->main_loop->poll; daemon->support = priv->support; daemon->n_support = 4; } diff --git a/pinos/server/daemon.h b/pinos/server/daemon.h index 2c68a058f..6aa184211 100644 --- a/pinos/server/daemon.h +++ b/pinos/server/daemon.h @@ -42,6 +42,7 @@ typedef struct _PinosDaemonPrivate PinosDaemonPrivate; #include #include #include +#include #include /** @@ -55,6 +56,8 @@ struct _PinosDaemon { SpaIDMap *map; SpaLog *log; + PinosMainLoop *main_loop; + SpaSupport *support; unsigned int n_support; @@ -86,11 +89,10 @@ void pinos_daemon_add_node (PinosDaemon *daemon, PinosNode void pinos_daemon_remove_node (PinosDaemon *daemon, PinosNode *node); PinosPort * pinos_daemon_find_port (PinosDaemon *daemon, - PinosDirection direction, + PinosPort *other_port, const gchar *name, PinosProperties *props, - unsigned int n_format_filters, - SpaFormat **format_filters, + GPtrArray *format_filter, GError **error); void pinos_daemon_add_node_factory (PinosDaemon *daemon, diff --git a/pinos/server/rt-loop.c b/pinos/server/data-loop.c similarity index 67% rename from pinos/server/rt-loop.c rename to pinos/server/data-loop.c index 88916e54d..4b686f2d8 100644 --- a/pinos/server/rt-loop.c +++ b/pinos/server/data-loop.c @@ -26,12 +26,12 @@ #include #include -#include "pinos/server/rt-loop.h" +#include "pinos/server/data-loop.h" -#define PINOS_RTLOOP_GET_PRIVATE(loop) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((loop), PINOS_TYPE_RTLOOP, PinosRTLoopPrivate)) +#define PINOS_DATA_LOOP_GET_PRIVATE(loop) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((loop), PINOS_TYPE_DATA_LOOP, PinosDataLoopPrivate)) -struct _PinosRTLoopPrivate +struct _PinosDataLoopPrivate { unsigned int n_poll; SpaPollItem poll[16]; @@ -45,7 +45,7 @@ struct _PinosRTLoopPrivate pthread_t thread; }; -G_DEFINE_TYPE (PinosRTLoop, pinos_rtloop, G_TYPE_OBJECT); +G_DEFINE_TYPE (PinosDataLoop, pinos_data_loop, G_TYPE_OBJECT); enum { @@ -60,11 +60,11 @@ enum static void * loop (void *user_data) { - PinosRTLoop *this = user_data; - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoop *this = user_data; + PinosDataLoopPrivate *priv = this->priv; unsigned int i, j; - g_debug ("rt-loop %p: enter thread", this); + g_debug ("data-loop %p: enter thread", this); while (priv->running) { SpaPollNotifyData ndata; unsigned int n_idle = 0; @@ -87,7 +87,7 @@ loop (void *user_data) /* rebuild */ if (priv->rebuild_fds) { - g_debug ("rt-loop %p: rebuild fds", this); + g_debug ("data-loop %p: rebuild fds", this); priv->n_fds = 1; for (i = 0; i < priv->n_poll; i++) { SpaPollItem *p = &priv->poll[i]; @@ -122,7 +122,7 @@ loop (void *user_data) break; } if (r == 0) { - g_debug ("rt-loop %p: select timeout", this); + g_debug ("data-loop %p: select timeout", this); break; } @@ -130,7 +130,7 @@ loop (void *user_data) if (priv->fds[0].revents & POLLIN) { uint64_t u; if (read (priv->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) - g_warning ("rt-loop %p: failed to read fd", strerror (errno)); + g_warning ("data-loop %p: failed to read fd", strerror (errno)); continue; } @@ -146,40 +146,40 @@ loop (void *user_data) } } } - g_debug ("rt-loop %p: leave thread", this); + g_debug ("data-loop %p: leave thread", this); return NULL; } static void -wakeup_thread (PinosRTLoop *this) +wakeup_thread (PinosDataLoop *this) { - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoopPrivate *priv = this->priv; uint64_t u = 1; if (write (priv->fds[0].fd, &u, sizeof(uint64_t)) != sizeof(uint64_t)) - g_warning ("rt-loop %p: failed to write fd", strerror (errno)); + g_warning ("data-loop %p: failed to write fd", strerror (errno)); } static void -start_thread (PinosRTLoop *this) +start_thread (PinosDataLoop *this) { - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoopPrivate *priv = this->priv; int err; if (!priv->running) { priv->running = true; if ((err = pthread_create (&priv->thread, NULL, loop, this)) != 0) { - g_warning ("rt-loop %p: can't create thread", strerror (err)); + g_warning ("data-loop %p: can't create thread", strerror (err)); priv->running = false; } } } static void -stop_thread (PinosRTLoop *this, gboolean in_thread) +stop_thread (PinosDataLoop *this, gboolean in_thread) { - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoopPrivate *priv = this->priv; if (priv->running) { priv->running = false; @@ -194,12 +194,12 @@ static SpaResult do_add_item (SpaPoll *poll, SpaPollItem *item) { - PinosRTLoop *this = SPA_CONTAINER_OF (poll, PinosRTLoop, poll); - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); + PinosDataLoopPrivate *priv = this->priv; gboolean in_thread = pthread_equal (priv->thread, pthread_self()); unsigned int i; - g_debug ("rt-loop %p: %d: add pollid %d, n_poll %d, n_fds %d", this, in_thread, item->id, priv->n_poll, item->n_fds); + g_debug ("data-loop %p: %d: add pollid %d, n_poll %d, n_fds %d", this, in_thread, item->id, priv->n_poll, item->n_fds); priv->poll[priv->n_poll] = *item; priv->n_poll++; if (item->n_fds) @@ -221,8 +221,8 @@ static SpaResult do_update_item (SpaPoll *poll, SpaPollItem *item) { - PinosRTLoop *this = SPA_CONTAINER_OF (poll, PinosRTLoop, poll); - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); + PinosDataLoopPrivate *priv = this->priv; gboolean in_thread = pthread_equal (priv->thread, pthread_self()); unsigned int i; @@ -243,12 +243,12 @@ static SpaResult do_remove_item (SpaPoll *poll, SpaPollItem *item) { - PinosRTLoop *this = SPA_CONTAINER_OF (poll, PinosRTLoop, poll); - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoop *this = SPA_CONTAINER_OF (poll, PinosDataLoop, poll); + PinosDataLoopPrivate *priv = this->priv; gboolean in_thread = pthread_equal (priv->thread, pthread_self()); unsigned int i; - g_debug ("rt-loop %p: remove poll %d %d", this, item->n_fds, priv->n_poll); + g_debug ("data-loop %p: remove poll %d %d", this, item->n_fds, priv->n_poll); for (i = 0; i < priv->n_poll; i++) { if (priv->poll[i].id == item->id && priv->poll[i].user_data == item->user_data) { priv->n_poll--; @@ -273,14 +273,14 @@ do_remove_item (SpaPoll *poll, } static void -pinos_rtloop_constructed (GObject * obj) +pinos_data_loop_constructed (GObject * obj) { - PinosRTLoop *this = PINOS_RTLOOP (obj); - PinosRTLoopPrivate *priv = this->priv; + PinosDataLoop *this = PINOS_DATA_LOOP (obj); + PinosDataLoopPrivate *priv = this->priv; - g_debug ("rt-loop %p: constructed", this); + g_debug ("data-loop %p: constructed", this); - G_OBJECT_CLASS (pinos_rtloop_parent_class)->constructed (obj); + G_OBJECT_CLASS (pinos_data_loop_parent_class)->constructed (obj); priv->fds[0].fd = eventfd (0, 0); priv->fds[0].events = POLLIN | POLLPRI | POLLERR; @@ -289,44 +289,44 @@ pinos_rtloop_constructed (GObject * obj) } static void -pinos_rtloop_dispose (GObject * obj) +pinos_data_loop_dispose (GObject * obj) { - PinosRTLoop *this = PINOS_RTLOOP (obj); + PinosDataLoop *this = PINOS_DATA_LOOP (obj); - g_debug ("rt-loop %p: dispose", this); + g_debug ("data-loop %p: dispose", this); stop_thread (this, FALSE); - G_OBJECT_CLASS (pinos_rtloop_parent_class)->dispose (obj); + G_OBJECT_CLASS (pinos_data_loop_parent_class)->dispose (obj); } static void -pinos_rtloop_finalize (GObject * obj) +pinos_data_loop_finalize (GObject * obj) { - PinosRTLoop *this = PINOS_RTLOOP (obj); + PinosDataLoop *this = PINOS_DATA_LOOP (obj); - g_debug ("rt-loop %p: finalize", this); + g_debug ("data-loop %p: finalize", this); - G_OBJECT_CLASS (pinos_rtloop_parent_class)->finalize (obj); + G_OBJECT_CLASS (pinos_data_loop_parent_class)->finalize (obj); } static void -pinos_rtloop_class_init (PinosRTLoopClass * klass) +pinos_data_loop_class_init (PinosDataLoopClass * klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - g_type_class_add_private (klass, sizeof (PinosRTLoopPrivate)); + g_type_class_add_private (klass, sizeof (PinosDataLoopPrivate)); - gobject_class->constructed = pinos_rtloop_constructed; - gobject_class->dispose = pinos_rtloop_dispose; - gobject_class->finalize = pinos_rtloop_finalize; + gobject_class->constructed = pinos_data_loop_constructed; + gobject_class->dispose = pinos_data_loop_dispose; + gobject_class->finalize = pinos_data_loop_finalize; } static void -pinos_rtloop_init (PinosRTLoop * this) +pinos_data_loop_init (PinosDataLoop * this) { - this->priv = PINOS_RTLOOP_GET_PRIVATE (this); + this->priv = PINOS_DATA_LOOP_GET_PRIVATE (this); - g_debug ("rt-loop %p: new", this); + g_debug ("data-loop %p: new", this); this->poll.size = sizeof (SpaPoll); this->poll.info = NULL; @@ -336,14 +336,14 @@ pinos_rtloop_init (PinosRTLoop * this) } /** - * pinos_rtloop_new: + * pinos_data_loop_new: * - * Create a new #PinosRTLoop. + * Create a new #PinosDataLoop. * - * Returns: a new #PinosRTLoop + * Returns: a new #PinosDataLoop */ -PinosRTLoop * -pinos_rtloop_new (void) +PinosDataLoop * +pinos_data_loop_new (void) { - return g_object_new (PINOS_TYPE_RTLOOP, NULL); + return g_object_new (PINOS_TYPE_DATA_LOOP, NULL); } diff --git a/pinos/server/data-loop.h b/pinos/server/data-loop.h new file mode 100644 index 000000000..0ff1a1c41 --- /dev/null +++ b/pinos/server/data-loop.h @@ -0,0 +1,71 @@ +/* Pinos + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PINOS_DATA_LOOP_H__ +#define __PINOS_DATA_LOOP_H__ + +#include + +G_BEGIN_DECLS + +#include + +typedef struct _PinosDataLoop PinosDataLoop; +typedef struct _PinosDataLoopClass PinosDataLoopClass; +typedef struct _PinosDataLoopPrivate PinosDataLoopPrivate; + +#define PINOS_TYPE_DATA_LOOP (pinos_data_loop_get_type ()) +#define PINOS_IS_DATA_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_DATA_LOOP)) +#define PINOS_IS_DATA_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_DATA_LOOP)) +#define PINOS_DATA_LOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_DATA_LOOP, PinosDataLoopClass)) +#define PINOS_DATA_LOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_DATA_LOOP, PinosDataLoop)) +#define PINOS_DATA_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_DATA_LOOP, PinosDataLoopClass)) +#define PINOS_DATA_LOOP_CAST(obj) ((PinosDataLoop*)(obj)) +#define PINOS_DATA_LOOP_CLASS_CAST(klass) ((PinosDataLoopClass*)(klass)) + +/** + * PinosDataLoop: + * + * Pinos rt-loop class. + */ +struct _PinosDataLoop { + GObject object; + + SpaPoll poll; + + PinosDataLoopPrivate *priv; +}; + +/** + * PinosDataLoopClass: + * + * Pinos rt-loop class. + */ +struct _PinosDataLoopClass { + GObjectClass parent_class; +}; + +/* normal GObject stuff */ +GType pinos_data_loop_get_type (void); + +PinosDataLoop * pinos_data_loop_new (void); + +G_END_DECLS + +#endif /* __PINOS_DATA_LOOP_H__ */ diff --git a/pinos/server/link.c b/pinos/server/link.c index 83faceb12..0507d87c8 100644 --- a/pinos/server/link.c +++ b/pinos/server/link.c @@ -46,11 +46,11 @@ struct _PinosLinkPrivate GPtrArray *format_filter; PinosProperties *properties; + PinosMainLoop *main_loop; + PinosLinkState state; GError *error; - uint32_t async_busy; - gboolean allocated; PinosMemblock buffer_mem; SpaBuffer **buffers; @@ -656,29 +656,24 @@ do_start (PinosLink *this, SpaNodeState in_state, SpaNodeState out_state) if (in_state == SPA_NODE_STATE_PAUSED) { pinos_node_set_state (this->input->node, PINOS_NODE_STATE_RUNNING); - if (pinos_node_get_state (this->input->node) != PINOS_NODE_STATE_RUNNING) - res = SPA_RESULT_RETURN_ASYNC (0); } if (out_state == SPA_NODE_STATE_PAUSED) { pinos_node_set_state (this->output->node, PINOS_NODE_STATE_RUNNING); - if (pinos_node_get_state (this->output->node) != PINOS_NODE_STATE_RUNNING) - res = SPA_RESULT_RETURN_ASYNC (0); } } return res; } static SpaResult -check_states (PinosLink *this) +check_states (PinosLink *this, SpaResult res) { - PinosLinkPrivate *priv = this->priv; - SpaResult res; SpaNodeState in_state, out_state; + PinosLinkPrivate *priv = this->priv; again: - if (priv->async_busy != SPA_ID_INVALID) - return SPA_RESULT_OK; + if (this->input == NULL || this->output == NULL) + return SPA_RESULT_OK; in_state = this->input->node->node->state; out_state = this->output->node->node->state; @@ -702,30 +697,19 @@ again: return SPA_RESULT_OK; exit: - if (SPA_RESULT_IS_ASYNC (res)) { - priv->async_busy = SPA_RESULT_ASYNC_SEQ (res); - g_debug ("link %p: waiting for async complete %d", this, priv->async_busy); - } + pinos_main_loop_defer (priv->main_loop, this, res, (PinosDeferFunc) check_states, this, NULL); return res; } -static gboolean -do_check_states (PinosLink *this) -{ - PinosLinkPrivate *priv = this->priv; - priv->async_busy = SPA_ID_INVALID; - check_states (this); - return G_SOURCE_REMOVE; -} - static void on_async_complete_notify (PinosNode *node, guint seq, guint res, PinosLink *this) { + PinosLinkPrivate *priv = this->priv; g_debug ("link %p: node %p async complete %d %d", this, node, seq, res); - g_idle_add ((GSourceFunc) do_check_states, this); + pinos_main_loop_defer_complete (priv->main_loop, this, seq, res); } static void @@ -756,28 +740,75 @@ on_property_notify (GObject *obj, } } +typedef struct { + PinosLink *link; + PinosPort *port; +} UnlinkedData; + +static void +on_input_unlinked (UnlinkedData *data) +{ + g_signal_emit (data->link, signals[SIGNAL_INPUT_UNLINKED], 0, data->port); +} + +static void +on_output_unlinked (UnlinkedData *data) +{ + g_signal_emit (data->link, signals[SIGNAL_OUTPUT_UNLINKED], 0, data->port); +} + static void on_node_remove (PinosNode *node, PinosLink *this) { PinosLinkPrivate *priv = this->priv; + SpaResult res = SPA_RESULT_OK; + UnlinkedData data; + + data.link = this; g_signal_handlers_disconnect_by_data (node, this); if (node == this->input->node) { if (this->input->allocated) { priv->buffers = NULL; priv->n_buffers = 0; + + if ((res = spa_node_port_use_buffers (this->output->node->node, + SPA_DIRECTION_OUTPUT, + this->output->port, + priv->buffers, + priv->n_buffers)) < 0) { + g_warning ("link %p: failed to clear output buffers: %d", this, res); + } } + data.port = this->input; this->input = NULL; - g_object_notify (G_OBJECT (this), "input-port"); - g_signal_emit (this, signals[SIGNAL_INPUT_UNLINKED], 0, node); + pinos_main_loop_defer (priv->main_loop, + this, + res, + (PinosDeferFunc) on_input_unlinked, + g_memdup (&data, sizeof (UnlinkedData)), + g_free); } else { if (this->output->allocated) { priv->buffers = NULL; priv->n_buffers = 0; + + if ((res = spa_node_port_use_buffers (this->input->node->node, + SPA_DIRECTION_INPUT, + this->input->port, + priv->buffers, + priv->n_buffers)) < 0) { + g_warning ("link %p: failed to clear input buffers: %d", this, res); + } } + data.port = this->output; this->output = NULL; - g_object_notify (G_OBJECT (this), "output-port"); - g_signal_emit (this, signals[SIGNAL_OUTPUT_UNLINKED], 0, node); + pinos_main_loop_defer (priv->main_loop, + this, + res, + (PinosDeferFunc) on_output_unlinked, + g_memdup (&data, sizeof (UnlinkedData)), + g_free); } if (this->input == NULL || this->output == NULL) @@ -788,6 +819,9 @@ static void pinos_link_constructed (GObject * object) { PinosLink *this = PINOS_LINK (object); + PinosLinkPrivate *priv = this->priv; + + priv->main_loop = priv->daemon->main_loop; g_signal_connect (this->input->node, "remove", (GCallback) on_node_remove, this); g_signal_connect (this->output->node, "remove", (GCallback) on_node_remove, this); @@ -1031,7 +1065,7 @@ pinos_link_activate (PinosLink *this) g_return_val_if_fail (PINOS_IS_LINK (this), FALSE); spa_ringbuffer_init (&this->ringbuffer, SPA_N_ELEMENTS (this->queue)); - check_states (this); + check_states (this, SPA_RESULT_OK); return TRUE; } diff --git a/pinos/server/link.h b/pinos/server/link.h index 7be10582f..03b8cbd7d 100644 --- a/pinos/server/link.h +++ b/pinos/server/link.h @@ -30,6 +30,7 @@ typedef struct _PinosLinkPrivate PinosLinkPrivate; #include #include +#include #include #define PINOS_TYPE_LINK (pinos_link_get_type ()) diff --git a/pinos/server/main-loop.c b/pinos/server/main-loop.c new file mode 100644 index 000000000..bc23cb7f3 --- /dev/null +++ b/pinos/server/main-loop.c @@ -0,0 +1,313 @@ +/* Pinos + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include +#include + +#include + +#include "pinos/server/main-loop.h" + +#define PINOS_MAIN_LOOP_GET_PRIVATE(loop) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((loop), PINOS_TYPE_MAIN_LOOP, PinosMainLoopPrivate)) + +struct _PinosMainLoopPrivate +{ + gulong counter; + + GQueue work; + gulong work_id; +}; + +G_DEFINE_TYPE (PinosMainLoop, pinos_main_loop, G_TYPE_OBJECT); + +enum +{ + PROP_0, +}; + +enum +{ + LAST_SIGNAL +}; + +typedef struct { + PinosMainLoop *loop; + SpaPollItem item; +} PollData; + +static gboolean +poll_event (GIOChannel *source, + GIOCondition condition, + gpointer user_data) +{ + PollData *data = user_data; + SpaPollNotifyData d; + + d.user_data = data->item.user_data; + d.fds = data->item.fds; + d.fds[0].revents = condition; + d.n_fds = data->item.n_fds; + data->item.after_cb (&d); + + return TRUE; +} + +static SpaResult +do_add_item (SpaPoll *poll, + SpaPollItem *item) +{ + PinosMainLoop *this = SPA_CONTAINER_OF (poll, PinosMainLoop, poll); + GIOChannel *channel; + GSource *source; + PollData data; + + channel = g_io_channel_unix_new (item->fds[0].fd); + source = g_io_create_watch (channel, G_IO_IN); + g_io_channel_unref (channel); + + data.loop = this; + data.item = *item; + + g_source_set_callback (source, (GSourceFunc) poll_event, g_slice_dup (PollData, &data) , NULL); + item->id = g_source_attach (source, g_main_context_get_thread_default ()); + g_source_unref (source); + + g_debug ("added main poll %d", item->id); + + return SPA_RESULT_OK; +} + +static SpaResult +do_update_item (SpaPoll *poll, + SpaPollItem *item) +{ + g_debug ("update main poll %d", item->id); + return SPA_RESULT_OK; +} + +static SpaResult +do_remove_item (SpaPoll *poll, + SpaPollItem *item) +{ + GSource *source; + + g_debug ("remove main poll %d", item->id); + source = g_main_context_find_source_by_id (g_main_context_get_thread_default (), item->id); + g_source_destroy (source); + + return SPA_RESULT_OK; +} + +static void +pinos_main_loop_constructed (GObject * obj) +{ + PinosMainLoop *this = PINOS_MAIN_LOOP (obj); + + g_debug ("main-loop %p: constructed", this); + + G_OBJECT_CLASS (pinos_main_loop_parent_class)->constructed (obj); +} + +static void +pinos_main_loop_dispose (GObject * obj) +{ + PinosMainLoop *this = PINOS_MAIN_LOOP (obj); + + g_debug ("main-loop %p: dispose", this); + + G_OBJECT_CLASS (pinos_main_loop_parent_class)->dispose (obj); +} + +static void +pinos_main_loop_finalize (GObject * obj) +{ + PinosMainLoop *this = PINOS_MAIN_LOOP (obj); + + g_debug ("main-loop %p: finalize", this); + + G_OBJECT_CLASS (pinos_main_loop_parent_class)->finalize (obj); +} + +static void +pinos_main_loop_class_init (PinosMainLoopClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosMainLoopPrivate)); + + gobject_class->constructed = pinos_main_loop_constructed; + gobject_class->dispose = pinos_main_loop_dispose; + gobject_class->finalize = pinos_main_loop_finalize; +} + +static void +pinos_main_loop_init (PinosMainLoop * this) +{ + PinosMainLoopPrivate *priv = this->priv = PINOS_MAIN_LOOP_GET_PRIVATE (this); + + g_debug ("main-loop %p: new", this); + + this->poll.size = sizeof (SpaPoll); + this->poll.info = NULL; + this->poll.add_item = do_add_item; + this->poll.update_item = do_update_item; + this->poll.remove_item = do_remove_item; + + g_queue_init (&priv->work); +} + +/** + * pinos_main_loop_new: + * + * Create a new #PinosMainLoop. + * + * Returns: a new #PinosMainLoop + */ +PinosMainLoop * +pinos_main_loop_new (void) +{ + return g_object_new (PINOS_TYPE_MAIN_LOOP, NULL); +} + +typedef struct { + gulong id; + gpointer obj; + uint32_t seq; + SpaResult res; + PinosDeferFunc func; + gpointer *data; + GDestroyNotify notify; +} WorkItem; + +static gboolean +process_work_queue (PinosMainLoop *this) +{ + PinosMainLoopPrivate *priv = this->priv; + GList *walk, *next; + + for (walk = priv->work.head; walk; walk = next) { + WorkItem *item = walk->data; + + next = g_list_next (walk); + + g_debug ("main-loop %p: peek work queue item %p seq %d", this, item, item ? item->seq : -1); + if (item->seq != SPA_ID_INVALID) + continue; + + g_debug ("main-loop %p: process work item %p", this, item); + if (item->func) + item->func (item->data, item->res, item->id); + if (item->notify) + item->notify (item->data); + + g_queue_delete_link (&priv->work, walk); + g_slice_free (WorkItem, item); + } + + priv->work_id = 0; + return FALSE; +} + +gulong +pinos_main_loop_defer (PinosMainLoop *loop, + gpointer obj, + SpaResult res, + PinosDeferFunc func, + gpointer data, + GDestroyNotify notify) +{ + PinosMainLoopPrivate *priv; + WorkItem *item; + gboolean have_work = FALSE; + + g_return_val_if_fail (PINOS_IS_MAIN_LOOP (loop), 0); + priv = loop->priv; + + item = g_slice_new (WorkItem); + item->id = ++priv->counter; + item->obj = obj; + item->func = func; + item->data = data; + item->notify = notify; + + if (SPA_RESULT_IS_ASYNC (res)) { + item->seq = SPA_RESULT_ASYNC_SEQ (res); + item->res = res; + g_debug ("main-loop %p: defer async %d for object %p", loop, item->seq, obj); + } else { + item->seq = SPA_ID_INVALID; + item->res = res; + have_work = TRUE; + g_debug ("main-loop %p: defer object %p", loop, obj); + } + g_queue_push_tail (&priv->work, item); + + if (priv->work_id == 0 && have_work) + priv->work_id = g_idle_add ((GSourceFunc) process_work_queue, loop); + + return item->id; +} + +void +pinos_main_loop_defer_cancel (PinosMainLoop *loop, + gulong id) +{ + GList *walk; + PinosMainLoopPrivate *priv; + + g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + priv = loop->priv; + + for (walk = priv->work.head; walk; walk = g_list_next (walk)) { + WorkItem *i = walk->data; + if (i->id == id) { + i->func = NULL; + } + } +} + +void +pinos_main_loop_defer_complete (PinosMainLoop *loop, + gpointer obj, + uint32_t seq, + SpaResult res) +{ + GList *walk; + PinosMainLoopPrivate *priv; + gboolean have_work = FALSE; + + g_return_if_fail (PINOS_IS_MAIN_LOOP (loop)); + priv = loop->priv; + + g_debug ("main-loop %p: async complete %d %d for object %p", loop, seq, res, obj); + + for (walk = priv->work.head; walk; walk = g_list_next (walk)) { + WorkItem *i = walk->data; + + if (i->obj == obj && i->seq == seq) { + g_debug ("main-loop %p: found defered %d for object %p", loop, seq, obj); + i->seq = SPA_ID_INVALID; + i->res = res; + have_work = TRUE; + } + } + if (priv->work_id == 0 && have_work) + priv->work_id = g_idle_add ((GSourceFunc) process_work_queue, loop); +} diff --git a/pinos/client/mainloop.h b/pinos/server/main-loop.h similarity index 59% rename from pinos/client/mainloop.h rename to pinos/server/main-loop.h index e4cad87a4..a5ef45052 100644 --- a/pinos/client/mainloop.h +++ b/pinos/server/main-loop.h @@ -1,5 +1,5 @@ /* Pinos - * Copyright (C) 2015 Wim Taymans + * Copyright (C) 2016 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -24,6 +24,12 @@ G_BEGIN_DECLS +#include + +typedef struct _PinosMainLoop PinosMainLoop; +typedef struct _PinosMainLoopClass PinosMainLoopClass; +typedef struct _PinosMainLoopPrivate PinosMainLoopPrivate; + #define PINOS_TYPE_MAIN_LOOP (pinos_main_loop_get_type ()) #define PINOS_IS_MAIN_LOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_MAIN_LOOP)) #define PINOS_IS_MAIN_LOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_MAIN_LOOP)) @@ -33,51 +39,50 @@ G_BEGIN_DECLS #define PINOS_MAIN_LOOP_CAST(obj) ((PinosMainLoop*)(obj)) #define PINOS_MAIN_LOOP_CLASS_CAST(klass) ((PinosMainLoopClass*)(klass)) -typedef struct _PinosMainLoop PinosMainLoop; -typedef struct _PinosMainLoopClass PinosMainLoopClass; -typedef struct _PinosMainLoopPrivate PinosMainLoopPrivate; - - /** * PinosMainLoop: * - * Pinos main loop object class. + * Pinos rt-loop class. */ struct _PinosMainLoop { GObject object; + SpaPoll poll; + PinosMainLoopPrivate *priv; }; /** * PinosMainLoopClass: * - * Pinos main loop object class. + * Pinos rt-loop class. */ struct _PinosMainLoopClass { GObjectClass parent_class; }; +typedef void (*PinosDeferFunc) (gpointer data, + SpaResult res, + gulong id); + /* normal GObject stuff */ -GType pinos_main_loop_get_type (void); +GType pinos_main_loop_get_type (void); -PinosMainLoop * pinos_main_loop_new (GMainContext * context, - const gchar *name); +PinosMainLoop * pinos_main_loop_new (void); -GMainLoop * pinos_main_loop_get_impl (PinosMainLoop *loop); - -gboolean pinos_main_loop_start (PinosMainLoop *loop, GError **error); -void pinos_main_loop_stop (PinosMainLoop *loop); - -void pinos_main_loop_lock (PinosMainLoop *loop); -void pinos_main_loop_unlock (PinosMainLoop *loop); - -void pinos_main_loop_wait (PinosMainLoop *loop); -void pinos_main_loop_signal (PinosMainLoop *loop, gboolean wait_for_accept); -void pinos_main_loop_accept (PinosMainLoop *loop); - -gboolean pinos_main_loop_in_thread (PinosMainLoop *loop); +gulong pinos_main_loop_defer (PinosMainLoop *loop, + gpointer obj, + SpaResult res, + PinosDeferFunc func, + gpointer data, + GDestroyNotify notify); +void pinos_main_loop_defer_cancel (PinosMainLoop *loop, + gulong id); +void pinos_main_loop_defer_complete (PinosMainLoop *loop, + gpointer obj, + uint32_t seq, + SpaResult res); G_END_DECLS diff --git a/pinos/server/meson.build b/pinos/server/meson.build index f2188994d..51798bbab 100644 --- a/pinos/server/meson.build +++ b/pinos/server/meson.build @@ -3,12 +3,13 @@ pinoscore_headers = [ 'client-node.h', 'command.h', 'daemon.h', + 'data-loop.h', 'dbus-client-node.h', 'link.h', + 'main-loop.h', 'module.h', 'node.h', 'node-factory.h', - 'rt-loop.h', 'utils.h', ] @@ -17,12 +18,13 @@ pinoscore_sources = [ 'client-node.c', 'command.c', 'daemon.c', + 'data-loop.c', 'dbus-client-node.c', 'link.c', + 'main-loop.c', 'module.c', 'node.c', 'node-factory.c', - 'rt-loop.c', 'utils.c', ] diff --git a/pinos/server/node.c b/pinos/server/node.c index ce5df18f6..bd4222260 100644 --- a/pinos/server/node.c +++ b/pinos/server/node.c @@ -25,7 +25,8 @@ #include "pinos/client/enumtypes.h" #include "pinos/server/node.h" -#include "pinos/server/rt-loop.h" +#include "pinos/server/data-loop.h" +#include "pinos/server/main-loop.h" #include "pinos/server/daemon.h" #include "pinos/dbus/org-pinos.h" @@ -89,11 +90,8 @@ struct _PinosNodePrivate PinosProperties *properties; - PinosRTLoop *loop; - - SpaNodeEventAsyncComplete ac; - uint32_t pending_state_seq; - PinosNodeState pending_state; + PinosDataLoop *data_loop; + PinosMainLoop *main_loop; }; G_DEFINE_TYPE (PinosNode, pinos_node, G_TYPE_OBJECT); @@ -103,7 +101,7 @@ enum PROP_0, PROP_DAEMON, PROP_CLIENT, - PROP_RTLOOP, + PROP_DATA_LOOP, PROP_OBJECT_PATH, PROP_NAME, PROP_PROPERTIES, @@ -330,12 +328,24 @@ send_clock_update (PinosNode *this) g_debug ("got error %d", res); } +typedef struct { + PinosNode *node; + PinosNodeState state; +} StateData; + +static void +on_state_complete (StateData *data) +{ + pinos_node_update_state (data->node, data->state); +} + static gboolean node_set_state (PinosNode *this, PinosNodeState state) { PinosNodePrivate *priv = this->priv; SpaResult res = SPA_RESULT_OK; + StateData data; g_debug ("node %p: set state %s", this, pinos_node_state_as_string (state)); @@ -365,12 +375,15 @@ node_set_state (PinosNode *this, if (SPA_RESULT_IS_ERROR (res)) return FALSE; - if (SPA_RESULT_IS_ASYNC (res)) { - priv->pending_state_seq = SPA_RESULT_ASYNC_SEQ (res); - priv->pending_state = state; - } else { - pinos_node_update_state (this, state); - } + data.node = this; + data.state = state; + + pinos_main_loop_defer (priv->main_loop, + this, + res, + (PinosDeferFunc) on_state_complete, + g_memdup (&data, sizeof (StateData)), + g_free); return TRUE; } @@ -387,7 +400,7 @@ do_read_link (PinosNode *this, PinosLink *link) if (areas[0].len > 0) { SpaPortInputInfo iinfo[1]; - if (link->in_ready <= 0) + if (link->in_ready <= 0 || link->input == NULL) return FALSE; link->in_ready--; @@ -406,24 +419,6 @@ do_read_link (PinosNode *this, PinosLink *link) return pushed; } -static void -do_handle_async_complete (PinosNode *this) -{ - PinosNodePrivate *priv = this->priv; - SpaNodeEventAsyncComplete *ac = &priv->ac; - - g_debug ("node %p: async complete %u %d", this, ac->seq, ac->res); - - if (priv->async_init) { - init_complete (this); - priv->async_init = FALSE; - } - if (priv->pending_state_seq == ac->seq) { - pinos_node_update_state (this, priv->pending_state); - } - g_signal_emit (this, signals[SIGNAL_ASYNC_COMPLETE], 0, ac->seq, ac->res); -} - static void on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) { @@ -443,10 +438,9 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) { SpaNodeEventAsyncComplete *ac = event->data; - priv->ac = *ac; - g_main_context_invoke (NULL, - (GSourceFunc) do_handle_async_complete, - this); + g_debug ("node %p: async complete event %d %d", this, ac->seq, ac->res); + pinos_main_loop_defer_complete (priv->main_loop, this, ac->seq, ac->res); + g_signal_emit (this, signals[SIGNAL_ASYNC_COMPLETE], 0, ac->seq, ac->res); break; } @@ -518,6 +512,9 @@ on_node_event (SpaNode *node, SpaNodeEvent *event, void *user_data) for (i = 0; i < p->links->len; i++) { PinosLink *link = g_ptr_array_index (p->links, i); + if (link->output == NULL) + continue; + if ((res = spa_node_port_reuse_buffer (link->output->node->node, link->output->port, rb->buffer_id)) < 0) @@ -564,8 +561,8 @@ pinos_node_get_property (GObject *_object, g_value_set_object (value, priv->client); break; - case PROP_RTLOOP: - g_value_set_object (value, priv->loop); + case PROP_DATA_LOOP: + g_value_set_object (value, priv->data_loop); break; case PROP_OBJECT_PATH: @@ -612,15 +609,15 @@ pinos_node_set_property (GObject *_object, priv->client = g_value_get_object (value); break; - case PROP_RTLOOP: + case PROP_DATA_LOOP: { SpaResult res; - if (priv->loop) - g_object_unref (priv->loop); - priv->loop = g_value_dup_object (value); + if (priv->data_loop) + g_object_unref (priv->data_loop); + priv->data_loop = g_value_dup_object (value); - if (priv->loop) { + if (priv->data_loop) { if ((res = spa_node_set_event_callback (this->node, on_node_event, this)) < 0) g_warning ("node %p: error setting callback", this); } @@ -640,13 +637,6 @@ pinos_node_set_property (GObject *_object, case PROP_NODE: { this->node = g_value_get_pointer (value); -#if 0 - void *iface; - if (this->node->handle->get_interface (this->node->handle, - spa_id_map_get_id (priv->daemon->map, SPA_CLOCK_URI), - &iface) >= 0) - this->clock = iface; -#endif break; } case PROP_CLOCK: @@ -734,6 +724,8 @@ pinos_node_constructed (GObject * obj) g_debug ("node %p: constructed", this); + priv->main_loop = priv->daemon->main_loop; + g_signal_connect (this, "notify", (GCallback) on_property_notify, this); G_OBJECT_CLASS (pinos_node_parent_class)->constructed (obj); @@ -753,6 +745,12 @@ pinos_node_constructed (GObject * obj) init_complete (this); } else { priv->async_init = TRUE; + pinos_main_loop_defer (priv->main_loop, + this, + SPA_RESULT_RETURN_ASYNC (0), + (PinosDeferFunc) init_complete, + this, + NULL); } node_register_object (this); } @@ -780,7 +778,7 @@ pinos_node_finalize (GObject * obj) g_debug ("node %p: finalize", node); g_clear_object (&priv->daemon); g_clear_object (&priv->iface); - g_clear_object (&priv->loop); + g_clear_object (&priv->data_loop); g_free (priv->name); g_clear_error (&priv->error); if (priv->properties) @@ -869,11 +867,11 @@ pinos_node_class_init (PinosNodeClass * klass) G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, - PROP_RTLOOP, - g_param_spec_object ("rt-loop", - "RTLoop", - "The RTLoop", - PINOS_TYPE_RTLOOP, + PROP_DATA_LOOP, + g_param_spec_object ("data-loop", + "Data Loop", + "The Data Loop", + PINOS_TYPE_DATA_LOOP, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); @@ -945,7 +943,6 @@ pinos_node_init (PinosNode * node) (GCallback) handle_remove, node); priv->state = PINOS_NODE_STATE_CREATING; - priv->pending_state_seq = SPA_ID_INVALID; pinos_node1_set_state (priv->iface, priv->state); } diff --git a/pinos/server/rt-loop.h b/pinos/server/rt-loop.h deleted file mode 100644 index f76d045fb..000000000 --- a/pinos/server/rt-loop.h +++ /dev/null @@ -1,79 +0,0 @@ -/* Pinos - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#ifndef __PINOS_RTLOOP_H__ -#define __PINOS_RTLOOP_H__ - -#include - -G_BEGIN_DECLS - -#include - -typedef struct _PinosRTLoop PinosRTLoop; -typedef struct _PinosRTLoopClass PinosRTLoopClass; -typedef struct _PinosRTLoopPrivate PinosRTLoopPrivate; - -#define PINOS_TYPE_RTLOOP (pinos_rtloop_get_type ()) -#define PINOS_IS_RTLOOP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_RTLOOP)) -#define PINOS_IS_RTLOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_RTLOOP)) -#define PINOS_RTLOOP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_RTLOOP, PinosRTLoopClass)) -#define PINOS_RTLOOP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_RTLOOP, PinosRTLoop)) -#define PINOS_RTLOOP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_RTLOOP, PinosRTLoopClass)) -#define PINOS_RTLOOP_CAST(obj) ((PinosRTLoop*)(obj)) -#define PINOS_RTLOOP_CLASS_CAST(klass) ((PinosRTLoopClass*)(klass)) - -/** - * PinosRTLoop: - * - * Pinos rt-loop class. - */ -struct _PinosRTLoop { - GObject object; - - SpaPoll poll; - - PinosRTLoopPrivate *priv; -}; - -/** - * PinosRTLoopClass: - * - * Pinos rt-loop class. - */ -struct _PinosRTLoopClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType pinos_rtloop_get_type (void); - -PinosRTLoop * pinos_rtloop_new (void); - - -gboolean pinos_rtloop_add_poll (PinosRTLoop *loop, - SpaPollItem *item); -gboolean pinos_rtloop_update_poll (PinosRTLoop *loop, - SpaPollItem *item); -gboolean pinos_rtloop_remove_poll (PinosRTLoop *loop, - SpaPollItem *item); - -G_END_DECLS - -#endif /* __PINOS_RTLOOP_H__ */ diff --git a/spa/include/spa/node.h b/spa/include/spa/node.h index 07abf25e8..de12284a4 100644 --- a/spa/include/spa/node.h +++ b/spa/include/spa/node.h @@ -39,12 +39,12 @@ typedef struct _SpaNode SpaNode; * @SPA_NODE_STATE_ERROR: the node is in error */ typedef enum { - SPA_NODE_STATE_INIT, + SPA_NODE_STATE_ERROR = -1, + SPA_NODE_STATE_INIT = 0, SPA_NODE_STATE_CONFIGURE, SPA_NODE_STATE_READY, SPA_NODE_STATE_PAUSED, SPA_NODE_STATE_STREAMING, - SPA_NODE_STATE_ERROR } SpaNodeState;