From 27bba6f587a6a276f9052fe92feb6fa8595f33a4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 24 Nov 2016 17:00:42 +0100 Subject: [PATCH] Make native protocol Remove DBus and work towards something like wayland. Remove more glib stuff from the client code --- pinos/client/connection.c | 497 ++++-- pinos/client/connection.h | 127 +- pinos/client/context.c | 862 +++++------ pinos/client/context.h | 93 +- pinos/client/introspect.c | 540 +------ pinos/client/introspect.h | 182 +-- pinos/client/meson.build | 4 +- pinos/client/pinos.c | 80 +- pinos/client/pinos.h | 23 +- pinos/client/private.h | 55 - pinos/client/properties.c | 115 +- pinos/client/properties.h | 39 +- pinos/client/proxy.c | 76 + pinos/client/proxy.h | 75 + pinos/client/serialize.c | 88 ++ pinos/client/serialize.h | 5 + pinos/client/signal.h | 16 +- pinos/client/stream.c | 1962 ++++++++---------------- pinos/client/stream.h | 106 +- pinos/client/subscribe.c | 819 ---------- pinos/client/subscribe.h | 58 +- pinos/client/thread-mainloop.c | 405 ++--- pinos/client/thread-mainloop.h | 55 +- pinos/client/transport.c | 10 + pinos/daemon/daemon-config.c | 4 +- pinos/daemon/main.c | 2 +- pinos/daemon/pinos.conf.in | 2 +- pinos/gst/gstpinosdeviceprovider.c | 224 ++- pinos/gst/gstpinosdeviceprovider.h | 8 +- pinos/gst/gstpinossink.c | 160 +- pinos/gst/gstpinossink.h | 13 +- pinos/gst/gstpinossrc.c | 199 ++- pinos/gst/gstpinossrc.h | 13 +- pinos/modules/module-autolink.c | 17 +- pinos/modules/module-protocol-dbus.c | 96 +- pinos/modules/module-protocol-native.c | 182 ++- pinos/modules/module-suspend-on-idle.c | 13 +- pinos/modules/spa/module.c | 2 +- pinos/server/client-node.c | 310 ++-- pinos/server/client-node.h | 13 +- pinos/server/client.c | 44 +- pinos/server/client.h | 30 +- pinos/server/command.c | 22 +- pinos/server/core.c | 4 + pinos/server/core.h | 5 + pinos/server/main-loop.c | 14 +- pinos/server/meson.build | 2 + pinos/server/module.c | 3 +- pinos/server/module.h | 7 +- pinos/server/resource.c | 86 ++ pinos/server/resource.h | 84 + pinos/server/uri.c | 3 + pinos/server/uri.h | 2 + pinos/tools/pinos-monitor.c | 200 ++- spa/include/spa/loop.h | 2 +- 55 files changed, 3089 insertions(+), 4969 deletions(-) delete mode 100644 pinos/client/private.h create mode 100644 pinos/client/proxy.c create mode 100644 pinos/client/proxy.h delete mode 100644 pinos/client/subscribe.c create mode 100644 pinos/server/resource.c create mode 100644 pinos/server/resource.h diff --git a/pinos/client/connection.c b/pinos/client/connection.c index 0f29cad57..d246d3e3f 100644 --- a/pinos/client/connection.c +++ b/pinos/client/connection.c @@ -39,6 +39,7 @@ typedef struct { int fds[MAX_FDS]; unsigned int n_fds; + uint32_t dest_id; PinosMessageType type; off_t offset; void *data; @@ -52,32 +53,77 @@ struct _PinosConnection { int fd; }; +static int +connection_get_fd (PinosConnection *conn, + int index) +{ + if (index < 0 || index >= conn->in.n_fds) + return -1; + + return conn->in.fds[index]; +} + +static int +connection_add_fd (PinosConnection *conn, + int fd) +{ + int index, i; + + for (i = 0; i < conn->out.n_fds; i++) { + if (conn->out.fds[i] == fd) + return i; + } + + index = conn->out.n_fds; + conn->out.fds[index] = fd; + conn->out.n_fds++; + + return index; +} + #if 0 #define PINOS_DEBUG_MESSAGE(format,args...) pinos_log_debug(stderr, format,##args) #else #define PINOS_DEBUG_MESSAGE(format,args...) #endif -static bool -read_length (uint8_t * data, unsigned int size, size_t * length, size_t * skip) +static void +connection_parse_notify_global (PinosConnection *conn, PinosMessageNotifyGlobal *ng) { - uint8_t b; + void *p; - /* start reading the length, we need this to skip to the data later */ - *length = *skip = 0; - do { - if (*skip >= size) - return false; + p = conn->in.data; + memcpy (ng, p, sizeof (PinosMessageNotifyGlobal)); + if (ng->type) + ng->type = SPA_MEMBER (p, SPA_PTR_TO_INT (ng->type), const char); +} - b = data[(*skip)++]; - *length = (*length << 7) | (b & 0x7f); - } while (b & 0x80); +static void +connection_parse_create_node (PinosConnection *conn, PinosMessageCreateNode *m) +{ + void *p; - /* check remaining command size */ - if (size - *skip < *length) - return false; + p = conn->in.data; + memcpy (m, p, sizeof (PinosMessageCreateNode)); + if (m->factory_name) + m->factory_name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->factory_name), const char); + if (m->name) + m->name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->name), const char); + if (m->props) + m->props = pinos_serialize_dict_deserialize (p, SPA_PTR_TO_INT (m->props)); +} - return true; +static void +connection_parse_create_client_node (PinosConnection *conn, PinosMessageCreateClientNode *m) +{ + void *p; + + p = conn->in.data; + memcpy (m, p, sizeof (PinosMessageCreateClientNode)); + if (m->name) + m->name = SPA_MEMBER (p, SPA_PTR_TO_INT (m->name), const char); + if (m->props) + m->props = pinos_serialize_dict_deserialize (p, SPA_PTR_TO_INT (m->props)); } static void @@ -173,34 +219,122 @@ connection_ensure_size (PinosConnection *conn, ConnectionBuffer *buf, size_t siz } static void * -connection_add_message (PinosConnection *conn, PinosMessageType type, size_t size) +connection_add_message (PinosConnection *conn, + uint32_t dest_id, + PinosMessageType type, + size_t size) { - uint8_t *p; - unsigned int plen; + uint32_t *p; ConnectionBuffer *buf = &conn->out; - plen = 1; - while (size >> (7 * plen)) - plen++; - - /* 1 for cmd, plen for size and size for payload */ - p = connection_ensure_size (conn, buf, 1 + plen + size); + /* 4 for dest_id, 2 for cmd, 2 for size and size for payload */ + p = connection_ensure_size (conn, buf, 8 + size); buf->type = type; buf->offset = buf->buffer_size; - buf->buffer_size += 1 + plen + size; + buf->buffer_size += 8 + size; + + *p++ = dest_id; + *p++ = (type << 16) | (size & 0xffff); - *p++ = type; - /* write length */ - while (plen) { - plen--; - *p++ = ((plen > 0) ? 0x80 : 0) | ((size >> (7 * plen)) & 0x7f); - } return p; } static void -connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu) +connection_add_notify_global (PinosConnection *conn, + uint32_t dest_id, + PinosMessageNotifyGlobal *m) +{ + size_t len; + void *p; + PinosMessageNotifyGlobal *d; + + /* calc len */ + len = sizeof (PinosMessageNotifyGlobal); + len += m->type ? strlen (m->type) + 1 : 0; + + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NOTIFY_GLOBAL, len); + memcpy (p, m, sizeof (PinosMessageNotifyGlobal)); + d = p; + + p = SPA_MEMBER (d, sizeof (PinosMessageNotifyGlobal), void); + if (m->type) { + strcpy (p, m->type); + d->type = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + } +} + +static void +connection_add_create_node (PinosConnection *conn, uint32_t dest_id, PinosMessageCreateNode *m) +{ + size_t len, slen; + void *p; + PinosMessageCreateNode *d; + + /* calc len */ + len = sizeof (PinosMessageCreateNode); + len += m->factory_name ? strlen (m->factory_name) + 1 : 0; + len += m->name ? strlen (m->name) + 1 : 0; + len += pinos_serialize_dict_get_size (m->props); + + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_CREATE_NODE, len); + memcpy (p, m, sizeof (PinosMessageCreateNode)); + d = p; + + p = SPA_MEMBER (d, sizeof (PinosMessageCreateNode), void); + if (m->factory_name) { + slen = strlen (m->factory_name) + 1; + memcpy (p, m->factory_name, slen); + d->factory_name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + p += slen; + } + if (m->name) { + slen = strlen (m->name) + 1; + memcpy (p, m->name, slen); + d->name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + p += slen; + } + if (m->props) { + len = pinos_serialize_dict_serialize (p, m->props); + d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + } else { + d->props = 0; + } +} + +static void +connection_add_create_client_node (PinosConnection *conn, uint32_t dest_id, PinosMessageCreateClientNode *m) +{ + size_t len, slen; + void *p; + PinosMessageCreateClientNode *d; + + /* calc len */ + len = sizeof (PinosMessageCreateClientNode); + len += m->name ? strlen (m->name) + 1 : 0; + len += pinos_serialize_dict_get_size (m->props); + + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_CREATE_CLIENT_NODE, len); + memcpy (p, m, sizeof (PinosMessageCreateClientNode)); + d = p; + + p = SPA_MEMBER (d, sizeof (PinosMessageCreateClientNode), void); + if (m->name) { + slen = strlen (m->name) + 1; + memcpy (p, m->name, slen); + d->name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + p += slen; + } + if (m->props) { + len = pinos_serialize_dict_serialize (p, m->props); + d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); + } else { + d->props = 0; + } +} + +static void +connection_add_node_update (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeUpdate *nu) { size_t len; void *p; @@ -210,7 +344,7 @@ connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu) len = sizeof (PinosMessageNodeUpdate); len += pinos_serialize_props_get_size (nu->props); - p = connection_add_message (conn, PINOS_MESSAGE_NODE_UPDATE, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_UPDATE, len); memcpy (p, nu, sizeof (PinosMessageNodeUpdate)); d = p; @@ -224,7 +358,7 @@ connection_add_node_update (PinosConnection *conn, PinosMessageNodeUpdate *nu) } static void -connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu) +connection_add_port_update (PinosConnection *conn, uint32_t dest_id, PinosMessagePortUpdate *pu) { size_t len; void *p; @@ -243,7 +377,7 @@ connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu) if (pu->info) len += pinos_serialize_port_info_get_size (pu->info); - p = connection_add_message (conn, PINOS_MESSAGE_PORT_UPDATE, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_PORT_UPDATE, len); memcpy (p, pu, sizeof (PinosMessagePortUpdate)); d = p; @@ -285,7 +419,7 @@ connection_add_port_update (PinosConnection *conn, PinosMessagePortUpdate *pu) } static void -connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf) +connection_add_set_format (PinosConnection *conn, uint32_t dest_id, PinosMessageSetFormat *sf) { size_t len; void *p; @@ -293,7 +427,7 @@ connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf) /* calculate length */ /* port_id + format + mask */ len = sizeof (PinosMessageSetFormat) + pinos_serialize_format_get_size (sf->format); - p = connection_add_message (conn, PINOS_MESSAGE_SET_FORMAT, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_SET_FORMAT, len); memcpy (p, sf, sizeof (PinosMessageSetFormat)); sf = p; @@ -306,7 +440,7 @@ connection_add_set_format (PinosConnection *conn, PinosMessageSetFormat *sf) } static void -connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub) +connection_add_use_buffers (PinosConnection *conn, uint32_t dest_id, PinosMessageUseBuffers *ub) { size_t len; int i; @@ -317,7 +451,7 @@ connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub) len = sizeof (PinosMessageUseBuffers); len += ub->n_buffers * sizeof (PinosMessageMemRef); - d = connection_add_message (conn, PINOS_MESSAGE_USE_BUFFERS, len); + d = connection_add_message (conn, dest_id, PINOS_MESSAGE_USE_BUFFERS, len); memcpy (d, ub, sizeof (PinosMessageUseBuffers)); mr = SPA_MEMBER (d, sizeof (PinosMessageUseBuffers), void); @@ -332,7 +466,7 @@ connection_add_use_buffers (PinosConnection *conn, PinosMessageUseBuffers *ub) } static void -connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev) +connection_add_node_event (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeEvent *ev) { size_t len; void *p; @@ -342,7 +476,7 @@ connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev) len = sizeof (PinosMessageNodeEvent); len += ev->event->size; - p = connection_add_message (conn, PINOS_MESSAGE_NODE_EVENT, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_EVENT, len); memcpy (p, ev, sizeof (PinosMessageNodeEvent)); d = p; @@ -353,7 +487,7 @@ connection_add_node_event (PinosConnection *conn, PinosMessageNodeEvent *ev) } static void -connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm) +connection_add_node_command (PinosConnection *conn, uint32_t dest_id, PinosMessageNodeCommand *cm) { size_t len; void *p; @@ -363,7 +497,7 @@ connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm) len = sizeof (PinosMessageNodeCommand); len += cm->command->size; - p = connection_add_message (conn, PINOS_MESSAGE_NODE_COMMAND, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_NODE_COMMAND, len); memcpy (p, cm, sizeof (PinosMessageNodeCommand)); d = p; @@ -374,7 +508,7 @@ connection_add_node_command (PinosConnection *conn, PinosMessageNodeCommand *cm) } static void -connection_add_port_command (PinosConnection *conn, PinosMessagePortCommand *cm) +connection_add_port_command (PinosConnection *conn, uint32_t dest_id, PinosMessagePortCommand *cm) { size_t len; void *p; @@ -384,7 +518,7 @@ connection_add_port_command (PinosConnection *conn, PinosMessagePortCommand *cm) len = sizeof (PinosMessagePortCommand); len += cm->command->size; - p = connection_add_message (conn, PINOS_MESSAGE_PORT_COMMAND, len); + p = connection_add_message (conn, dest_id, PINOS_MESSAGE_PORT_COMMAND, len); memcpy (p, cm, sizeof (PinosMessagePortCommand)); d = p; @@ -422,7 +556,7 @@ refill_buffer (PinosConnection *conn, ConnectionBuffer *buf) break; } - if (len < 4) + if (len < 8) return false; buf->buffer_size += len; @@ -450,14 +584,6 @@ recv_error: static void clear_buffer (ConnectionBuffer *buf) { - unsigned int i; - - for (i = 0; i < buf->n_fds; i++) { - if (buf->fds[i] > 0) { - if (close (buf->fds[i]) < 0) - perror ("close"); - } - } buf->n_fds = 0; buf->type = PINOS_MESSAGE_INVALID; buf->offset = 0; @@ -471,6 +597,7 @@ pinos_connection_new (int fd) PinosConnection *c; c = calloc (1, sizeof (PinosConnection)); + pinos_log_debug ("connection %p: new", c); c->fd = fd; c->out.buffer_data = malloc (MAX_BUFFER_SIZE); c->out.buffer_maxsize = MAX_BUFFER_SIZE; @@ -482,8 +609,9 @@ pinos_connection_new (int fd) } void -pinos_connection_free (PinosConnection *conn) +pinos_connection_destroy (PinosConnection *conn) { + pinos_log_debug ("connection %p: destroy", conn); free (conn->out.buffer_data); free (conn->in.buffer_data); free (conn); @@ -498,11 +626,15 @@ pinos_connection_free (PinosConnection *conn) * Returns: %true if more packets are available. */ bool -pinos_connection_has_next (PinosConnection *conn) +pinos_connection_get_next (PinosConnection *conn, + PinosMessageType *type, + uint32_t *dest_id, + size_t *sz) { - size_t len, size, skip; + size_t len, size; uint8_t *data; ConnectionBuffer *buf; + uint32_t *p; spa_return_val_if_fail (conn != NULL, false); @@ -530,30 +662,35 @@ again: data += buf->offset; size -= buf->offset; - buf->type = *data; - data++; - size--; + if (size < 8) { + connection_ensure_size (conn, buf, 8); + buf->update = true; + goto again; + } + p = (uint32_t *) data; + data += 8; + size -= 8; - if (!read_length (data, size, &len, &skip)) { - connection_ensure_size (conn, buf, len + skip); + buf->dest_id = p[0]; + buf->type = p[1] >> 16; + len = p[1] & 0xffff; + + if (len > size) { + connection_ensure_size (conn, buf, len); buf->update = true; goto again; } buf->size = len; - buf->data = data + skip; - buf->offset += 1 + skip; + buf->data = data; + buf->offset += 8; + + *type = buf->type; + *dest_id = buf->dest_id; + *sz = buf->size; return true; } -PinosMessageType -pinos_connection_get_type (PinosConnection *conn) -{ - spa_return_val_if_fail (conn != NULL, PINOS_MESSAGE_INVALID); - - return conn->in.type; -} - bool pinos_connection_parse_message (PinosConnection *conn, void *message) @@ -561,6 +698,58 @@ pinos_connection_parse_message (PinosConnection *conn, spa_return_val_if_fail (conn != NULL, false); switch (conn->in.type) { + case PINOS_MESSAGE_SYNC: + if (conn->in.size < sizeof (PinosMessageSync)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageSync)); + break; + + case PINOS_MESSAGE_NOTIFY_DONE: + if (conn->in.size < sizeof (PinosMessageNotifyDone)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageNotifyDone)); + break; + + case PINOS_MESSAGE_SUBSCRIBE: + if (conn->in.size < sizeof (PinosMessageSubscribe)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageSubscribe)); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL: + connection_parse_notify_global (conn, message); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE: + if (conn->in.size < sizeof (PinosMessageNotifyGlobalRemove)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageNotifyGlobalRemove)); + break; + + case PINOS_MESSAGE_CREATE_NODE: + connection_parse_create_node (conn, message); + break; + + case PINOS_MESSAGE_CREATE_NODE_DONE: + if (conn->in.size < sizeof (PinosMessageCreateNodeDone)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageCreateNodeDone)); + break; + + case PINOS_MESSAGE_CREATE_CLIENT_NODE: + connection_parse_create_client_node (conn, message); + break; + + case PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE: + { + PinosMessageCreateClientNodeDone *d = message; + if (conn->in.size < sizeof (PinosMessageCreateClientNodeDone)) + return false; + memcpy (message, conn->in.data, sizeof (PinosMessageCreateClientNodeDone)); + d->datafd = connection_get_fd (conn, d->datafd); + break; + } + /* C -> S */ case PINOS_MESSAGE_NODE_UPDATE: connection_parse_node_update (conn, message); @@ -603,21 +792,19 @@ pinos_connection_parse_message (PinosConnection *conn, /* bidirectional */ case PINOS_MESSAGE_ADD_MEM: + { + PinosMessageAddMem *d = message; if (conn->in.size < sizeof (PinosMessageAddMem)) return false; memcpy (message, conn->in.data, sizeof (PinosMessageAddMem)); + d->memfd = connection_get_fd (conn, d->memfd); break; + } case PINOS_MESSAGE_USE_BUFFERS: connection_parse_use_buffers (conn, message); break; - case PINOS_MESSAGE_PROCESS_BUFFER: - if (conn->in.size < sizeof (PinosMessageProcessBuffer)) - return false; - memcpy (message, conn->in.data, sizeof (PinosMessageProcessBuffer)); - break; - case PINOS_MESSAGE_NODE_EVENT: connection_parse_node_event (conn, message); break; @@ -631,10 +818,14 @@ pinos_connection_parse_message (PinosConnection *conn, break; case PINOS_MESSAGE_TRANSPORT_UPDATE: + { + PinosMessageTransportUpdate *d = message; if (conn->in.size < sizeof (PinosMessageTransportUpdate)) return false; memcpy (message, conn->in.data, sizeof (PinosMessageTransportUpdate)); + d->memfd = connection_get_fd (conn, d->memfd); break; + } case PINOS_MESSAGE_INVALID: return false; @@ -642,66 +833,6 @@ pinos_connection_parse_message (PinosConnection *conn, return true; } -/** - * pinos_connection_get_fd: - * @conn: a #PinosConnection - * @index: an index - * @steal: steal the fd - * - * Get the file descriptor at @index in @conn. - * - * Returns: a file descriptor at @index in @conn. The file descriptor - * is not duplicated in any way. -1 is returned on error. - */ -int -pinos_connection_get_fd (PinosConnection *conn, - unsigned int index, - bool close) -{ - int fd; - - spa_return_val_if_fail (conn != NULL, -1); - spa_return_val_if_fail (index < conn->in.n_fds, -1); - - fd = conn->in.fds[index]; - if (fd < 0) - fd = -fd; - conn->in.fds[index] = close ? fd : -fd; - - return fd; -} - -/** - * pinos_connection_add_fd: - * @conn: a #PinosConnection - * @fd: a valid fd - * @close: if the descriptor should be closed when sent - * - * Add the file descriptor @fd to @builder. - * - * Returns: the index of the file descriptor in @builder. - */ -int -pinos_connection_add_fd (PinosConnection *conn, - int fd, - bool close) -{ - int index, i; - - spa_return_val_if_fail (conn != NULL, -1); - - for (i = 0; i < conn->out.n_fds; i++) { - if (conn->out.fds[i] == fd || conn->out.fds[i] == -fd) - return i; - } - - index = conn->out.n_fds; - conn->out.fds[index] = close ? fd : -fd; - conn->out.n_fds++; - - return index; -} - /** * pinos_connection_add_message: * @conn: a #PinosConnection @@ -714,6 +845,7 @@ pinos_connection_add_fd (PinosConnection *conn, */ bool pinos_connection_add_message (PinosConnection *conn, + uint32_t dest_id, PinosMessageType type, void *message) { @@ -723,37 +855,83 @@ pinos_connection_add_message (PinosConnection *conn, spa_return_val_if_fail (message != NULL, false); switch (type) { + case PINOS_MESSAGE_SYNC: + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageSync)); + memcpy (p, message, sizeof (PinosMessageSync)); + break; + + case PINOS_MESSAGE_NOTIFY_DONE: + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNotifyDone)); + memcpy (p, message, sizeof (PinosMessageNotifyDone)); + break; + + case PINOS_MESSAGE_SUBSCRIBE: + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageSubscribe)); + memcpy (p, message, sizeof (PinosMessageSubscribe)); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL: + connection_add_notify_global (conn, dest_id, message); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE: + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNotifyGlobalRemove)); + memcpy (p, message, sizeof (PinosMessageNotifyGlobalRemove)); + break; + + case PINOS_MESSAGE_CREATE_NODE: + connection_add_create_node (conn, dest_id, message); + break; + + case PINOS_MESSAGE_CREATE_NODE_DONE: + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageCreateNodeDone)); + memcpy (p, message, sizeof (PinosMessageCreateNodeDone)); + break; + + case PINOS_MESSAGE_CREATE_CLIENT_NODE: + connection_add_create_client_node (conn, dest_id, message); + break; + + case PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE: + { + PinosMessageCreateClientNodeDone *d; + d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageCreateClientNodeDone)); + memcpy (d, message, sizeof (PinosMessageCreateClientNodeDone)); + d->datafd = connection_add_fd (conn, d->datafd); + break; + } + /* C -> S */ case PINOS_MESSAGE_NODE_UPDATE: - connection_add_node_update (conn, message); + connection_add_node_update (conn, dest_id, message); break; case PINOS_MESSAGE_PORT_UPDATE: - connection_add_port_update (conn, message); + connection_add_port_update (conn, dest_id, message); break; case PINOS_MESSAGE_PORT_STATUS_CHANGE: - p = connection_add_message (conn, type, 0); + p = connection_add_message (conn, dest_id, type, 0); break; case PINOS_MESSAGE_NODE_STATE_CHANGE: - p = connection_add_message (conn, type, sizeof (PinosMessageNodeStateChange)); + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageNodeStateChange)); memcpy (p, message, sizeof (PinosMessageNodeStateChange)); break; /* S -> C */ case PINOS_MESSAGE_ADD_PORT: - p = connection_add_message (conn, type, sizeof (PinosMessageAddPort)); + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageAddPort)); memcpy (p, message, sizeof (PinosMessageAddPort)); break; case PINOS_MESSAGE_REMOVE_PORT: - p = connection_add_message (conn, type, sizeof (PinosMessageRemovePort)); + p = connection_add_message (conn, dest_id, type, sizeof (PinosMessageRemovePort)); memcpy (p, message, sizeof (PinosMessageRemovePort)); break; case PINOS_MESSAGE_SET_FORMAT: - connection_add_set_format (conn, message); + connection_add_set_format (conn, dest_id, message); break; case PINOS_MESSAGE_SET_PROPERTY: @@ -762,35 +940,38 @@ pinos_connection_add_message (PinosConnection *conn, /* bidirectional */ case PINOS_MESSAGE_ADD_MEM: - p = connection_add_message (conn, type, sizeof (PinosMessageAddMem)); - memcpy (p, message, sizeof (PinosMessageAddMem)); + { + PinosMessageAddMem *d; + d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageAddMem)); + memcpy (d, message, sizeof (PinosMessageAddMem)); + d->memfd = connection_add_fd (conn, d->memfd); break; + } case PINOS_MESSAGE_USE_BUFFERS: - connection_add_use_buffers (conn, message); - break; - - case PINOS_MESSAGE_PROCESS_BUFFER: - p = connection_add_message (conn, type, sizeof (PinosMessageProcessBuffer)); - memcpy (p, message, sizeof (PinosMessageProcessBuffer)); + connection_add_use_buffers (conn, dest_id, message); break; case PINOS_MESSAGE_NODE_EVENT: - connection_add_node_event (conn, message); + connection_add_node_event (conn, dest_id, message); break; case PINOS_MESSAGE_NODE_COMMAND: - connection_add_node_command (conn, message); + connection_add_node_command (conn, dest_id, message); break; case PINOS_MESSAGE_PORT_COMMAND: - connection_add_port_command (conn, message); + connection_add_port_command (conn, dest_id, message); break; case PINOS_MESSAGE_TRANSPORT_UPDATE: - p = connection_add_message (conn, type, sizeof (PinosMessageTransportUpdate)); - memcpy (p, message, sizeof (PinosMessageTransportUpdate)); + { + PinosMessageTransportUpdate *d; + d = connection_add_message (conn, dest_id, type, sizeof (PinosMessageTransportUpdate)); + memcpy (d, message, sizeof (PinosMessageTransportUpdate)); + d->memfd = connection_add_fd (conn, d->memfd); break; + } case PINOS_MESSAGE_INVALID: return false; diff --git a/pinos/client/connection.h b/pinos/client/connection.h index 4f0b3d884..38aea4871 100644 --- a/pinos/client/connection.h +++ b/pinos/client/connection.h @@ -34,34 +34,100 @@ typedef struct _PinosConnection PinosConnection; typedef enum { PINOS_MESSAGE_INVALID = 0, - /* client to server */ - PINOS_MESSAGE_NODE_UPDATE = 1, - PINOS_MESSAGE_PORT_UPDATE = 2, - PINOS_MESSAGE_NODE_STATE_CHANGE = 3, - PINOS_MESSAGE_PORT_STATUS_CHANGE = 4, - PINOS_MESSAGE_NODE_EVENT = 5, + PINOS_MESSAGE_SYNC, + PINOS_MESSAGE_NOTIFY_DONE, + + PINOS_MESSAGE_SUBSCRIBE, + PINOS_MESSAGE_NOTIFY_GLOBAL, + PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE, + + PINOS_MESSAGE_CREATE_NODE, + PINOS_MESSAGE_CREATE_NODE_DONE, + + PINOS_MESSAGE_CREATE_CLIENT_NODE, + PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE, + + /* client to server */ + PINOS_MESSAGE_NODE_UPDATE, + PINOS_MESSAGE_PORT_UPDATE, + PINOS_MESSAGE_NODE_STATE_CHANGE, + + PINOS_MESSAGE_PORT_STATUS_CHANGE, + PINOS_MESSAGE_NODE_EVENT, /* server to client */ - PINOS_MESSAGE_TRANSPORT_UPDATE = 32, + PINOS_MESSAGE_TRANSPORT_UPDATE, - PINOS_MESSAGE_ADD_PORT = 33, - PINOS_MESSAGE_REMOVE_PORT = 34, + PINOS_MESSAGE_ADD_PORT, + PINOS_MESSAGE_REMOVE_PORT, - PINOS_MESSAGE_SET_FORMAT = 35, - PINOS_MESSAGE_SET_PROPERTY = 36, + PINOS_MESSAGE_SET_FORMAT, + PINOS_MESSAGE_SET_PROPERTY, - PINOS_MESSAGE_NODE_COMMAND = 37, - PINOS_MESSAGE_PORT_COMMAND = 38, + PINOS_MESSAGE_NODE_COMMAND, + PINOS_MESSAGE_PORT_COMMAND, /* both */ - PINOS_MESSAGE_ADD_MEM = 64, - PINOS_MESSAGE_USE_BUFFERS = 66, - - PINOS_MESSAGE_PROCESS_BUFFER = 67, + PINOS_MESSAGE_ADD_MEM, + PINOS_MESSAGE_USE_BUFFERS, } PinosMessageType; +/* PINOS_MESSAGE_SYNC */ +typedef struct { + uint32_t seq; +} PinosMessageSync; + +/* PINOS_MESSAGE_NOTIFY_DONE */ +typedef struct { + uint32_t seq; +} PinosMessageNotifyDone; + +/* PINOS_MESSAGE_SUBSCRIBE */ +typedef struct { + uint32_t seq; +} PinosMessageSubscribe; + +/* PINOS_MESSAGE_NOTIFY_GLOBAL */ +typedef struct { + uint32_t id; + const char * type; +} PinosMessageNotifyGlobal; + +/* PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE */ +typedef struct { + uint32_t id; +} PinosMessageNotifyGlobalRemove; + +/* PINOS_MESSAGE_CREATE_NODE */ +typedef struct { + uint32_t seq; + const char *factory_name; + const char *name; + SpaDict *props; + uint32_t id; +} PinosMessageCreateNode; + +/* PINOS_MESSAGE_CREATE_NODE_DONE */ +typedef struct { + uint32_t seq; +} PinosMessageCreateNodeDone; + +/* PINOS_MESSAGE_CREATE_CLIENT_NODE */ +typedef struct { + uint32_t seq; + const char *name; + SpaDict *props; + uint32_t id; +} PinosMessageCreateClientNode; + +/* PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE */ +typedef struct { + uint32_t seq; + int datafd; +} PinosMessageCreateClientNodeDone; + /* PINOS_MESSAGE_NODE_UPDATE */ typedef struct { #define PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS (1 << 0) @@ -147,7 +213,7 @@ typedef struct { /* PINOS_MESSAGE_TRANSPORT_UPDATE */ typedef struct { - unsigned int memfd_index; + int memfd; off_t offset; size_t size; } PinosMessageTransportUpdate; @@ -158,7 +224,7 @@ typedef struct { uint32_t port_id; uint32_t mem_id; SpaDataType type; - unsigned int fd_index; + int memfd; uint32_t flags; off_t offset; size_t size; @@ -179,28 +245,17 @@ typedef struct { PinosMessageMemRef *buffers; } PinosMessageUseBuffers; -/* PINOS_MESSAGE_PROCESS_BUFFER */ -typedef struct { - SpaDirection direction; - uint32_t port_id; - uint32_t buffer_id; -} PinosMessageProcessBuffer; - PinosConnection * pinos_connection_new (int fd); -void pinos_connection_free (PinosConnection *conn); +void pinos_connection_destroy (PinosConnection *conn); -bool pinos_connection_has_next (PinosConnection *conn); -PinosMessageType pinos_connection_get_type (PinosConnection *conn); +bool pinos_connection_get_next (PinosConnection *conn, + PinosMessageType *type, + uint32_t *dest_id, + size_t *size); bool pinos_connection_parse_message (PinosConnection *conn, void *msg); -int pinos_connection_get_fd (PinosConnection *conn, - unsigned int index, - bool close); - -int pinos_connection_add_fd (PinosConnection *conn, - int fd, - bool close); bool pinos_connection_add_message (PinosConnection *conn, + uint32_t dest_id, PinosMessageType type, void *msg); diff --git a/pinos/client/context.c b/pinos/client/context.c index 1845b08be..7c52b61d9 100644 --- a/pinos/client/context.c +++ b/pinos/client/context.c @@ -17,283 +17,31 @@ * Boston, MA 02110-1301, USA. */ +#include +#include +#include +#include +#include + #include "pinos/client/pinos.h" #include "pinos/client/context.h" -#include "pinos/client/enumtypes.h" +#include "pinos/client/connection.h" #include "pinos/client/subscribe.h" -#include "pinos/client/private.h" +typedef struct { + PinosContext this; -#define PINOS_CONTEXT_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_CONTEXT, PinosContextPrivate)) + int fd; + PinosConnection *connection; + SpaSource source; -G_DEFINE_TYPE (PinosContext, pinos_context, G_TYPE_OBJECT); + bool disconnecting; -static void subscription_state (GObject *object, GParamSpec *pspec, gpointer user_data); -static void subscription_cb (PinosSubscribe *subscribe, - PinosSubscriptionEvent event, - PinosSubscriptionFlags flags, - GDBusProxy *object, - gpointer user_data); - -enum -{ - PROP_0, - PROP_MAIN_CONTEXT, - PROP_NAME, - PROP_PROPERTIES, - PROP_STATE, - PROP_CONNECTION, - PROP_SUBSCRIPTION_MASK, -}; - -enum -{ - SIGNAL_SUBSCRIPTION_EVENT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -pinos_context_get_property (GObject *_object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PinosContext *context = PINOS_CONTEXT (_object); - PinosContextPrivate *priv = context->priv; - - switch (prop_id) { - case PROP_MAIN_CONTEXT: - g_value_set_boxed (value, priv->context); - break; - - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - - case PROP_PROPERTIES: - g_value_set_boxed (value, priv->properties); - break; - - case PROP_STATE: - g_value_set_enum (value, priv->state); - break; - - case PROP_CONNECTION: - g_value_set_object (value, priv->connection); - break; - - case PROP_SUBSCRIPTION_MASK: - g_value_set_flags (value, priv->subscription_mask); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec); - break; - } -} - -static void -pinos_context_set_property (GObject *_object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - PinosContext *context = PINOS_CONTEXT (_object); - PinosContextPrivate *priv = context->priv; - - switch (prop_id) { - case PROP_MAIN_CONTEXT: - priv->context = g_value_dup_boxed (value); - break; - - case PROP_NAME: - g_free (priv->name); - priv->name = g_value_dup_string (value); - break; - - case PROP_PROPERTIES: - if (priv->properties) - pinos_properties_free (priv->properties); - priv->properties = g_value_dup_boxed (value); - break; - - case PROP_SUBSCRIPTION_MASK: - priv->subscription_mask = g_value_get_flags (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (context, prop_id, pspec); - break; - } -} - -static void -pinos_context_finalize (GObject * object) -{ - PinosContext *context = PINOS_CONTEXT (object); - PinosContextPrivate *priv = context->priv; - - pinos_log_debug ("free context %p", context); - - if (priv->id) - g_bus_unwatch_name(priv->id); - - g_clear_pointer (&priv->context, g_main_context_unref); - g_free (priv->name); - if (priv->properties) - pinos_properties_free (priv->properties); - - g_list_free (priv->nodes); - g_list_free (priv->links); - g_list_free (priv->clients); - g_clear_object (&priv->subscribe); - g_clear_error (&priv->error); - - G_OBJECT_CLASS (pinos_context_parent_class)->finalize (object); -} - -static void -pinos_context_class_init (PinosContextClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosContextPrivate)); - - gobject_class->finalize = pinos_context_finalize; - gobject_class->set_property = pinos_context_set_property; - gobject_class->get_property = pinos_context_get_property; - - /** - * PinosContext:main-context - * - * The main context to use - */ - g_object_class_install_property (gobject_class, - PROP_MAIN_CONTEXT, - g_param_spec_boxed ("main-context", - "Main Context", - "The main context to use", - G_TYPE_MAIN_CONTEXT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:name - * - * The application name of the context. - */ - g_object_class_install_property (gobject_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "The application name", - NULL, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:properties - * - * Properties of the context. - */ - g_object_class_install_property (gobject_class, - PROP_PROPERTIES, - g_param_spec_boxed ("properties", - "Properties", - "Extra properties", - PINOS_TYPE_PROPERTIES, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:state - * - * The state of the context. - */ - g_object_class_install_property (gobject_class, - PROP_STATE, - g_param_spec_enum ("state", - "State", - "The context state", - PINOS_TYPE_CONTEXT_STATE, - PINOS_CONTEXT_STATE_UNCONNECTED, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:connection - * - * The connection of the context. - */ - g_object_class_install_property (gobject_class, - PROP_CONNECTION, - g_param_spec_object ("connection", - "Connection", - "The DBus connection", - G_TYPE_DBUS_CONNECTION, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:subscription-mask - * - * The subscription mask - */ - g_object_class_install_property (gobject_class, - PROP_SUBSCRIPTION_MASK, - g_param_spec_flags ("subscription-mask", - "Subscription Mask", - "The object to receive subscription events of", - PINOS_TYPE_SUBSCRIPTION_FLAGS, - 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosContext:subscription-event - * @subscribe: The #PinosContext emitting the signal. - * @event: A #PinosSubscriptionEvent - * @flags: #PinosSubscriptionFlags indicating the object - * @object: the GDBusProxy object - * - * Notify about a new object that was added/removed/modified. - */ - signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 3, - PINOS_TYPE_SUBSCRIPTION_EVENT, - PINOS_TYPE_SUBSCRIPTION_FLAGS, - G_TYPE_DBUS_PROXY); - -} - -static void -pinos_context_init (PinosContext * context) -{ - PinosContextPrivate *priv = context->priv = PINOS_CONTEXT_GET_PRIVATE (context); - - pinos_log_debug ("new context %p", context); - - priv->state = PINOS_CONTEXT_STATE_UNCONNECTED; - - priv->subscribe = pinos_subscribe_new (); - g_object_set (priv->subscribe, - "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, - NULL); - g_signal_connect (priv->subscribe, - "subscription-event", - (GCallback) subscription_cb, - context); - g_signal_connect (priv->subscribe, - "notify::state", - (GCallback) subscription_state, - context); -} + PinosSubscriptionFlags subscribe_mask; + PinosSubscriptionFunc subscribe_func; + void *subscribe_data; +} PinosContextImpl; /** * pinos_context_state_as_string: @@ -303,15 +51,157 @@ pinos_context_init (PinosContext * context) * * Returns: the string representation of @state. */ -const gchar * +const char * pinos_context_state_as_string (PinosContextState state) { - GEnumValue *val; + switch (state) { + case PINOS_CONTEXT_STATE_ERROR: + return "error"; + case PINOS_CONTEXT_STATE_UNCONNECTED: + return "unconnected"; + case PINOS_CONTEXT_STATE_CONNECTING: + return "connecting"; + case PINOS_CONTEXT_STATE_CONNECTED: + return "connected"; + } + return "invalid-state"; +} - val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_CONTEXT_STATE)), - state); +static void +context_set_state (PinosContext *context, + PinosContextState state, + const char *fmt, + ...) +{ + if (context->state != state) { + pinos_log_debug ("context %p: update state from %s -> %s", context, + pinos_context_state_as_string (context->state), + pinos_context_state_as_string (state)); - return val == NULL ? "invalid-state" : val->value_nick; + if (context->error) + free (context->error); + + if (fmt) { + va_list varargs; + + va_start (varargs, fmt); + vasprintf (&context->error, fmt, varargs); + va_end (varargs); + } else { + context->error = NULL; + } + + context->state = state; + pinos_signal_emit (&context->state_changed, context); + } +} + +static SpaResult +core_dispatch_func (void *object, + PinosMessageType type, + void *message, + void *data) +{ + PinosContext *context = data; + + switch (type) { + case PINOS_MESSAGE_NOTIFY_DONE: + { + PinosMessageNotifyDone *nd = message; + + if (nd->seq == 0) + context_set_state (context, PINOS_CONTEXT_STATE_CONNECTED, NULL); + break; + } + case PINOS_MESSAGE_NOTIFY_GLOBAL: + { + PinosMessageNotifyGlobal *ng = message; + pinos_log_warn ("global %u %s", ng->id, ng->type); + break; + } + default: + pinos_log_warn ("unhandled message %d", type); + break; + } + return SPA_RESULT_OK; +} + +static PinosProxy * +find_proxy (PinosContext *context, + uint32_t id) +{ + PinosProxy *p; + + spa_list_for_each (p, &context->proxy_list, link) { + if (p->id == id) + return p; + } + return NULL; +} + +static void +on_context_data (SpaSource *source, + int fd, + SpaIO mask, + void *data) +{ + PinosContextImpl *impl = data; + PinosContext *this = &impl->this; + + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + context_set_state (this, + PINOS_CONTEXT_STATE_ERROR, + "connection closed"); + return; + } + + if (mask & SPA_IO_IN) { + PinosConnection *conn = impl->connection; + PinosMessageType type; + uint32_t id; + size_t size; + + while (pinos_connection_get_next (conn, &type, &id, &size)) { + void *p = alloca (size); + PinosProxy *proxy; + + pinos_log_error ("context %p: got message %d from %u", this, type, id); + + if (!pinos_connection_parse_message (conn, p)) { + pinos_log_error ("context %p: failed to parse message", this); + continue; + } + + proxy = find_proxy (this, id); + if (proxy == NULL) { + pinos_log_error ("context %p: could not find proxy %u", this, id); + continue; + } + + proxy->dispatch_func (proxy, type, p, proxy->dispatch_data); + } + } +} + +static SpaResult +context_send_func (void *object, + uint32_t id, + PinosMessageType type, + void *message, + bool flush, + void *data) +{ + PinosContextImpl *impl = SPA_CONTAINER_OF (data, PinosContextImpl, this); + + pinos_log_error ("context %p: send message %d to %u", &impl->this, type, id); + pinos_connection_add_message (impl->connection, + id, + type, + message); + if (flush) + pinos_connection_flush (impl->connection); + + return SPA_RESULT_OK; } /** @@ -325,197 +215,67 @@ pinos_context_state_as_string (PinosContextState state) * Returns: a new unconnected #PinosContext */ PinosContext * -pinos_context_new (GMainContext *context, - const gchar *name, +pinos_context_new (PinosLoop *loop, + const char *name, PinosProperties *properties) { - PinosContext *ctx; + PinosContextImpl *impl; + PinosContext *this; - g_return_val_if_fail (name != NULL, NULL); + impl = calloc (1, sizeof (PinosContextImpl)); + this = &impl->this; + pinos_log_debug ("context %p: new", impl); + + this->name = strdup (name); if (properties == NULL) properties = pinos_properties_new ("application.name", name, NULL); - pinos_fill_context_properties (properties); + this->properties = properties; - ctx = g_object_new (PINOS_TYPE_CONTEXT, - "main-context", context, - "name", name, - "properties", properties, - NULL); + this->loop = loop; - pinos_properties_free (properties); + this->state = PINOS_CONTEXT_STATE_UNCONNECTED; - return ctx; + this->send_func = context_send_func; + this->send_data = this; + + pinos_map_init (&this->objects, 64); + + spa_list_init (&this->stream_list); + spa_list_init (&this->global_list); + spa_list_init (&this->proxy_list); + + pinos_signal_init (&this->state_changed); + pinos_signal_init (&this->destroy_signal); + + return this; } -static gboolean -do_notify_state (PinosContext *context) +void +pinos_context_destroy (PinosContext *context) { - g_object_notify (G_OBJECT (context), "state"); - g_object_unref (context); - return FALSE; -} + PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this); + PinosStream *stream, *t1; + PinosProxy *proxy, *t2; -static void -context_set_state (PinosContext *context, - PinosContextState state, - GError *error) -{ - if (context->priv->state != state) { - if (error) { - g_clear_error (&context->priv->error); - context->priv->error = error; - } - context->priv->state = state; - g_main_context_invoke (context->priv->context, - (GSourceFunc) do_notify_state, - g_object_ref (context)); - } else { - if (error) - g_error_free (error); - } -} + pinos_log_debug ("context %p: destroy", context); + pinos_signal_emit (&context->destroy_signal, context); -static void -on_daemon_connected (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosContext *context = user_data; + spa_list_for_each_safe (stream, t1, &context->stream_list, link) + pinos_stream_destroy (stream); + spa_list_for_each_safe (proxy, t2, &context->proxy_list, link) + pinos_proxy_destroy (proxy); - context_set_state (context, PINOS_CONTEXT_STATE_CONNECTED, NULL); -} + if (context->name) + free (context->name); + if (context->properties) + pinos_properties_free (context->properties); -static void -subscription_cb (PinosSubscribe *subscribe, - PinosSubscriptionEvent event, - PinosSubscriptionFlags flags, - GDBusProxy *object, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; + if (context->error) + free (context->error); - switch (flags) { - case PINOS_SUBSCRIPTION_FLAG_DAEMON: - priv->daemon = g_object_ref (object); - break; - - case PINOS_SUBSCRIPTION_FLAG_CLIENT: - if (event == PINOS_SUBSCRIPTION_EVENT_NEW) - priv->clients = g_list_prepend (priv->clients, object); - else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) - priv->clients = g_list_remove (priv->clients, object); - break; - - case PINOS_SUBSCRIPTION_FLAG_NODE: - if (event == PINOS_SUBSCRIPTION_EVENT_NEW) - priv->nodes = g_list_prepend (priv->nodes, object); - else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) - priv->nodes = g_list_remove (priv->nodes, object); - break; - - case PINOS_SUBSCRIPTION_FLAG_LINK: - if (event == PINOS_SUBSCRIPTION_EVENT_NEW) - priv->links = g_list_prepend (priv->links, object); - else if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) - priv->links = g_list_remove (priv->links, object); - break; - } - - if (flags & priv->subscription_mask) - g_signal_emit (context, - signals[SIGNAL_SUBSCRIPTION_EVENT], - 0, - event, - flags, - object); - -} - -static void -subscription_state (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - PinosSubscriptionState state; - - g_assert (object == G_OBJECT (priv->subscribe)); - - state = pinos_subscribe_get_state (priv->subscribe); - - switch (state) { - case PINOS_SUBSCRIPTION_STATE_READY: - on_daemon_connected (NULL, NULL, context); - break; - - default: - break; - } - -} - -static void -on_name_appeared (GDBusConnection *connection, - const gchar *name, - const gchar *name_owner, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - - priv->connection = connection; - - g_object_set (priv->subscribe, "connection", priv->connection, - "service", name, NULL); -} - -static void -on_name_vanished (GDBusConnection *connection, - const gchar *name, - gpointer user_data) -{ - PinosContext *context = user_data; - PinosContextPrivate *priv = context->priv; - - priv->connection = connection; - - g_object_set (priv->subscribe, "connection", connection, NULL); - - if (priv->flags & PINOS_CONTEXT_FLAGS_NOFAIL) { - context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL); - } else { - context_set_state (context, - PINOS_CONTEXT_STATE_ERROR, - g_error_new_literal (G_IO_ERROR, - G_IO_ERROR_CLOSED, - "Connection closed")); - } -} - -static gboolean -do_connect (PinosContext *context) -{ - PinosContextPrivate *priv = context->priv; - GBusNameWatcherFlags nw_flags; - - nw_flags = G_BUS_NAME_WATCHER_FLAGS_NONE; - if (!(priv->flags & PINOS_CONTEXT_FLAGS_NOAUTOSPAWN)) - nw_flags = G_BUS_NAME_WATCHER_FLAGS_AUTO_START; - - priv->id = g_bus_watch_name (G_BUS_TYPE_SESSION, - PINOS_DBUS_SERVICE, - nw_flags, - on_name_appeared, - on_name_vanished, - context, - NULL); - g_object_unref (context); - - return FALSE; + free (impl); } /** @@ -527,38 +287,77 @@ do_connect (PinosContext *context) * * Returns: %TRUE on success. */ -gboolean -pinos_context_connect (PinosContext *context, - PinosContextFlags flags) +bool +pinos_context_connect (PinosContext *context) { - PinosContextPrivate *priv; - - g_return_val_if_fail (PINOS_IS_CONTEXT (context), FALSE); - - priv = context->priv; - g_return_val_if_fail (priv->connection == NULL, FALSE); - - priv->flags = flags; + PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this); + struct sockaddr_un addr; + socklen_t size; + const char *runtime_dir, *name = NULL; + int name_size, fd; + PinosMessageSubscribe sm; context_set_state (context, PINOS_CONTEXT_STATE_CONNECTING, NULL); - g_main_context_invoke (priv->context, - (GSourceFunc) do_connect, - g_object_ref (context)); - return TRUE; -} - -static void -do_disconnect (PinosContext *context) -{ - PinosContextPrivate *priv = context->priv; - - g_clear_object (&priv->daemon); - if (priv->id) { - g_bus_unwatch_name(priv->id); - priv->id = 0; + if ((runtime_dir = getenv ("XDG_RUNTIME_DIR")) == NULL) { + context_set_state (context, + PINOS_CONTEXT_STATE_ERROR, + "connect failed: XDG_RUNTIME_DIR not set in the environment"); + return false; } - context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL); + + if (name == NULL) + name = getenv("PINOS_CORE"); + if (name == NULL) + name = "pinos-0"; + + if ((fd = socket (PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0)) < 0) + return false; + + memset (&addr, 0, sizeof (addr)); + addr.sun_family = AF_LOCAL; + name_size = snprintf (addr.sun_path, sizeof (addr.sun_path), + "%s/%s", runtime_dir, name) + 1; + + if (name_size > (int)sizeof addr.sun_path) { + pinos_log_error ("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", + runtime_dir, name); + close (fd); + return false; + }; + + size = offsetof (struct sockaddr_un, sun_path) + name_size; + + if (connect (fd, (struct sockaddr *) &addr, size) < 0) { + context_set_state (context, + PINOS_CONTEXT_STATE_ERROR, + "connect failed: %s", strerror (errno)); + close (fd); + return false; + } + + impl->fd = fd; + impl->connection = pinos_connection_new (fd); + + pinos_loop_add_io (context->loop, + fd, + SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, + false, + on_context_data, + impl); + + context->core_proxy = pinos_proxy_new (context, + SPA_ID_INVALID, + 0); + context->core_proxy->dispatch_func = core_dispatch_func; + context->core_proxy->dispatch_data = context; + + sm.seq = 0; + pinos_proxy_send_message (context->core_proxy, + PINOS_MESSAGE_SUBSCRIBE, + &sm, + true); + return true; } /** @@ -569,60 +368,89 @@ do_disconnect (PinosContext *context) * * Returns: %TRUE on success. */ -gboolean +bool pinos_context_disconnect (PinosContext *context) { - PinosContextPrivate *priv; + PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this); - g_return_val_if_fail (PINOS_IS_CONTEXT (context), FALSE); + impl->disconnecting = true; - priv = context->priv; - g_return_val_if_fail (!priv->disconnecting, FALSE); + pinos_connection_destroy (impl->connection); + close (impl->fd); - priv->disconnecting = TRUE; + context_set_state (context, PINOS_CONTEXT_STATE_UNCONNECTED, NULL); - g_main_context_invoke (priv->context, - (GSourceFunc) do_disconnect, - g_object_ref (context)); - - return TRUE; + return true; } -/** - * pinos_context_get_state: - * @context: a #PinosContext - * - * Get the state of @context. - * - * Returns: the state of @context - */ -PinosContextState -pinos_context_get_state (PinosContext *context) +void +pinos_context_subscribe (PinosContext *context, + PinosSubscriptionFlags mask, + PinosSubscriptionFunc func, + void *data) { - PinosContextPrivate *priv; + PinosContextImpl *impl = SPA_CONTAINER_OF (context, PinosContextImpl, this); - g_return_val_if_fail (PINOS_IS_CONTEXT (context), PINOS_CONTEXT_STATE_ERROR); - priv = context->priv; - - return priv->state; + impl->subscribe_mask = mask; + impl->subscribe_func = func; + impl->subscribe_data = data; } -/** - * pinos_context_get_error: - * @context: a #PinosContext - * - * Get the current error of @context or %NULL when the context state - * is not #PINOS_CONTEXT_STATE_ERROR - * - * Returns: the last error or %NULL - */ -const GError * -pinos_context_get_error (PinosContext *context) +void +pinos_context_get_daemon_info (PinosContext *context, + PinosDaemonInfoCallback cb, + void *user_data) { - PinosContextPrivate *priv; - - g_return_val_if_fail (PINOS_IS_CONTEXT (context), NULL); - priv = context->priv; - - return priv->error; + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_list_client_info (PinosContext *context, + PinosClientInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_get_client_info_by_id (PinosContext *context, + uint32_t id, + PinosClientInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_list_node_info (PinosContext *context, + PinosNodeInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_get_node_info_by_id (PinosContext *context, + uint32_t id, + PinosNodeInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_list_link_info (PinosContext *context, + PinosLinkInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); +} + +void +pinos_context_get_link_info_by_id (PinosContext *context, + uint32_t id, + PinosLinkInfoCallback cb, + void *user_data) +{ + cb (context, SPA_RESULT_OK, NULL, user_data); } diff --git a/pinos/client/context.h b/pinos/client/context.h index 40d3ada4c..64faadbeb 100644 --- a/pinos/client/context.h +++ b/pinos/client/context.h @@ -20,42 +20,18 @@ #ifndef __PINOS_CONTEXT_H__ #define __PINOS_CONTEXT_H__ -#include - - -G_BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif typedef struct _PinosContext PinosContext; -typedef struct _PinosContextClass PinosContextClass; -typedef struct _PinosContextPrivate PinosContextPrivate; +#include +#include #include #include - -#define PINOS_TYPE_CONTEXT (pinos_context_get_type ()) -#define PINOS_IS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_CONTEXT)) -#define PINOS_IS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_CONTEXT)) -#define PINOS_CONTEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_CONTEXT, PinosContextClass)) -#define PINOS_CONTEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_CONTEXT, PinosContext)) -#define PINOS_CONTEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_CONTEXT, PinosContextClass)) -#define PINOS_CONTEXT_CAST(obj) ((PinosContext*)(obj)) -#define PINOS_CONTEXT_CLASS_CAST(klass) ((PinosContextClass*)(klass)) - -/** - * PinosContextFlags: - * @PINOS_CONTEXT_FLAGS_NONE: no flags - * @PINOS_CONTEXT_FLAGS_NOAUTOSPAWN: disable autostart of the daemon - * @PINOS_CONTEXT_FLAGS_NOFAIL: Don't fail if the daemon is not available, - * instead enter PINOS_CONTEXT_CONNECTING state and wait for the daemon - * to appear. - * - * Context flags passed to pinos_context_connect() - */ -typedef enum { - PINOS_CONTEXT_FLAGS_NONE = 0, - PINOS_CONTEXT_FLAGS_NOAUTOSPAWN = (1 << 0), - PINOS_CONTEXT_FLAGS_NOFAIL = (1 << 1) -} PinosContextFlags; +#include +#include /** * PinosContextState: @@ -73,7 +49,7 @@ typedef enum { PINOS_CONTEXT_STATE_CONNECTED = 2, } PinosContextState; -const gchar * pinos_context_state_as_string (PinosContextState state); +const char * pinos_context_state_as_string (PinosContextState state); /** * PinosContext: @@ -81,33 +57,42 @@ const gchar * pinos_context_state_as_string (PinosContextState state); * Pinos context object class. */ struct _PinosContext { - GObject object; + char *name; + PinosProperties *properties; - PinosContextPrivate *priv; + PinosLoop *loop; + + PinosProxy *core_proxy; + + PinosMap objects; + + SpaList global_list; + SpaList stream_list; + SpaList proxy_list; + + PinosSendFunc send_func; + void *send_data; + + PinosContextState state; + char *error; + PINOS_SIGNAL (state_changed, (PinosListener *listener, + PinosContext *context)); + + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosContext *context)); }; -/** - * PinosContextClass: - * - * Pinos context object class. - */ -struct _PinosContextClass { - GObjectClass parent_class; -}; +PinosContext * pinos_context_new (PinosLoop *loop, + const char *name, + PinosProperties *properties); +void pinos_context_destroy (PinosContext *context); -/* normal GObject stuff */ -GType pinos_context_get_type (void); +bool pinos_context_connect (PinosContext *context); +bool pinos_context_disconnect (PinosContext *context); -PinosContext * pinos_context_new (GMainContext *ctx, - const gchar *name, - PinosProperties *properties); +#ifdef __cplusplus +} +#endif -gboolean pinos_context_connect (PinosContext *context, PinosContextFlags flags); -gboolean pinos_context_disconnect (PinosContext *context); - -PinosContextState pinos_context_get_state (PinosContext *context); -const GError * pinos_context_get_error (PinosContext *context); - -G_END_DECLS #endif /* __PINOS_CONTEXT_H__ */ diff --git a/pinos/client/introspect.c b/pinos/client/introspect.c index 06a9f9b30..4eb5143f8 100644 --- a/pinos/client/introspect.c +++ b/pinos/client/introspect.c @@ -22,270 +22,8 @@ #include "pinos/client/pinos.h" #include "pinos/client/context.h" -#include "pinos/client/enumtypes.h" #include "pinos/client/subscribe.h" -#include "pinos/client/private.h" - -/** - * pinos_context_info_finish: - * @object: a #GObject - * @res: a #GAsyncResult - * @error: location to place an error - * - * Call this function in the introspection GAsyncReadyCallback function - * to get the final result of the operation. - * - * Returns: %TRUE if the lookup was successful. If %FALSE is returned, @error - * will contain more details. - */ -gboolean -pinos_context_info_finish (GObject *object, - GAsyncResult *res, - GError **error) -{ - g_return_val_if_fail (g_task_is_valid (res, object), FALSE); - - return g_task_propagate_boolean (G_TASK (res), error); -} - -#define SET_STRING(name, field, idx) \ -G_STMT_START { \ - GVariant *variant; \ - if (!changed || g_hash_table_contains (changed, name)) \ - info->change_mask |= 1 << idx; \ - if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \ - info->field = g_variant_get_string (variant, NULL); \ - g_variant_unref (variant); \ - } else { \ - info->field = "Unknown"; \ - } \ -} G_STMT_END - -#define SET_UINT32(name, field, idx, def) \ -G_STMT_START { \ - GVariant *variant; \ - if (!changed || g_hash_table_contains (changed, name)) \ - info->change_mask |= 1 << idx; \ - if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \ - info->field = g_variant_get_uint32 (variant); \ - g_variant_unref (variant); \ - } else { \ - info->field = def; \ - } \ -} G_STMT_END - -#define SET_PROPERTIES(name, field, idx) \ -G_STMT_START { \ - GVariant *variant; \ - if (!changed || g_hash_table_contains (changed, name)) \ - info->change_mask |= 1 << idx; \ - if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \ - info->field = pinos_properties_from_variant (variant); \ - g_variant_unref (variant); \ - } else { \ - info->field = NULL; \ - } \ -} G_STMT_END - -#define SET_BYTES(name, field, idx) \ -G_STMT_START { \ - GVariant *variant; \ - if (!changed || g_hash_table_contains (changed, name)) \ - info->change_mask |= 1 << idx; \ - if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \ - gsize len; \ - gchar *bytes = g_variant_dup_string (variant, &len); \ - info->field = g_bytes_new_take (bytes, len +1); \ - g_variant_unref (variant); \ - } else { \ - info->field = NULL; \ - } \ -} G_STMT_END - -#define SET_OBJV(name, field, idx) \ -G_STMT_START { \ - GVariant *variant; \ - if (!changed || g_hash_table_contains (changed, name)) \ - info->change_mask |= 1 << idx; \ - if ((variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), name))) { \ - info->field = g_variant_dup_objv (variant, NULL); \ - g_variant_unref (variant); \ - } else { \ - info->field = NULL; \ - } \ -} G_STMT_END - -static void -daemon_fill_info (PinosDaemonInfo *info, GDBusProxy *proxy) -{ - GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - info->id = proxy; - info->daemon_path = g_dbus_proxy_get_object_path (proxy); - - info->change_mask = 0; - SET_STRING ("UserName", user_name, 0); - SET_STRING ("HostName", host_name, 1); - SET_STRING ("Version", version, 2); - SET_STRING ("Name", name, 3); - SET_UINT32 ("Cookie", cookie, 4, 0); - SET_PROPERTIES ("Properties", properties, 5); - - if (changed) - g_hash_table_remove_all (changed); -} - -static void -daemon_clear_info (PinosDaemonInfo *info) -{ - if (info->properties) - pinos_properties_free (info->properties); -} - -/** - * pinos_context_get_daemon_info: - * @context: a #PinosContext - * @flags: extra flags - * @cb: a callback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Get the information of the daemon @context is connected to. - */ -void -pinos_context_get_daemon_info (PinosContext *context, - PinosDaemonInfoFlags flags, - PinosDaemonInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosDaemonInfo info; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - daemon_fill_info (&info, context->priv->daemon); - cb (context, &info, user_data); - daemon_clear_info (&info); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -static void -client_fill_info (PinosClientInfo *info, GDBusProxy *proxy) -{ - GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - info->id = proxy; - info->client_path = g_dbus_proxy_get_object_path (proxy); - SET_STRING ("Sender", sender, 0); - - info->change_mask = 0; - SET_PROPERTIES ("Properties", properties, 0); - - if (changed) - g_hash_table_remove_all (changed); -} - -static void -client_clear_info (PinosClientInfo *info) -{ - if (info->properties) - pinos_properties_free (info->properties); -} - - -/** - * pinos_context_list_client_info: - * @context: a connected #PinosContext - * @flags: extra #PinosClientInfoFlags - * @cb: a #PinosClientInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for each client. - */ -void -pinos_context_list_client_info (PinosContext *context, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosContextPrivate *priv; - GList *walk; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - priv = context->priv; - - for (walk = priv->clients; walk; walk = g_list_next (walk)) { - GDBusProxy *proxy = walk->data; - PinosClientInfo info; - - client_fill_info (&info, proxy); - cb (context, &info, user_data); - client_clear_info (&info); - } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/** - * pinos_context_get_client_info_by_id: - * @context: a connected #PinosContext - * @id: a client id - * @flags: extra #PinosClientInfoFlags - * @cb: a #PinosClientInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for the client with @id. - */ -void -pinos_context_get_client_info_by_id (PinosContext *context, - gpointer id, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosClientInfo info; - GDBusProxy *proxy; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (id != NULL); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - proxy = G_DBUS_PROXY (id); - - client_fill_info (&info, proxy); - cb (context, &info, user_data); - client_clear_info (&info); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - /** * pinos_node_state_as_string: * @state: a #PinosNodeeState @@ -294,124 +32,24 @@ pinos_context_get_client_info_by_id (PinosContext *context, * * Returns: the string representation of @state. */ -const gchar * +const char * pinos_node_state_as_string (PinosNodeState state) { - GEnumValue *val; - - val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_NODE_STATE)), - state); - - return val == NULL ? "invalid-state" : val->value_nick; -} - -static void -node_fill_info (PinosNodeInfo *info, GDBusProxy *proxy) -{ - GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - info->id = proxy; - info->node_path = g_dbus_proxy_get_object_path (proxy); - SET_STRING ("Owner", owner, 0); - - info->change_mask = 0; - SET_STRING ("Name", name, 0); - SET_PROPERTIES ("Properties", properties, 1); - SET_UINT32 ("State", state, 2, PINOS_NODE_STATE_ERROR); - - if (changed) - g_hash_table_remove_all (changed); -} - -static void -node_clear_info (PinosNodeInfo *info) -{ - if (info->properties) - pinos_properties_free (info->properties); -} - -/** - * pinos_context_list_node_info: - * @context: a connected #PinosContext - * @flags: extra #PinosNodeInfoFlags - * @cb: a #PinosNodeInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for each node. - */ -void -pinos_context_list_node_info (PinosContext *context, - PinosNodeInfoFlags flags, - PinosNodeInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosContextPrivate *priv; - GList *walk; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - priv = context->priv; - - for (walk = priv->nodes; walk; walk = g_list_next (walk)) { - GDBusProxy *proxy = walk->data; - PinosNodeInfo info; - - node_fill_info (&info, proxy); - cb (context, &info, user_data); - node_clear_info (&info); + switch (state) { + case PINOS_NODE_STATE_ERROR: + return "error"; + case PINOS_NODE_STATE_CREATING: + return "creating"; + case PINOS_NODE_STATE_SUSPENDED: + return "suspended"; + case PINOS_NODE_STATE_INITIALIZING: + return "initializing"; + case PINOS_NODE_STATE_IDLE: + return "idle"; + case PINOS_NODE_STATE_RUNNING: + return "running"; } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/** - * pinos_context_get_node_info_by_id: - * @context: a connected #PinosContext - * @id: a node id - * @flags: extra #PinosNodeInfoFlags - * @cb: a #PinosNodeInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for the node with @id. - */ -void -pinos_context_get_node_info_by_id (PinosContext *context, - gpointer id, - PinosNodeInfoFlags flags, - PinosNodeInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosNodeInfo info; - GDBusProxy *proxy; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (id != NULL); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - proxy = G_DBUS_PROXY (id); - - node_fill_info (&info, proxy); - cb (context, &info, user_data); - node_clear_info (&info); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); + return "invalid-state"; } /** @@ -422,15 +60,18 @@ pinos_context_get_node_info_by_id (PinosContext *context, * * Returns: the string representation of @direction. */ -const gchar * +const char * pinos_direction_as_string (PinosDirection direction) { - GEnumValue *val; - - val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_DIRECTION)), - direction); - - return val == NULL ? "invalid-direction" : val->value_nick; + switch (direction) { + case PINOS_DIRECTION_INVALID: + return "invalid"; + case PINOS_DIRECTION_INPUT: + return "input"; + case PINOS_DIRECTION_OUTPUT: + return "output"; + } + return "invalid-direction"; } /** @@ -441,121 +82,24 @@ pinos_direction_as_string (PinosDirection direction) * * Returns: the string representation of @state. */ -const gchar * +const char * pinos_link_state_as_string (PinosLinkState state) { - GEnumValue *val; - - val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_LINK_STATE)), - state); - - return val == NULL ? "invalid-state" : val->value_nick; -} - - -static void -link_fill_info (PinosLinkInfo *info, GDBusProxy *proxy) -{ - GHashTable *changed = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - info->id = proxy; - info->link_path = g_dbus_proxy_get_object_path (proxy); - - info->change_mask = 0; - SET_STRING ("OutputNode", output_node_path, 0); - SET_UINT32 ("OutputPort", output_port, 1, -1); - SET_STRING ("InputNode", input_node_path, 2); - SET_UINT32 ("InputPort", input_port, 3, -1); - - if (changed) - g_hash_table_remove_all (changed); -} - -static void -link_clear_info (PinosLinkInfo *info) -{ -} - -/** - * pinos_context_list_link_info: - * @context: a connected #PinosContext - * @flags: extra #PinosLinkInfoFlags - * @cb: a #PinosLinkInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for each link. - */ -void -pinos_context_list_link_info (PinosContext *context, - PinosLinkInfoFlags flags, - PinosLinkInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosContextPrivate *priv; - GList *walk; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - priv = context->priv; - - for (walk = priv->links; walk; walk = g_list_next (walk)) { - GDBusProxy *proxy = walk->data; - PinosLinkInfo info; - - link_fill_info (&info, proxy); - cb (context, &info, user_data); - link_clear_info (&info); + switch (state) { + case PINOS_LINK_STATE_ERROR: + return "error"; + case PINOS_LINK_STATE_UNLINKED: + return "unlinked"; + case PINOS_LINK_STATE_INIT: + return "init"; + case PINOS_LINK_STATE_NEGOTIATING: + return "negotiating"; + case PINOS_LINK_STATE_ALLOCATING: + return "allocating"; + case PINOS_LINK_STATE_PAUSED: + return "paused"; + case PINOS_LINK_STATE_RUNNING: + return "running"; } - - g_task_return_boolean (task, TRUE); - g_object_unref (task); -} - -/** - * pinos_context_get_link_info_by_id: - * @context: a connected #PinosContext - * @id: a link id - * @flags: extra #PinosLinkInfoFlags - * @cb: a #PinosLinkInfoCallback - * @cancelable: a #GCancellable - * @callback: a #GAsyncReadyCallback to call when the operation is finished - * @user_data: user data passed to @cb - * - * Call @cb for the link with @id. - */ -void -pinos_context_get_link_info_by_id (PinosContext *context, - gpointer id, - PinosLinkInfoFlags flags, - PinosLinkInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosLinkInfo info; - GDBusProxy *proxy; - GTask *task; - - g_return_if_fail (PINOS_IS_CONTEXT (context)); - g_return_if_fail (id != NULL); - g_return_if_fail (cb != NULL); - - task = g_task_new (context, cancellable, callback, user_data); - - proxy = G_DBUS_PROXY (id); - - link_fill_info (&info, proxy); - cb (context, &info, user_data); - link_clear_info (&info); - - g_task_return_boolean (task, TRUE); - g_object_unref (task); + return "invalid-state"; } diff --git a/pinos/client/introspect.h b/pinos/client/introspect.h index d41873830..a810171be 100644 --- a/pinos/client/introspect.h +++ b/pinos/client/introspect.h @@ -20,12 +20,11 @@ #ifndef __PINOS_INTROSPECT_H__ #define __PINOS_INTROSPECT_H__ -#include -#include - #include -G_BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif /** * PinosNodeState: @@ -50,7 +49,7 @@ typedef enum { PINOS_NODE_STATE_RUNNING = 4, } PinosNodeState; -const gchar * pinos_node_state_as_string (PinosNodeState state); +const char * pinos_node_state_as_string (PinosNodeState state); /** * PinosDirection: @@ -66,7 +65,7 @@ typedef enum { PINOS_DIRECTION_OUTPUT = SPA_DIRECTION_OUTPUT } PinosDirection; -const gchar * pinos_direction_as_string (PinosDirection direction); +const char * pinos_direction_as_string (PinosDirection direction); /** * PinosLinkState: @@ -90,19 +89,14 @@ typedef enum { PINOS_LINK_STATE_RUNNING = 4, } PinosLinkState; -const gchar * pinos_link_state_as_string (PinosLinkState state); +const char * pinos_link_state_as_string (PinosLinkState state); #include #include -gboolean pinos_context_info_finish (GObject *object, - GAsyncResult *res, - GError **error); - /** * PinosDaemonInfo: * @id: generic id of the daemon - * @daemon-path: unique path of the daemon * @change_mask: bitfield of changed fields since last call * @user_name: name of the user that started the daemon * @host_name: name of the machine the daemon is running on @@ -115,25 +109,16 @@ gboolean pinos_context_info_finish (GObject *object, * versions. */ typedef struct { - gpointer id; - const char *daemon_path; - guint64 change_mask; + uint32_t id; + uint64_t change_mask; const char *user_name; const char *host_name; const char *version; const char *name; - guint32 cookie; + uint32_t cookie; PinosProperties *properties; } PinosDaemonInfo; -/**PinosDaemonInfoFlags: - * @PINOS_DAEMON_INFO_FLAGS_NONE: no flags - * - * Extra flags that can be passed to pinos_context_get_daemon_info() - */ -typedef enum { - PINOS_DAEMON_INFO_FLAGS_NONE = 0, -} PinosDaemonInfoFlags; /** * PinosDaemonInfoCallback: @@ -144,21 +129,17 @@ typedef enum { * Callback with information about the Pinos daemon in @info. */ typedef void (*PinosDaemonInfoCallback) (PinosContext *c, + SpaResult res, const PinosDaemonInfo *info, - gpointer user_data); + void *user_data); -void pinos_context_get_daemon_info (PinosContext *context, - PinosDaemonInfoFlags flags, - PinosDaemonInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void pinos_context_get_daemon_info (PinosContext *context, + PinosDaemonInfoCallback cb, + void *user_data); /** * PinosClientInfo: * @id: generic id of the client - * @client_path: unique path of the client - * @sender: sender of client * @change_mask: bitfield of changed fields since last call * @properties: extra properties * @@ -166,24 +147,11 @@ void pinos_context_get_daemon_info (PinosContext *context, * versions. */ typedef struct { - gpointer id; - const char *client_path; - const char *sender; - guint64 change_mask; + uint32_t id; + uint64_t change_mask; PinosProperties *properties; } PinosClientInfo; -/** - * PinosClientInfoFlags: - * @PINOS_CLIENT_INFO_FLAGS_NONE: no flags - * - * Extra flags for pinos_context_list_client_info() and - * pinos_context_get_client_info_by_id(). - */ -typedef enum { - PINOS_CLIENT_INFO_FLAGS_NONE = 0, -} PinosClientInfoFlags; - /** * PinosClientInfoCallback: * @c: a #PinosContext @@ -193,28 +161,21 @@ typedef enum { * Callback with information about the Pinos client in @info. */ typedef void (*PinosClientInfoCallback) (PinosContext *c, + SpaResult res, const PinosClientInfo *info, - gpointer user_data); + void *user_data); -void pinos_context_list_client_info (PinosContext *context, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -void pinos_context_get_client_info_by_id (PinosContext *context, - gpointer id, - PinosClientInfoFlags flags, - PinosClientInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void pinos_context_list_client_info (PinosContext *context, + PinosClientInfoCallback cb, + void *user_data); +void pinos_context_get_client_info_by_id (PinosContext *context, + uint32_t id, + PinosClientInfoCallback cb, + void *user_data); /** * PinosNodeInfo: * @id: generic id of the node - * @node_path: the unique path of the node - * @owner: the unique name of the owner * @change_mask: bitfield of changed fields since last call * @name: name the node, suitable for display * @properties: the properties of the node @@ -224,25 +185,13 @@ void pinos_context_get_client_info_by_id (PinosContext *context, * versions. */ typedef struct { - gpointer id; - const char *node_path; - const char *owner; - guint64 change_mask; + uint32_t id; + uint64_t change_mask; const char *name; PinosProperties *properties; PinosNodeState state; } PinosNodeInfo; -/** - * PinosNodeInfoFlags: - * @PINOS_NODE_INFO_FLAGS_NONE: no flags - * - * Extra flags to pass to pinos_context_get_node_info_list. - */ -typedef enum { - PINOS_NODE_INFO_FLAGS_NONE = 0, -} PinosNodeInfoFlags; - /** * PinosNodeInfoCallback: * @c: a #PinosContext @@ -252,28 +201,22 @@ typedef enum { * Callback with information about the Pinos node in @info. */ typedef void (*PinosNodeInfoCallback) (PinosContext *c, + SpaResult res, const PinosNodeInfo *info, - gpointer user_data); + void *user_data); -void pinos_context_list_node_info (PinosContext *context, - PinosNodeInfoFlags flags, - PinosNodeInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -void pinos_context_get_node_info_by_id (PinosContext *context, - gpointer id, - PinosNodeInfoFlags flags, - PinosNodeInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); +void pinos_context_list_node_info (PinosContext *context, + PinosNodeInfoCallback cb, + void *user_data); +void pinos_context_get_node_info_by_id (PinosContext *context, + uint32_t id, + PinosNodeInfoCallback cb, + void *user_data); /** * PinosLinkInfo: * @id: generic id of the link - * @link_path: the unique path of the link * @change_mask: bitfield of changed fields since last call * @output_node_path: the output node * @output_port: the output port @@ -284,25 +227,14 @@ void pinos_context_get_node_info_by_id (PinosContext *context, * versions. */ typedef struct { - gpointer id; - const char *link_path; - guint64 change_mask; - const char *output_node_path; - guint output_port; - const char *input_node_path; - guint input_port; + uint32_t id; + uint64_t change_mask; + uint32_t output_node_id; + uint32_t output_port_id; + uint32_t input_node_id; + uint32_t input_port_id; } PinosLinkInfo; -/** - * PinosLinkInfoFlags: - * @PINOS_LINK_INFO_FLAGS_NONE: no flags - * - * Extra flags to pass to pinos_context_list_link_info() and - * pinos_context_get_link_info_by_id(). - */ -typedef enum { - PINOS_LINK_INFO_FLAGS_NONE = 0, -} PinosLinkInfoFlags; /** * PinosLinkInfoCallback: @@ -312,23 +244,21 @@ typedef enum { * * Callback with information about the Pinos link in @info. */ -typedef void (*PinosLinkInfoCallback) (PinosContext *c, +typedef void (*PinosLinkInfoCallback) (PinosContext *c, + SpaResult res, const PinosLinkInfo *info, - gpointer user_data); + void *user_data); -void pinos_context_list_link_info (PinosContext *context, - PinosLinkInfoFlags flags, - PinosLinkInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -void pinos_context_get_link_info_by_id (PinosContext *context, - gpointer id, - PinosLinkInfoFlags flags, - PinosLinkInfoCallback cb, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -G_END_DECLS +void pinos_context_list_link_info (PinosContext *context, + PinosLinkInfoCallback cb, + void *user_data); +void pinos_context_get_link_info_by_id (PinosContext *context, + uint32_t id, + PinosLinkInfoCallback cb, + void *user_data); + +#ifdef __cplusplus +} +#endif #endif /* __PINOS_INTROSPECT_H__ */ diff --git a/pinos/client/meson.build b/pinos/client/meson.build index 883f7b9c9..14de25c14 100644 --- a/pinos/client/meson.build +++ b/pinos/client/meson.build @@ -9,6 +9,7 @@ pinos_headers = [ 'mem.h', 'pinos.h', 'properties.h', + 'proxy.h', 'rtkit.h', 'stream.h', 'subscribe.h', @@ -27,11 +28,11 @@ pinos_sources = [ 'mapper.c', 'mem.c', 'properties.c', + 'proxy.c', 'serialize.c', 'stream.c', 'pinos.c', 'rtkit.c', - 'subscribe.c', 'thread-mainloop.c', 'transport.c', 'utils.c', @@ -67,7 +68,6 @@ libpinos_c_args = [ pinos_gen_sources = [enumtypes_h] libpinos = shared_library('pinos', pinos_sources, - enumtypes_h, enumtypes_c, version : libversion, soversion : soversion, c_args : libpinos_c_args, diff --git a/pinos/client/pinos.c b/pinos/client/pinos.c index 4ef17f624..ceac1de57 100644 --- a/pinos/client/pinos.c +++ b/pinos/client/pinos.c @@ -17,22 +17,11 @@ * Boston, MA 02110-1301, USA. */ -#include +#include +#include #include "pinos/client/pinos.h" -const gchar g_log_domain_pinos[] = "Pinos"; - -GQuark -pinos_error_quark (void) -{ - static GQuark quark = 0; - if (!quark) - quark = g_quark_from_static_string ("pinos-error-quark"); - return quark; -} - - /** * pinos_init: * @argc: pointer to argc @@ -46,22 +35,48 @@ pinos_init (int *argc, char **argv[]) { } +static char * +pinos_get_application_name (void) +{ + return NULL; +} + +static char * +pinos_get_prgname (void) +{ + return NULL; +} + +static char * +pinos_get_user_name (void) +{ + return NULL; +} + +static char * +pinos_get_host_name (void) +{ + return NULL; +} + /** * pinos_client_name: * * Make a new pinos client name that can be used to construct a context. */ -gchar * +char * pinos_client_name (void) { - const char *c; + char *c; - if ((c = g_get_application_name ())) - return g_strdup (c); - else if ((c = g_get_prgname ())) - return g_strdup (c); - else - return g_strdup_printf ("pinos-pid-%lu", (gulong) getpid ()); + if ((c = pinos_get_application_name ())) + return strdup (c); + else if ((c = pinos_get_prgname ())) + return strdup (c); + else { + asprintf (&c, "pinos-pid-%zd", (size_t) getpid ()); + return c; + } } /** @@ -73,34 +88,26 @@ pinos_client_name (void) void pinos_fill_context_properties (PinosProperties *properties) { - g_return_if_fail (properties != NULL); - if (!pinos_properties_get (properties, "application.name")) - pinos_properties_set (properties, "application.name", g_get_application_name ()); + pinos_properties_set (properties, "application.name", pinos_get_application_name ()); if (!pinos_properties_get (properties, "application.prgname")) - pinos_properties_set (properties, "application.prgname", g_get_prgname ()); + pinos_properties_set (properties, "application.prgname", pinos_get_prgname ()); if (!pinos_properties_get (properties, "application.language")) { - const gchar *str = g_getenv ("LANG"); - if (str) - pinos_properties_set (properties, "application.language", str); + pinos_properties_set (properties, "application.language", getenv ("LANG")); } if (!pinos_properties_get (properties, "application.process.id")) { - gchar *str = g_strdup_printf ("%lu", (gulong) getpid()); - pinos_properties_set (properties, "application.process.id", str); - g_free (str); + pinos_properties_setf (properties, "application.process.id", "%zd", (size_t) getpid ()); } if (!pinos_properties_get (properties, "application.process.user")) - pinos_properties_set (properties, "application.process.user", g_get_user_name ()); + pinos_properties_set (properties, "application.process.user", pinos_get_user_name ()); if (!pinos_properties_get (properties, "application.process.host")) - pinos_properties_set (properties, "application.process.host", g_get_host_name ()); + pinos_properties_set (properties, "application.process.host", pinos_get_host_name ()); if (!pinos_properties_get (properties, "application.process.session_id")) { - const gchar *str = g_getenv ("XDG_SESSION_ID"); - if (str) - pinos_properties_set (properties, "application.process.session_id", str); + pinos_properties_set (properties, "application.process.session_id", getenv ("XDG_SESSION_ID")); } } @@ -113,7 +120,6 @@ pinos_fill_context_properties (PinosProperties *properties) void pinos_fill_stream_properties (PinosProperties *properties) { - g_return_if_fail (properties != NULL); } PinosDirection diff --git a/pinos/client/pinos.h b/pinos/client/pinos.h index 9e9e77795..5ceff29a0 100644 --- a/pinos/client/pinos.h +++ b/pinos/client/pinos.h @@ -20,10 +20,11 @@ #ifndef __PINOS_H__ #define __PINOS_H__ -extern const char g_log_domain_pinos[]; +#ifdef __cplusplus +extern "C" { +#endif #include -#include #include #include #include @@ -43,21 +44,9 @@ extern const char g_log_domain_pinos[]; #define PINOS_DBUS_OBJECT_NODE PINOS_DBUS_OBJECT_PREFIX "/node" #define PINOS_DBUS_OBJECT_LINK PINOS_DBUS_OBJECT_PREFIX "/link" -typedef enum { - PINOS_ERROR_FAILED, - PINOS_ERROR_FORMAT_NEGOTIATION, - PINOS_ERROR_BUFFER_ALLOCATION, - PINOS_ERROR_NODE_STATE, - PINOS_ERROR_NODE_PORT, - PINOS_ERROR_NODE_LINK, -} PinosErrorEnum; - -GQuark pinos_error_quark (void); -#define PINOS_ERROR pinos_error_quark() - void pinos_init (int *argc, char **argv[]); -gchar *pinos_client_name (void); +char * pinos_client_name (void); void pinos_fill_context_properties (PinosProperties *properties); void pinos_fill_stream_properties (PinosProperties *properties); @@ -66,4 +55,8 @@ PinosDirection pinos_direction_reverse (PinosDirection direction); SpaIDMap * pinos_id_map_get_default (void); +#ifdef __cplusplus +} +#endif + #endif /* __PINOS_H__ */ diff --git a/pinos/client/private.h b/pinos/client/private.h deleted file mode 100644 index e072c8b5d..000000000 --- a/pinos/client/private.h +++ /dev/null @@ -1,55 +0,0 @@ -/* 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. - */ - -struct _PinosContextPrivate -{ - GMainContext *context; - - gchar *name; - PinosProperties *properties; - - guint id; - GDBusConnection *connection; - - PinosContextFlags flags; - - PinosContextState state; - GError *error; - - GDBusProxy *daemon; - gboolean disconnecting; - - PinosSubscriptionFlags subscription_mask; - PinosSubscribe *subscribe; - - GList *clients; - GList *nodes; - GList *links; -}; - -void pinos_subscribe_get_proxy (PinosSubscribe *subscribe, - const gchar *name, - const gchar *object_path, - const gchar *interface_name, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data); -GDBusProxy * pinos_subscribe_get_proxy_finish (PinosSubscribe *subscribe, - GAsyncResult *res, - GError **error); diff --git a/pinos/client/properties.c b/pinos/client/properties.c index b78ec3627..852107b05 100644 --- a/pinos/client/properties.c +++ b/pinos/client/properties.c @@ -27,7 +27,7 @@ struct _PinosProperties { }; static void -copy_func (const gchar *key, const gchar *value, GHashTable *copy) +copy_func (const char *key, const char *value, GHashTable *copy) { g_hash_table_insert (copy, g_strdup (key), g_strdup (value)); } @@ -42,20 +42,20 @@ copy_func (const gchar *key, const gchar *value, GHashTable *copy) * Returns: a new #PinosProperties */ PinosProperties * -pinos_properties_new (const gchar *key, ...) +pinos_properties_new (const char *key, ...) { PinosProperties *props; va_list varargs; - const gchar *value; + const char *value; props = g_new (PinosProperties, 1); props->hashtable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); va_start (varargs, key); while (key != NULL) { - value = va_arg (varargs, gchar *); + value = va_arg (varargs, char *); copy_func (key, value, props->hashtable); - key = va_arg (varargs, gchar *); + key = va_arg (varargs, char *); } va_end (varargs); @@ -97,8 +97,8 @@ pinos_properties_merge (PinosProperties *oldprops, } else if (newprops == NULL) { res = pinos_properties_copy (oldprops); } else { - const gchar *key; - gpointer state = NULL; + const char *key; + void * state = NULL; res = pinos_properties_copy (oldprops); while ((key = pinos_properties_iterate (newprops, &state))) { @@ -137,8 +137,8 @@ pinos_properties_free (PinosProperties *properties) */ void pinos_properties_set (PinosProperties *properties, - const gchar *key, - const gchar *value) + const char *key, + const char *value) { g_return_if_fail (properties != NULL); g_return_if_fail (key != NULL); @@ -161,8 +161,8 @@ pinos_properties_set (PinosProperties *properties, */ void pinos_properties_setf (PinosProperties *properties, - const gchar *key, - const gchar *format, + const char *key, + const char *format, ...) { va_list varargs; @@ -187,9 +187,9 @@ pinos_properties_setf (PinosProperties *properties, * * Returns: the property for @key or %NULL when the key was not found */ -const gchar * +const char * pinos_properties_get (PinosProperties *properties, - const gchar *key) + const char *key) { g_return_val_if_fail (properties != NULL, NULL); g_return_val_if_fail (key != NULL, NULL); @@ -211,12 +211,12 @@ pinos_properties_get (PinosProperties *properties, * * Returns: The next key or %NULL when there are no more keys to iterate. */ -const gchar * +const char * pinos_properties_iterate (PinosProperties *properties, - gpointer *state) + void **state) { - static gpointer dummy = GINT_TO_POINTER (1); - const gchar *res = NULL; + static void * dummy = GINT_TO_POINTER (1); + const char *res = NULL; GList *items; g_return_val_if_fail (properties != NULL, NULL); @@ -241,84 +241,3 @@ pinos_properties_iterate (PinosProperties *properties, return res; } - -static void -add_to_variant (const gchar *key, const gchar *value, GVariantBuilder *b) -{ - g_variant_builder_add (b, "{sv}", key, g_variant_new_string (value)); -} - -/** - * pinos_properties_init_builder: - * @properties: a #PinosProperties - * @builder: a #GVariantBuilder - * - * Initialize the @builder of type a{sv} and add @properties to it. - * - * Returns: %TRUE if @builder could be initialized. - */ -gboolean -pinos_properties_init_builder (PinosProperties *properties, - GVariantBuilder *builder) -{ - g_return_val_if_fail (properties != NULL, FALSE); - g_return_val_if_fail (builder != NULL, FALSE); - - g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}")); - g_hash_table_foreach (properties->hashtable, (GHFunc) add_to_variant, builder); - - return TRUE; -} - -/** - * pinos_properties_to_variant: - * @properties: a #PinosProperties - * - * Convert @properties to a #GVariant of type a{sv} - * - * Returns: a new #GVariant of @properties. use g_variant_unref() after - * use. - */ -GVariant * -pinos_properties_to_variant (PinosProperties *properties) -{ - GVariantBuilder builder; - - if (!pinos_properties_init_builder (properties, &builder)) - return NULL; - - return g_variant_builder_end (&builder); -} - -/** - * pinos_properties_from_variant: - * @variant: a #GVariant - * - * Convert @variant to a #PinosProperties - * - * Returns: a new #PinosProperties of @variant. use pinos_properties_free() - * after use. - */ -PinosProperties * -pinos_properties_from_variant (GVariant *variant) -{ - PinosProperties *props; - GVariantIter iter; - GVariant *value; - gchar *key; - - g_return_val_if_fail (variant != NULL, NULL); - - props = pinos_properties_new (NULL, NULL); - - g_variant_iter_init (&iter, variant); - while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) - g_hash_table_replace (props->hashtable, - g_strdup (key), - g_variant_dup_string (value, NULL)); - - return props; -} - -G_DEFINE_BOXED_TYPE (PinosProperties, pinos_properties, - pinos_properties_copy, pinos_properties_free); diff --git a/pinos/client/properties.h b/pinos/client/properties.h index e7afbbcf4..0f4ed4853 100644 --- a/pinos/client/properties.h +++ b/pinos/client/properties.h @@ -20,40 +20,33 @@ #ifndef __PINOS_PROPERTIES_H__ #define __PINOS_PROPERTIES_H__ -#include - -G_BEGIN_DECLS +#ifdef __cplusplus +extern "C" { +#endif typedef struct _PinosProperties PinosProperties; -#define PINOS_TYPE_PROPERTIES (pinos_properties_get_type()) -GType pinos_properties_get_type (void); - -PinosProperties * pinos_properties_new (const gchar *key, ...) G_GNUC_NULL_TERMINATED; +PinosProperties * pinos_properties_new (const char *key, ...); PinosProperties * pinos_properties_copy (PinosProperties *properties); PinosProperties * pinos_properties_merge (PinosProperties *oldprops, PinosProperties *newprops); void pinos_properties_free (PinosProperties *properties); void pinos_properties_set (PinosProperties *properties, - const gchar *key, - const gchar *value); + const char *key, + const char *value); void pinos_properties_setf (PinosProperties *properties, - const gchar *key, - const gchar *format, - ...) G_GNUC_PRINTF (3, 4); -const gchar * pinos_properties_get (PinosProperties *properties, - const gchar *key); + const char *key, + const char *format, + ...) SPA_PRINTF_FUNC (3, 4); +const char * pinos_properties_get (PinosProperties *properties, + const char *key); -const gchar * pinos_properties_iterate (PinosProperties *properties, - gpointer *state); +const char * pinos_properties_iterate (PinosProperties *properties, + void **state); -gboolean pinos_properties_init_builder (PinosProperties *properties, - GVariantBuilder *builder); -GVariant * pinos_properties_to_variant (PinosProperties *properties); -PinosProperties * pinos_properties_from_variant (GVariant *variant); - - -G_END_DECLS +#ifdef __cplusplus +} +#endif #endif /* __PINOS_PROPERTIES_H__ */ diff --git a/pinos/client/proxy.c b/pinos/client/proxy.c new file mode 100644 index 000000000..076e6836b --- /dev/null +++ b/pinos/client/proxy.c @@ -0,0 +1,76 @@ +/* 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. + */ + +#include +#include + +typedef struct { + PinosProxy this; +} PinosProxyImpl; + +PinosProxy * +pinos_proxy_new (PinosContext *context, + uint32_t id, + uint32_t type) +{ + PinosProxyImpl *impl; + PinosProxy *this; + + impl = calloc (1, sizeof (PinosProxyImpl)); + this = &impl->this; + + this->context = context; + this->type = type; + this->send_func = context->send_func; + this->send_data = context->send_data; + + pinos_signal_init (&this->destroy_signal); + + this->id = pinos_map_insert_new (&context->objects, this); + + spa_list_insert (&this->context->proxy_list, &this->link); + + return this; +} + +void +pinos_proxy_destroy (PinosProxy *proxy) +{ + PinosProxyImpl *impl = SPA_CONTAINER_OF (proxy, PinosProxyImpl, this); + + pinos_signal_emit (&proxy->destroy_signal, proxy); + + pinos_map_remove (&proxy->context->objects, proxy->id); + spa_list_remove (&proxy->link); + free (impl); +} + +SpaResult +pinos_proxy_send_message (PinosProxy *proxy, + PinosMessageType type, + void *message, + bool flush) +{ + if (proxy->send_func) + return proxy->send_func (proxy, proxy->id, type, message, flush, proxy->send_data); + + pinos_log_error ("proxy %p: send func not implemented", proxy); + + return SPA_RESULT_NOT_IMPLEMENTED; +} diff --git a/pinos/client/proxy.h b/pinos/client/proxy.h new file mode 100644 index 000000000..154baf529 --- /dev/null +++ b/pinos/client/proxy.h @@ -0,0 +1,75 @@ +/* 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_PROXY_H__ +#define __PINOS_PROXY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +typedef struct _PinosProxy PinosProxy; + +typedef SpaResult (*PinosSendFunc) (void *object, + uint32_t id, + PinosMessageType type, + void *message, + bool flush, + void *data); + +typedef SpaResult (*PinosDispatchFunc) (void *object, + PinosMessageType type, + void *message, + void *data); +#include + +struct _PinosProxy { + PinosContext *context; + SpaList link; + + uint32_t id; + uint32_t type; + + PinosSendFunc send_func; + void *send_data; + PinosDispatchFunc dispatch_func; + void *dispatch_data; + + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosProxy *proxy)); +}; + +PinosProxy * pinos_proxy_new (PinosContext *context, + uint32_t id, + uint32_t type); +void pinos_proxy_destroy (PinosProxy *proxy); + +SpaResult pinos_proxy_send_message (PinosProxy *proxy, + PinosMessageType type, + void *message, + bool flush); + +#ifdef __cplusplus +} +#endif + + +#endif /* __PINOS_PROXY_H__ */ diff --git a/pinos/client/serialize.c b/pinos/client/serialize.c index 8d0b68089..0b8f949e7 100644 --- a/pinos/client/serialize.c +++ b/pinos/client/serialize.c @@ -352,3 +352,91 @@ pinos_serialize_props_copy_into (void *dest, const SpaProps *props) pinos_serialize_props_serialize (dest, props); return pinos_serialize_props_deserialize (dest, 0); } + +size_t +pinos_serialize_dict_get_size (const SpaDict *dict) +{ + size_t len; + unsigned int i; + + if (dict == NULL) + return 0; + + len = sizeof (SpaDict); + len += dict->n_items * sizeof (SpaDictItem); + for (i = 0; i < dict->n_items; i++) { + SpaDictItem *di = &dict->items[i]; + len += di->key ? strlen (di->key) + 1 : 0; + len += di->value ? strlen (di->value) + 1 : 0; + } + return len; +} + +size_t +pinos_serialize_dict_serialize (void *p, const SpaDict *dict) +{ + SpaDict *pi; + SpaDictItem *di; + int i; + size_t len; + + if (dict == NULL) + return 0; + + pi = p; + memcpy (pi, dict, sizeof (SpaDict)); + + di = SPA_MEMBER (pi, sizeof (SpaDict), SpaDictItem); + if (dict->n_items) + pi->items = SPA_INT_TO_PTR (SPA_PTRDIFF (di, pi)); + else + pi->items = 0; + + p = SPA_MEMBER (di, sizeof (SpaDictItem) * dict->n_items, void); + + for (i = 0; i < dict->n_items; i++) { + if (dict->items[i].key) { + len = strlen (dict->items[i].key) + 1; + memcpy (p, dict->items[i].key, len); + di[i].key = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi)); + p += len; + } else { + di[i].key = NULL; + } + if (dict->items[i].value) { + len = strlen (dict->items[i].value) + 1; + memcpy (p, dict->items[i].value, len); + di[i].value = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi)); + p += len; + } else { + di[i].value = NULL; + } + } + return SPA_PTRDIFF (p, pi); +} + +SpaDict * +pinos_serialize_dict_deserialize (void *p, off_t offset) +{ + SpaDict *pi; + unsigned int i; + + pi = SPA_MEMBER (p, offset, SpaDict); + if (pi->items) + pi->items = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items), SpaDictItem); + for (i = 0; i < pi->n_items; i++) { + pi->items[i].key = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items[i].key), char); + pi->items[i].value = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->items[i].value), char); + } + return pi; +} + +SpaDict * +pinos_serialize_dict_copy_into (void *dest, const SpaDict *dict) +{ + if (dict == NULL) + return NULL; + + pinos_serialize_dict_serialize (dest, dict); + return pinos_serialize_dict_deserialize (dest, 0); +} diff --git a/pinos/client/serialize.h b/pinos/client/serialize.h index f1eaa4a7d..7f8a3035a 100644 --- a/pinos/client/serialize.h +++ b/pinos/client/serialize.h @@ -48,6 +48,11 @@ size_t pinos_serialize_props_serialize (void *dest, const SpaProp SpaProps * pinos_serialize_props_deserialize (void *src, off_t offset); SpaProps * pinos_serialize_props_copy_into (void *dest, const SpaProps *props); +size_t pinos_serialize_dict_get_size (const SpaDict *dict); +size_t pinos_serialize_dict_serialize (void *dest, const SpaDict *dict); +SpaDict * pinos_serialize_dict_deserialize (void *src, off_t offset); +SpaDict * pinos_serialize_dict_copy_into (void *dest, const SpaDict *dict); + #ifdef __cplusplus } #endif diff --git a/pinos/client/signal.h b/pinos/client/signal.h index ec175658f..6684cabef 100644 --- a/pinos/client/signal.h +++ b/pinos/client/signal.h @@ -41,19 +41,19 @@ struct _PinosSignal { }; #endif -#define PINOS_SIGNAL(name,func) \ - union { \ - SpaList listeners; \ - void (*notify) func; \ +#define PINOS_SIGNAL(name,func) \ + union { \ + SpaList listeners; \ + void (*notify) func; \ } name; -#define pinos_signal_init(signal) \ +#define pinos_signal_init(signal) \ spa_list_init (&(signal)->listeners); #define pinos_signal_add(signal,listener,func) \ do { \ - __typeof__((signal)->notify) n = (func); \ - (listener)->notify = (void (*) (void *)) n; \ + __typeof__((signal)->notify) n = (func); \ + (listener)->notify = (void (*) (void *)) n; \ spa_list_insert ((signal)->listeners.prev, &(listener)->link); \ } while (false); @@ -67,7 +67,7 @@ pinos_signal_remove (PinosListener *listener) do { \ PinosListener *l, *next; \ spa_list_for_each_safe (l, next, &(signal)->listeners, link) \ - ((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__); \ + ((__typeof__((signal)->notify))l->notify) (l,__VA_ARGS__); \ } while (false); #ifdef __cplusplus diff --git a/pinos/client/stream.c b/pinos/client/stream.c index adb139fd7..4e8663ac9 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -17,6 +17,7 @@ * Boston, MA 02110-1301, USA. */ +#include #include #include #include @@ -24,20 +25,12 @@ #include "spa/lib/debug.h" -#include -#include -#include - -#include "pinos/dbus/org-pinos.h" - #include "pinos/client/pinos.h" #include "pinos/client/array.h" #include "pinos/client/connection.h" #include "pinos/client/context.h" #include "pinos/client/stream.h" -#include "pinos/client/enumtypes.h" #include "pinos/client/format.h" -#include "pinos/client/private.h" #include "pinos/client/serialize.h" #include "pinos/client/transport.h" @@ -62,21 +55,17 @@ typedef struct { SpaData *datas; } BufferId; -struct _PinosStreamPrivate +typedef struct { - PinosContext *context; - gchar *name; - PinosProperties *properties; - - guint id; - - PinosStreamState state; - GError *error; - - gchar *path; + PinosStream this; SpaNodeState node_state; - GPtrArray *possible_formats; + + uint32_t seq; + + unsigned int n_possible_formats; + SpaFormat **possible_formats; + SpaFormat *format; SpaPortInfo port_info; SpaDirection direction; @@ -85,448 +74,55 @@ struct _PinosStreamPrivate PinosStreamFlags flags; - GDBusProxy *node; - gboolean disconnecting; + bool disconnecting; PinosStreamMode mode; - GSocket *socket; - GSource *socket_source; - int fd; - GSocket *rtsocket; - GSource *rtsocket_source; int rtfd; + SpaSource *rtsocket_source; - PinosConnection *conn; + PinosProxy *node_proxy; PinosTransport *trans; - GSource *timeout_source; + SpaSource *timeout_source; PinosArray mem_ids; PinosArray buffer_ids; - gboolean in_order; + bool in_order; - gint64 last_ticks; - gint32 last_rate; - gint64 last_monotonic; -}; - -#define PINOS_STREAM_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_STREAM, PinosStreamPrivate)) - -G_DEFINE_TYPE (PinosStream, pinos_stream, G_TYPE_OBJECT); - -enum -{ - PROP_0, - PROP_CONTEXT, - PROP_NAME, - PROP_PROPERTIES, - PROP_STATE, - PROP_POSSIBLE_FORMATS, - PROP_FORMAT, -}; - -enum -{ - SIGNAL_ADD_BUFFER, - SIGNAL_REMOVE_BUFFER, - SIGNAL_NEW_BUFFER, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; + int64_t last_ticks; + int32_t last_rate; + int64_t last_monotonic; +} PinosStreamImpl; static void clear_buffers (PinosStream *stream) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); BufferId *bid; - pinos_array_for_each (bid, &priv->buffer_ids) { - g_signal_emit (stream, signals[SIGNAL_REMOVE_BUFFER], 0, bid->id); + pinos_array_for_each (bid, &impl->buffer_ids) { + pinos_signal_emit (&stream->remove_buffer, stream, bid->id); bid->buf = NULL; } - priv->buffer_ids.size = 0; - priv->in_order = TRUE; -} - -static void -pinos_stream_get_property (GObject *_object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PinosStream *stream = PINOS_STREAM (_object); - PinosStreamPrivate *priv = stream->priv; - - switch (prop_id) { - case PROP_CONTEXT: - g_value_set_object (value, priv->context); - break; - - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - - case PROP_PROPERTIES: - g_value_set_boxed (value, priv->properties); - break; - - case PROP_STATE: - g_value_set_enum (value, priv->state); - break; - - case PROP_POSSIBLE_FORMATS: - g_value_set_boxed (value, priv->possible_formats); - break; - - case PROP_FORMAT: - g_value_set_boxed (value, priv->format); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (stream, prop_id, pspec); - break; - } -} - -static void -pinos_stream_set_property (GObject *_object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - PinosStream *stream = PINOS_STREAM (_object); - PinosStreamPrivate *priv = stream->priv; - - switch (prop_id) { - case PROP_CONTEXT: - priv->context = g_value_dup_object (value); - break; - - case PROP_NAME: - priv->name = g_value_dup_string (value); - break; - - case PROP_PROPERTIES: - if (priv->properties) - pinos_properties_free (priv->properties); - priv->properties = g_value_dup_boxed (value); - break; - - case PROP_FORMAT: - if (priv->format) - g_boxed_free (SPA_TYPE_FORMAT, priv->format); - priv->format = g_value_dup_boxed (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (stream, prop_id, pspec); - break; - } -} - -static gboolean -do_notify_state (PinosStream *stream) -{ - g_object_notify (G_OBJECT (stream), "state"); - g_object_unref (stream); - return FALSE; + impl->buffer_ids.size = 0; + impl->in_order = true; } static void stream_set_state (PinosStream *stream, PinosStreamState state, - GError *error) + char *error) { - if (stream->priv->state != state) { - if (error) { - g_clear_error (&stream->priv->error); - stream->priv->error = error; - } - stream->priv->state = state; - g_main_context_invoke (stream->priv->context->priv->context, - (GSourceFunc) do_notify_state, - g_object_ref (stream)); - } else { - if (error) - g_error_free (error); + if (stream->state != state) { + if (stream->error) + free (stream->error); + stream->error = error; + stream->state = state; + pinos_signal_emit (&stream->state_changed, stream); } } -static void -on_node_info (PinosContext *c, - const PinosNodeInfo *info, - gpointer user_data) -{ - PinosStream *stream = PINOS_STREAM (user_data); - - if (info->state == PINOS_NODE_STATE_ERROR) { - pinos_log_debug ("stream %p: node %s in error", stream, info->node_path); - stream_set_state (stream, - PINOS_STREAM_STATE_ERROR, - g_error_new (PINOS_ERROR, - PINOS_ERROR_NODE_STATE, - "node is in error")); - } -} - -static void -info_ready (GObject *o, GAsyncResult *res, gpointer user_data) -{ - GError *error = NULL; - - if (!pinos_context_info_finish (o, res, &error)) { - pinos_log_error ("introspection failure: %s\n", error->message); - g_clear_error (&error); - } -} - -static void -subscription_cb (PinosSubscribe *subscribe, - PinosSubscriptionEvent event, - PinosSubscriptionFlags flags, - GDBusProxy *object, - gpointer user_data) -{ - PinosStream *stream = PINOS_STREAM (user_data); - PinosStreamPrivate *priv = stream->priv; - - switch (flags) { - case PINOS_SUBSCRIPTION_FLAG_NODE: - if (event == PINOS_SUBSCRIPTION_EVENT_REMOVE) { - if (object == priv->node && !priv->disconnecting) { - stream_set_state (stream, - PINOS_STREAM_STATE_ERROR, - g_error_new_literal (G_IO_ERROR, - G_IO_ERROR_CLOSED, - "Node disappeared")); - } - } else if (event == PINOS_SUBSCRIPTION_EVENT_CHANGE) { - if (object == priv->node && !priv->disconnecting) { - pinos_context_get_node_info_by_id (priv->context, - object, - PINOS_NODE_INFO_FLAGS_NONE, - on_node_info, - NULL, - info_ready, - stream); - } - } - break; - - default: - break; - } -} - -static void -pinos_stream_constructed (GObject * object) -{ - PinosStream *stream = PINOS_STREAM (object); - PinosStreamPrivate *priv = stream->priv; - - priv->id = g_signal_connect (priv->context->priv->subscribe, - "subscription-event", - (GCallback) subscription_cb, - stream); - - G_OBJECT_CLASS (pinos_stream_parent_class)->constructed (object); -} - -static void -pinos_stream_finalize (GObject * object) -{ - PinosStream *stream = PINOS_STREAM (object); - PinosStreamPrivate *priv = stream->priv; - - pinos_log_debug ("free stream %p", stream); - - g_clear_object (&priv->node); - - if (priv->possible_formats) - g_ptr_array_unref (priv->possible_formats); - if (priv->format) - g_boxed_free (SPA_TYPE_FORMAT, priv->format); - - g_free (priv->path); - g_clear_error (&priv->error); - - pinos_array_clear (&priv->buffer_ids); - pinos_array_clear (&priv->mem_ids); - - if (priv->properties) - pinos_properties_free (priv->properties); - g_signal_handler_disconnect (priv->context->priv->subscribe, priv->id); - g_clear_object (&priv->context); - g_free (priv->name); - - G_OBJECT_CLASS (pinos_stream_parent_class)->finalize (object); -} - -static void -pinos_stream_class_init (PinosStreamClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosStreamPrivate)); - - gobject_class->constructed = pinos_stream_constructed; - gobject_class->finalize = pinos_stream_finalize; - gobject_class->set_property = pinos_stream_set_property; - gobject_class->get_property = pinos_stream_get_property; - - /** - * PinosStream:context - * - * The context of the stream. - */ - g_object_class_install_property (gobject_class, - PROP_CONTEXT, - g_param_spec_object ("context", - "Context", - "The context", - PINOS_TYPE_CONTEXT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:name - * - * The name of the stream as specified at construction time. - */ - g_object_class_install_property (gobject_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "The name of the stream", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:properties - * - * The properties of the stream as specified at construction time. - */ - g_object_class_install_property (gobject_class, - PROP_PROPERTIES, - g_param_spec_boxed ("properties", - "Properties", - "The properties of the stream", - PINOS_TYPE_PROPERTIES, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:state - * - * The state of the stream. Use the notify::state signal to be notified - * of state changes. - */ - g_object_class_install_property (gobject_class, - PROP_STATE, - g_param_spec_enum ("state", - "State", - "The stream state", - PINOS_TYPE_STREAM_STATE, - PINOS_STREAM_STATE_UNCONNECTED, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:possible-formats - * - * The possible formats for the stream. this can only be used after connecting - * the stream for capture or provide. - */ - g_object_class_install_property (gobject_class, - PROP_POSSIBLE_FORMATS, - g_param_spec_boxed ("possible-formats", - "Possible Formats", - "The possbile formats of the stream", - G_TYPE_PTR_ARRAY, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:formats - * - * The format of the stream. This will be set after starting the stream. - */ - g_object_class_install_property (gobject_class, - PROP_FORMAT, - g_param_spec_boxed ("format", - "Format", - "The format of the stream", - SPA_TYPE_FORMAT, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosStream:new-buffer - * @id: the buffer id - * - * this signal will be fired whenever a buffer is added to the pool of buffers. - */ - signals[SIGNAL_ADD_BUFFER] = g_signal_new ("add-buffer", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, - G_TYPE_UINT); - /** - * PinosStream:remove-buffer - * @id: the buffer id - * - * this signal will be fired whenever a buffer is removed from the pool of buffers. - */ - signals[SIGNAL_REMOVE_BUFFER] = g_signal_new ("remove-buffer", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, - G_TYPE_UINT); - /** - * PinosStream:new-buffer - * @id: the buffer id - * - * this signal will be fired whenever a buffer is ready to be processed. - */ - signals[SIGNAL_NEW_BUFFER] = g_signal_new ("new-buffer", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 1, - G_TYPE_UINT); -} - -static void -pinos_stream_init (PinosStream * stream) -{ - PinosStreamPrivate *priv = stream->priv = PINOS_STREAM_GET_PRIVATE (stream); - - pinos_log_debug ("new stream %p", stream); - - priv->state = PINOS_STREAM_STATE_UNCONNECTED; - priv->node_state = SPA_NODE_STATE_INIT; - pinos_array_init (&priv->mem_ids); - pinos_array_ensure_size (&priv->mem_ids, sizeof (MemId) * 64); - pinos_array_init (&priv->buffer_ids); - pinos_array_ensure_size (&priv->buffer_ids, sizeof (BufferId) * 64); - priv->pending_seq = SPA_ID_INVALID; -} - /** * pinos_stream_state_as_string: * @state: a #PinosStreamState @@ -535,15 +131,26 @@ pinos_stream_init (PinosStream * stream) * * Returns: the string representation of @state. */ -const gchar * +const char * pinos_stream_state_as_string (PinosStreamState state) { - GEnumValue *val; - - val = g_enum_get_value (G_ENUM_CLASS (g_type_class_ref (PINOS_TYPE_STREAM_STATE)), - state); - - return val == NULL ? "invalid-state" : val->value_nick; + switch (state) { + case PINOS_STREAM_STATE_ERROR: + return "error"; + case PINOS_STREAM_STATE_UNCONNECTED: + return "unconnected"; + case PINOS_STREAM_STATE_CONNECTING: + return "connecting"; + case PINOS_STREAM_STATE_CONFIGURE: + return "configure"; + case PINOS_STREAM_STATE_READY: + return "ready"; + case PINOS_STREAM_STATE_PAUSED: + return "paused"; + case PINOS_STREAM_STATE_STREAMING: + return "streaming"; + } + return "invalid-state"; } /** @@ -558,126 +165,148 @@ pinos_stream_state_as_string (PinosStreamState state) */ PinosStream * pinos_stream_new (PinosContext *context, - const gchar *name, + const char *name, PinosProperties *props) { - PinosStream *stream; + PinosStreamImpl *impl; + PinosStream *this; - g_return_val_if_fail (PINOS_IS_CONTEXT (context), NULL); - g_return_val_if_fail (name != NULL, NULL); + impl = calloc (1, sizeof (PinosStreamImpl)); + this = &impl->this; + pinos_log_debug ("stream %p: new", impl); + + this->context = context; + this->name = strdup (name); if (props == NULL) { props = pinos_properties_new ("media.name", name, NULL); } else if (!pinos_properties_get (props, "media.name")) { pinos_properties_set (props, "media.name", name); } + this->properties = props; - stream = g_object_new (PINOS_TYPE_STREAM, - "context", context, - "name", name, - "properties", props, - NULL); + pinos_signal_init (&this->destroy_signal); + pinos_signal_init (&this->state_changed); + pinos_signal_init (&this->format_changed); + pinos_signal_init (&this->add_buffer); + pinos_signal_init (&this->remove_buffer); + pinos_signal_init (&this->new_buffer); - pinos_properties_free (props); + this->state = PINOS_STREAM_STATE_UNCONNECTED; - return stream; + impl->node_state = SPA_NODE_STATE_INIT; + pinos_array_init (&impl->mem_ids); + pinos_array_ensure_size (&impl->mem_ids, sizeof (MemId) * 64); + pinos_array_init (&impl->buffer_ids); + pinos_array_ensure_size (&impl->buffer_ids, sizeof (BufferId) * 64); + impl->pending_seq = SPA_ID_INVALID; + + spa_list_insert (&context->stream_list, &this->link); + + return this; } -/** - * pinos_stream_get_state: - * @stream: a #PinosStream - * - * Get the state of @stream. - * - * Returns: the state of @stream - */ -PinosStreamState -pinos_stream_get_state (PinosStream *stream) +void +pinos_stream_destroy (PinosStream *stream) { - g_return_val_if_fail (PINOS_IS_STREAM (stream), PINOS_STREAM_STATE_ERROR); + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - return stream->priv->state; -} + pinos_log_debug ("stream %p: destroy", stream); -/** - * pinos_stream_get_error: - * @stream: a #PinosStream - * - * Get the error of @stream. - * - * Returns: the error of @stream or %NULL when there is no error - */ -const GError * -pinos_stream_get_error (PinosStream *stream) -{ - g_return_val_if_fail (PINOS_IS_STREAM (stream), NULL); + pinos_signal_emit (&stream->destroy_signal, stream); - return stream->priv->error; + spa_list_remove (&stream->link); + + if (impl->format) + free (impl->format); + + if (stream->error) + free (stream->error); + + pinos_array_clear (&impl->buffer_ids); + pinos_array_clear (&impl->mem_ids); + + if (stream->properties) + pinos_properties_free (stream->properties); + + if (stream->name) + free (stream->name); + + free (impl); } static void -add_node_update (PinosStream *stream, uint32_t change_mask) +add_node_update (PinosStream *stream, uint32_t change_mask, bool flush) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); PinosMessageNodeUpdate nu = { 0, }; nu.change_mask = change_mask; if (change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS) - nu.max_input_ports = priv->direction == SPA_DIRECTION_INPUT ? 1 : 0; + nu.max_input_ports = impl->direction == SPA_DIRECTION_INPUT ? 1 : 0; if (change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS) - nu.max_output_ports = priv->direction == SPA_DIRECTION_OUTPUT ? 1 : 0; + nu.max_output_ports = impl->direction == SPA_DIRECTION_OUTPUT ? 1 : 0; nu.props = NULL; - pinos_connection_add_message (priv->conn, PINOS_MESSAGE_NODE_UPDATE, &nu); + + pinos_proxy_send_message (impl->node_proxy, + PINOS_MESSAGE_NODE_UPDATE, + &nu, + flush); } static void -add_state_change (PinosStream *stream, SpaNodeState state) +add_state_change (PinosStream *stream, SpaNodeState state, bool flush) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); PinosMessageNodeStateChange sc; - if (priv->node_state != state) { - sc.state = priv->node_state = state; - pinos_connection_add_message (priv->conn, PINOS_MESSAGE_NODE_STATE_CHANGE, &sc); + if (impl->node_state != state) { + sc.state = impl->node_state = state; + pinos_proxy_send_message (impl->node_proxy, + PINOS_MESSAGE_NODE_STATE_CHANGE, + &sc, + flush); } } static void -add_port_update (PinosStream *stream, uint32_t change_mask) +add_port_update (PinosStream *stream, uint32_t change_mask, bool flush) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); PinosMessagePortUpdate pu = { 0, };; - pu.direction = priv->direction; - pu.port_id = priv->port_id; + pu.direction = impl->direction; + pu.port_id = impl->port_id; pu.change_mask = change_mask; if (change_mask & PINOS_MESSAGE_PORT_UPDATE_POSSIBLE_FORMATS) { - pu.n_possible_formats = priv->possible_formats->len; - pu.possible_formats = (SpaFormat **)priv->possible_formats->pdata; + pu.n_possible_formats = impl->n_possible_formats; + pu.possible_formats = impl->possible_formats; } if (change_mask & PINOS_MESSAGE_PORT_UPDATE_FORMAT) { - pu.format = priv->format; + pu.format = impl->format; } pu.props = NULL; if (change_mask & PINOS_MESSAGE_PORT_UPDATE_INFO) { - pu.info = &priv->port_info; + pu.info = &impl->port_info; } - pinos_connection_add_message (priv->conn, PINOS_MESSAGE_PORT_UPDATE, &pu); + pinos_proxy_send_message (impl->node_proxy, + PINOS_MESSAGE_PORT_UPDATE, + &pu, + flush); } static inline void send_need_input (PinosStream *stream) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); uint8_t cmd = PINOS_TRANSPORT_CMD_NEED_DATA; - write (priv->rtfd, &cmd, 1); - + write (impl->rtfd, &cmd, 1); } static void -add_request_clock_update (PinosStream *stream) +add_request_clock_update (PinosStream *stream, bool flush) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); PinosMessageNodeEvent cne; SpaNodeEventRequestClockUpdate rcu; @@ -687,15 +316,19 @@ add_request_clock_update (PinosStream *stream) rcu.update_mask = SPA_NODE_EVENT_REQUEST_CLOCK_UPDATE_TIME; rcu.timestamp = 0; rcu.offset = 0; - pinos_connection_add_message (priv->conn, PINOS_MESSAGE_NODE_EVENT, &cne); + pinos_proxy_send_message (impl->node_proxy, + PINOS_MESSAGE_NODE_EVENT, + &cne, + flush); } static void -add_async_complete (PinosStream *stream, - uint32_t seq, - SpaResult res) +add_async_complete (PinosStream *stream, + uint32_t seq, + SpaResult res, + bool flush) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); PinosMessageNodeEvent cne; SpaNodeEventAsyncComplete ac; @@ -704,34 +337,44 @@ add_async_complete (PinosStream *stream, ac.event.size = sizeof (ac); ac.seq = seq; ac.res = res; - pinos_connection_add_message (priv->conn, PINOS_MESSAGE_NODE_EVENT, &cne); + pinos_proxy_send_message (impl->node_proxy, + PINOS_MESSAGE_NODE_EVENT, + &cne, + flush); } static void do_node_init (PinosStream *stream) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); add_node_update (stream, PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS | - PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS); + PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS, + false); - priv->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; + impl->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; add_port_update (stream, PINOS_MESSAGE_PORT_UPDATE_POSSIBLE_FORMATS | - PINOS_MESSAGE_PORT_UPDATE_INFO); + PINOS_MESSAGE_PORT_UPDATE_INFO, + false); + add_state_change (stream, SPA_NODE_STATE_CONFIGURE, true); +} - add_state_change (stream, SPA_NODE_STATE_CONFIGURE); +static void +on_timeout (SpaSource *source, + void *data) +{ + PinosStream *stream = data; - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); + add_request_clock_update (stream, true); } static MemId * find_mem (PinosStream *stream, uint32_t id) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); MemId *mid; - pinos_array_for_each (mid, &priv->mem_ids) { + pinos_array_for_each (mid, &impl->mem_ids) { if (mid->id == id) return mid; } @@ -741,14 +384,14 @@ find_mem (PinosStream *stream, uint32_t id) static BufferId * find_buffer (PinosStream *stream, uint32_t id) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - if (priv->in_order && pinos_array_check_index (&priv->buffer_ids, id, BufferId)) { - return pinos_array_get_unchecked (&priv->buffer_ids, id, BufferId); + if (impl->in_order && pinos_array_check_index (&impl->buffer_ids, id, BufferId)) { + return pinos_array_get_unchecked (&impl->buffer_ids, id, BufferId); } else { BufferId *bid; - pinos_array_for_each (bid, &priv->buffer_ids) { + pinos_array_for_each (bid, &impl->buffer_ids) { if (bid->id == id) return bid; } @@ -756,367 +399,11 @@ find_buffer (PinosStream *stream, uint32_t id) return NULL; } -static gboolean -handle_node_event (PinosStream *stream, - SpaNodeEvent *event) -{ - switch (event->type) { - case SPA_NODE_EVENT_TYPE_INVALID: - case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: - case SPA_NODE_EVENT_TYPE_NEED_INPUT: - case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE: - case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: - case SPA_NODE_EVENT_TYPE_ERROR: - case SPA_NODE_EVENT_TYPE_BUFFERING: - case SPA_NODE_EVENT_TYPE_REQUEST_REFRESH: - case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE: - pinos_log_warn ("unhandled node event %d", event->type); - break; - } - return TRUE; -} - -static gboolean -handle_node_command (PinosStream *stream, - uint32_t seq, - SpaNodeCommand *command) -{ - PinosStreamPrivate *priv = stream->priv; - - switch (command->type) { - case SPA_NODE_COMMAND_INVALID: - break; - case SPA_NODE_COMMAND_PAUSE: - { - pinos_log_debug ("stream %p: pause %d", stream, seq); - - add_state_change (stream, SPA_NODE_STATE_PAUSED); - add_async_complete (stream, seq, SPA_RESULT_OK); - - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - - stream_set_state (stream, PINOS_STREAM_STATE_PAUSED, NULL); - break; - } - case SPA_NODE_COMMAND_START: - { - pinos_log_debug ("stream %p: start %d", stream, seq); - add_state_change (stream, SPA_NODE_STATE_STREAMING); - add_async_complete (stream, seq, SPA_RESULT_OK); - - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - - if (priv->direction == SPA_DIRECTION_INPUT) - send_need_input (stream); - - stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL); - break; - } - case SPA_NODE_COMMAND_FLUSH: - case SPA_NODE_COMMAND_DRAIN: - case SPA_NODE_COMMAND_MARKER: - { - pinos_log_warn ("unhandled node command %d", command->type); - add_async_complete (stream, seq, SPA_RESULT_NOT_IMPLEMENTED); - - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - break; - } - case SPA_NODE_COMMAND_CLOCK_UPDATE: - { - SpaNodeCommandClockUpdate *cu = (SpaNodeCommandClockUpdate *) command; - if (cu->flags & SPA_NODE_COMMAND_CLOCK_UPDATE_FLAG_LIVE) { - pinos_properties_set (priv->properties, - "pinos.latency.is-live", "1"); - pinos_properties_setf (priv->properties, - "pinos.latency.min", "%"PRId64, cu->latency); - } - priv->last_ticks = cu->ticks; - priv->last_rate = cu->rate; - priv->last_monotonic = cu->monotonic_time; - break; - } - } - return TRUE; -} - -static gboolean -parse_connection (PinosStream *stream) -{ - PinosStreamPrivate *priv = stream->priv; - PinosConnection *conn = priv->conn; - - while (pinos_connection_has_next (conn)) { - PinosMessageType type = pinos_connection_get_type (conn); - - switch (type) { - case PINOS_MESSAGE_NODE_UPDATE: - case PINOS_MESSAGE_PORT_UPDATE: - case PINOS_MESSAGE_PORT_STATUS_CHANGE: - case PINOS_MESSAGE_NODE_STATE_CHANGE: - case PINOS_MESSAGE_PROCESS_BUFFER: - pinos_log_warn ("got unexpected message %d", type); - break; - - case PINOS_MESSAGE_ADD_PORT: - case PINOS_MESSAGE_REMOVE_PORT: - pinos_log_warn ("add/remove port not supported"); - break; - - case PINOS_MESSAGE_SET_FORMAT: - { - PinosMessageSetFormat p; - gpointer mem; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - if (priv->format) - g_free (priv->format); - mem = malloc (pinos_serialize_format_get_size (p.format)); - priv->format = pinos_serialize_format_copy_into (mem, p.format); - - priv->pending_seq = p.seq; - g_object_notify (G_OBJECT (stream), "format"); - stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); - break; - } - case PINOS_MESSAGE_SET_PROPERTY: - pinos_log_warn ("set property not implemented"); - break; - - case PINOS_MESSAGE_ADD_MEM: - { - PinosMessageAddMem p; - int fd; - MemId *m; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - fd = pinos_connection_get_fd (conn, p.fd_index, false); - if (fd == -1) - break; - - m = find_mem (stream, p.mem_id); - if (m) { - pinos_log_debug ("update mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size); - } else { - m = pinos_array_add (&priv->mem_ids, sizeof (MemId)); - pinos_log_debug ("add mem %u, fd %d, flags %d, size %zd", p.mem_id, fd, p.flags, p.size); - } - m->id = p.mem_id; - m->fd = fd; - m->flags = p.flags; - m->ptr = NULL; - m->size = p.size; - break; - } - case PINOS_MESSAGE_USE_BUFFERS: - { - PinosMessageUseBuffers p; - BufferId *bid; - unsigned int i, j, len; - SpaBuffer *b; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - /* clear previous buffers */ - clear_buffers (stream); - - for (i = 0; i < p.n_buffers; i++) { - MemId *mid = find_mem (stream, p.buffers[i].mem_id); - if (mid == NULL) { - pinos_log_warn ("unknown memory id %u", mid->id); - continue; - } - - if (mid->ptr == NULL) { - mid->ptr = mmap (NULL, mid->size, PROT_READ | PROT_WRITE, MAP_SHARED, mid->fd, 0); - if (mid->ptr == MAP_FAILED) { - mid->ptr = NULL; - pinos_log_warn ("Failed to mmap memory %zd %p: %s", mid->size, mid, strerror (errno)); - continue; - } - } - len = pinos_array_get_len (&priv->buffer_ids, BufferId); - bid = pinos_array_add (&priv->buffer_ids, sizeof (BufferId)); - - bid->buf_ptr = SPA_MEMBER (mid->ptr, p.buffers[i].offset, void); - { - size_t size; - unsigned int i; - SpaMeta *m; - - b = bid->buf_ptr; - size = sizeof (SpaBuffer); - m = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); - for (i = 0; i < b->n_metas; i++) - size += sizeof (SpaMeta) + m[i].size; - for (i = 0; i < b->n_datas; i++) - size += sizeof (SpaData); - - b = bid->buf = g_memdup (bid->buf_ptr, size); - - if (b->metas) - b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); - if (b->datas) { - bid->datas = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (b->datas), SpaData); - b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); - } - } - - bid->id = b->id; - - if (bid->id != len) { - pinos_log_warn ("unexpected id %u found, expected %u", bid->id, len); - priv->in_order = FALSE; - } - pinos_log_debug ("add buffer %d %d %zd", mid->id, bid->id, p.buffers[i].offset); - - for (j = 0; j < b->n_metas; j++) { - SpaMeta *m = &b->metas[j]; - if (m->data) - m->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (m->data), void); - } - - for (j = 0; j < b->n_datas; j++) { - SpaData *d = &b->datas[j]; - - switch (d->type) { - case SPA_DATA_TYPE_ID: - { - MemId *bmid = find_mem (stream, SPA_PTR_TO_UINT32 (d->data)); - d->type = SPA_DATA_TYPE_MEMFD; - d->data = NULL; - d->fd = bmid->fd; - pinos_log_debug (" data %d %u -> fd %d", j, bmid->id, bmid->fd); - break; - } - case SPA_DATA_TYPE_MEMPTR: - { - d->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (d->data), void); - d->fd = -1; - pinos_log_debug (" data %d %u -> mem %p", j, bid->id, d->data); - break; - } - default: - pinos_log_warn ("unknown buffer data type %d", d->type); - break; - } - } - - g_signal_emit (stream, signals[SIGNAL_ADD_BUFFER], 0, bid->id); - } - - if (p.n_buffers) { - add_state_change (stream, SPA_NODE_STATE_PAUSED); - } else { - add_state_change (stream, SPA_NODE_STATE_READY); - } - add_async_complete (stream, p.seq, SPA_RESULT_OK); - - if (!pinos_connection_flush (conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - - if (p.n_buffers) - stream_set_state (stream, PINOS_STREAM_STATE_PAUSED, NULL); - else - stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); - break; - } - case PINOS_MESSAGE_NODE_EVENT: - { - PinosMessageNodeEvent p; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - handle_node_event (stream, p.event); - break; - } - case PINOS_MESSAGE_NODE_COMMAND: - { - PinosMessageNodeCommand p; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - handle_node_command (stream, p.seq, p.command); - break; - } - case PINOS_MESSAGE_PORT_COMMAND: - { - PinosMessagePortCommand p; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - break; - } - case PINOS_MESSAGE_TRANSPORT_UPDATE: - { - PinosMessageTransportUpdate p; - PinosTransportInfo info; - - if (!pinos_connection_parse_message (conn, &p)) - break; - - info.memfd = pinos_connection_get_fd (conn, p.memfd_index, false); - if (info.memfd == -1) - break; - info.offset = p.offset; - info.size = p.size; - - pinos_log_debug ("transport update %d %p", priv->rtfd, priv->trans); - - if (priv->trans) - pinos_transport_free (priv->trans); - priv->trans = pinos_transport_new_from_info (&info); - - break; - } - case PINOS_MESSAGE_INVALID: - pinos_log_warn ("unhandled message %d", type); - break; - } - } - return TRUE; -} - -static gboolean -on_socket_condition (GSocket *socket, - GIOCondition condition, - gpointer user_data) -{ - PinosStream *stream = user_data; - - switch (condition) { - case G_IO_IN: - { - parse_connection (stream); - break; - } - - case G_IO_OUT: - pinos_log_warn ("can do IO\n"); - break; - - default: - break; - } - return TRUE; -} - -static gboolean +static void handle_rtnode_event (PinosStream *stream, SpaNodeEvent *event) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); switch (event->type) { case SPA_NODE_EVENT_TYPE_INVALID: @@ -1138,270 +425,422 @@ handle_rtnode_event (PinosStream *stream, SpaNodeEventReuseBuffer *p = (SpaNodeEventReuseBuffer *) event; BufferId *bid; - if (p->port_id != priv->port_id) + if (p->port_id != impl->port_id) break; - if (priv->direction != SPA_DIRECTION_OUTPUT) + if (impl->direction != SPA_DIRECTION_OUTPUT) break; if ((bid = find_buffer (stream, p->buffer_id))) { bid->used = FALSE; - g_signal_emit (stream, signals[SIGNAL_NEW_BUFFER], 0, p->buffer_id); + pinos_signal_emit (&stream->new_buffer, stream, p->buffer_id); } break; } } - return TRUE; -} - -static gboolean -on_rtsocket_condition (GSocket *socket, - GIOCondition condition, - gpointer user_data) -{ - PinosStream *stream = user_data; - PinosStreamPrivate *priv = stream->priv; - - switch (condition) { - case G_IO_IN: - { - uint8_t cmd; - int i; - - read (priv->rtfd, &cmd, 1); - - if (cmd & PINOS_TRANSPORT_CMD_HAVE_DATA) { - BufferId *bid; - - for (i = 0; i < priv->trans->area->n_inputs; i++) { - SpaPortInput *input = &priv->trans->inputs[i]; - - if (input->buffer_id == SPA_ID_INVALID) - continue; - - if ((bid = find_buffer (stream, input->buffer_id))) { - for (i = 0; i < bid->buf->n_datas; i++) { - bid->buf->datas[i].size = bid->datas[i].size; - } - g_signal_emit (stream, signals[SIGNAL_NEW_BUFFER], 0, bid->id); - } - input->buffer_id = SPA_ID_INVALID; - } - send_need_input (stream); - } - if (cmd & PINOS_TRANSPORT_CMD_HAVE_EVENT) { - SpaNodeEvent event; - while (pinos_transport_next_event (priv->trans, &event) == SPA_RESULT_OK) { - SpaNodeEvent *ev = alloca (event.size); - pinos_transport_parse_event (priv->trans, ev); - handle_rtnode_event (stream, ev); - } - } - break; - } - - case G_IO_OUT: - pinos_log_warn ("can do IO"); - break; - - default: - break; - } - return TRUE; -} - -static gboolean -on_timeout (gpointer user_data) -{ - PinosStream *stream = user_data; - PinosStreamPrivate *priv = stream->priv; - - add_request_clock_update (stream); - - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - - return G_SOURCE_CONTINUE; } static void -handle_socket (PinosStream *stream, gint fd, gint rtfd) +on_rtsocket_condition (SpaSource *source, + int fd, + SpaIO mask, + void *data) { - PinosStreamPrivate *priv = stream->priv; - GError *error = NULL; + PinosStream *stream = data; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - priv->socket = g_socket_new_from_fd (fd, &error); - if (priv->socket == NULL) - goto socket_failed; - priv->rtsocket = g_socket_new_from_fd (rtfd, &error); - if (priv->rtsocket == NULL) - goto socket_failed; - - priv->fd = g_socket_get_fd (priv->socket); - priv->socket_source = g_socket_create_source (priv->socket, G_IO_IN, NULL); - g_source_set_callback (priv->socket_source, (GSourceFunc) on_socket_condition, stream, NULL); - g_source_attach (priv->socket_source, priv->context->priv->context); - priv->conn = pinos_connection_new (priv->fd); - - priv->rtfd = g_socket_get_fd (priv->rtsocket); - priv->rtsocket_source = g_socket_create_source (priv->rtsocket, G_IO_IN, NULL); - g_source_set_callback (priv->rtsocket_source, (GSourceFunc) on_rtsocket_condition, stream, NULL); - g_source_attach (priv->rtsocket_source, priv->context->priv->context); - - pinos_log_debug ("sockets %d %d", priv->fd, priv->rtfd); - - priv->timeout_source = g_timeout_source_new (100); - g_source_set_callback (priv->timeout_source, (GSourceFunc) on_timeout, stream, NULL); - g_source_attach (priv->timeout_source, priv->context->priv->context); - - return; - - /* ERRORS */ -socket_failed: - { - pinos_log_warn ("failed to create socket: %s", error->message); - stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); - return; + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + pinos_log_warn ("got error"); } + + if (mask & SPA_IO_IN) { + uint8_t cmd; + int i; + + read (impl->rtfd, &cmd, 1); + + if (cmd & PINOS_TRANSPORT_CMD_HAVE_DATA) { + BufferId *bid; + + for (i = 0; i < impl->trans->area->n_inputs; i++) { + SpaPortInput *input = &impl->trans->inputs[i]; + + if (input->buffer_id == SPA_ID_INVALID) + continue; + + if ((bid = find_buffer (stream, input->buffer_id))) { + for (i = 0; i < bid->buf->n_datas; i++) { + bid->buf->datas[i].size = bid->datas[i].size; + } + pinos_signal_emit (&stream->new_buffer, stream, bid->id); + } + input->buffer_id = SPA_ID_INVALID; + } + send_need_input (stream); + } + if (cmd & PINOS_TRANSPORT_CMD_HAVE_EVENT) { + SpaNodeEvent event; + while (pinos_transport_next_event (impl->trans, &event) == SPA_RESULT_OK) { + SpaNodeEvent *ev = alloca (event.size); + pinos_transport_parse_event (impl->trans, ev); + handle_rtnode_event (stream, ev); + } + } + } +} + +static void +handle_socket (PinosStream *stream, gint rtfd) +{ + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); + struct timespec interval; + + impl->rtfd = rtfd; + impl->rtsocket_source = pinos_loop_add_io (stream->context->loop, + impl->rtfd, + SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP, + false, + on_rtsocket_condition, + stream); + pinos_log_debug ("socket %d", impl->rtfd); + + impl->timeout_source = pinos_loop_add_timer (stream->context->loop, + on_timeout, + stream); + interval.tv_sec = 0; + interval.tv_nsec = 100000000; + pinos_loop_update_timer (stream->context->loop, + impl->timeout_source, + NULL, + &interval, + false); + return; } static void unhandle_socket (PinosStream *stream) { - PinosStreamPrivate *priv = stream->priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - if (priv->socket_source) { - g_source_destroy (priv->socket_source); - g_clear_pointer (&priv->socket_source, g_source_unref); - } - if (priv->rtsocket_source) { - g_source_destroy (priv->rtsocket_source); - g_clear_pointer (&priv->rtsocket_source, g_source_unref); + if (impl->rtsocket_source) { + pinos_loop_destroy_source (stream->context->loop, impl->rtsocket_source); + impl->rtsocket_source = NULL; } } static void -on_node_proxy (GObject *source_object, - GAsyncResult *res, - gpointer user_data) +handle_node_event (PinosStream *stream, + SpaNodeEvent *event) { - PinosStream *stream = user_data; - PinosStreamPrivate *priv = stream->priv; - PinosContext *context = priv->context; - - GError *error = NULL; - - priv->node = pinos_subscribe_get_proxy_finish (context->priv->subscribe, - res, - &error); - if (priv->node == NULL) - goto node_failed; - - do_node_init (stream); - - stream_set_state (stream, PINOS_STREAM_STATE_CONFIGURE, NULL); - g_object_unref (stream); - - return; - -node_failed: - { - pinos_log_warn ("failed to get node proxy: %s", error->message); - stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); - g_object_unref (stream); - return; - } -} - -static void -on_node_created (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosStream *stream = user_data; - PinosStreamPrivate *priv = stream->priv; - PinosContext *context = priv->context; - GVariant *ret; - GError *error = NULL; - const gchar *node_path; - GUnixFDList *fd_list; - gint fd_idx, fd; - gint rtfd_idx, rtfd; - - g_assert (context->priv->daemon == G_DBUS_PROXY (source_object)); - - ret = g_dbus_proxy_call_with_unix_fd_list_finish (context->priv->daemon, - &fd_list, - res, &error); - if (ret == NULL) - goto create_failed; - - g_variant_get (ret, "(&ohh)", &node_path, &fd_idx, &rtfd_idx); - g_variant_unref (ret); - - if ((fd = g_unix_fd_list_get (fd_list, fd_idx, &error)) < 0) - goto fd_failed; - if ((rtfd = g_unix_fd_list_get (fd_list, rtfd_idx, &error)) < 0) - goto fd_failed; - - priv->fd = fd; - priv->rtfd = rtfd; - g_object_unref (fd_list); - - handle_socket (stream, priv->fd, priv->rtfd); - - pinos_subscribe_get_proxy (context->priv->subscribe, - PINOS_DBUS_SERVICE, - node_path, - "org.pinos.Node1", - NULL, - on_node_proxy, - stream); - - return; - - /* ERRORS */ -create_failed: - { - pinos_log_warn ("failed to connect: %s", error->message); - goto exit_error; - } -fd_failed: - { - pinos_log_warn ("failed to get FD: %s", error->message); - g_object_unref (fd_list); - goto exit_error; - } -exit_error: - { - stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); - g_object_unref (stream); - return; + switch (event->type) { + case SPA_NODE_EVENT_TYPE_INVALID: + case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: + case SPA_NODE_EVENT_TYPE_NEED_INPUT: + case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE: + case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: + case SPA_NODE_EVENT_TYPE_ERROR: + case SPA_NODE_EVENT_TYPE_BUFFERING: + case SPA_NODE_EVENT_TYPE_REQUEST_REFRESH: + case SPA_NODE_EVENT_TYPE_REQUEST_CLOCK_UPDATE: + pinos_log_warn ("unhandled node event %d", event->type); + break; } } static gboolean -do_connect (PinosStream *stream) +handle_node_command (PinosStream *stream, + uint32_t seq, + SpaNodeCommand *command) { - PinosStreamPrivate *priv = stream->priv; - PinosContext *context = priv->context; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - if (priv->properties == NULL) - priv->properties = pinos_properties_new (NULL, NULL); - if (priv->path) - pinos_properties_set (priv->properties, - "pinos.target.node", priv->path); + switch (command->type) { + case SPA_NODE_COMMAND_INVALID: + break; + case SPA_NODE_COMMAND_PAUSE: + { + pinos_log_debug ("stream %p: pause %d", stream, seq); - g_dbus_proxy_call (context->priv->daemon, - "CreateClientNode", - g_variant_new ("(s@a{sv})", - "client-node", - pinos_properties_to_variant (priv->properties)), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* GCancellable *cancellable */ - on_node_created, - stream); - return FALSE; + add_state_change (stream, SPA_NODE_STATE_PAUSED, false); + add_async_complete (stream, seq, SPA_RESULT_OK, true); + stream_set_state (stream, PINOS_STREAM_STATE_PAUSED, NULL); + break; + } + case SPA_NODE_COMMAND_START: + { + pinos_log_debug ("stream %p: start %d", stream, seq); + add_state_change (stream, SPA_NODE_STATE_STREAMING, false); + add_async_complete (stream, seq, SPA_RESULT_OK, true); + + if (impl->direction == SPA_DIRECTION_INPUT) + send_need_input (stream); + + stream_set_state (stream, PINOS_STREAM_STATE_STREAMING, NULL); + break; + } + case SPA_NODE_COMMAND_FLUSH: + case SPA_NODE_COMMAND_DRAIN: + case SPA_NODE_COMMAND_MARKER: + { + pinos_log_warn ("unhandled node command %d", command->type); + add_async_complete (stream, seq, SPA_RESULT_NOT_IMPLEMENTED, true); + break; + } + case SPA_NODE_COMMAND_CLOCK_UPDATE: + { + SpaNodeCommandClockUpdate *cu = (SpaNodeCommandClockUpdate *) command; + if (cu->flags & SPA_NODE_COMMAND_CLOCK_UPDATE_FLAG_LIVE) { + pinos_properties_set (stream->properties, + "pinos.latency.is-live", "1"); + pinos_properties_setf (stream->properties, + "pinos.latency.min", "%"PRId64, cu->latency); + } + impl->last_ticks = cu->ticks; + impl->last_rate = cu->rate; + impl->last_monotonic = cu->monotonic_time; + break; + } + } + return TRUE; +} + +static SpaResult +stream_dispatch_func (void *object, + PinosMessageType type, + void *message, + void *data) +{ + PinosStream *stream = data; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); + + switch (type) { + case PINOS_MESSAGE_SYNC: + case PINOS_MESSAGE_SUBSCRIBE: + case PINOS_MESSAGE_CREATE_NODE: + case PINOS_MESSAGE_CREATE_CLIENT_NODE: + case PINOS_MESSAGE_NODE_UPDATE: + case PINOS_MESSAGE_PORT_UPDATE: + case PINOS_MESSAGE_PORT_STATUS_CHANGE: + case PINOS_MESSAGE_NODE_STATE_CHANGE: + pinos_log_warn ("got unexpected message %d", type); + break; + + case PINOS_MESSAGE_NOTIFY_DONE: + pinos_log_warn ("notify done %d", type); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL: + pinos_log_warn ("notify global %d", type); + break; + + case PINOS_MESSAGE_NOTIFY_GLOBAL_REMOVE: + pinos_log_warn ("notify global %d", type); + break; + + case PINOS_MESSAGE_CREATE_NODE_DONE: + pinos_log_warn ("create node done %d", type); + break; + + case PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE: + { + PinosMessageCreateClientNodeDone *cnd = message; + + pinos_log_warn ("create client node done %d", type); + handle_socket (stream, cnd->datafd); + do_node_init (stream); + break; + } + + case PINOS_MESSAGE_ADD_PORT: + case PINOS_MESSAGE_REMOVE_PORT: + pinos_log_warn ("add/remove port not supported"); + break; + + case PINOS_MESSAGE_SET_FORMAT: + { + PinosMessageSetFormat *p = message; + gpointer mem; + + if (impl->format) + free (impl->format); + mem = malloc (pinos_serialize_format_get_size (p->format)); + impl->format = pinos_serialize_format_copy_into (mem, p->format); + + impl->pending_seq = p->seq; + + pinos_signal_emit (&stream->format_changed, stream, impl->format); + stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); + break; + } + case PINOS_MESSAGE_SET_PROPERTY: + pinos_log_warn ("set property not implemented"); + break; + + case PINOS_MESSAGE_ADD_MEM: + { + PinosMessageAddMem *p = message; + MemId *m; + + m = find_mem (stream, p->mem_id); + if (m) { + pinos_log_debug ("update mem %u, fd %d, flags %d, size %zd", p->mem_id, p->memfd, p->flags, p->size); + } else { + m = pinos_array_add (&impl->mem_ids, sizeof (MemId)); + pinos_log_debug ("add mem %u, fd %d, flags %d, size %zd", p->mem_id, p->memfd, p->flags, p->size); + } + m->id = p->mem_id; + m->fd = p->memfd; + m->flags = p->flags; + m->ptr = NULL; + m->size = p->size; + break; + } + case PINOS_MESSAGE_USE_BUFFERS: + { + PinosMessageUseBuffers *p = message; + BufferId *bid; + unsigned int i, j, len; + SpaBuffer *b; + + /* clear previous buffers */ + clear_buffers (stream); + + for (i = 0; i < p->n_buffers; i++) { + MemId *mid = find_mem (stream, p->buffers[i].mem_id); + if (mid == NULL) { + pinos_log_warn ("unknown memory id %u", mid->id); + continue; + } + + if (mid->ptr == NULL) { + mid->ptr = mmap (NULL, mid->size, PROT_READ | PROT_WRITE, MAP_SHARED, mid->fd, 0); + if (mid->ptr == MAP_FAILED) { + mid->ptr = NULL; + pinos_log_warn ("Failed to mmap memory %zd %p: %s", mid->size, mid, strerror (errno)); + continue; + } + } + len = pinos_array_get_len (&impl->buffer_ids, BufferId); + bid = pinos_array_add (&impl->buffer_ids, sizeof (BufferId)); + + bid->buf_ptr = SPA_MEMBER (mid->ptr, p->buffers[i].offset, void); + { + size_t size; + unsigned int i; + SpaMeta *m; + + b = bid->buf_ptr; + size = sizeof (SpaBuffer); + m = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); + for (i = 0; i < b->n_metas; i++) + size += sizeof (SpaMeta) + m[i].size; + for (i = 0; i < b->n_datas; i++) + size += sizeof (SpaData); + + b = bid->buf = g_memdup (bid->buf_ptr, size); + + if (b->metas) + b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); + if (b->datas) { + bid->datas = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (b->datas), SpaData); + b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); + } + } + + bid->id = b->id; + + if (bid->id != len) { + pinos_log_warn ("unexpected id %u found, expected %u", bid->id, len); + impl->in_order = FALSE; + } + pinos_log_debug ("add buffer %d %d %zd", mid->id, bid->id, p->buffers[i].offset); + + for (j = 0; j < b->n_metas; j++) { + SpaMeta *m = &b->metas[j]; + if (m->data) + m->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (m->data), void); + } + + for (j = 0; j < b->n_datas; j++) { + SpaData *d = &b->datas[j]; + + switch (d->type) { + case SPA_DATA_TYPE_ID: + { + MemId *bmid = find_mem (stream, SPA_PTR_TO_UINT32 (d->data)); + d->type = SPA_DATA_TYPE_MEMFD; + d->data = NULL; + d->fd = bmid->fd; + pinos_log_debug (" data %d %u -> fd %d", j, bmid->id, bmid->fd); + break; + } + case SPA_DATA_TYPE_MEMPTR: + { + d->data = SPA_MEMBER (bid->buf_ptr, SPA_PTR_TO_INT (d->data), void); + d->fd = -1; + pinos_log_debug (" data %d %u -> mem %p", j, bid->id, d->data); + break; + } + default: + pinos_log_warn ("unknown buffer data type %d", d->type); + break; + } + } + + pinos_signal_emit (&stream->add_buffer, stream, bid->id); + } + + if (p->n_buffers) { + add_state_change (stream, SPA_NODE_STATE_PAUSED, false); + } else { + add_state_change (stream, SPA_NODE_STATE_READY, false); + } + add_async_complete (stream, p->seq, SPA_RESULT_OK, true); + + if (p->n_buffers) + stream_set_state (stream, PINOS_STREAM_STATE_PAUSED, NULL); + else + stream_set_state (stream, PINOS_STREAM_STATE_READY, NULL); + break; + } + case PINOS_MESSAGE_NODE_EVENT: + { + PinosMessageNodeEvent *p = message; + handle_node_event (stream, p->event); + break; + } + case PINOS_MESSAGE_NODE_COMMAND: + { + PinosMessageNodeCommand *p = message; + handle_node_command (stream, p->seq, p->command); + break; + } + case PINOS_MESSAGE_PORT_COMMAND: + { + break; + } + case PINOS_MESSAGE_TRANSPORT_UPDATE: + { + PinosMessageTransportUpdate *p = message; + PinosTransportInfo info; + + info.memfd = p->memfd; + if (info.memfd == -1) + break; + info.offset = p->offset; + info.size = p->size; + + if (impl->trans) + pinos_transport_free (impl->trans); + impl->trans = pinos_transport_new_from_info (&info); + + pinos_log_debug ("transport update %d %p", impl->rtfd, impl->trans); + break; + } + case PINOS_MESSAGE_INVALID: + pinos_log_warn ("unhandled message %d", type); + break; + } + return SPA_RESULT_OK; } /** @@ -1421,42 +860,58 @@ do_connect (PinosStream *stream) * * Returns: %TRUE on success. */ -gboolean +bool pinos_stream_connect (PinosStream *stream, PinosDirection direction, PinosStreamMode mode, const gchar *port_path, PinosStreamFlags flags, - GPtrArray *possible_formats) + unsigned int n_possible_formats, + SpaFormat **possible_formats) { - PinosStreamPrivate *priv; - PinosContext *context; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); + PinosMessageCreateClientNode ccn; + SpaDict dict; + SpaDictItem items[1]; - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - g_return_val_if_fail (possible_formats != NULL, FALSE); + impl->direction = direction == PINOS_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT; + impl->port_id = 0; + impl->mode = mode; - priv = stream->priv; - context = priv->context; - g_return_val_if_fail (pinos_context_get_state (context) == PINOS_CONTEXT_STATE_CONNECTED, FALSE); - g_return_val_if_fail (pinos_stream_get_state (stream) == PINOS_STREAM_STATE_UNCONNECTED, FALSE); + impl->flags = flags; - priv->direction = direction == PINOS_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT; - priv->port_id = 0; - priv->mode = mode; - g_free (priv->path); - priv->path = g_strdup (port_path); - priv->flags = flags; - if (priv->possible_formats) - g_ptr_array_unref (priv->possible_formats); - priv->possible_formats = possible_formats; + impl->n_possible_formats = n_possible_formats; + impl->possible_formats = possible_formats; stream_set_state (stream, PINOS_STREAM_STATE_CONNECTING, NULL); - g_main_context_invoke (context->priv->context, - (GSourceFunc) do_connect, - g_object_ref (stream)); + if (stream->properties == NULL) + stream->properties = pinos_properties_new (NULL, NULL); + if (port_path) + pinos_properties_set (stream->properties, + "pinos.target.node", port_path); - return TRUE; + impl->node_proxy = pinos_proxy_new (stream->context, + SPA_ID_INVALID, + 0); + + impl->node_proxy->dispatch_func = stream_dispatch_func; + impl->node_proxy->dispatch_data = impl; + + ccn.seq = ++impl->seq; + ccn.name = "client-node"; + dict.n_items = 1; + dict.items = items; + items[0].key = "pinos.target.node"; + items[0].value = port_path; + ccn.props = &dict; + ccn.id = impl->node_proxy->id; + pinos_proxy_send_message (stream->context->core_proxy, + PINOS_MESSAGE_CREATE_CLIENT_NODE, + &ccn, + true); + + return true; } /** @@ -1475,53 +930,36 @@ pinos_stream_connect (PinosStream *stream, * * Returns: %TRUE on success */ -gboolean +bool pinos_stream_finish_format (PinosStream *stream, SpaResult res, SpaAllocParam **params, unsigned int n_params) { - PinosStreamPrivate *priv; - PinosContext *context; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->pending_seq != SPA_ID_INVALID, FALSE); - context = priv->context; - - g_return_val_if_fail (pinos_context_get_state (context) == PINOS_CONTEXT_STATE_CONNECTED, FALSE); - - priv->port_info.params = params; - priv->port_info.n_params = n_params; + impl->port_info.params = params; + impl->port_info.n_params = n_params; if (SPA_RESULT_IS_OK (res)) { add_port_update (stream, PINOS_MESSAGE_PORT_UPDATE_INFO | - PINOS_MESSAGE_PORT_UPDATE_FORMAT); - if (priv->format) { - add_state_change (stream, SPA_NODE_STATE_READY); + PINOS_MESSAGE_PORT_UPDATE_FORMAT, + false); + if (impl->format) { + add_state_change (stream, SPA_NODE_STATE_READY, false); } else { clear_buffers (stream); - add_state_change (stream, SPA_NODE_STATE_CONFIGURE); + add_state_change (stream, SPA_NODE_STATE_CONFIGURE, false); } } - priv->port_info.params = NULL; - priv->port_info.n_params = 0; + impl->port_info.params = NULL; + impl->port_info.n_params = 0; - add_async_complete (stream, priv->pending_seq, res); + add_async_complete (stream, impl->pending_seq, res, true); - priv->pending_seq = SPA_ID_INVALID; + impl->pending_seq = SPA_ID_INVALID; - if (!pinos_connection_flush (priv->conn)) - pinos_log_warn ("stream %p: error writing connection", stream); - - return TRUE; -} - -static gboolean -do_start (PinosStream *stream) -{ - g_object_unref (stream); - return FALSE; + return true; } /** @@ -1533,28 +971,10 @@ do_start (PinosStream *stream) * * Returns: %TRUE on success. */ -gboolean +bool pinos_stream_start (PinosStream *stream) { - PinosStreamPrivate *priv; - - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - - priv = stream->priv; - //g_return_val_if_fail (priv->state == PINOS_STREAM_STATE_PAUSED, FALSE); - - g_main_context_invoke (priv->context->priv->context, - (GSourceFunc) do_start, - g_object_ref (stream)); - - return TRUE; -} - -static gboolean -do_stop (PinosStream *stream) -{ - g_object_unref (stream); - return FALSE; + return true; } /** @@ -1565,76 +985,10 @@ do_stop (PinosStream *stream) * * Returns: %TRUE on success. */ -gboolean +bool pinos_stream_stop (PinosStream *stream) { - PinosStreamPrivate *priv; - - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - - priv = stream->priv; - g_return_val_if_fail (priv->state == PINOS_STREAM_STATE_STREAMING, FALSE); - - g_main_context_invoke (priv->context->priv->context, - (GSourceFunc) do_stop, - g_object_ref (stream)); - - return TRUE; -} - -static void -on_node_removed (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosStream *stream = user_data; - PinosStreamPrivate *priv = stream->priv; - GVariant *ret; - GError *error = NULL; - - g_assert (priv->node == G_DBUS_PROXY (source_object)); - - priv->disconnecting = FALSE; - g_clear_object (&priv->node); - - ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), res, &error); - if (ret == NULL) - goto proxy_failed; - - g_variant_unref (ret); - - unhandle_socket (stream); - - stream_set_state (stream, PINOS_STREAM_STATE_UNCONNECTED, NULL); - g_object_unref (stream); - return; - - /* ERRORS */ -proxy_failed: - { - pinos_log_warn ("failed to disconnect: %s", error->message); - stream_set_state (stream, PINOS_STREAM_STATE_ERROR, error); - g_object_unref (stream); - return; - } -} - - -static gboolean -do_disconnect (PinosStream *stream) -{ - PinosStreamPrivate *priv = stream->priv; - - g_dbus_proxy_call (priv->node, - "Remove", - g_variant_new ("()"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* GCancellable *cancellable */ - on_node_removed, - stream); - - return FALSE; + return true; } /** @@ -1645,47 +999,32 @@ do_disconnect (PinosStream *stream) * * Returns: %TRUE on success */ -gboolean +bool pinos_stream_disconnect (PinosStream *stream) { - PinosStreamPrivate *priv; - PinosContext *context; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->state >= PINOS_STREAM_STATE_READY, FALSE); - g_return_val_if_fail (priv->node != NULL, FALSE); - context = priv->context; - g_return_val_if_fail (pinos_context_get_state (context) >= PINOS_CONTEXT_STATE_CONNECTED, FALSE); - g_return_val_if_fail (!priv->disconnecting, FALSE); + impl->disconnecting = true; - priv->disconnecting = TRUE; - - g_main_context_invoke (context->priv->context, - (GSourceFunc) do_disconnect, - g_object_ref (stream)); - - return TRUE; + return true; } -gboolean -pinos_stream_get_time (PinosStream *stream, - PinosTime *time) +bool +pinos_stream_get_time (PinosStream *stream, + PinosTime *time) { - PinosStreamPrivate *priv; - gint64 now, elapsed; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); + int64_t now, elapsed; + struct timespec ts; - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - priv = stream->priv; - g_return_val_if_fail (time, FALSE); + clock_gettime (CLOCK_MONOTONIC, &ts); + now = SPA_TIMESPEC_TO_TIME (&ts); + elapsed = (now - impl->last_monotonic) / 1000; - now = g_get_monotonic_time (); - elapsed = now - (priv->last_monotonic / 1000); + time->ticks = impl->last_ticks + (elapsed * impl->last_rate) / SPA_USEC_PER_SEC; + time->rate = impl->last_rate; - time->ticks = priv->last_ticks + (elapsed * priv->last_rate) / G_USEC_PER_SEC; - time->rate = priv->last_rate; - - return TRUE; + return true; } /** @@ -1697,17 +1036,13 @@ pinos_stream_get_time (PinosStream *stream, * Returns: the id of an empty buffer or #SPA_ID_INVALID when no buffer is * available. */ -guint +uint32_t pinos_stream_get_empty_buffer (PinosStream *stream) { - PinosStreamPrivate *priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); BufferId *bid; - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->direction == SPA_DIRECTION_OUTPUT, FALSE); - - pinos_array_for_each (bid, &priv->buffer_ids) { + pinos_array_for_each (bid, &impl->buffer_ids) { if (!bid->used) return bid->id; } @@ -1723,27 +1058,22 @@ pinos_stream_get_empty_buffer (PinosStream *stream) * * Returns: %TRUE on success. */ -gboolean -pinos_stream_recycle_buffer (PinosStream *stream, - guint id) +bool +pinos_stream_recycle_buffer (PinosStream *stream, + uint32_t id) { - PinosStreamPrivate *priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); SpaNodeEventReuseBuffer rb; uint8_t cmd = PINOS_TRANSPORT_CMD_HAVE_EVENT; - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - g_return_val_if_fail (id != SPA_ID_INVALID, FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->direction == SPA_DIRECTION_INPUT, FALSE); - rb.event.type = SPA_NODE_EVENT_TYPE_REUSE_BUFFER; rb.event.size = sizeof (rb); - rb.port_id = priv->port_id; + rb.port_id = impl->port_id; rb.buffer_id = id; - pinos_transport_add_event (priv->trans, &rb.event); - write (priv->rtfd, &cmd, 1); + pinos_transport_add_event (impl->trans, &rb.event); + write (impl->rtfd, &cmd, 1); - return TRUE; + return true; } /** @@ -1757,12 +1087,11 @@ pinos_stream_recycle_buffer (PinosStream *stream, * Returns: a #SpaBuffer or %NULL when there is no buffer. */ SpaBuffer * -pinos_stream_peek_buffer (PinosStream *stream, guint id) +pinos_stream_peek_buffer (PinosStream *stream, + uint32_t id) { BufferId *bid; - g_return_val_if_fail (PINOS_IS_STREAM (stream), NULL); - if ((bid = find_buffer (stream, id))) return bid->buf; @@ -1783,19 +1112,14 @@ pinos_stream_peek_buffer (PinosStream *stream, guint id) * * Returns: %TRUE when @id was handled */ -gboolean +bool pinos_stream_send_buffer (PinosStream *stream, - guint id) + uint32_t id) { - PinosStreamPrivate *priv; + PinosStreamImpl *impl = SPA_CONTAINER_OF (stream, PinosStreamImpl, this); BufferId *bid; guint i; - g_return_val_if_fail (PINOS_IS_STREAM (stream), FALSE); - g_return_val_if_fail (id != SPA_ID_INVALID, FALSE); - priv = stream->priv; - g_return_val_if_fail (priv->direction == SPA_DIRECTION_OUTPUT, FALSE); - if ((bid = find_buffer (stream, id))) { uint8_t cmd = PINOS_TRANSPORT_CMD_HAVE_DATA; @@ -1803,11 +1127,11 @@ pinos_stream_send_buffer (PinosStream *stream, for (i = 0; i < bid->buf->n_datas; i++) { bid->datas[i].size = bid->buf->datas[i].size; } - priv->trans->outputs[0].buffer_id = id; - priv->trans->outputs[0].status = SPA_RESULT_OK; - write (priv->rtfd, &cmd, 1); - return TRUE; + impl->trans->outputs[0].buffer_id = id; + impl->trans->outputs[0].status = SPA_RESULT_OK; + write (impl->rtfd, &cmd, 1); + return true; } else { - return FALSE; + return true; } } diff --git a/pinos/client/stream.h b/pinos/client/stream.h index 6237dc786..caac7c0fd 100644 --- a/pinos/client/stream.h +++ b/pinos/client/stream.h @@ -20,28 +20,16 @@ #ifndef __PINOS_STREAM_H__ #define __PINOS_STREAM_H__ -#include - #include #include #include - -G_BEGIN_DECLS - -#define PINOS_TYPE_STREAM (pinos_stream_get_type ()) -#define PINOS_IS_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_STREAM)) -#define PINOS_IS_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_STREAM)) -#define PINOS_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_STREAM, PinosStreamClass)) -#define PINOS_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_STREAM, PinosStream)) -#define PINOS_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_STREAM, PinosStreamClass)) -#define PINOS_STREAM_CAST(obj) ((PinosStream*)(obj)) -#define PINOS_STREAM_CLASS_CAST(klass) ((PinosStreamClass*)(klass)) +#ifdef __cplusplus +extern "C" { +#endif typedef struct _PinosStream PinosStream; -typedef struct _PinosStreamClass PinosStreamClass; -typedef struct _PinosStreamPrivate PinosStreamPrivate; typedef enum { PINOS_STREAM_STATE_ERROR = -1, @@ -53,7 +41,7 @@ typedef enum { PINOS_STREAM_STATE_STREAMING = 5 } PinosStreamState; -const gchar * pinos_stream_state_as_string (PinosStreamState state); +const char * pinos_stream_state_as_string (PinosStreamState state); typedef enum { PINOS_STREAM_FLAG_NONE = 0, @@ -66,8 +54,8 @@ typedef enum { } PinosStreamMode; typedef struct { - gint64 ticks; - gint32 rate; + int64_t ticks; + int32_t rate; } PinosTime; /** @@ -76,57 +64,71 @@ typedef struct { * Pinos stream object class. */ struct _PinosStream { - GObject object; + PinosContext *context; + SpaList link; - PinosStreamPrivate *priv; + char *name; + PinosProperties *properties; + + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosStream *stream)); + + PinosStreamState state; + char *error; + PINOS_SIGNAL (state_changed, (PinosListener *listener, + PinosStream *stream)); + + PINOS_SIGNAL (format_changed, (PinosListener *listener, + PinosStream *stream, + SpaFormat *format)); + + PINOS_SIGNAL (add_buffer, (PinosListener *listener, + PinosStream *stream, + uint32_t id)); + PINOS_SIGNAL (remove_buffer, (PinosListener *listener, + PinosStream *stream, + uint32_t id)); + PINOS_SIGNAL (new_buffer, (PinosListener *listener, + PinosStream *stream, + uint32_t id)); }; -/** - * PinosStreamClass: - * - * Pinos stream object class. - */ -struct _PinosStreamClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType pinos_stream_get_type (void); - - PinosStream * pinos_stream_new (PinosContext *context, - const gchar *name, + const char *name, PinosProperties *props); +void pinos_stream_destroy (PinosStream *stream); -PinosStreamState pinos_stream_get_state (PinosStream *stream); -const GError * pinos_stream_get_error (PinosStream *stream); - -gboolean pinos_stream_connect (PinosStream *stream, +bool pinos_stream_connect (PinosStream *stream, PinosDirection direction, PinosStreamMode mode, - const gchar *port_path, + const char *port_path, PinosStreamFlags flags, - GPtrArray *possible_formats); -gboolean pinos_stream_disconnect (PinosStream *stream); + unsigned int n_possible_formats, + SpaFormat **possible_formats); +bool pinos_stream_disconnect (PinosStream *stream); -gboolean pinos_stream_finish_format (PinosStream *stream, +bool pinos_stream_finish_format (PinosStream *stream, SpaResult res, SpaAllocParam **params, unsigned int n_params); -gboolean pinos_stream_start (PinosStream *stream); -gboolean pinos_stream_stop (PinosStream *stream); -gboolean pinos_stream_get_time (PinosStream *stream, + +bool pinos_stream_start (PinosStream *stream); +bool pinos_stream_stop (PinosStream *stream); + +bool pinos_stream_get_time (PinosStream *stream, PinosTime *time); -guint pinos_stream_get_empty_buffer (PinosStream *stream); -gboolean pinos_stream_recycle_buffer (PinosStream *stream, - guint id); +uint32_t pinos_stream_get_empty_buffer (PinosStream *stream); +bool pinos_stream_recycle_buffer (PinosStream *stream, + uint32_t id); SpaBuffer * pinos_stream_peek_buffer (PinosStream *stream, - guint id); -gboolean pinos_stream_send_buffer (PinosStream *stream, - guint id); -G_END_DECLS + uint32_t id); +bool pinos_stream_send_buffer (PinosStream *stream, + uint32_t id); +#ifdef __cplusplus +} +#endif #endif /* __PINOS_STREAM_H__ */ diff --git a/pinos/client/subscribe.c b/pinos/client/subscribe.c deleted file mode 100644 index 660cc0b15..000000000 --- a/pinos/client/subscribe.c +++ /dev/null @@ -1,819 +0,0 @@ -/* 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. - */ - -#include - -#include "pinos/client/pinos.h" -#include "pinos/client/enumtypes.h" -#include "pinos/client/private.h" - -struct _PinosSubscribePrivate -{ - gchar *service; - PinosSubscriptionFlags subscription_mask; - - GDBusConnection *connection; - GCancellable *cancellable; - - GDBusProxy *manager_proxy; - guint owner_id; - guint signal_id; - - guint pending_proxies; - GList *objects; - - PinosSubscriptionState state; - GError *error; -}; - -typedef struct -{ - PinosSubscribe *subscribe; - gchar *sender_name; - gchar *object_path; - gchar *interface_name; - gboolean pending; - GDBusProxy *proxy; - guint prop_id; - GList *tasks; - gboolean removed; -} PinosObjectData; - - -#define PINOS_SUBSCRIBE_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribePrivate)) - -G_DEFINE_TYPE (PinosSubscribe, pinos_subscribe, G_TYPE_OBJECT); - -enum -{ - PROP_0, - PROP_CONNECTION, - PROP_SERVICE, - PROP_SUBSCRIPTION_MASK, - PROP_STATE, -}; - -enum -{ - SIGNAL_SUBSCRIPTION_EVENT, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static void -subscription_set_state (PinosSubscribe *subscribe, - PinosSubscriptionState state) -{ - PinosSubscribePrivate *priv = subscribe->priv; - - if (state != priv->state) { - priv->state = state; - g_object_notify (G_OBJECT (subscribe), "state"); - } -} - -static void -notify_event (PinosSubscribe *subscribe, - PinosObjectData *data, - PinosSubscriptionEvent event) -{ - const gchar *interface_name; - PinosSubscriptionFlags flags = 0; - - interface_name = g_dbus_proxy_get_interface_name (data->proxy); - if (g_strcmp0 (interface_name, "org.pinos.Daemon1") == 0) { - flags = PINOS_SUBSCRIPTION_FLAG_DAEMON; - } - if (g_strcmp0 (interface_name, "org.pinos.Client1") == 0) { - flags = PINOS_SUBSCRIPTION_FLAG_CLIENT; - } - else if (g_strcmp0 (interface_name, "org.pinos.Node1") == 0) { - flags = PINOS_SUBSCRIPTION_FLAG_NODE; - } - else if (g_strcmp0 (interface_name, "org.pinos.Link1") == 0) { - flags = PINOS_SUBSCRIPTION_FLAG_LINK; - } - g_signal_emit (subscribe, signals[SIGNAL_SUBSCRIPTION_EVENT], 0, - event, flags, data->proxy); -} - -static void -on_proxy_properties_changed (GDBusProxy *proxy, - GVariant *changed_properties, - GStrv invalidated_properties, - gpointer user_data) -{ - PinosObjectData *data = user_data; - GVariantIter iter; - GVariant *value; - gchar *key; - GHashTable *props; - gboolean need_notify = FALSE; - - props = g_object_get_data (G_OBJECT (proxy), "pinos-changed-properties"); - - g_variant_iter_init (&iter, changed_properties); - while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) { - if (!g_hash_table_contains (props, key)) - g_hash_table_add (props, g_strdup (key)); - need_notify = TRUE; - } - if (need_notify) - notify_event (data->subscribe, data, PINOS_SUBSCRIPTION_EVENT_CHANGE); -} - -static void -object_data_free (PinosObjectData *data) -{ - g_signal_handler_disconnect (data->proxy, data->prop_id); - g_object_unref (data->proxy); - g_free (data->sender_name); - g_free (data->object_path); - g_free (data->interface_name); - g_free (data); -} - -static void -remove_data (PinosSubscribe *subscribe, - PinosObjectData *data) -{ - if (data->pending) { - data->removed = TRUE; - } else { - GHashTable *props = g_object_get_data (G_OBJECT (data->proxy), "pinos-changed-properties"); - - g_hash_table_remove_all (props); - notify_event (subscribe, data, PINOS_SUBSCRIPTION_EVENT_REMOVE); - object_data_free (data); - } -} - -static void -remove_all_data (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv; - GList *walk; - - for (walk = priv->objects; walk; walk = g_list_next (walk)) { - PinosObjectData *data = walk->data; - remove_data (subscribe, data); - } - g_list_free (priv->objects); - priv->objects = NULL; -} - -static void -on_proxy_created (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosObjectData *data = user_data; - PinosSubscribe *subscribe = data->subscribe; - PinosSubscribePrivate *priv = subscribe->priv; - GError *error = NULL; - GList *walk; - - data->pending = FALSE; - - data->proxy = g_dbus_proxy_new_finish (res, &error); - if (data->proxy == NULL) { - priv->objects = g_list_remove (priv->objects, data); - pinos_log_warn ("could not create proxy: %s", error->message); - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR); - priv->error = error; - return; - } - - data->prop_id = g_signal_connect (data->proxy, - "g-properties-changed", - (GCallback) on_proxy_properties_changed, - data); - - notify_event (subscribe, data, PINOS_SUBSCRIPTION_EVENT_NEW); - - g_object_set_data_full (G_OBJECT (data->proxy), - "pinos-changed-properties", - g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL), - (GDestroyNotify) g_hash_table_unref); - - for (walk = data->tasks; walk; walk = g_list_next (walk)) { - GTask *task = walk->data; - g_task_return_pointer (task, g_object_ref (data->proxy), g_object_unref); - g_object_unref (task); - } - g_list_free (data->tasks); - data->tasks = NULL; - - if (--priv->pending_proxies == 0) - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_READY); - - if (data->removed) { - priv->objects = g_list_remove (priv->objects, data); - remove_data (subscribe, data); - } -} - - -static void -add_interface (PinosSubscribe *subscribe, - const gchar *object_path, - const gchar *interface_name, - GVariant *properties) -{ - PinosSubscribePrivate *priv = subscribe->priv; - PinosObjectData *data; - - data = g_new0 (PinosObjectData, 1); - data->subscribe = subscribe; - data->sender_name = g_strdup (priv->service); - data->object_path = g_strdup (object_path); - data->interface_name = g_strdup (interface_name); - data->pending = TRUE; - - priv->objects = g_list_prepend (priv->objects, data); - priv->pending_proxies++; - - g_dbus_proxy_new (priv->connection, - G_DBUS_PROXY_FLAGS_NONE, - NULL, /* GDBusInterfaceInfo* */ - priv->service, - object_path, - interface_name, - priv->cancellable, - on_proxy_created, - data); -} - -static void -remove_interface (PinosSubscribe *subscribe, - const gchar *object_path, - const gchar *interface_name) -{ - PinosSubscribePrivate *priv = subscribe->priv; - GList *walk; - - for (walk = priv->objects; walk; walk = g_list_next (walk)) { - PinosObjectData *data = walk->data; - - if (g_strcmp0 (data->object_path, object_path) == 0 && - g_strcmp0 (data->interface_name, interface_name) == 0) { - priv->objects = g_list_remove (priv->objects, data); - remove_data (subscribe, data); - break; - } - } -} - -static void -add_ifaces_and_properties (PinosSubscribe *subscribe, - const gchar *object_path, - GVariant *ifaces_and_properties) -{ - GVariantIter iter; - const gchar *interface_name; - GVariant *properties; - - g_variant_iter_init (&iter, ifaces_and_properties); - while (g_variant_iter_next (&iter, - "{&s@a{sv}}", - &interface_name, - &properties)) { - - add_interface (subscribe, object_path, interface_name, properties); - - g_variant_unref (properties); - } -} - -static void -remove_ifaces (PinosSubscribe *subscribe, - const gchar *object_path, - const gchar **ifaces) -{ - while (*ifaces) { - remove_interface (subscribe, object_path, *ifaces); - - ifaces++; - } -} - -static void -on_manager_proxy_signal (GDBusProxy *proxy, - const gchar *sender_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - PinosSubscribe *subscribe = user_data; - const gchar *object_path; - - if (g_strcmp0 (signal_name, "InterfacesAdded") == 0) { - GVariant *ifaces_and_properties; - - g_variant_get (parameters, - "(&o@a{sa{sv}})", - &object_path, - &ifaces_and_properties); - - add_ifaces_and_properties (subscribe, object_path, ifaces_and_properties); - - g_variant_unref (ifaces_and_properties); - } else if (g_strcmp0 (signal_name, "InterfacesRemoved") == 0) { - const gchar **ifaces; - g_variant_get (parameters, - "(&o^a&s)", - &object_path, - &ifaces); - - remove_ifaces (subscribe, object_path, ifaces); - - g_free (ifaces); - } -} - -static void -on_managed_objects_ready (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosSubscribe *subscribe = user_data; - PinosSubscribePrivate *priv = subscribe->priv; - GError *error = NULL; - GVariant *objects; - GVariant *arg0; - const gchar *object_path; - GVariant *ifaces_and_properties; - GVariantIter object_iter; - - objects = g_dbus_proxy_call_finish (priv->manager_proxy, res, &error); - if (objects == NULL) { - pinos_log_warn ("could not get objects: %s", error->message); - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR); - priv->error = error; - return; - } - - arg0 = g_variant_get_child_value (objects, 0); - g_variant_iter_init (&object_iter, arg0); - while (g_variant_iter_next (&object_iter, - "{&o@a{sa{sv}}}", - &object_path, - &ifaces_and_properties)) { - - add_ifaces_and_properties (subscribe, object_path, ifaces_and_properties); - - g_variant_unref (ifaces_and_properties); - } - g_variant_unref (arg0); - g_variant_unref (objects); - - if (priv->pending_proxies == 0) - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_READY); -} - -static void -manager_proxy_appeared (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv; - - g_dbus_proxy_call (priv->manager_proxy, - "GetManagedObjects", - NULL, /* parameters */ - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->cancellable, - on_managed_objects_ready, - subscribe); -} - -static void -manager_proxy_disappeared (PinosSubscribe *subscribe) -{ - remove_all_data (subscribe); -} - -static void -on_manager_proxy_name_owner (GObject *object, - GParamSpec *pspec, - gpointer user_data) -{ - PinosSubscribe *subscribe = user_data; - PinosSubscribePrivate *priv = subscribe->priv; - gchar *name_owner; - - g_object_get (priv->manager_proxy, "g-name-owner", &name_owner, NULL); - - if (name_owner) { - manager_proxy_appeared (subscribe); - g_free (name_owner); - } else { - manager_proxy_disappeared (subscribe); - } -} - -static void -connect_client_signals (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv; - - priv->owner_id = g_signal_connect (priv->manager_proxy, "notify::g-name-owner", - (GCallback) on_manager_proxy_name_owner, subscribe); - - priv->signal_id = g_signal_connect (priv->manager_proxy, "g-signal", - (GCallback) on_manager_proxy_signal, subscribe); -} - -static void -on_manager_proxy_ready (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - PinosSubscribe *subscribe = user_data; - PinosSubscribePrivate *priv = subscribe->priv; - GError *error = NULL; - - priv->manager_proxy = g_dbus_proxy_new_finish (res, &error); - if (priv->manager_proxy == NULL) - goto manager_error; - - connect_client_signals (subscribe); - - on_manager_proxy_name_owner (G_OBJECT (priv->manager_proxy), NULL, subscribe); - g_object_unref (subscribe); - - return; - - /* ERRORS */ -manager_error: - { - pinos_log_warn ("could not create client manager: %s", error->message); - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_ERROR); - priv->error = error; - g_object_unref (subscribe); - return; - } -} - -static void -install_subscription (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv; - - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_CONNECTING); - - g_dbus_proxy_new (priv->connection, - G_DBUS_PROXY_FLAGS_NONE, - NULL, /* GDBusInterfaceInfo* */ - priv->service, - PINOS_DBUS_OBJECT_PREFIX, - "org.freedesktop.DBus.ObjectManager", - priv->cancellable, - on_manager_proxy_ready, - g_object_ref (subscribe)); -} - -static void -uninstall_subscription (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv; - - if (priv->manager_proxy) { - g_signal_handler_disconnect (priv->manager_proxy, priv->owner_id); - g_signal_handler_disconnect (priv->manager_proxy, priv->signal_id); - g_clear_object (&priv->manager_proxy); - } - g_clear_error (&priv->error); - subscription_set_state (subscribe, PINOS_SUBSCRIPTION_STATE_UNCONNECTED); -} - -static void -pinos_subscribe_get_property (GObject *_object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - PinosSubscribe *subscribe = PINOS_SUBSCRIBE (_object); - PinosSubscribePrivate *priv = subscribe->priv; - - switch (prop_id) { - case PROP_CONNECTION: - g_value_set_object (value, priv->connection); - break; - - case PROP_SERVICE: - g_value_set_string (value, priv->service); - break; - - case PROP_SUBSCRIPTION_MASK: - g_value_set_flags (value, priv->subscription_mask); - break; - - case PROP_STATE: - g_value_set_enum (value, priv->state); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec); - break; - } -} - -static void -pinos_subscribe_set_property (GObject *_object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - PinosSubscribe *subscribe = PINOS_SUBSCRIBE (_object); - PinosSubscribePrivate *priv = subscribe->priv; - - switch (prop_id) { - case PROP_CONNECTION: - { - uninstall_subscription (subscribe); - if (priv->connection) - g_object_unref (priv->connection); - priv->connection = g_value_dup_object (value); - if (priv->connection) - install_subscription (subscribe); - break; - } - - case PROP_SERVICE: - g_free (priv->service); - priv->service = g_value_dup_string (value); - break; - - case PROP_SUBSCRIPTION_MASK: - priv->subscription_mask = g_value_get_flags (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (subscribe, prop_id, pspec); - break; - } -} - -static void -pinos_subscribe_finalize (GObject * object) -{ - PinosSubscribe *subscribe = PINOS_SUBSCRIBE (object); - PinosSubscribePrivate *priv = subscribe->priv; - - remove_all_data (subscribe); - - g_cancellable_cancel (priv->cancellable); - if (priv->manager_proxy) - g_object_unref (priv->manager_proxy); - g_object_unref (priv->cancellable); - g_free (priv->service); - - G_OBJECT_CLASS (pinos_subscribe_parent_class)->finalize (object); -} - -static void -pinos_subscribe_class_init (PinosSubscribeClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosSubscribePrivate)); - - gobject_class->finalize = pinos_subscribe_finalize; - gobject_class->set_property = pinos_subscribe_set_property; - gobject_class->get_property = pinos_subscribe_get_property; - - /** - * PinosSubscribe:connection - * - * The connection of the subscribe. - */ - g_object_class_install_property (gobject_class, - PROP_CONNECTION, - g_param_spec_object ("connection", - "Connection", - "The DBus connection", - G_TYPE_DBUS_CONNECTION, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosSubscribe:service - * - * The service of the subscribe. - */ - g_object_class_install_property (gobject_class, - PROP_SERVICE, - g_param_spec_string ("service", - "Service", - "The service", - PINOS_DBUS_SERVICE, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosSubscribe:subscription-mask - * - * A mask for what object notifications will be signaled with - * PinosSubscribe:subscription-event - */ - g_object_class_install_property (gobject_class, - PROP_SUBSCRIPTION_MASK, - g_param_spec_flags ("subscription-mask", - "Subscription Mask", - "The object to receive subscription events of", - PINOS_TYPE_SUBSCRIPTION_FLAGS, - 0, - G_PARAM_READWRITE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosSubscribe:state - * - * The state of the subscription - */ - g_object_class_install_property (gobject_class, - PROP_STATE, - g_param_spec_enum ("state", - "State", - "The state", - PINOS_TYPE_SUBSCRIPTION_STATE, - PINOS_SUBSCRIPTION_STATE_UNCONNECTED, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); - /** - * PinosSubscribe:subscription-event - * @subscribe: The #PinosSubscribe emitting the signal. - * @event: A #PinosSubscriptionEvent - * @flags: #PinosSubscriptionFlags indicating the object - * @id: the unique and opaque object id - * - * Notify about a new object that was added/removed/modified. - */ - signals[SIGNAL_SUBSCRIPTION_EVENT] = g_signal_new ("subscription-event", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - 0, - NULL, - NULL, - g_cclosure_marshal_generic, - G_TYPE_NONE, - 3, - PINOS_TYPE_SUBSCRIPTION_EVENT, - PINOS_TYPE_SUBSCRIPTION_FLAGS, - G_TYPE_POINTER); -} - -static void -pinos_subscribe_init (PinosSubscribe * subscribe) -{ - PinosSubscribePrivate *priv = subscribe->priv = PINOS_SUBSCRIBE_GET_PRIVATE (subscribe); - - priv->service = g_strdup (PINOS_DBUS_SERVICE); - priv->state = PINOS_SUBSCRIPTION_STATE_UNCONNECTED; - priv->cancellable = g_cancellable_new (); -} - -/** - * pinos_subscribe_new: - * @name: an application name - * @properties: optional properties - * - * Make a new unconnected #PinosSubscribe - * - * Returns: a new unconnected #PinosSubscribe - */ -PinosSubscribe * -pinos_subscribe_new (void) -{ - return g_object_new (PINOS_TYPE_SUBSCRIBE, NULL); -} - -PinosSubscriptionState -pinos_subscribe_get_state (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv; - - g_return_val_if_fail (PINOS_IS_SUBSCRIBE (subscribe), PINOS_SUBSCRIPTION_STATE_ERROR); - priv = subscribe->priv; - - return priv->state; -} - -GError * -pinos_subscribe_get_error (PinosSubscribe *subscribe) -{ - PinosSubscribePrivate *priv; - - g_return_val_if_fail (PINOS_IS_SUBSCRIBE (subscribe), NULL); - priv = subscribe->priv; - - return priv->error; -} - -static gint -compare_data (PinosObjectData *data, - const gchar *name, - const gchar *object_path, - const gchar *interface_name) -{ - gint res; - - if ((res = g_strcmp0 (data->sender_name, name)) != 0) - return res; - - if ((res = g_strcmp0 (data->object_path, object_path)) != 0) - return res; - - return g_strcmp0 (data->interface_name, interface_name); -} - -/** - * pinos_subscribe_get_proxy: - * @subscribe: a #PinosSubscribe - * @name: the owner name - * @object_path: the object path - * @interface_name: the interface name - * @cancellable: a #GCancellable - * @callback: a #GAsyncReadyCallback - * @user_data: extra user data - * - * Asyncronously get a #GDBusProxy for the object with the given - * @name/@object_path/@interface. - * - * Use pinos_subscribe_get_proxy_finish() to get the result or error in - * @callback. - */ -void -pinos_subscribe_get_proxy (PinosSubscribe *subscribe, - const gchar *name, - const gchar *object_path, - const gchar *interface_name, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) -{ - PinosSubscribePrivate *priv; - GList *walk; - - g_return_if_fail (PINOS_IS_SUBSCRIBE (subscribe)); - priv = subscribe->priv; - - for (walk = priv->objects; walk; walk = g_list_next (walk)) { - PinosObjectData *data = walk->data; - - if (compare_data (data, name, object_path, interface_name) == 0) { - GTask *task; - - task = g_task_new (subscribe, - cancellable, - callback, - user_data); - - if (data->pending) { - data->tasks = g_list_prepend (data->tasks, task); - } else { - if (data->proxy) - g_task_return_pointer (task, g_object_ref (data->proxy), g_object_unref); - else - g_task_return_error (task, NULL); - g_object_unref (task); - } - break; - } - } -} - -/** - * pinos_subscribe_get_proxy_finish: - * @subscribe: a #PinosSubscribe - * @res: a #GAsyncResult - * @error: a #GError or %NULL - * - * Get the requested #GDBusProxy. This function should be called in the callback - * of pinos_subscribe_get_proxy() to get the result or error. - * - * Returns: the requested #GDBusProxy. If %NULL is returned, @error will - * be set. - */ -GDBusProxy * -pinos_subscribe_get_proxy_finish (PinosSubscribe *subscribe, - GAsyncResult *res, - GError **error) -{ - return g_task_propagate_pointer (G_TASK (res), error); -} diff --git a/pinos/client/subscribe.h b/pinos/client/subscribe.h index e6e7dd8cb..e8e14bec3 100644 --- a/pinos/client/subscribe.h +++ b/pinos/client/subscribe.h @@ -20,22 +20,11 @@ #ifndef __PINOS_SUBSCRIBE_H__ #define __PINOS_SUBSCRIBE_H__ -#include +#include -G_BEGIN_DECLS - -#define PINOS_TYPE_SUBSCRIBE (pinos_subscribe_get_type ()) -#define PINOS_IS_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PINOS_TYPE_SUBSCRIBE)) -#define PINOS_IS_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PINOS_TYPE_SUBSCRIBE)) -#define PINOS_SUBSCRIBE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribeClass)) -#define PINOS_SUBSCRIBE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PINOS_TYPE_SUBSCRIBE, PinosSubscribe)) -#define PINOS_SUBSCRIBE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PINOS_TYPE_SUBSCRIBE, PinosSubscribeClass)) -#define PINOS_SUBSCRIBE_CAST(obj) ((PinosSubscribe*)(obj)) -#define PINOS_SUBSCRIBE_CLASS_CAST(klass) ((PinosSubscribeClass*)(klass)) - -typedef struct _PinosSubscribe PinosSubscribe; -typedef struct _PinosSubscribeClass PinosSubscribeClass; -typedef struct _PinosSubscribePrivate PinosSubscribePrivate; +#ifdef __cplusplus +extern "C" { +#endif typedef enum { PINOS_SUBSCRIPTION_STATE_UNCONNECTED = 0, @@ -59,34 +48,19 @@ typedef enum { PINOS_SUBSCRIPTION_EVENT_REMOVE = 2, } PinosSubscriptionEvent; -/** - * PinosSubscribe: - * - * Pinos subscribe object class. - */ -struct _PinosSubscribe { - GObject object; +typedef void (*PinosSubscriptionFunc) (PinosContext *context, + PinosSubscriptionFlags flags, + PinosSubscriptionEvent event, + uint32_t id, + void *data); - PinosSubscribePrivate *priv; -}; +void pinos_context_subscribe (PinosContext *context, + PinosSubscriptionFlags mask, + PinosSubscriptionFunc func, + void *data); -/** - * PinosSubscribeClass: - * - * Pinos subscribe object class. - */ -struct _PinosSubscribeClass { - GObjectClass parent_class; -}; - -/* normal GObject stuff */ -GType pinos_subscribe_get_type (void); - -PinosSubscribe * pinos_subscribe_new (void); - -PinosSubscriptionState pinos_subscribe_get_state (PinosSubscribe *subscribe); -GError * pinos_subscribe_get_error (PinosSubscribe *subscribe); - -G_END_DECLS +#ifdef __cplusplus +} +#endif #endif /* __PINOS_SUBSCRIBE_H__ */ diff --git a/pinos/client/thread-mainloop.c b/pinos/client/thread-mainloop.c index 943136a09..4b75e4d5b 100644 --- a/pinos/client/thread-mainloop.c +++ b/pinos/client/thread-mainloop.c @@ -17,185 +17,51 @@ * Boston, MA 02110-1301, USA. */ +#include + #include "pinos.h" #include "thread-mainloop.h" -struct _PinosThreadMainLoopPrivate -{ - GMainContext *maincontext; - GMainLoop *mainloop; +typedef struct { + PinosThreadMainLoop this; - gchar *name; + char *name; - GPollFunc poll_func; + pthread_mutex_t lock; + pthread_cond_t cond; + pthread_cond_t accept_cond; - GMutex lock; - GCond cond; - GCond accept_cond; - GThread *thread; + bool running; + pthread_t thread; - gint n_waiting; - gint n_waiting_for_accept; -}; + SpaSource *event; -#define PINOS_THREAD_MAIN_LOOP_GET_PRIVATE(obj) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((obj), PINOS_TYPE_THREAD_MAIN_LOOP, PinosThreadMainLoopPrivate)) - -G_DEFINE_TYPE (PinosThreadMainLoop, pinos_thread_main_loop, G_TYPE_OBJECT); - -enum -{ - PROP_0, - PROP_MAIN_CONTEXT, - PROP_NAME, - PROP_MAIN_LOOP, -}; + int n_waiting; + int n_waiting_for_accept; +} PinosThreadMainLoopImpl; static void -pinos_thread_main_loop_get_property (GObject *_object, - guint prop_id, - GValue *value, - GParamSpec *pspec) +pre_hook (SpaLoopControl *ctrl, + void *data) { - PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object); - PinosThreadMainLoopPrivate *priv = loop->priv; - - switch (prop_id) { - case PROP_MAIN_CONTEXT: - g_value_set_boxed (value, priv->maincontext); - break; - - case PROP_NAME: - g_value_set_string (value, priv->name); - break; - - case PROP_MAIN_LOOP: - g_value_set_boxed (value, priv->mainloop); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec); - break; - } + PinosThreadMainLoopImpl *impl = data; + pthread_mutex_unlock (&impl->lock); } static void -pinos_thread_main_loop_set_property (GObject *_object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) +post_hook (SpaLoopControl *ctrl, + void *data) { - PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (_object); - PinosThreadMainLoopPrivate *priv = loop->priv; - - switch (prop_id) { - case PROP_MAIN_CONTEXT: - priv->maincontext = g_value_dup_boxed (value); - break; - - case PROP_NAME: - priv->name = g_value_dup_string (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (loop, prop_id, pspec); - break; - } + PinosThreadMainLoopImpl *impl = data; + pthread_mutex_lock (&impl->lock); } static void -pinos_thread_main_loop_constructed (GObject * object) +do_stop (SpaSource *source, + void *data) { - PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object); - PinosThreadMainLoopPrivate *priv = loop->priv; - - priv->mainloop = g_main_loop_new (priv->maincontext, FALSE); - pinos_log_debug ("thread-mainloop %p: contructed %p %p", loop, priv->maincontext, priv->mainloop); - - G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->constructed (object); -} - -static void -pinos_thread_main_loop_finalize (GObject * object) -{ - PinosThreadMainLoop *loop = PINOS_THREAD_MAIN_LOOP (object); - PinosThreadMainLoopPrivate *priv = loop->priv; - - if (priv->maincontext) - g_main_context_unref (priv->maincontext); - g_main_loop_unref (priv->mainloop); - - g_free (priv->name); - g_mutex_clear (&priv->lock); - g_cond_clear (&priv->cond); - g_cond_clear (&priv->accept_cond); - - G_OBJECT_CLASS (pinos_thread_main_loop_parent_class)->finalize (object); -} - -static void -pinos_thread_main_loop_class_init (PinosThreadMainLoopClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosThreadMainLoopPrivate)); - - 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; - - /** - * PinosThreadMainLoop:main-context - * - * The GMainContext of the loop. - */ - g_object_class_install_property (gobject_class, - PROP_MAIN_CONTEXT, - g_param_spec_boxed ("main-context", - "Main Context", - "The GMainContext of the loop", - G_TYPE_MAIN_CONTEXT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosThreadMainLoop:name - * - * The name of the loop as specified at construction time. - */ - g_object_class_install_property (gobject_class, - PROP_NAME, - g_param_spec_string ("name", - "Name", - "The name of the loop thread", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - /** - * PinosThreadMainLoop:main-loop - * - * The GMainLoop of the loop. - */ - g_object_class_install_property (gobject_class, - PROP_MAIN_LOOP, - g_param_spec_boxed ("main-loop", - "Main Loop", - "The GMainLoop", - G_TYPE_MAIN_LOOP, - G_PARAM_READABLE | - G_PARAM_STATIC_STRINGS)); -} - -static void -pinos_thread_main_loop_init (PinosThreadMainLoop * loop) -{ - PinosThreadMainLoopPrivate *priv = loop->priv = PINOS_THREAD_MAIN_LOOP_GET_PRIVATE (loop); - - g_mutex_init (&priv->lock); - g_cond_init (&priv->cond); - g_cond_init (&priv->accept_cond); + PinosThreadMainLoopImpl *impl = data; + impl->running = false; } /** @@ -209,101 +75,100 @@ pinos_thread_main_loop_init (PinosThreadMainLoop * loop) * Returns: a #PinosThreadMainLoop */ PinosThreadMainLoop * -pinos_thread_main_loop_new (GMainContext * context, const gchar *name) +pinos_thread_main_loop_new (PinosLoop *loop, + const char *name) { - PinosThreadMainLoop *loop; + PinosThreadMainLoopImpl *impl; + PinosThreadMainLoop *this; - loop = g_object_new (PINOS_TYPE_THREAD_MAIN_LOOP, - "main-context", context, - "name", name, - NULL); - return loop; + impl = calloc (1, sizeof (PinosThreadMainLoopImpl)); + this = &impl->this; + pinos_log_debug ("thread-mainloop %p: new", impl); + + this->loop = loop; + if (name) + this->name = strdup (name); + + pinos_loop_set_hooks (loop, + pre_hook, + post_hook, + impl); + + pinos_signal_init (&this->destroy_signal); + + pthread_mutex_init (&impl->lock, NULL); + pthread_cond_init (&impl->cond, NULL); + pthread_cond_init (&impl->accept_cond, NULL); + + impl->event = pinos_loop_add_event (this->loop, + do_stop, + impl); + + return this; } -/** - * pinos_thread_main_loop_get_impl: - * @loop: a #PinosThreadMainLoop - * - * Get the #GMainLoop used by @loop. - * - * Returns: the #GMainLoop used by @loop. It remains valid as long as - * @loop is valid. - */ -GMainLoop * -pinos_thread_main_loop_get_impl (PinosThreadMainLoop *loop) +void +pinos_thread_main_loop_destroy (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), NULL); + pinos_signal_emit (&loop->destroy_signal, loop); - priv = loop->priv; + if (loop->name) + free (loop->name); + pthread_mutex_destroy (&impl->lock); + pthread_cond_destroy (&impl->cond); + pthread_cond_destroy (&impl->accept_cond); - return priv->mainloop; + free (impl); } -static GPrivate loop_key; - -static gint -do_poll (GPollFD *ufds, guint nfsd, gint timeout_) +static void * +do_loop (void *user_data) { - gint res; - PinosThreadMainLoop *loop = g_private_get (&loop_key); - PinosThreadMainLoopPrivate *priv = loop->priv; + PinosThreadMainLoopImpl *impl = user_data; + PinosThreadMainLoop *this = &impl->this; + SpaResult res; - g_mutex_unlock (&priv->lock); - res = priv->poll_func (ufds, nfsd, timeout_); - g_mutex_lock (&priv->lock); + pthread_mutex_lock (&impl->lock); + pinos_log_debug ("thread-mainloop %p: enter thread", this); + pinos_loop_enter (this->loop); - return res; -} - -static gpointer -handle_mainloop (PinosThreadMainLoop *loop) -{ - PinosThreadMainLoopPrivate *priv = loop->priv; - - g_mutex_lock (&priv->lock); - g_private_set (&loop_key, loop); - - priv->poll_func = g_main_context_get_poll_func (priv->maincontext); - g_main_context_set_poll_func (priv->maincontext, do_poll); - - g_main_context_push_thread_default (priv->maincontext); - pinos_log_debug ("thread-mainloop %p: run mainloop %p context %p", loop, priv->mainloop, priv->maincontext); - g_main_loop_run (priv->mainloop); - pinos_log_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); - - g_mutex_unlock (&priv->lock); + while (impl->running) { + if ((res = pinos_loop_iterate (this->loop, -1)) < 0) + pinos_log_warn ("thread-mainloop %p: iterate error %d", this, res); + } + pinos_log_debug ("thread-mainloop %p: leave thread", this); + pinos_loop_leave (this->loop); + pthread_mutex_unlock (&impl->lock); return NULL; } - /** * pinos_thread_main_loop_start: * @loop: a #PinosThreadMainLoop - * @error: am optional #GError * * Start the thread to handle @loop. * - * Returns: %TRUE on success. %FALSE will be returned when an error occured - * and @error will contain more information. + * Returns: %SPA_RESULT_OK on success. */ -gboolean -pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error) +SpaResult +pinos_thread_main_loop_start (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE); - priv = loop->priv; - g_return_val_if_fail (priv->thread == NULL, FALSE); + if (!impl->running) { + int err; - priv->thread = g_thread_try_new (priv->name, (GThreadFunc) handle_mainloop, loop, error); - - return priv->thread != NULL; + impl->running = true; + if ((err = pthread_create (&impl->thread, NULL, do_loop, impl)) != 0) { + pinos_log_warn ("thread-mainloop %p: can't create thread: %s", impl, strerror (err)); + impl->running = false; + return SPA_RESULT_ERROR; + } + } + return SPA_RESULT_OK; } /** @@ -315,20 +180,11 @@ pinos_thread_main_loop_start (PinosThreadMainLoop *loop, GError **error) void pinos_thread_main_loop_stop (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; + pinos_loop_signal_event (loop->loop, impl->event); - g_return_if_fail (priv->thread != NULL); - g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); - - g_mutex_lock (&priv->lock); - g_main_loop_quit (priv->mainloop); - g_mutex_unlock (&priv->lock); - - g_thread_join (priv->thread); - priv->thread = NULL; + pthread_join (impl->thread, NULL); } /** @@ -340,13 +196,8 @@ pinos_thread_main_loop_stop (PinosThreadMainLoop *loop) void pinos_thread_main_loop_lock (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; - - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; - g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); - - g_mutex_lock (&priv->lock); + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); + pthread_mutex_lock (&impl->lock); } /** @@ -358,13 +209,8 @@ pinos_thread_main_loop_lock (PinosThreadMainLoop *loop) void pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; - - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; - g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); - - g_mutex_unlock (&priv->lock); + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); + pthread_mutex_unlock (&impl->lock); } /** @@ -375,21 +221,19 @@ pinos_thread_main_loop_unlock (PinosThreadMainLoop *loop) * this function waits until pinos_thread_main_loop_accept() is called. */ void -pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_accept) +pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, + bool wait_for_accept) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; - - if (priv->n_waiting > 0) - g_cond_broadcast (&priv->cond); + if (impl->n_waiting > 0) + pthread_cond_broadcast (&impl->cond); if (wait_for_accept) { - priv->n_waiting_for_accept++; + impl->n_waiting_for_accept++; - while (priv->n_waiting_for_accept > 0) - g_cond_wait (&priv->accept_cond, &priv->lock); + while (impl->n_waiting_for_accept > 0) + pthread_cond_wait (&impl->accept_cond, &impl->lock); } } @@ -402,18 +246,12 @@ pinos_thread_main_loop_signal (PinosThreadMainLoop *loop, gboolean wait_for_acce void pinos_thread_main_loop_wait (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; - g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); + impl->n_waiting++; - priv->n_waiting ++; - - g_cond_wait (&priv->cond, &priv->lock); - - g_assert (priv->n_waiting > 0); - priv->n_waiting --; + pthread_cond_wait (&impl->cond, &impl->lock); + impl->n_waiting --; } /** @@ -425,16 +263,10 @@ pinos_thread_main_loop_wait (PinosThreadMainLoop *loop) void pinos_thread_main_loop_accept (PinosThreadMainLoop *loop) { - PinosThreadMainLoopPrivate *priv; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); - g_return_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop)); - priv = loop->priv; - g_return_if_fail (!pinos_thread_main_loop_in_thread (loop)); - - g_assert (priv->n_waiting_for_accept > 0); - priv->n_waiting_for_accept--; - - g_cond_signal (&priv->accept_cond); + impl->n_waiting_for_accept--; + pthread_cond_signal (&impl->accept_cond); } /** @@ -445,10 +277,9 @@ pinos_thread_main_loop_accept (PinosThreadMainLoop *loop) * * Returns: %TRUE when called inside the thread of @loop. */ -gboolean +bool pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop) { - g_return_val_if_fail (PINOS_IS_THREAD_MAIN_LOOP (loop), FALSE); - - return g_thread_self() == loop->priv->thread; + PinosThreadMainLoopImpl *impl = SPA_CONTAINER_OF (loop, PinosThreadMainLoopImpl, this); + return pthread_self() == impl->thread; } diff --git a/pinos/client/thread-mainloop.h b/pinos/client/thread-mainloop.h index df8e8801e..db2195c29 100644 --- a/pinos/client/thread-mainloop.h +++ b/pinos/client/thread-mainloop.h @@ -20,23 +20,13 @@ #ifndef __PINOS_THREAD_MAIN_LOOP_H__ #define __PINOS_THREAD_MAIN_LOOP_H__ -#include +#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)) +#ifdef __cplusplus +extern "C" { +#endif typedef struct _PinosThreadMainLoop PinosThreadMainLoop; -typedef struct _PinosThreadMainLoopClass PinosThreadMainLoopClass; -typedef struct _PinosThreadMainLoopPrivate PinosThreadMainLoopPrivate; - /** * PinosThreadMainLoop: @@ -44,41 +34,32 @@ typedef struct _PinosThreadMainLoopPrivate PinosThreadMainLoopPrivate; * Pinos main loop object class. */ struct _PinosThreadMainLoop { - GObject object; + PinosLoop *loop; + char *name; - PinosThreadMainLoopPrivate *priv; + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosThreadMainLoop *loop)); }; -/** - * PinosThreadMainLoopClass: - * - * Pinos main loop object class. - */ -struct _PinosThreadMainLoopClass { - GObjectClass parent_class; -}; +PinosThreadMainLoop * pinos_thread_main_loop_new (PinosLoop *loop, + const char *name); +void pinos_thread_main_loop_destroy (PinosThreadMainLoop *loop); -/* 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); +SpaResult pinos_thread_main_loop_start (PinosThreadMainLoop *loop); 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_signal (PinosThreadMainLoop *loop, + bool wait_for_accept); void pinos_thread_main_loop_accept (PinosThreadMainLoop *loop); -gboolean pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop); +bool pinos_thread_main_loop_in_thread (PinosThreadMainLoop *loop); - -G_END_DECLS +#ifdef __cplusplus +} +#endif #endif /* __PINOS_THREAD_MAIN_LOOP_H__ */ diff --git a/pinos/client/transport.c b/pinos/client/transport.c index cf74cbb1a..684ed61b7 100644 --- a/pinos/client/transport.c +++ b/pinos/client/transport.c @@ -20,6 +20,7 @@ #include #include +#include #include #define INPUT_BUFFER_SIZE (1<<12) @@ -131,6 +132,11 @@ pinos_transport_new_from_info (PinosTransportInfo *info) impl->mem.fd = info->memfd; impl->mem.size = info->size; impl->mem.ptr = mmap (NULL, info->size, PROT_READ | PROT_WRITE, MAP_SHARED, info->memfd, info->offset); + if (impl->mem.ptr == MAP_FAILED) { + pinos_log_warn ("transport %p: failed to map fd %d", impl, info->memfd); + goto mmap_failed; + } + impl->offset = info->offset; transport_setup_area (impl->mem.ptr, trans); @@ -144,6 +150,10 @@ pinos_transport_new_from_info (PinosTransportInfo *info) trans->input_data = tmp; return trans; + +mmap_failed: + free (impl); + return NULL; } diff --git a/pinos/daemon/daemon-config.c b/pinos/daemon/daemon-config.c index b13234a10..a67cdb3f9 100644 --- a/pinos/daemon/daemon-config.c +++ b/pinos/daemon/daemon-config.c @@ -30,7 +30,7 @@ #include "pinos/daemon/daemon-config.h" -#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR G_DIR_SEPARATOR_S "pinos.conf" +#define DEFAULT_CONFIG_FILE PINOS_CONFIG_DIR "/pinos.conf" static bool parse_line (PinosDaemonConfig *config, @@ -165,7 +165,7 @@ bool pinos_daemon_config_load (PinosDaemonConfig *config, char **err) { - const gchar *filename; + const char *filename; filename = getenv ("PINOS_CONFIG_FILE"); if (filename != NULL && *filename != '\0') { diff --git a/pinos/daemon/main.c b/pinos/daemon/main.c index 088f72faf..c3036f828 100644 --- a/pinos/daemon/main.c +++ b/pinos/daemon/main.c @@ -36,7 +36,7 @@ main (int argc, char *argv[]) /* parse configuration */ config = pinos_daemon_config_new (); if (!pinos_daemon_config_load (config, &err)) { - g_error ("failed to parse config: %s", err); + pinos_log_error ("failed to parse config: %s", err); free (err); return -1; } diff --git a/pinos/daemon/pinos.conf.in b/pinos/daemon/pinos.conf.in index f0ddb414f..f29bd35b4 100644 --- a/pinos/daemon/pinos.conf.in +++ b/pinos/daemon/pinos.conf.in @@ -1,4 +1,4 @@ -load-module libpinos-module-protocol-dbus +#load-module libpinos-module-protocol-dbus load-module libpinos-module-protocol-native load-module libpinos-module-suspend-on-idle load-module libpinos-module-spa diff --git a/pinos/gst/gstpinosdeviceprovider.c b/pinos/gst/gstpinosdeviceprovider.c index 2d3e105d0..e425f6ac0 100644 --- a/pinos/gst/gstpinosdeviceprovider.c +++ b/pinos/gst/gstpinosdeviceprovider.c @@ -39,19 +39,18 @@ G_DEFINE_TYPE (GstPinosDevice, gst_pinos_device, GST_TYPE_DEVICE); enum { - PROP_PATH = 1, + PROP_ID = 1, }; static GstDevice * -gst_pinos_device_new (gpointer id, const gchar * device_name, - GstCaps * caps, const gchar * path, const gchar *klass, +gst_pinos_device_new (uint32_t id, const gchar * device_name, + GstCaps * caps, const gchar *klass, GstPinosDeviceType type, GstStructure *props) { GstPinosDevice *gstdev; const gchar *element = NULL; g_return_val_if_fail (device_name, NULL); - g_return_val_if_fail (path, NULL); g_return_val_if_fail (caps, NULL); switch (type) { @@ -68,7 +67,7 @@ gst_pinos_device_new (gpointer id, const gchar * device_name, gstdev = g_object_new (GST_TYPE_PINOS_DEVICE, "display-name", device_name, "caps", caps, "device-class", klass, - "path", path, "properties", props, NULL); + "id", id, "properties", props, NULL); gstdev->id = id; gstdev->type = type; @@ -84,7 +83,7 @@ gst_pinos_device_create_element (GstDevice * device, const gchar * name) GstElement *elem; elem = gst_element_factory_make (pinos_dev->element, name); - g_object_set (elem, "path", pinos_dev->path, NULL); + g_object_set (elem, "path", pinos_dev->id, NULL); return elem; } @@ -104,7 +103,7 @@ gst_pinos_device_reconfigure_element (GstDevice * device, GstElement * element) g_assert_not_reached (); } - g_object_set (element, "path", pinos_dev->path, NULL); + g_object_set (element, "path", pinos_dev->id, NULL); return TRUE; } @@ -119,8 +118,8 @@ gst_pinos_device_get_property (GObject * object, guint prop_id, device = GST_PINOS_DEVICE_CAST (object); switch (prop_id) { - case PROP_PATH: - g_value_set_string (value, device->path); + case PROP_ID: + g_value_set_uint (value, device->id); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -137,8 +136,8 @@ gst_pinos_device_set_property (GObject * object, guint prop_id, device = GST_PINOS_DEVICE_CAST (object); switch (prop_id) { - case PROP_PATH: - device->path = g_value_dup_string (value); + case PROP_ID: + device->id = g_value_get_uint (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -149,10 +148,6 @@ gst_pinos_device_set_property (GObject * object, guint prop_id, static void gst_pinos_device_finalize (GObject * object) { - GstPinosDevice *device = GST_PINOS_DEVICE (object); - - g_free (device->path); - G_OBJECT_CLASS (gst_pinos_device_parent_class)->finalize (object); } @@ -169,9 +164,9 @@ gst_pinos_device_class_init (GstPinosDeviceClass * klass) object_class->set_property = gst_pinos_device_set_property; object_class->finalize = gst_pinos_device_finalize; - g_object_class_install_property (object_class, PROP_PATH, - g_param_spec_string ("path", "Path", - "The internal path of the Pinos device", "", + g_object_class_install_property (object_class, PROP_ID, + g_param_spec_uint ("id", "Id", + "The internal id of the Pinos device", 0, G_MAXUINT32, SPA_ID_INVALID, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } @@ -225,7 +220,6 @@ new_node (const PinosNodeInfo *info) return gst_pinos_device_new (info->id, info->name, caps, - info->node_path, klass, GST_PINOS_DEVICE_TYPE_SOURCE, props); @@ -233,19 +227,22 @@ new_node (const PinosNodeInfo *info) static void get_node_info_cb (PinosContext *context, + SpaResult res, const PinosNodeInfo *info, gpointer user_data) { GstPinosDeviceProvider *self = user_data; - GstDevice *dev; - dev = new_node (info); - if (dev) - gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); + if (info) { + GstDevice *dev; + dev = new_node (info); + if (dev) + gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); + } } static GstPinosDevice * -find_device (GstDeviceProvider *provider, gpointer id) +find_device (GstDeviceProvider *provider, uint32_t id) { GList *item; GstPinosDevice *dev = NULL; @@ -266,10 +263,10 @@ find_device (GstDeviceProvider *provider, gpointer id) static void context_subscribe_cb (PinosContext *context, - PinosSubscriptionEvent type, PinosSubscriptionFlags flags, - gpointer id, - gpointer user_data) + PinosSubscriptionEvent type, + uint32_t id, + void *user_data) { GstPinosDeviceProvider *self = user_data; GstDeviceProvider *provider = user_data; @@ -284,10 +281,7 @@ context_subscribe_cb (PinosContext *context, if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev == NULL) pinos_context_get_node_info_by_id (context, id, - PINOS_NODE_INFO_FLAGS_NONE, get_node_info_cb, - NULL, - NULL, self); } else if (type == PINOS_SUBSCRIPTION_EVENT_REMOVE) { if (flags == PINOS_SUBSCRIPTION_FLAG_NODE && dev != NULL) { @@ -306,31 +300,23 @@ typedef struct { static void list_node_info_cb (PinosContext *c, + SpaResult res, const PinosNodeInfo *info, - gpointer user_data) + void *user_data) { InfoData *data = user_data; - - *data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (new_node (info))); -} - -static void -list_node_info_end_cb (GObject *source_object, - GAsyncResult *res, - gpointer user_data) -{ - InfoData *data = user_data; - GError *error = NULL; - - if (!pinos_context_info_finish (source_object, res, &error)) { - GST_WARNING_OBJECT (source_object, "failed to list nodes: %s", error->message); - g_clear_error (&error); + if (info) { + *data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (new_node (info))); + } else { + data->end = TRUE; } - data->end = TRUE; } static void -get_daemon_info_cb (PinosContext *c, const PinosDaemonInfo *info, gpointer user_data) +get_daemon_info_cb (PinosContext *c, + SpaResult res, + const PinosDaemonInfo *info, + void *user_data) { GstDeviceProvider *provider = user_data; const gchar *value; @@ -353,30 +339,27 @@ static GList * gst_pinos_device_provider_probe (GstDeviceProvider * provider) { GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider); - GMainContext *m = NULL; + PinosLoop *l = NULL; PinosContext *c = NULL; InfoData data; GST_DEBUG_OBJECT (self, "starting probe"); - if (!(m = g_main_context_new ())) + if (!(l = pinos_loop_new ())) return NULL; - if (!(c = pinos_context_new (m, self->client_name, NULL))) + if (!(c = pinos_context_new (l, self->client_name, NULL))) goto failed; - g_main_context_push_thread_default (m); - - pinos_context_connect (c, PINOS_CONTEXT_FLAGS_NONE); + pinos_context_connect (c); for (;;) { PinosContextState state; - state = pinos_context_get_state (c); + state = c->state; if (state <= 0) { - GST_ERROR_OBJECT (self, "Failed to connect: %s", - pinos_context_get_error (c)->message); + GST_ERROR_OBJECT (self, "Failed to connect: %s", c->error); goto failed; } @@ -384,59 +367,47 @@ gst_pinos_device_provider_probe (GstDeviceProvider * provider) break; /* Wait until something happens */ - g_main_context_iteration (m, TRUE); + pinos_loop_iterate (l, -1); } GST_DEBUG_OBJECT (self, "connected"); pinos_context_get_daemon_info (c, - PINOS_DAEMON_INFO_FLAGS_NONE, get_daemon_info_cb, - NULL, - NULL, self); data.end = FALSE; data.devices = NULL; pinos_context_list_node_info (c, - PINOS_NODE_INFO_FLAGS_NONE, list_node_info_cb, - NULL, - list_node_info_end_cb, &data); for (;;) { - if (pinos_context_get_state (c) <= 0) + if (c->state <= 0) break; if (data.end) break; - g_main_context_iteration (m, TRUE); + pinos_loop_iterate (l, -1); } pinos_context_disconnect (c); - g_clear_object (&c); - - g_main_context_pop_thread_default (m); - g_main_context_unref (m); + pinos_context_destroy (c); + pinos_loop_destroy (l); return *data.devices; failed: - g_main_context_pop_thread_default (m); - g_main_context_unref (m); - + pinos_loop_destroy (l); return NULL; } static void -context_state_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_context_state_changed (PinosListener *listener, + PinosContext *context) { - GstPinosDeviceProvider *self = user_data; - PinosContext *context = PINOS_CONTEXT (gobject); + GstPinosDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPinosDeviceProvider, ctx_state_changed); PinosContextState state; - state= pinos_context_get_state (context); + state= context->state; GST_DEBUG ("got context state %d", state); @@ -447,67 +418,53 @@ context_state_notify (GObject *gobject, case PINOS_CONTEXT_STATE_CONNECTED: break; case PINOS_CONTEXT_STATE_ERROR: - GST_ERROR_OBJECT (self, "context error: %s", - pinos_context_get_error (context)->message); + GST_ERROR_OBJECT (self, "context error: %s", context->error); break; } - pinos_thread_main_loop_signal (self->loop, FALSE); + pinos_thread_main_loop_signal (self->main_loop, FALSE); } static gboolean gst_pinos_device_provider_start (GstDeviceProvider * provider) { GstPinosDeviceProvider *self = GST_PINOS_DEVICE_PROVIDER (provider); - GError *error = NULL; - GMainContext *c; GST_DEBUG_OBJECT (self, "starting provider"); - c = g_main_context_new (); + self->loop = pinos_loop_new (); - if (!(self->loop = pinos_thread_main_loop_new (c, "pinos-device-monitor"))) { + if (!(self->main_loop = pinos_thread_main_loop_new (self->loop, "pinos-device-monitor"))) { GST_ERROR_OBJECT (self, "Could not create pinos mainloop"); - goto failed; + goto failed_main_loop; } - 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; + if (pinos_thread_main_loop_start (self->main_loop) != SPA_RESULT_OK) { + GST_ERROR_OBJECT (self, "Could not start pinos mainloop"); + goto failed_start; } - pinos_thread_main_loop_lock (self->loop); + pinos_thread_main_loop_lock (self->main_loop); - if (!(self->context = pinos_context_new (c, self->client_name, NULL))) { + if (!(self->context = pinos_context_new (self->loop, self->client_name, NULL))) { GST_ERROR_OBJECT (self, "Failed to create context"); - pinos_thread_main_loop_unlock (self->loop); - pinos_thread_main_loop_stop (self->loop); - g_clear_object (&self->loop); - goto failed; + goto failed_context; } - g_signal_connect (self->context, - "notify::state", - (GCallback) context_state_notify, - self); + pinos_signal_add (&self->context->state_changed, &self->ctx_state_changed, on_context_state_changed); - g_object_set (self->context, - "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, - NULL); - g_signal_connect (self->context, - "subscription-event", - (GCallback) context_subscribe_cb, - self); + pinos_context_subscribe (self->context, + PINOS_SUBSCRIPTION_FLAGS_ALL, + context_subscribe_cb, + self); - pinos_context_connect (self->context, PINOS_CONTEXT_FLAGS_NONE); + pinos_context_connect (self->context); for (;;) { PinosContextState state; - state = pinos_context_get_state (self->context); + state = self->context->state; if (state <= 0) { - GST_WARNING_OBJECT (self, "Failed to connect: %s", - pinos_context_get_error (self->context)->message); + GST_WARNING_OBJECT (self, "Failed to connect: %s", self->context->error); goto not_running; } @@ -515,34 +472,28 @@ gst_pinos_device_provider_start (GstDeviceProvider * provider) break; /* Wait until something happens */ - pinos_thread_main_loop_wait (self->loop); + pinos_thread_main_loop_wait (self->main_loop); } GST_DEBUG_OBJECT (self, "connected"); pinos_context_get_daemon_info (self->context, - PINOS_DAEMON_INFO_FLAGS_NONE, get_daemon_info_cb, - NULL, - NULL, self); - pinos_thread_main_loop_unlock (self->loop); - - g_main_context_unref (c); + pinos_thread_main_loop_unlock (self->main_loop); return TRUE; -failed: - { - g_main_context_unref (c); - return FALSE; - } not_running: - { - 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; - } + pinos_context_destroy (self->context); + self->context = NULL; +failed_context: + pinos_thread_main_loop_unlock (self->main_loop); +failed_start: + pinos_thread_main_loop_destroy (self->main_loop); + self->main_loop = NULL; +failed_main_loop: + pinos_loop_destroy (self->loop); + self->loop = NULL; + return FALSE; } static void @@ -552,12 +503,17 @@ gst_pinos_device_provider_stop (GstDeviceProvider * provider) if (self->context) { pinos_context_disconnect (self->context); + pinos_context_destroy (self->context); + self->context = NULL; + } + if (self->main_loop) { + pinos_thread_main_loop_destroy (self->main_loop); + self->main_loop = NULL; } if (self->loop) { - pinos_thread_main_loop_stop (self->loop); + pinos_loop_destroy (self->loop); + self->loop = NULL; } - g_clear_object (&self->context); - g_clear_object (&self->loop); } static void diff --git a/pinos/gst/gstpinosdeviceprovider.h b/pinos/gst/gstpinosdeviceprovider.h index 49115389d..4024f9428 100644 --- a/pinos/gst/gstpinosdeviceprovider.h +++ b/pinos/gst/gstpinosdeviceprovider.h @@ -54,8 +54,7 @@ struct _GstPinosDevice { GstDevice parent; GstPinosDeviceType type; - gpointer id; - gchar *path; + uint32_t id; const gchar *element; }; @@ -81,10 +80,11 @@ struct _GstPinosDeviceProvider { gchar *client_name; - GMainContext *maincontext; - PinosThreadMainLoop *loop; + PinosLoop *loop; + PinosThreadMainLoop *main_loop; PinosContext *context; + PinosListener ctx_state_changed; }; struct _GstPinosDeviceProviderClass { diff --git a/pinos/gst/gstpinossink.c b/pinos/gst/gstpinossink.c index 224876a21..4071334c9 100644 --- a/pinos/gst/gstpinossink.c +++ b/pinos/gst/gstpinossink.c @@ -348,11 +348,11 @@ process_mem_data_destroy (gpointer user_data) } static void -on_add_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_add_buffer (PinosListener *listener, + PinosStream *stream, + uint32_t id) { - GstPinosSink *pinossink = user_data; + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_add_buffer); SpaBuffer *b; GstBuffer *buf; unsigned int i; @@ -415,15 +415,15 @@ 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_thread_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->main_loop, FALSE); } static void -on_remove_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_remove_buffer (PinosListener *listener, + PinosStream *stream, + uint32_t id) { - GstPinosSink *pinossink = user_data; + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_remove_buffer); GstBuffer *buf; GST_LOG_OBJECT (pinossink, "remove buffer"); @@ -435,11 +435,11 @@ on_remove_buffer (GObject *gobject, } static void -on_new_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_new_buffer (PinosListener *listener, + PinosStream *stream, + uint32_t id) { - GstPinosSink *pinossink = user_data; + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_new_buffer); GstBuffer *buf; GST_LOG_OBJECT (pinossink, "got new buffer"); @@ -451,20 +451,18 @@ on_new_buffer (GObject *gobject, if (buf) { gst_buffer_unref (buf); - pinos_thread_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->main_loop, FALSE); } } static void -on_stream_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_state_changed (PinosListener *listener, + PinosStream *stream) { + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_state_changed); PinosStreamState state; - PinosStream *stream = PINOS_STREAM (gobject); - GstPinosSink *pinossink = user_data; - state = pinos_stream_get_state (stream); + state = stream->state; GST_DEBUG ("got stream state %d", state); switch (state) { @@ -477,20 +475,19 @@ on_stream_notify (GObject *gobject, break; case PINOS_STREAM_STATE_ERROR: GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED, - ("stream error: %s", - pinos_stream_get_error (stream)->message), (NULL)); + ("stream error: %s", stream->error), (NULL)); break; } - pinos_thread_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->main_loop, FALSE); } static void -on_format_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_format_changed (PinosListener *listener, + PinosStream *stream, + SpaFormat *format) { #if 0 - GstPinosSink *pinossink = user_data; + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, stream_format_changed); GstStructure *config; GstCaps *caps; guint size; @@ -532,8 +529,8 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) possible = gst_caps_to_format_all (caps); - pinos_thread_main_loop_lock (pinossink->loop); - state = pinos_stream_get_state (pinossink->stream); + pinos_thread_main_loop_lock (pinossink->main_loop); + state = pinossink->stream->state; if (state == PINOS_STREAM_STATE_ERROR) goto start_error; @@ -549,10 +546,11 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) PINOS_STREAM_MODE_BUFFER, pinossink->path, flags, - possible); + possible->len, + (SpaFormat **) possible->pdata); while (TRUE) { - state = pinos_stream_get_state (pinossink->stream); + state = pinossink->stream->state; if (state == PINOS_STREAM_STATE_READY) break; @@ -560,7 +558,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_thread_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->main_loop); } } res = TRUE; @@ -570,7 +568,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) res = pinos_stream_start (pinossink->stream); while (TRUE) { - state = pinos_stream_get_state (pinossink->stream); + state = pinossink->stream->state; if (state == PINOS_STREAM_STATE_STREAMING) break; @@ -578,11 +576,11 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_thread_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->main_loop); } } #endif - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); pinossink->negotiated = res; @@ -591,7 +589,7 @@ gst_pinos_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) start_error: { GST_ERROR ("could not start stream"); - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); g_ptr_array_unref (possible); return FALSE; } @@ -610,8 +608,8 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) if (!pinossink->negotiated) goto not_negotiated; - pinos_thread_main_loop_lock (pinossink->loop); - if (pinos_stream_get_state (pinossink->stream) != PINOS_STREAM_STATE_STREAMING) + pinos_thread_main_loop_lock (pinossink->main_loop); + if (pinossink->stream->state != PINOS_STREAM_STATE_STREAMING) goto done; // goto streaming_error; @@ -645,7 +643,7 @@ gst_pinos_sink_render (GstBaseSink * bsink, GstBuffer * buffer) done: - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); return GST_FLOW_OK; @@ -655,7 +653,7 @@ not_negotiated: } //streaming_error: // { -// pinos_thread_main_loop_unlock (pinossink->loop); +// pinos_thread_main_loop_unlock (pinossink->main_loop); // return GST_FLOW_ERROR; // } } @@ -689,15 +687,16 @@ gst_pinos_sink_start (GstBaseSink * basesink) props = NULL; } - pinos_thread_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->main_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); - g_signal_connect (pinossink->stream, "notify::format", (GCallback) on_format_notify, pinossink); - 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_thread_main_loop_unlock (pinossink->loop); + + pinos_signal_add (&pinossink->stream->state_changed, &pinossink->stream_state_changed, on_state_changed); + pinos_signal_add (&pinossink->stream->format_changed, &pinossink->stream_format_changed, on_format_changed); + pinos_signal_add (&pinossink->stream->add_buffer, &pinossink->stream_add_buffer, on_add_buffer); + pinos_signal_add (&pinossink->stream->remove_buffer, &pinossink->stream_remove_buffer, on_remove_buffer); + pinos_signal_add (&pinossink->stream->new_buffer, &pinossink->stream_new_buffer, on_new_buffer); + pinos_thread_main_loop_unlock (pinossink->main_loop); return TRUE; } @@ -707,14 +706,14 @@ gst_pinos_sink_stop (GstBaseSink * basesink) { GstPinosSink *pinossink = GST_PINOS_SINK (basesink); - pinos_thread_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->main_loop); if (pinossink->stream) { pinos_stream_stop (pinossink->stream); pinos_stream_disconnect (pinossink->stream); g_clear_object (&pinossink->stream); pinossink->pool->stream = NULL; } - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); pinossink->negotiated = FALSE; @@ -722,15 +721,13 @@ gst_pinos_sink_stop (GstBaseSink * basesink) } static void -on_context_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_ctx_state_changed (PinosListener *listener, + PinosContext *ctx) { - GstPinosSink *pinossink = user_data; - PinosContext *ctx = PINOS_CONTEXT (gobject); + GstPinosSink *pinossink = SPA_CONTAINER_OF (listener, GstPinosSink, ctx_state_changed); PinosContextState state; - state = pinos_context_get_state (ctx); + state = ctx->state; GST_DEBUG ("got context state %d", state); switch (state) { @@ -740,33 +737,31 @@ on_context_notify (GObject *gobject, break; case PINOS_CONTEXT_STATE_ERROR: GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED, - ("context error: %s", - pinos_context_get_error (pinossink->ctx)->message), (NULL)); + ("context error: %s", ctx->error), (NULL)); break; } - pinos_thread_main_loop_signal (pinossink->loop, FALSE); + pinos_thread_main_loop_signal (pinossink->main_loop, FALSE); } static gboolean gst_pinos_sink_open (GstPinosSink * pinossink) { - GError *error = NULL; + pinossink->loop = pinos_loop_new (); + GST_DEBUG ("loop %p", pinossink->loop); - pinossink->context = g_main_context_new (); - GST_DEBUG ("context %p", pinossink->context); - - pinossink->loop = pinos_thread_main_loop_new (pinossink->context, "pinos-sink-loop"); - if (!pinos_thread_main_loop_start (pinossink->loop, &error)) + pinossink->main_loop = pinos_thread_main_loop_new (pinossink->loop, "pinos-sink-loop"); + if (pinos_thread_main_loop_start (pinossink->main_loop) != SPA_RESULT_OK) goto mainloop_error; - 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); + pinos_thread_main_loop_lock (pinossink->main_loop); + pinossink->ctx = pinos_context_new (pinossink->loop, g_get_application_name (), NULL); - pinos_context_connect(pinossink->ctx, PINOS_CONTEXT_FLAGS_NONE); + pinos_signal_add (&pinossink->ctx->state_changed, &pinossink->ctx_state_changed, on_ctx_state_changed); + + pinos_context_connect(pinossink->ctx); while (TRUE) { - PinosContextState state = pinos_context_get_state (pinossink->ctx); + PinosContextState state = pinossink->ctx->state; if (state == PINOS_CONTEXT_STATE_CONNECTED) break; @@ -774,9 +769,9 @@ gst_pinos_sink_open (GstPinosSink * pinossink) if (state == PINOS_CONTEXT_STATE_ERROR) goto connect_error; - pinos_thread_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->main_loop); } - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); return TRUE; @@ -784,12 +779,12 @@ gst_pinos_sink_open (GstPinosSink * pinossink) mainloop_error: { GST_ELEMENT_ERROR (pinossink, RESOURCE, FAILED, - ("Failed to start mainloop: %s", error->message), (NULL)); + ("Failed to start mainloop"), (NULL)); return FALSE; } connect_error: { - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); return FALSE; } } @@ -797,7 +792,7 @@ connect_error: static gboolean gst_pinos_sink_close (GstPinosSink * pinossink) { - pinos_thread_main_loop_lock (pinossink->loop); + pinos_thread_main_loop_lock (pinossink->main_loop); if (pinossink->stream) { pinos_stream_disconnect (pinossink->stream); } @@ -805,7 +800,7 @@ gst_pinos_sink_close (GstPinosSink * pinossink) pinos_context_disconnect (pinossink->ctx); while (TRUE) { - PinosContextState state = pinos_context_get_state (pinossink->ctx); + PinosContextState state = pinossink->ctx->state; if (state == PINOS_CONTEXT_STATE_UNCONNECTED) break; @@ -813,16 +808,17 @@ gst_pinos_sink_close (GstPinosSink * pinossink) if (state == PINOS_CONTEXT_STATE_ERROR) break; - pinos_thread_main_loop_wait (pinossink->loop); + pinos_thread_main_loop_wait (pinossink->main_loop); } } - pinos_thread_main_loop_unlock (pinossink->loop); + pinos_thread_main_loop_unlock (pinossink->main_loop); - pinos_thread_main_loop_stop (pinossink->loop); - g_clear_object (&pinossink->loop); - g_clear_object (&pinossink->stream); - g_clear_object (&pinossink->ctx); - g_main_context_unref (pinossink->context); + pinos_thread_main_loop_stop (pinossink->main_loop); + pinos_thread_main_loop_destroy (pinossink->main_loop); + pinos_stream_destroy (pinossink->stream); + pinos_context_destroy (pinossink->ctx); + pinos_loop_destroy (pinossink->loop); + pinossink->loop = NULL; return TRUE; } diff --git a/pinos/gst/gstpinossink.h b/pinos/gst/gstpinossink.h index 59a23a208..9e413ee00 100644 --- a/pinos/gst/gstpinossink.h +++ b/pinos/gst/gstpinossink.h @@ -77,10 +77,19 @@ struct _GstPinosSink { /* video state */ gboolean negotiated; - GMainContext *context; - PinosThreadMainLoop *loop; + PinosLoop *loop; + PinosThreadMainLoop *main_loop; + PinosContext *ctx; + PinosListener ctx_state_changed; + PinosStream *stream; + PinosListener stream_state_changed; + PinosListener stream_format_changed; + PinosListener stream_add_buffer; + PinosListener stream_remove_buffer; + PinosListener stream_new_buffer; + GstAllocator *allocator; GstStructure *properties; GstPinosSinkMode mode; diff --git a/pinos/gst/gstpinossrc.c b/pinos/gst/gstpinossrc.c index e2fa1abcd..f0f2e2cae 100644 --- a/pinos/gst/gstpinossrc.c +++ b/pinos/gst/gstpinossrc.c @@ -354,19 +354,19 @@ buffer_recycle (GstMiniObject *obj) src = data->src; GST_LOG_OBJECT (obj, "recycle buffer"); - pinos_thread_main_loop_lock (src->loop); + pinos_thread_main_loop_lock (src->main_loop); pinos_stream_recycle_buffer (src->stream, data->id); - pinos_thread_main_loop_unlock (src->loop); + pinos_thread_main_loop_unlock (src->main_loop); return FALSE; } static void -on_add_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_add_buffer (PinosListener *listener, + PinosStream *stream, + guint id) { - GstPinosSrc *pinossrc = user_data; + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_add_buffer); SpaBuffer *b; GstBuffer *buf; unsigned int i; @@ -430,11 +430,11 @@ on_add_buffer (GObject *gobject, } static void -on_remove_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_remove_buffer (PinosListener *listener, + PinosStream *stream, + guint id) { - GstPinosSrc *pinossrc = user_data; + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_remove_buffer); GstBuffer *buf; GST_LOG_OBJECT (pinossrc, "remove buffer"); @@ -445,11 +445,11 @@ on_remove_buffer (GObject *gobject, } static void -on_new_buffer (GObject *gobject, - guint id, - gpointer user_data) +on_new_buffer (PinosListener *listener, + PinosStream *stream, + guint id) { - GstPinosSrc *pinossrc = user_data; + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_new_buffer); GstBuffer *buf; ProcessMemData *data; SpaMetaHeader *h; @@ -483,17 +483,16 @@ on_new_buffer (GObject *gobject, } g_queue_push_tail (&pinossrc->queue, buf); - pinos_thread_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE); return; } static void -on_stream_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_state_changed (PinosListener *listener, + PinosStream *stream) { - GstPinosSrc *pinossrc = user_data; - PinosStreamState state = pinos_stream_get_state (pinossrc->stream); + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_state_changed); + PinosStreamState state = stream->state; GST_DEBUG ("got stream state %s", pinos_stream_state_as_string (state)); @@ -507,11 +506,10 @@ on_stream_notify (GObject *gobject, break; case PINOS_STREAM_STATE_ERROR: GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, - ("stream error: %s", - pinos_stream_get_error (pinossrc->stream)->message), (NULL)); + ("stream error: %s", stream->error), (NULL)); break; } - pinos_thread_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE); } static void @@ -540,13 +538,12 @@ static gboolean gst_pinos_src_stream_start (GstPinosSrc *pinossrc) { gboolean res; - PinosProperties *props; - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); GST_DEBUG_OBJECT (pinossrc, "doing stream start"); res = pinos_stream_start (pinossrc->stream); while (TRUE) { - PinosStreamState state = pinos_stream_get_state (pinossrc->stream); + PinosStreamState state = pinossrc->stream->state; GST_DEBUG_OBJECT (pinossrc, "waiting for STREAMING, now %s", pinos_stream_state_as_string (state)); if (state == PINOS_STREAM_STATE_STREAMING) @@ -555,27 +552,24 @@ gst_pinos_src_stream_start (GstPinosSrc *pinossrc) if (state == PINOS_STREAM_STATE_ERROR) goto start_error; - pinos_thread_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->main_loop); } - g_object_get (pinossrc->stream, "properties", &props, NULL); - pinos_thread_main_loop_unlock (pinossrc->loop); + parse_stream_properties (pinossrc, pinossrc->stream->properties); + pinos_thread_main_loop_unlock (pinossrc->main_loop); - parse_stream_properties (pinossrc, props); - pinos_properties_free (props); - - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); GST_DEBUG_OBJECT (pinossrc, "signal started"); pinossrc->started = TRUE; - pinos_thread_main_loop_signal (pinossrc->loop, FALSE); - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return res; start_error: { GST_DEBUG_OBJECT (pinossrc, "error starting stream"); - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return FALSE; } } @@ -585,9 +579,9 @@ wait_negotiated (GstPinosSrc *this) { PinosStreamState state; - pinos_thread_main_loop_lock (this->loop); + pinos_thread_main_loop_lock (this->main_loop); while (TRUE) { - state = pinos_stream_get_state (this->stream); + state = this->stream->state; GST_DEBUG_OBJECT (this, "waiting for started signal, state now %s", pinos_stream_state_as_string (state)); @@ -597,10 +591,10 @@ wait_negotiated (GstPinosSrc *this) if (this->started) break; - pinos_thread_main_loop_wait (this->loop); + pinos_thread_main_loop_wait (this->main_loop); } GST_DEBUG_OBJECT (this, "got started signal"); - pinos_thread_main_loop_unlock (this->loop); + pinos_thread_main_loop_unlock (this->main_loop); return state; } @@ -645,12 +639,12 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) possible = gst_caps_to_format_all (caps); /* first disconnect */ - pinos_thread_main_loop_lock (pinossrc->loop); - if (pinos_stream_get_state (pinossrc->stream) != PINOS_STREAM_STATE_UNCONNECTED) { + pinos_thread_main_loop_lock (pinossrc->main_loop); + if (pinossrc->stream->state != PINOS_STREAM_STATE_UNCONNECTED) { GST_DEBUG_OBJECT (basesrc, "disconnect capture"); pinos_stream_disconnect (pinossrc->stream); while (TRUE) { - PinosStreamState state = pinos_stream_get_state (pinossrc->stream); + PinosStreamState state = pinossrc->stream->state; GST_DEBUG_OBJECT (basesrc, "waiting for UNCONNECTED, now %s", pinos_stream_state_as_string (state)); if (state == PINOS_STREAM_STATE_UNCONNECTED) @@ -661,7 +655,7 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) goto connect_error; } - pinos_thread_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->main_loop); } } @@ -671,10 +665,11 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) PINOS_STREAM_MODE_BUFFER, pinossrc->path, PINOS_STREAM_FLAG_AUTOCONNECT, - possible); + possible->len, + (SpaFormat **)possible->pdata); while (TRUE) { - PinosStreamState state = pinos_stream_get_state (pinossrc->stream); + PinosStreamState state = pinossrc->stream->state; GST_DEBUG_OBJECT (basesrc, "waiting for PAUSED, now %s", pinos_stream_state_as_string (state)); if (state == PINOS_STREAM_STATE_PAUSED || @@ -684,9 +679,9 @@ gst_pinos_src_negotiate (GstBaseSrc * basesrc) if (state == PINOS_STREAM_STATE_ERROR) goto connect_error; - pinos_thread_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->main_loop); } - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); result = gst_pinos_src_stream_start (pinossrc); @@ -721,23 +716,20 @@ no_common_caps: } connect_error: { - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return FALSE; } } static void -on_format_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_format_changed (PinosListener *listener, + PinosStream *stream, + SpaFormat *format) { - GstPinosSrc *pinossrc = user_data; - SpaFormat *format; + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, stream_format_changed); GstCaps *caps; gboolean res; - g_object_get (gobject, "format", &format, NULL); - caps = gst_caps_from_format (format); GST_DEBUG_OBJECT (pinossrc, "we got format %" GST_PTR_FORMAT, caps); res = gst_base_src_set_caps (GST_BASE_SRC (pinossrc), caps); @@ -765,11 +757,11 @@ gst_pinos_src_unlock (GstBaseSrc * basesrc) { GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc); - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); GST_DEBUG_OBJECT (pinossrc, "setting flushing"); pinossrc->flushing = TRUE; - pinos_thread_main_loop_signal (pinossrc->loop, FALSE); - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return TRUE; } @@ -779,10 +771,10 @@ gst_pinos_src_unlock_stop (GstBaseSrc * basesrc) { GstPinosSrc *pinossrc = GST_PINOS_SRC (basesrc); - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); GST_DEBUG_OBJECT (pinossrc, "unsetting flushing"); pinossrc->flushing = FALSE; - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return TRUE; } @@ -868,14 +860,14 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (!pinossrc->negotiated) goto not_negotiated; - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); while (TRUE) { PinosStreamState state; if (pinossrc->flushing) goto streaming_stopped; - state = pinos_stream_get_state (pinossrc->stream); + state = pinossrc->stream->state; if (state == PINOS_STREAM_STATE_ERROR) goto streaming_error; @@ -886,9 +878,9 @@ gst_pinos_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (*buffer != NULL) break; - pinos_thread_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->main_loop); } - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); if (pinossrc->is_live) base_time = GST_ELEMENT_CAST (psrc)->base_time; @@ -919,12 +911,12 @@ not_negotiated: } streaming_error: { - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return GST_FLOW_ERROR; } streaming_stopped: { - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return GST_FLOW_FLUSHING; } } @@ -949,20 +941,19 @@ gst_pinos_src_stop (GstBaseSrc * basesrc) pinossrc = GST_PINOS_SRC (basesrc); - pinos_thread_main_loop_lock (pinossrc->loop); + pinos_thread_main_loop_lock (pinossrc->main_loop); clear_queue (pinossrc); - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return TRUE; } static void -on_context_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_ctx_state_changed (PinosListener *listener, + PinosContext *ctx) { - GstPinosSrc *pinossrc = user_data; - PinosContextState state = pinos_context_get_state (pinossrc->ctx); + GstPinosSrc *pinossrc = SPA_CONTAINER_OF (listener, GstPinosSrc, ctx_state_changed); + PinosContextState state = ctx->state; GST_DEBUG ("got context state %s", pinos_context_state_as_string (state)); @@ -973,11 +964,10 @@ on_context_notify (GObject *gobject, break; case PINOS_CONTEXT_STATE_ERROR: GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, - ("context error: %s", - pinos_context_get_error (pinossrc->ctx)->message), (NULL)); + ("context error: %s", ctx->error), (NULL)); break; } - pinos_thread_main_loop_signal (pinossrc->loop, FALSE); + pinos_thread_main_loop_signal (pinossrc->main_loop, FALSE); } static gboolean @@ -997,24 +987,24 @@ copy_properties (GQuark field_id, static gboolean gst_pinos_src_open (GstPinosSrc * pinossrc) { - GError *error = NULL; PinosProperties *props; - pinossrc->context = g_main_context_new (); - GST_DEBUG ("context %p", pinossrc->context); + pinossrc->loop = pinos_loop_new (); + GST_DEBUG ("loop %p", pinossrc->loop); - pinossrc->loop = pinos_thread_main_loop_new (pinossrc->context, "pinos-main-loop"); - if (!pinos_thread_main_loop_start (pinossrc->loop, &error)) + pinossrc->main_loop = pinos_thread_main_loop_new (pinossrc->loop, "pinos-main-loop"); + if (pinos_thread_main_loop_start (pinossrc->main_loop) != SPA_RESULT_OK) goto mainloop_failed; - 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); + pinos_thread_main_loop_lock (pinossrc->main_loop); + pinossrc->ctx = pinos_context_new (pinossrc->loop, g_get_application_name (), NULL); - pinos_context_connect (pinossrc->ctx, PINOS_CONTEXT_FLAGS_NONE); + pinos_signal_add (&pinossrc->ctx->state_changed, &pinossrc->ctx_state_changed, on_ctx_state_changed); + + pinos_context_connect (pinossrc->ctx); while (TRUE) { - PinosContextState state = pinos_context_get_state (pinossrc->ctx); + PinosContextState state = pinossrc->ctx->state; GST_DEBUG ("waiting for CONNECTED, now %s", pinos_context_state_as_string (state)); if (state == PINOS_CONTEXT_STATE_CONNECTED) @@ -1023,7 +1013,7 @@ gst_pinos_src_open (GstPinosSrc * pinossrc) if (state == PINOS_CONTEXT_STATE_ERROR) goto connect_error; - pinos_thread_main_loop_wait (pinossrc->loop); + pinos_thread_main_loop_wait (pinossrc->main_loop); } if (pinossrc->properties) { @@ -1034,26 +1024,27 @@ gst_pinos_src_open (GstPinosSrc * pinossrc) } pinossrc->stream = pinos_stream_new (pinossrc->ctx, pinossrc->client_name, props); - g_signal_connect (pinossrc->stream, "notify::state", (GCallback) on_stream_notify, pinossrc); - g_signal_connect (pinossrc->stream, "notify::format", (GCallback) on_format_notify, pinossrc); - g_signal_connect (pinossrc->stream, "add-buffer", (GCallback) on_add_buffer, 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); + + pinos_signal_add (&pinossrc->stream->state_changed, &pinossrc->stream_state_changed, on_state_changed); + pinos_signal_add (&pinossrc->stream->format_changed, &pinossrc->stream_format_changed, on_format_changed); + pinos_signal_add (&pinossrc->stream->add_buffer, &pinossrc->stream_add_buffer, on_add_buffer); + pinos_signal_add (&pinossrc->stream->remove_buffer, &pinossrc->stream_remove_buffer, on_remove_buffer); + pinos_signal_add (&pinossrc->stream->new_buffer, &pinossrc->stream_new_buffer, on_new_buffer); + pinossrc->clock = gst_pinos_clock_new (pinossrc->stream); - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return TRUE; /* ERRORS */ mainloop_failed: { - GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, - ("mainloop error: %s", error->message), (NULL)); + GST_ELEMENT_ERROR (pinossrc, RESOURCE, FAILED, ("error starting mainloop"), (NULL)); return FALSE; } connect_error: { - pinos_thread_main_loop_unlock (pinossrc->loop); + pinos_thread_main_loop_unlock (pinossrc->main_loop); return FALSE; } } @@ -1061,10 +1052,16 @@ connect_error: static void gst_pinos_src_close (GstPinosSrc * pinossrc) { - pinos_thread_main_loop_stop (pinossrc->loop); - g_clear_object (&pinossrc->loop); - g_clear_object (&pinossrc->ctx); - g_main_context_unref (pinossrc->context); + pinos_thread_main_loop_stop (pinossrc->main_loop); + pinos_thread_main_loop_destroy (pinossrc->main_loop); + pinossrc->main_loop = NULL; + + pinos_context_destroy (pinossrc->ctx); + pinossrc->ctx = NULL; + + pinos_loop_destroy (pinossrc->loop); + pinossrc->loop = NULL; + GST_OBJECT_LOCK (pinossrc); g_clear_object (&pinossrc->clock); g_clear_object (&pinossrc->stream); diff --git a/pinos/gst/gstpinossrc.h b/pinos/gst/gstpinossrc.h index 01bc48e99..97e1e28de 100644 --- a/pinos/gst/gstpinossrc.h +++ b/pinos/gst/gstpinossrc.h @@ -63,10 +63,19 @@ struct _GstPinosSrc { GstClockTime min_latency; GstClockTime max_latency; - GMainContext *context; - PinosThreadMainLoop *loop; + PinosLoop *loop; + PinosThreadMainLoop *main_loop; + PinosContext *ctx; + PinosListener ctx_state_changed; + PinosStream *stream; + PinosListener stream_state_changed; + PinosListener stream_format_changed; + PinosListener stream_add_buffer; + PinosListener stream_remove_buffer; + PinosListener stream_new_buffer; + GstAllocator *fd_allocator; GstStructure *properties; diff --git a/pinos/modules/module-autolink.c b/pinos/modules/module-autolink.c index fbfe88b03..f29960b01 100644 --- a/pinos/modules/module-autolink.c +++ b/pinos/modules/module-autolink.c @@ -26,18 +26,11 @@ #include "pinos/server/core.h" #include "pinos/server/module.h" -#define MODULE_URI "http://pinos.org/ns/module-autolink" -#define MODULE_PREFIX MODULE_URI "#" - typedef struct { PinosCore *core; PinosProperties *properties; PinosGlobal *global; - struct { - uint32_t module; - } uri; - PinosListener global_added; PinosListener global_removed; PinosListener port_added; @@ -57,8 +50,10 @@ try_link_port (PinosNode *node, PinosPort *port, ModuleImpl *impl) PinosLink *link; props = node->properties; - if (props == NULL) + if (props == NULL) { + pinos_log_debug ("module %p: node has no properties", impl); return; + } path = pinos_properties_get (props, "pinos.target.node"); @@ -275,10 +270,8 @@ module_new (PinosCore *core, pinos_signal_add (&core->port_unlinked, &impl->port_unlinked, on_link_port_unlinked); pinos_signal_add (&core->link_state_changed, &impl->link_state_changed, on_link_state_changed); - impl->uri.module = spa_id_map_get_id (core->uri.map, MODULE_URI); - impl->global = pinos_core_add_global (core, - impl->uri.module, + core->uri.module, impl); return impl; } @@ -306,5 +299,5 @@ bool pinos__module_init (PinosModule * module, const char * args) { module_new (module->core, NULL); - return TRUE; + return true; } diff --git a/pinos/modules/module-protocol-dbus.c b/pinos/modules/module-protocol-dbus.c index d8c506d24..5d8a0da62 100644 --- a/pinos/modules/module-protocol-dbus.c +++ b/pinos/modules/module-protocol-dbus.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -34,6 +35,7 @@ #include "pinos/server/module.h" #include "pinos/server/client-node.h" #include "pinos/server/client.h" +#include "pinos/server/resource.h" #include "pinos/server/link.h" #include "pinos/server/node-factory.h" #include "pinos/server/data-loop.h" @@ -41,9 +43,6 @@ #include "pinos/dbus/org-pinos.h" -#define PINOS_PROTOCOL_DBUS_URI "http://pinos.org/ns/protocol-dbus" -#define PINOS_PROTOCOL_DBUS_PREFIX PINOS_PROTOCOL_DBUS_URI "#" - typedef struct { PinosCore *core; SpaList link; @@ -51,10 +50,6 @@ typedef struct { PinosProperties *properties; - struct { - uint32_t protocol_dbus; - } uri; - GDBusConnection *connection; GDBusObjectManagerServer *server_manager; @@ -162,6 +157,51 @@ find_object (PinosProtocolDBus *impl, return NULL; } +struct _PinosProperties { + GHashTable *hashtable; +}; + +static void +add_to_variant (const gchar *key, const gchar *value, GVariantBuilder *b) +{ + g_variant_builder_add (b, "{sv}", key, g_variant_new_string (value)); +} + +static void +pinos_properties_init_builder (PinosProperties *properties, + GVariantBuilder *builder) +{ + g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}")); + g_hash_table_foreach (properties->hashtable, (GHFunc) add_to_variant, builder); +} + +static GVariant * +pinos_properties_to_variant (PinosProperties *properties) +{ + GVariantBuilder builder; + pinos_properties_init_builder (properties, &builder); + return g_variant_builder_end (&builder); +} + +static PinosProperties * +pinos_properties_from_variant (GVariant *variant) +{ + PinosProperties *props; + GVariantIter iter; + GVariant *value; + gchar *key; + + props = pinos_properties_new (NULL, NULL); + + g_variant_iter_init (&iter, variant); + while (g_variant_iter_loop (&iter, "{sv}", &key, &value)) + g_hash_table_replace (props->hashtable, + g_strdup (key), + g_variant_dup_string (value, NULL)); + + return props; +} + static void client_name_appeared_handler (GDBusConnection *connection, const gchar *name, @@ -176,8 +216,10 @@ client_name_appeared_handler (GDBusConnection *connection, static void client_destroy (PinosProtocolDBusClient *this) { - spa_list_remove (&this->link); - free (this->sender); + if (this->sender) { + spa_list_remove (&this->link); + free (this->sender); + } } static void @@ -279,10 +321,11 @@ handle_create_node (PinosDaemon1 *interface, if (object == NULL) goto object_failed; - pinos_client_add_resource (client, - impl->core->uri.node, - node, - (PinosDestroy) pinos_node_destroy); + pinos_resource_new (client, + SPA_ID_INVALID, + impl->core->uri.node, + node, + (PinosDestroy) pinos_node_destroy); object_path = object->object_path; pinos_log_debug ("protocol-dbus %p: added node %p with path %s", impl, node, object_path); @@ -350,6 +393,7 @@ handle_create_client_node (PinosDaemon1 *interface, int ctrl_fd, data_fd; int ctrl_idx, data_idx; PinosProtocolDBusObject *object; + int fd[2]; sender = g_dbus_method_invocation_get_sender (invocation); client = sender_get_client (impl, sender, TRUE); @@ -364,8 +408,13 @@ handle_create_client_node (PinosDaemon1 *interface, } } + if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0) + goto no_socket_pair; - node = pinos_client_node_new (impl->core, + ctrl_fd = fd[1]; + + node = pinos_client_node_new (client, + SPA_ID_INVALID, arg_name, props); @@ -373,17 +422,9 @@ handle_create_client_node (PinosDaemon1 *interface, if (object == NULL) goto object_failed; - if ((res = pinos_client_node_get_ctrl_socket (node, &ctrl_fd)) < 0) - goto no_socket; - if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0) goto no_socket; - pinos_client_add_resource (client, - impl->core->uri.client_node, - node, - (PinosDestroy) pinos_client_node_destroy); - object_path = object->object_path; pinos_log_debug ("protocol-dbus %p: add client-node %p, %s", impl, node, object_path); @@ -402,6 +443,11 @@ object_failed: pinos_log_debug ("protocol-dbus %p: could not create object", impl); goto exit_error; } +no_socket_pair: + { + pinos_log_debug ("protocol-dbus %p: could not create socketpair: %s", impl, strerror (errno)); + goto exit_error; + } no_socket: { pinos_log_debug ("protocol-dbus %p: could not create socket: %s", impl, strerror (errno)); @@ -519,7 +565,7 @@ on_global_added (PinosListener *listener, true, NULL); } - else if (global->type == impl->uri.protocol_dbus) { + else if (global->object == impl) { PinosProtocolDBus *proto = global->object; PinosProtocolDBusServer *server; PinosDaemon1 *iface; @@ -631,10 +677,8 @@ pinos_protocol_dbus_new (PinosCore *core, impl->server_manager = g_dbus_object_manager_server_new (PINOS_DBUS_OBJECT_PREFIX); - impl->uri.protocol_dbus = spa_id_map_get_id (core->uri.map, PINOS_PROTOCOL_DBUS_URI); - impl->global = pinos_core_add_global (core, - impl->uri.protocol_dbus, + core->uri.module, impl); return impl; } diff --git a/pinos/modules/module-protocol-native.c b/pinos/modules/module-protocol-native.c index 2c7b6fd04..df4cc8fdc 100644 --- a/pinos/modules/module-protocol-native.c +++ b/pinos/modules/module-protocol-native.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -36,14 +37,12 @@ #include "pinos/server/module.h" #include "pinos/server/client-node.h" #include "pinos/server/client.h" +#include "pinos/server/resource.h" #include "pinos/server/link.h" #include "pinos/server/node-factory.h" #include "pinos/server/data-loop.h" #include "pinos/server/main-loop.h" -#define PINOS_PROTOCOL_NATIVE_URI "http://pinos.org/ns/protocol-native" -#define PINOS_PROTOCOL_NATIVE_PREFIX PINOS_PROTOCOL_NATIVE_URI "#" - #ifndef UNIX_PATH_MAX #define UNIX_PATH_MAX 108 #endif @@ -69,10 +68,6 @@ typedef struct { PinosProperties *properties; - struct { - uint32_t protocol_native; - } uri; - SpaList socket_list; SpaList client_list; @@ -102,6 +97,7 @@ typedef struct { struct ucred ucred; SpaSource *source; PinosConnection *connection; + PinosResource *core_resource; } PinosProtocolNativeClient; typedef struct { @@ -153,9 +149,120 @@ static void client_destroy (PinosProtocolNativeClient *this) { spa_list_remove (&this->link); + pinos_loop_destroy_source (this->parent.impl->core->main_loop->loop, + this->source); + pinos_connection_destroy (this->connection); close (this->fd); } +static SpaResult +core_dispatch_func (void *object, + PinosMessageType type, + void *message, + void *data) +{ + PinosProtocolNativeClient *client = data; + PinosProtocolNative *impl = client->parent.impl; + PinosClient *c = client->parent.global->object; + + switch (type) { + case PINOS_MESSAGE_SUBSCRIBE: + { + PinosMessageSubscribe *m = message; + PinosGlobal *global; + PinosMessageNotifyDone nd; + + spa_list_for_each (global, &impl->core->global_list, link) { + PinosMessageNotifyGlobal ng; + + ng.id = global->id; + ng.type = spa_id_map_get_uri (impl->core->uri.map, global->type); + pinos_resource_send_message (client->core_resource, + PINOS_MESSAGE_NOTIFY_GLOBAL, + &ng, + false); + } + nd.seq = m->seq; + pinos_resource_send_message (client->core_resource, + PINOS_MESSAGE_NOTIFY_DONE, + &nd, + true); + break; + } + case PINOS_MESSAGE_CREATE_CLIENT_NODE: + { + PinosMessageCreateClientNode *m = message; + PinosClientNode *node; + SpaResult res; + int data_fd, i; + PinosMessageCreateClientNodeDone r; + PinosProperties *props; + + props = pinos_properties_new (NULL, NULL); + for (i = 0; i < m->props->n_items; i++) { + pinos_properties_set (props, m->props->items[i].key, + m->props->items[i].value); + } + + node = pinos_client_node_new (c, + m->id, + m->name, + props); + + if ((res = pinos_client_node_get_data_socket (node, &data_fd)) < 0) { + pinos_log_error ("can't get data fd"); + break; + } + + r.seq = m->seq; + r.datafd = data_fd; + pinos_resource_send_message (node->resource, + PINOS_MESSAGE_CREATE_CLIENT_NODE_DONE, + &r, + true); + break; + } + default: + pinos_log_error ("unhandled message %d", type); + break; + } + return SPA_RESULT_OK; +} + +static SpaResult +client_send_func (void *object, + uint32_t id, + PinosMessageType type, + void *message, + bool flush, + void *data) +{ + PinosProtocolNativeClient *client = data; + + pinos_log_debug ("protocol-native %p: sending message %d to %u", client->parent.impl, type, id); + + pinos_connection_add_message (client->connection, + id, + type, + message); + if (flush) + pinos_connection_flush (client->connection); + + return SPA_RESULT_OK; +} + +static PinosResource * +find_resource (PinosClient *client, uint32_t id) +{ + PinosResource *resource; + + spa_list_for_each (resource, &client->resource_list, link) { + if (resource->id == id) + return resource; + } + return NULL; +} + static void connection_data (SpaSource *source, int fd, @@ -164,15 +271,36 @@ connection_data (SpaSource *source, { PinosProtocolNativeClient *client = data; PinosConnection *conn = client->connection; + PinosMessageType type; + uint32_t id; + size_t size; - while (pinos_connection_has_next (conn)) { - PinosMessageType type = pinos_connection_get_type (conn); + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + pinos_client_destroy (client->parent.global->object); + return; + } - switch (type) { - default: - pinos_log_error ("unhandled message %d", type); - break; + while (pinos_connection_get_next (conn, &type, &id, &size)) { + PinosResource *resource; + void *message = alloca (size); + + pinos_log_debug ("protocol-native %p: got message %d from %u", client->parent.impl, type, id); + + if (!pinos_connection_parse_message (conn, message)) { + pinos_log_error ("protocol-native %p: failed to parse message", client->parent.impl); + continue; } + + resource = find_resource (client->parent.global->object, id); + if (resource == NULL) { + pinos_log_error ("protocol-native %p: unknown resource %u", client->parent.impl, id); + continue; + } + + resource->dispatch_func (resource, + type, + message, + resource->dispatch_data); } } @@ -190,11 +318,22 @@ client_new (PinosProtocolNative *impl, close (fd); return NULL; } + client->send_func = client_send_func; + client->send_data = this; + + this->core_resource = pinos_resource_new (client, + 0, + impl->core->uri.core, + impl->core, + NULL); + + this->core_resource->dispatch_func = core_dispatch_func; + this->core_resource->dispatch_data = this; this->fd = fd; this->source = pinos_loop_add_io (impl->core->main_loop->loop, this->fd, - SPA_IO_IN, + SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this); @@ -224,7 +363,10 @@ on_global_added (PinosListener *listener, global, (PinosDestroy) client_destroy); } else if (global->type == impl->core->uri.node) { - } else if (global->type == impl->uri.protocol_native) { + object_new (sizeof (PinosProtocolNativeNode), + impl, + global, + NULL); } else if (global->type == impl->core->uri.link) { } } @@ -234,7 +376,7 @@ on_global_removed (PinosListener *listener, PinosCore *core, PinosGlobal *global) { - PinosProtocolNative *impl = SPA_CONTAINER_OF (listener, PinosProtocolNative, global_added); + PinosProtocolNative *impl = SPA_CONTAINER_OF (listener, PinosProtocolNative, global_removed); PinosProtocolNativeObject *object; if ((object = find_object (impl, global->object))) { @@ -284,7 +426,7 @@ init_socket_name (Socket *s, const char *name) s->addr.sun_family = AF_LOCAL; name_size = snprintf (s->addr.sun_path, sizeof (s->addr.sun_path), - "%s/%s", runtime_dir, name) + 1; + "%s/%s", runtime_dir, name) + 1; s->core_name = (s->addr.sun_path + name_size - 1) - strlen (name); @@ -434,10 +576,8 @@ pinos_protocol_native_new (PinosCore *core, pinos_signal_add (&core->global_added, &impl->global_added, on_global_added); pinos_signal_add (&core->global_removed, &impl->global_removed, on_global_removed); - impl->uri.protocol_native = spa_id_map_get_id (core->uri.map, PINOS_PROTOCOL_NATIVE_URI); - impl->global = pinos_core_add_global (core, - impl->uri.protocol_native, + core->uri.module, impl); return impl; @@ -472,5 +612,5 @@ bool pinos__module_init (PinosModule * module, const char * args) { pinos_protocol_native_new (module->core, NULL); - return TRUE; + return true; } diff --git a/pinos/modules/module-suspend-on-idle.c b/pinos/modules/module-suspend-on-idle.c index 11090d8be..fe9aac47b 100644 --- a/pinos/modules/module-suspend-on-idle.c +++ b/pinos/modules/module-suspend-on-idle.c @@ -26,18 +26,11 @@ #include "pinos/server/core.h" #include "pinos/server/module.h" -#define MODULE_URI "http://pinos.org/ns/module-suspend-on-idle" -#define MODULE_PREFIX MODULE_URI "#" - typedef struct { PinosCore *core; PinosProperties *properties; PinosGlobal *global; - struct { - uint32_t module; - } uri; - PinosListener global_added; PinosListener global_removed; PinosListener node_state_request; @@ -196,10 +189,8 @@ module_new (PinosCore *core, pinos_signal_add (&core->node_state_request, &impl->node_state_request, on_node_state_request); pinos_signal_add (&core->node_state_changed, &impl->node_state_changed, on_node_state_changed); - impl->uri.module = spa_id_map_get_id (core->uri.map, MODULE_URI); - impl->global = pinos_core_add_global (core, - impl->uri.module, + core->uri.module, impl); return impl; } @@ -221,5 +212,5 @@ bool pinos__module_init (PinosModule * module, const char * args) { module_new (module->core, NULL); - return TRUE; + return true; } diff --git a/pinos/modules/spa/module.c b/pinos/modules/spa/module.c index e8c60dc3c..f5be2aba8 100644 --- a/pinos/modules/spa/module.c +++ b/pinos/modules/spa/module.c @@ -89,5 +89,5 @@ pinos__module_init (PinosModule * module, const char * args) "videotestsrc", video_props); - return TRUE; + return true; } diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index b8d622508..2886ba931 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -29,7 +29,6 @@ #include #include "pinos/client/pinos.h" -#include "pinos/client/private.h" #include "pinos/client/connection.h" #include "pinos/client/serialize.h" #include "pinos/client/transport.h" @@ -99,8 +98,7 @@ struct _SpaProxy SpaNodeEventCallback event_cb; void *user_data; - SpaSource ctrl_source; - PinosConnection *conn; + PinosResource *resource; SpaSource data_source; @@ -125,7 +123,6 @@ typedef struct PinosListener transport_changed; PinosListener loop_changed; - int ctrl_fd; int data_fd; } PinosClientNodeImpl; @@ -195,13 +192,11 @@ spa_proxy_node_send_command (SpaNode *node, /* send start */ cnc.seq = this->seq++; cnc.command = command; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_NODE_COMMAND, &cnc); - - if (!pinos_connection_flush (this->conn)) { - spa_log_error (this->log, "proxy %p: error writing connection", this); - res = SPA_RESULT_ERROR; - } else - res = SPA_RESULT_RETURN_ASYNC (cnc.seq); + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_NODE_COMMAND, + &cnc, + true); + res = SPA_RESULT_RETURN_ASYNC (cnc.seq); break; } @@ -211,12 +206,10 @@ spa_proxy_node_send_command (SpaNode *node, /* send start */ cnc.command = command; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_NODE_COMMAND, &cnc); - - if (!pinos_connection_flush (this->conn)) { - spa_log_error (this->log, "proxy %p: error writing connection", this); - res = SPA_RESULT_ERROR; - } + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_NODE_COMMAND, + &cnc, + true); break; } } @@ -489,11 +482,10 @@ spa_proxy_node_port_set_format (SpaNode *node, sf.port_id = port_id; sf.flags = flags; sf.format = (SpaFormat *) format; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_SET_FORMAT, &sf); - - if (!pinos_connection_flush (this->conn)) - spa_log_error (this->log, "proxy %p: error writing connection", this); - + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_SET_FORMAT, + &sf, + true); return SPA_RESULT_RETURN_ASYNC (sf.seq); } @@ -668,12 +660,14 @@ spa_proxy_node_port_use_buffers (SpaNode *node, am.port_id = port_id; am.mem_id = n_mem; am.type = d->type; - am.fd_index = pinos_connection_add_fd (this->conn, d->fd, false); + am.memfd = d->fd; am.flags = d->flags; am.offset = d->offset; am.size = d->maxsize; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_ADD_MEM, &am); - + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_ADD_MEM, + &am, + false); b->buffer.datas[j].type = SPA_DATA_TYPE_ID; b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem); n_mem++; @@ -732,11 +726,14 @@ spa_proxy_node_port_use_buffers (SpaNode *node, am.port_id = port_id; am.mem_id = port->buffer_mem_id; am.type = SPA_DATA_TYPE_MEMFD; - am.fd_index = pinos_connection_add_fd (this->conn, port->buffer_mem.fd, false); + am.memfd = port->buffer_mem.fd; am.flags = 0; am.offset = 0; am.size = size; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_ADD_MEM, &am); + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_ADD_MEM, + &am, + false); memref = alloca (n_buffers * sizeof (PinosMessageMemRef)); for (i = 0; i < n_buffers; i++) { @@ -754,11 +751,10 @@ spa_proxy_node_port_use_buffers (SpaNode *node, ub.port_id = port_id; ub.n_buffers = n_buffers; ub.buffers = memref; - pinos_connection_add_message (this->conn, PINOS_MESSAGE_USE_BUFFERS, &ub); - - if (!pinos_connection_flush (this->conn)) - spa_log_error (this->log, "proxy %p: error writing connection", this); - + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_USE_BUFFERS, + &ub, + true); return SPA_RESULT_RETURN_ASYNC (ub.seq); } @@ -983,118 +979,95 @@ handle_node_event (SpaProxy *this, } static SpaResult -parse_connection (SpaProxy *this) +client_node_dispatch_func (void *object, + PinosMessageType type, + void *message, + void *data) { - PinosConnection *conn = this->conn; + PinosClientNode *node = data; + PinosClientNodeImpl *impl = SPA_CONTAINER_OF (node, PinosClientNodeImpl, this); + SpaProxy *this = &impl->proxy; - while (pinos_connection_has_next (conn)) { - PinosMessageType type = pinos_connection_get_type (conn); + switch (type) { + case PINOS_MESSAGE_INVALID: + case PINOS_MESSAGE_ADD_PORT: + case PINOS_MESSAGE_REMOVE_PORT: + case PINOS_MESSAGE_SET_FORMAT: + case PINOS_MESSAGE_SET_PROPERTY: + case PINOS_MESSAGE_NODE_COMMAND: + case PINOS_MESSAGE_PORT_COMMAND: + case PINOS_MESSAGE_TRANSPORT_UPDATE: + spa_log_error (this->log, "proxy %p: got unexpected command %d", this, type); + break; - switch (type) { - case PINOS_MESSAGE_INVALID: - case PINOS_MESSAGE_ADD_PORT: - case PINOS_MESSAGE_REMOVE_PORT: - case PINOS_MESSAGE_SET_FORMAT: - case PINOS_MESSAGE_SET_PROPERTY: - case PINOS_MESSAGE_NODE_COMMAND: - case PINOS_MESSAGE_PORT_COMMAND: - case PINOS_MESSAGE_PROCESS_BUFFER: - case PINOS_MESSAGE_TRANSPORT_UPDATE: - spa_log_error (this->log, "proxy %p: got unexpected command %d", this, type); + case PINOS_MESSAGE_NODE_UPDATE: + { + PinosMessageNodeUpdate *nu = message; + + if (nu->change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS) + this->max_inputs = nu->max_input_ports; + if (nu->change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS) + this->max_outputs = nu->max_output_ports; + + spa_log_info (this->log, "proxy %p: got node update %d, max_in %u, max_out %u", this, type, + this->max_inputs, this->max_outputs); + + break; + } + + case PINOS_MESSAGE_PORT_UPDATE: + { + PinosMessagePortUpdate *pu = message; + bool remove; + + spa_log_info (this->log, "proxy %p: got port update %d", this, type); + if (!CHECK_PORT_ID (this, pu->direction, pu->port_id)) break; - case PINOS_MESSAGE_NODE_UPDATE: - { - PinosMessageNodeUpdate nu; + remove = (pu->change_mask == 0); - if (!pinos_connection_parse_message (conn, &nu)) - break; - - if (nu.change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_INPUTS) - this->max_inputs = nu.max_input_ports; - if (nu.change_mask & PINOS_MESSAGE_NODE_UPDATE_MAX_OUTPUTS) - this->max_outputs = nu.max_output_ports; - - spa_log_info (this->log, "proxy %p: got node update %d, max_in %u, max_out %u", this, type, - this->max_inputs, this->max_outputs); - - break; + if (remove) { + do_uninit_port (this, pu->direction, pu->port_id); + } else { + do_update_port (this, pu); } + break; + } - case PINOS_MESSAGE_PORT_UPDATE: - { - PinosMessagePortUpdate pu; - bool remove; + case PINOS_MESSAGE_PORT_STATUS_CHANGE: + { + spa_log_warn (this->log, "proxy %p: command not implemented %d", this, type); + break; + } - spa_log_info (this->log, "proxy %p: got port update %d", this, type); - if (!pinos_connection_parse_message (conn, &pu)) - break; + case PINOS_MESSAGE_NODE_STATE_CHANGE: + { + PinosMessageNodeStateChange *sc = message; + SpaNodeState old = this->node.state; - if (!CHECK_PORT_ID (this, pu.direction, pu.port_id)) - break; + spa_log_info (this->log, "proxy %p: got node state change %d -> %d", this, old, sc->state); + this->node.state = sc->state; + if (old == SPA_NODE_STATE_INIT) + send_async_complete (this, 0, SPA_RESULT_OK); - remove = (pu.change_mask == 0); + break; + } - if (remove) { - do_uninit_port (this, pu.direction, pu.port_id); - } else { - do_update_port (this, &pu); - } - break; - } + case PINOS_MESSAGE_ADD_MEM: + break; + case PINOS_MESSAGE_USE_BUFFERS: + break; - case PINOS_MESSAGE_PORT_STATUS_CHANGE: - { - spa_log_warn (this->log, "proxy %p: command not implemented %d", this, type); - break; - } - - case PINOS_MESSAGE_NODE_STATE_CHANGE: - { - PinosMessageNodeStateChange sc; - SpaNodeState old = this->node.state; - - if (!pinos_connection_parse_message (conn, &sc)) - break; - - spa_log_info (this->log, "proxy %p: got node state change %d -> %d", this, old, sc.state); - this->node.state = sc.state; - if (old == SPA_NODE_STATE_INIT) - send_async_complete (this, 0, SPA_RESULT_OK); - - break; - } - - case PINOS_MESSAGE_ADD_MEM: - break; - case PINOS_MESSAGE_USE_BUFFERS: - break; - - case PINOS_MESSAGE_NODE_EVENT: - { - PinosMessageNodeEvent cne; - - if (!pinos_connection_parse_message (conn, &cne)) - break; - - handle_node_event (this, cne.event); - break; - } + case PINOS_MESSAGE_NODE_EVENT: + { + PinosMessageNodeEvent *cne = message; + handle_node_event (this, cne->event); + break; } } - return SPA_RESULT_OK; } -static void -proxy_on_fd_events (SpaSource *source) -{ - SpaProxy *this = source->data; - - if (source->rmask & SPA_IO_IN) - parse_connection (this); -} - static void proxy_on_data_fd_events (SpaSource *source) { @@ -1184,16 +1157,10 @@ proxy_init (SpaProxy *this, this->node = proxy_node; - this->ctrl_source.func = proxy_on_fd_events; - this->ctrl_source.data = this; - this->ctrl_source.fd = -1; - this->ctrl_source.mask = SPA_IO_IN | SPA_IO_ERR; - this->ctrl_source.rmask = 0; - this->data_source.func = proxy_on_data_fd_events; this->data_source.data = this; this->data_source.fd = -1; - this->data_source.mask = SPA_IO_IN | SPA_IO_ERR; + this->data_source.mask = SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP; this->data_source.rmask = 0; return SPA_RESULT_RETURN_ASYNC (this->seq++); @@ -1207,17 +1174,16 @@ on_transport_changed (PinosListener *listener, PinosClientNode *this = &impl->this; PinosTransportInfo info; PinosMessageTransportUpdate tu; - PinosConnection *conn = impl->proxy.conn; pinos_transport_get_info (node->transport, &info); - tu.memfd_index = pinos_connection_add_fd (conn, info.memfd, false); + tu.memfd = info.memfd; tu.offset = info.offset; tu.size = info.size; - pinos_connection_add_message (conn, PINOS_MESSAGE_TRANSPORT_UPDATE, &tu); - - if (!pinos_connection_flush (conn)) - pinos_log_error ("client-node %p: error writing connection", this); + pinos_resource_send_message (this->resource, + PINOS_MESSAGE_TRANSPORT_UPDATE, + &tu, + true); } static void @@ -1241,10 +1207,6 @@ proxy_clear (SpaProxy *this) if (this->out_ports[i].valid) clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i); } - if (this->ctrl_source.fd != -1) { - spa_loop_remove_source (this->main_loop, &this->ctrl_source); - close (this->ctrl_source.fd); - } if (this->data_source.fd != -1) { spa_loop_remove_source (this->data_loop, &this->data_source); close (this->data_source.fd); @@ -1264,25 +1226,25 @@ proxy_clear (SpaProxy *this) * Returns: a new #PinosNode */ PinosClientNode * -pinos_client_node_new (PinosCore *core, - const gchar *name, +pinos_client_node_new (PinosClient *client, + uint32_t id, + const char *name, PinosProperties *properties) { PinosClientNodeImpl *impl; PinosClientNode *this; impl = calloc (1, sizeof (PinosClientNodeImpl)); - impl->core = core; - impl->ctrl_fd = -1; - impl->data_fd = -1; this = &impl->this; + impl->core = client->core; + impl->data_fd = -1; pinos_log_debug ("client-node %p: new", impl); pinos_signal_init (&this->destroy_signal); - proxy_init (&impl->proxy, NULL, core->support, core->n_support); + proxy_init (&impl->proxy, NULL, client->core->support, client->core->n_support); - this->node = pinos_node_new (core, + this->node = pinos_node_new (client->core, name, &impl->proxy.node, NULL, @@ -1298,12 +1260,22 @@ pinos_client_node_new (PinosCore *core, &impl->loop_changed, on_loop_changed); + this->resource = pinos_resource_new (client, + id, + client->core->uri.client_node, + this, + (PinosDestroy) pinos_client_node_destroy); + impl->proxy.resource = this->resource; + + this->resource->dispatch_func = client_node_dispatch_func; + this->resource->dispatch_data = this; + return this; } static void on_node_remove (PinosNode *node, - gpointer data, + void *data, SpaResult res) { PinosClientNode *this = data; @@ -1312,8 +1284,6 @@ on_node_remove (PinosNode *node, pinos_log_debug ("client-node %p: finalize", node); proxy_clear (&impl->proxy); - if (impl->ctrl_fd != -1) - close (impl->ctrl_fd); if (impl->data_fd != -1) close (impl->data_fd); free (impl); @@ -1340,37 +1310,6 @@ pinos_client_node_destroy (PinosClientNode * this) return res; } -/** - * pinos_client_node_get_ctrl_socket: - * @node: a #PinosClientNode - * @fd: a result socket - * - * Create or return a previously create socket pair for @node. The - * socket for the other end is returned. - * - * Returns: %SPA_RESULT_OK on success - */ -SpaResult -pinos_client_node_get_ctrl_socket (PinosClientNode *this, - int *fd) -{ - PinosClientNodeImpl *impl = SPA_CONTAINER_OF (this, PinosClientNodeImpl, this); - - if (impl->ctrl_fd == -1) { - int fd[2]; - - if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0, fd) != 0) - return SPA_RESULT_ERRNO; - - impl->proxy.ctrl_source.fd = fd[0]; - impl->proxy.conn = pinos_connection_new (impl->proxy.ctrl_source.fd); - spa_loop_add_source (impl->proxy.main_loop, &impl->proxy.ctrl_source); - impl->ctrl_fd = fd[1]; - } - *fd = impl->ctrl_fd; - return SPA_RESULT_OK; -} - /** * pinos_client_node_get_data_socket: * @node: a #PinosClientNode @@ -1390,11 +1329,12 @@ pinos_client_node_get_data_socket (PinosClientNode *this, if (impl->data_fd == -1) { int fd[2]; - if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0) + if (socketpair (AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fd) != 0) return SPA_RESULT_ERRNO; impl->proxy.data_source.fd = fd[0]; spa_loop_add_source (impl->proxy.data_loop, &impl->proxy.data_source); + pinos_log_debug ("client-node %p: add data fd %d", this, fd[0]); impl->data_fd = fd[1]; } *fd = impl->data_fd; diff --git a/pinos/server/client-node.h b/pinos/server/client-node.h index 5be81bbbf..afec213bd 100644 --- a/pinos/server/client-node.h +++ b/pinos/server/client-node.h @@ -39,18 +39,25 @@ typedef struct _PinosClientNode PinosClientNode; struct _PinosClientNode { PinosNode *node; + PinosClient *client; + PinosResource *resource; + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosClientNode *node)); }; -PinosClientNode * pinos_client_node_new (PinosCore *core, - const gchar *name, +PinosClientNode * pinos_client_node_new (PinosClient *client, + uint32_t id, + const char *name, PinosProperties *properties); SpaResult pinos_client_node_destroy (PinosClientNode *node); -SpaResult pinos_client_node_get_ctrl_socket (PinosClientNode *node, int *fd); SpaResult pinos_client_node_get_data_socket (PinosClientNode *node, int *fd); +SpaResult pinos_client_node_dispatch_message (PinosClientNode *node, + PinosMessageType type, + void *message); + #ifdef __cplusplus } #endif diff --git a/pinos/server/client.c b/pinos/server/client.c index 724336691..f4f594737 100644 --- a/pinos/server/client.c +++ b/pinos/server/client.c @@ -21,55 +21,13 @@ #include "pinos/client/pinos.h" #include "pinos/server/client.h" - -#include "pinos/dbus/org-pinos.h" +#include "pinos/server/resource.h" typedef struct { PinosClient this; } PinosClientImpl; -PinosResource * -pinos_client_add_resource (PinosClient *client, - uint32_t type, - void *object, - PinosDestroy destroy) -{ - PinosResource *resource; - - resource = calloc (1, sizeof (PinosResource)); - resource->core = client->core; - resource->client = client; - resource->id = 0; - resource->type = type; - resource->object = object; - resource->destroy = destroy; - - pinos_signal_init (&resource->destroy_signal); - - pinos_log_debug ("client %p: add resource %p", client, resource); - - spa_list_insert (client->resource_list.prev, &resource->link); - - return resource; -} - -SpaResult -pinos_resource_destroy (PinosResource *resource) -{ - pinos_log_debug ("resource %p: destroy", resource); - pinos_signal_emit (&resource->destroy_signal, resource); - - spa_list_remove (&resource->link); - - if (resource->destroy) - resource->destroy (resource->object); - - free (resource); - - return SPA_RESULT_OK; -} - /** * pinos_client_new: * @daemon: a #PinosDaemon diff --git a/pinos/server/client.h b/pinos/server/client.h index de0e78b99..2dfe9f4dd 100644 --- a/pinos/server/client.h +++ b/pinos/server/client.h @@ -28,26 +28,9 @@ extern "C" { #define PINOS_CLIENT_PREFIX PINOS_CLIENT_URI "#" typedef struct _PinosClient PinosClient; -typedef struct _PinosResource PinosResource; - -typedef void (*PinosDestroy) (void *object); #include - -struct _PinosResource { - PinosCore *core; - SpaList link; - - PinosClient *client; - - uint32_t id; - uint32_t type; - void *object; - PinosDestroy destroy; - - PINOS_SIGNAL (destroy_signal, (PinosListener *listener, - PinosResource *resource)); -}; +#include /** * PinosClient: @@ -63,6 +46,9 @@ struct _PinosClient { SpaList resource_list; + PinosSendFunc send_func; + void *send_data; + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, PinosClient *client)); }; @@ -71,14 +57,6 @@ PinosClient * pinos_client_new (PinosCore *core, PinosProperties *properties); SpaResult pinos_client_destroy (PinosClient *client); - -PinosResource * pinos_client_add_resource (PinosClient *client, - uint32_t type, - void *object, - PinosDestroy destroy); - -SpaResult pinos_resource_destroy (PinosResource *resource); - #ifdef __cplusplus } #endif diff --git a/pinos/server/command.c b/pinos/server/command.c index 33946ab4e..2e359b43f 100644 --- a/pinos/server/command.c +++ b/pinos/server/command.c @@ -27,17 +27,17 @@ #include "command.h" typedef bool (*PinosCommandFunc) (PinosCommand *command, - PinosCore *core, - char **err); + PinosCore *core, + char **err); static bool execute_command_module_load (PinosCommand *command, - PinosCore *core, + PinosCore *core, + char **err); + +typedef PinosCommand * (*PinosCommandParseFunc) (const char *line, char **err); -typedef PinosCommand * (*PinosCommandParseFunc) (const gchar *line, - char **err); - -static PinosCommand * parse_command_module_load (const gchar *line, +static PinosCommand * parse_command_module_load (const char *line, char **err); typedef struct @@ -51,7 +51,7 @@ typedef struct typedef struct _CommandParse { - const gchar *name; + const char *name; PinosCommandParseFunc func; } CommandParse; @@ -60,7 +60,7 @@ static const CommandParse parsers[] = { {NULL, NULL} }; -static const gchar whitespace[] = " \t"; +static const char whitespace[] = " \t"; static PinosCommand * parse_command_module_load (const char * line, char ** err) @@ -130,8 +130,8 @@ pinos_command_parse (const char *line, { PinosCommand *command = NULL; const CommandParse *parse; - gchar *name; - gsize len; + char *name; + size_t len; len = strcspn (line, whitespace); diff --git a/pinos/server/core.c b/pinos/server/core.c index c4a3e4a39..9fa54fc69 100644 --- a/pinos/server/core.c +++ b/pinos/server/core.c @@ -73,6 +73,10 @@ pinos_core_new (PinosMainLoop *main_loop) pinos_signal_init (&this->node_unlink); pinos_signal_init (&this->node_unlink_done); + this->global = pinos_core_add_global (this, + this->uri.core, + this); + return this; } diff --git a/pinos/server/core.h b/pinos/server/core.h index 03406f40c..7f2a7aadc 100644 --- a/pinos/server/core.h +++ b/pinos/server/core.h @@ -27,6 +27,9 @@ extern "C" { typedef struct _PinosCore PinosCore; typedef struct _PinosGlobal PinosGlobal; +#define PINOS_CORE_URI "http://pinos.org/ns/core" +#define PINOS_CORE_PREFIX PINOS_CORE_URI "#" + #include #include @@ -53,6 +56,8 @@ struct _PinosGlobal { * Pinos core object class. */ struct _PinosCore { + PinosGlobal *global; + PinosURI uri; PinosMap objects; diff --git a/pinos/server/main-loop.c b/pinos/server/main-loop.c index 2b2af0397..95789e6a8 100644 --- a/pinos/server/main-loop.c +++ b/pinos/server/main-loop.c @@ -95,9 +95,21 @@ do_add_source (SpaLoop *loop, GIOChannel *channel; GSource *s; LoopData *data; + GIOCondition cond; channel = g_io_channel_unix_new (source->fd); - s = g_io_create_watch (channel, G_IO_IN); + + cond = 0; + if (source->mask & SPA_IO_IN) + cond |= G_IO_IN; + if (source->mask & SPA_IO_OUT) + cond |= G_IO_OUT; + if (source->mask & SPA_IO_ERR) + cond |= G_IO_ERR; + if (source->mask & SPA_IO_HUP) + cond |= G_IO_HUP; + + s = g_io_create_watch (channel, cond); g_io_channel_unref (channel); data = g_new0 (LoopData, 1); diff --git a/pinos/server/meson.build b/pinos/server/meson.build index 8eeab3be9..31806a992 100644 --- a/pinos/server/meson.build +++ b/pinos/server/meson.build @@ -10,6 +10,7 @@ pinoscore_headers = [ 'node.h', 'node-factory.h', 'port.h', + 'resource.h', 'uri.h', ] @@ -25,6 +26,7 @@ pinoscore_sources = [ 'node.c', 'node-factory.c', 'port.c', + 'resource.c', 'uri.c', ] diff --git a/pinos/server/module.c b/pinos/server/module.c index 9b5d4bdcc..b253ed4b8 100644 --- a/pinos/server/module.c +++ b/pinos/server/module.c @@ -23,6 +23,7 @@ #endif #include +#include #include "pinos/client/pinos.h" #include "pinos/client/utils.h" @@ -40,7 +41,7 @@ typedef struct static char * find_module (const char * path, const char *name) { - gchar *filename; + char *filename; GDir *dir; const gchar *entry; GError *err = NULL; diff --git a/pinos/server/module.h b/pinos/server/module.h index b85c5fe55..5ced81060 100644 --- a/pinos/server/module.h +++ b/pinos/server/module.h @@ -27,6 +27,9 @@ extern "C" { #include +#define PINOS_MODULE_URI "http://pinos.org/ns/module" +#define PINOS_MODULE_PREFIX PINOS_MODULE_URI "#" + typedef struct _PinosModule PinosModule; struct _PinosModule { @@ -52,8 +55,8 @@ struct _PinosModule { typedef bool (*PinosModuleInitFunc) (PinosModule *module, char *args); PinosModule * pinos_module_load (PinosCore *core, - const gchar *name, - const gchar *args, + const char *name, + const char *args, char **err); void pinos_module_destroy (PinosModule *module); diff --git a/pinos/server/resource.c b/pinos/server/resource.c new file mode 100644 index 000000000..9b43c0b97 --- /dev/null +++ b/pinos/server/resource.c @@ -0,0 +1,86 @@ +/* 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. + */ + +#include + +#include "pinos/server/resource.h" + +PinosResource * +pinos_resource_new (PinosClient *client, + uint32_t id, + uint32_t type, + void *object, + PinosDestroy destroy) +{ + PinosResource *resource; + + resource = calloc (1, sizeof (PinosResource)); + pinos_log_debug ("resource %p: new for client %p", resource, client); + + resource->core = client->core; + resource->client = client; + resource->id = id; + resource->type = type; + resource->object = object; + resource->destroy = destroy; + + resource->send_func = client->send_func; + resource->send_data = client->send_data; + + pinos_signal_init (&resource->destroy_signal); + + spa_list_insert (client->resource_list.prev, &resource->link); + + return resource; +} + +SpaResult +pinos_resource_destroy (PinosResource *resource) +{ + pinos_log_debug ("resource %p: destroy", resource); + pinos_signal_emit (&resource->destroy_signal, resource); + + spa_list_remove (&resource->link); + + if (resource->destroy) + resource->destroy (resource->object); + + free (resource); + + return SPA_RESULT_OK; +} + +SpaResult +pinos_resource_send_message (PinosResource *resource, + PinosMessageType type, + void *message, + bool flush) +{ + if (resource->send_func) + return resource->send_func (resource, + resource->id, + type, + message, + flush, + resource->send_data); + + pinos_log_error ("resource %p: send func not implemented", resource); + + return SPA_RESULT_NOT_IMPLEMENTED; +} diff --git a/pinos/server/resource.h b/pinos/server/resource.h new file mode 100644 index 000000000..d13981ae8 --- /dev/null +++ b/pinos/server/resource.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_RESOURCE_H__ +#define __PINOS_RESOURCE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define PINOS_RESOURCE_URI "http://pinos.org/ns/resource" +#define PINOS_RESOURCE_PREFIX PINOS_RESOURCE_URI "#" + +typedef struct _PinosResource PinosResource; + +#include + +typedef void (*PinosDestroy) (void *object); + +typedef SpaResult (*PinosSendFunc) (void *object, + uint32_t id, + PinosMessageType type, + void *message, + bool flush, + void *data); + +typedef SpaResult (*PinosDispatchFunc) (void *object, + PinosMessageType type, + void *message, + void *data); + +struct _PinosResource { + PinosCore *core; + SpaList link; + + PinosClient *client; + + uint32_t id; + uint32_t type; + void *object; + PinosDestroy destroy; + + PinosSendFunc send_func; + void *send_data; + PinosDispatchFunc dispatch_func; + void *dispatch_data; + + PINOS_SIGNAL (destroy_signal, (PinosListener *listener, + PinosResource *resource)); +}; + +PinosResource * pinos_resource_new (PinosClient *client, + uint32_t id, + uint32_t type, + void *object, + PinosDestroy destroy); +SpaResult pinos_resource_destroy (PinosResource *resource); + +SpaResult pinos_resource_send_message (PinosResource *resource, + PinosMessageType type, + void *message, + bool flush); + +#ifdef __cplusplus +} +#endif + +#endif /* __PINOS_RESOURCE_H__ */ diff --git a/pinos/server/uri.c b/pinos/server/uri.c index 4e9fc9568..e517727ff 100644 --- a/pinos/server/uri.c +++ b/pinos/server/uri.c @@ -26,6 +26,7 @@ #include "pinos/server/node-factory.h" #include "pinos/server/client.h" #include "pinos/server/client-node.h" +#include "pinos/server/module.h" #include "spa/include/spa/monitor.h" @@ -34,11 +35,13 @@ pinos_uri_init (PinosURI *uri) { uri->map = pinos_id_map_get_default(); + uri->core = spa_id_map_get_id (uri->map, PINOS_CORE_URI); uri->node = spa_id_map_get_id (uri->map, PINOS_NODE_URI); uri->node_factory = spa_id_map_get_id (uri->map, PINOS_NODE_FACTORY_URI); uri->link = spa_id_map_get_id (uri->map, PINOS_LINK_URI); uri->client = spa_id_map_get_id (uri->map, PINOS_CLIENT_URI); uri->client_node = spa_id_map_get_id (uri->map, PINOS_CLIENT_NODE_URI); + uri->module = spa_id_map_get_id (uri->map, PINOS_MODULE_URI); uri->spa_node = spa_id_map_get_id (uri->map, SPA_NODE_URI); uri->spa_clock = spa_id_map_get_id (uri->map, SPA_CLOCK_URI); diff --git a/pinos/server/uri.h b/pinos/server/uri.h index 8ea3e9e96..52eca7e4b 100644 --- a/pinos/server/uri.h +++ b/pinos/server/uri.h @@ -40,11 +40,13 @@ typedef struct _PinosURI PinosURI; struct _PinosURI { SpaIDMap *map; + uint32_t core; uint32_t node; uint32_t node_factory; uint32_t link; uint32_t client; uint32_t client_node; + uint32_t module; uint32_t spa_node; uint32_t spa_clock; diff --git a/pinos/tools/pinos-monitor.c b/pinos/tools/pinos-monitor.c index c94d24aed..ed261abd5 100644 --- a/pinos/tools/pinos-monitor.c +++ b/pinos/tools/pinos-monitor.c @@ -17,218 +17,192 @@ * Boston, MA 02110-1301, USA. */ -#include +#include -static GMainLoop *loop; +#include +#include + +typedef struct { + bool running; + PinosLoop *loop; + PinosContext *context; + + PinosListener on_state_changed; +} Data; static void -print_properties (PinosProperties *props, gchar mark) +print_properties (PinosProperties *props, char mark) { - gpointer state = NULL; - const gchar *key; + void *state = NULL; + const char *key; if (props == NULL) return; - g_print ("%c\tproperties:\n", mark); + printf ("%c\tproperties:\n", mark); while ((key = pinos_properties_iterate (props, &state))) { - g_print ("%c\t\t%s = \"%s\"\n", mark, key, pinos_properties_get (props, key)); - } -} - -static void -info_ready (GObject *o, GAsyncResult *res, gpointer user_data) -{ - GError *error = NULL; - - if (!pinos_context_info_finish (o, res, &error)) { - g_printerr ("introspection failure: %s\n", error->message); - g_clear_error (&error); + printf ("%c\t\t%s = \"%s\"\n", mark, key, pinos_properties_get (props, key)); } } typedef struct { - gboolean print_mark; - gboolean print_all; + bool print_mark; + bool print_all; } DumpData; #define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ') static void -dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, gpointer user_data) +dump_daemon_info (PinosContext *c, const PinosDaemonInfo *info, void * user_data) { DumpData *data = user_data; - g_print ("\tid: %p\n", info->id); - g_print ("\tdaemon-path: \"%s\"\n", info->daemon_path); + printf ("\tid: %u\n", info->id); if (data->print_all) { - g_print ("%c\tuser-name: \"%s\"\n", MARK_CHANGE (0), info->user_name); - g_print ("%c\thost-name: \"%s\"\n", MARK_CHANGE (1), info->host_name); - g_print ("%c\tversion: \"%s\"\n", MARK_CHANGE (2), info->version); - g_print ("%c\tname: \"%s\"\n", MARK_CHANGE (3), info->name); - g_print ("%c\tcookie: %u\n", MARK_CHANGE (4), info->cookie); + printf ("%c\tuser-name: \"%s\"\n", MARK_CHANGE (0), info->user_name); + printf ("%c\thost-name: \"%s\"\n", MARK_CHANGE (1), info->host_name); + printf ("%c\tversion: \"%s\"\n", MARK_CHANGE (2), info->version); + printf ("%c\tname: \"%s\"\n", MARK_CHANGE (3), info->name); + printf ("%c\tcookie: %u\n", MARK_CHANGE (4), info->cookie); print_properties (info->properties, MARK_CHANGE (5)); } } static void -dump_client_info (PinosContext *c, const PinosClientInfo *info, gpointer user_data) +dump_client_info (PinosContext *c, const PinosClientInfo *info, void * user_data) { DumpData *data = user_data; - g_print ("\tid: %p\n", info->id); - g_print ("\tclient-path: \"%s\"\n", info->client_path); + printf ("\tid: %u\n", info->id); if (data->print_all) { - g_print ("\tsender: \"%s\"\n", info->sender); print_properties (info->properties, MARK_CHANGE (0)); } } static void -dump_node_info (PinosContext *c, const PinosNodeInfo *info, gpointer user_data) +dump_node_info (PinosContext *c, const PinosNodeInfo *info, void * user_data) { DumpData *data = user_data; - g_print ("\tid: %p\n", info->id); - g_print ("\tnode-path: \"%s\"\n", info->node_path); + printf ("\tid: %u\n", info->id); if (data->print_all) { - g_print ("%c\towner: \"%s\"\n", MARK_CHANGE (0), info->owner); - g_print ("%c\tname: \"%s\"\n", MARK_CHANGE (0), info->name); + printf ("%c\tname: \"%s\"\n", MARK_CHANGE (0), info->name); print_properties (info->properties, MARK_CHANGE (1)); - g_print ("%c\tstate: \"%s\"\n", MARK_CHANGE (2), pinos_node_state_as_string (info->state)); + printf ("%c\tstate: \"%s\"\n", MARK_CHANGE (2), pinos_node_state_as_string (info->state)); } } static void -dump_link_info (PinosContext *c, const PinosLinkInfo *info, gpointer user_data) +dump_link_info (PinosContext *c, const PinosLinkInfo *info, void * user_data) { DumpData *data = user_data; - g_print ("\tid: %p\n", info->id); - g_print ("\tlink-path: \"%s\"\n", info->link_path); + printf ("\tid: %u\n", info->id); if (data->print_all) { - g_print ("%c\toutput-node-path: \"%s\"\n", MARK_CHANGE (0), info->output_node_path); - g_print ("%c\toutput-port: %u\n", MARK_CHANGE (1), info->output_port); - g_print ("%c\tinput-node-path: \"%s\"\n", MARK_CHANGE (2), info->input_node_path); - g_print ("%c\tinput-port: %u\n", MARK_CHANGE (3), info->input_port); + printf ("%c\toutput-node-id: %u\n", MARK_CHANGE (0), info->output_node_id); + printf ("%c\toutput-port-id: %u\n", MARK_CHANGE (1), info->output_port_id); + printf ("%c\tinput-node-id: %u\n", MARK_CHANGE (2), info->input_node_id); + printf ("%c\tinput-port-id: %u\n", MARK_CHANGE (3), info->input_port_id); } } static void -dump_object (PinosContext *context, gpointer id, PinosSubscriptionFlags flags, - DumpData *data) +dump_object (PinosContext *context, + uint32_t id, + PinosSubscriptionFlags flags, + DumpData *data) { if (flags & PINOS_SUBSCRIPTION_FLAG_DAEMON) { - pinos_context_get_daemon_info (context, - PINOS_DAEMON_INFO_FLAGS_NONE, - dump_daemon_info, - NULL, - info_ready, - data); } else if (flags & PINOS_SUBSCRIPTION_FLAG_CLIENT) { - pinos_context_get_client_info_by_id (context, - id, - PINOS_CLIENT_INFO_FLAGS_NONE, - dump_client_info, - NULL, - info_ready, - data); } else if (flags & PINOS_SUBSCRIPTION_FLAG_NODE) { - pinos_context_get_node_info_by_id (context, - id, - PINOS_NODE_INFO_FLAGS_NONE, - dump_node_info, - NULL, - info_ready, - data); } else if (flags & PINOS_SUBSCRIPTION_FLAG_LINK) { - pinos_context_get_link_info_by_id (context, - id, - PINOS_LINK_INFO_FLAGS_NONE, - dump_link_info, - NULL, - info_ready, - data); } } static void subscription_cb (PinosContext *context, - PinosSubscriptionEvent type, PinosSubscriptionFlags flags, - gpointer id, - gpointer user_data) + PinosSubscriptionEvent type, + uint32_t id, + void *data) { - DumpData data; + DumpData dd; switch (type) { case PINOS_SUBSCRIPTION_EVENT_NEW: - g_print ("added:\n"); - data.print_mark = FALSE; - data.print_all = TRUE; - dump_object (context, id, flags, &data); + printf ("added:\n"); + dd.print_mark = false; + dd.print_all = true; + dump_object (context, id, flags, &dd); break; case PINOS_SUBSCRIPTION_EVENT_CHANGE: - g_print ("changed:\n"); - data.print_mark = TRUE; - data.print_all = TRUE; - dump_object (context, id, flags, &data); + printf ("changed:\n"); + dd.print_mark = true; + dd.print_all = true; + dump_object (context, id, flags, &dd); break; case PINOS_SUBSCRIPTION_EVENT_REMOVE: - g_print ("removed:\n"); - data.print_mark = FALSE; - data.print_all = FALSE; - dump_object (context, id, flags, &data); + printf ("removed:\n"); + dd.print_mark = false; + dd.print_all = false; + dump_object (context, id, flags, &dd); break; } } static void -on_state_notify (GObject *gobject, - GParamSpec *pspec, - gpointer user_data) +on_state_changed (PinosListener *listener, + PinosContext *context) { - PinosContextState state; - PinosContext *c = PINOS_CONTEXT (gobject); - const GError *error; + Data *data = SPA_CONTAINER_OF (listener, Data, on_state_changed); - g_object_get (c, "state", &state, NULL); - - switch (state) { + switch (context->state) { case PINOS_CONTEXT_STATE_ERROR: - error = pinos_context_get_error (c); - g_print ("context error: %s\n", error->message); + printf ("context error: %s\n", context->error); + data->running = false; break; default: - g_print ("context state: \"%s\"\n", pinos_context_state_as_string (state)); + printf ("context state: \"%s\"\n", pinos_context_state_as_string (context->state)); break; } } -gint -main (gint argc, gchar *argv[]) +int +main (int argc, char *argv[]) { - PinosContext *c; + Data data; pinos_init (&argc, &argv); - loop = g_main_loop_new (NULL, FALSE); + data.loop = pinos_loop_new (); + data.running = true; + data.context = pinos_context_new (data.loop, "pinos-monitor", NULL); - c = pinos_context_new (NULL, "pinos-monitor", NULL); - g_signal_connect (c, "notify::state", (GCallback) on_state_notify, c); - g_object_set (c, "subscription-mask", PINOS_SUBSCRIPTION_FLAGS_ALL, NULL); - g_signal_connect (c, "subscription-event", (GCallback) subscription_cb, NULL); - pinos_context_connect(c, PINOS_CONTEXT_FLAGS_NOFAIL); + pinos_signal_add (&data.context->state_changed, + &data.on_state_changed, + on_state_changed); - g_main_loop_run (loop); + pinos_context_subscribe (data.context, + PINOS_SUBSCRIPTION_FLAGS_ALL, + subscription_cb, + &data); - g_object_unref (c); + pinos_context_connect (data.context); + + pinos_loop_enter (data.loop); + while (data.running) { + pinos_loop_iterate (data.loop, -1); + } + pinos_loop_leave (data.loop); + + pinos_context_destroy (data.context); + pinos_loop_destroy (data.loop); return 0; } diff --git a/spa/include/spa/loop.h b/spa/include/spa/loop.h index 81945f96e..b0f2e22c2 100644 --- a/spa/include/spa/loop.h +++ b/spa/include/spa/loop.h @@ -119,7 +119,7 @@ struct _SpaLoopControl { }; #define spa_loop_control_get_fd(l) (l)->get_fd(l) -#define spa_loop_control_set_hooks(l,...) (l)->set_hook((l),__VA_ARGS__) +#define spa_loop_control_set_hooks(l,...) (l)->set_hooks((l),__VA_ARGS__) #define spa_loop_control_enter(l) (l)->enter(l) #define spa_loop_control_iterate(l,...) (l)->iterate((l),__VA_ARGS__) #define spa_loop_control_leave(l) (l)->leave(l)