From d8903b708d8e022fff33d5901847779e2910f4ff Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 17 Oct 2016 12:20:49 +0200 Subject: [PATCH] Reorganize serialization code a bit Move the proxy plugin to the client-node Move serialization code to pinos because its specific to pinos Move some functions to the .h files Make the mapper dynamic --- {spa/lib => pinos/client}/control.c | 131 +- {spa/include/spa => pinos/client}/control.h | 11 +- pinos/client/format.c | 5 +- pinos/client/meson.build | 2 + pinos/client/serialize.c | 354 ++++ pinos/client/serialize.h | 55 + pinos/client/stream.c | 7 +- pinos/server/client-node.c | 1630 ++++++++++++++++--- pinos/server/dbus-client-node.c | 3 - spa/include/spa/buffer.h | 21 +- spa/include/spa/format.h | 15 +- spa/include/spa/log.h | 4 +- spa/include/spa/port.h | 6 - spa/include/spa/props.h | 7 - spa/lib/buffer.c | 113 -- spa/lib/format.c | 87 - spa/lib/mapper.c | 57 +- spa/lib/meson.build | 4 - spa/lib/port.c | 101 -- spa/lib/props.c | 140 -- spa/plugins/meson.build | 1 - spa/plugins/remote/dbus-proxy.c | 1439 ---------------- spa/plugins/remote/meson.build | 10 - spa/plugins/remote/plugin.c | 50 - spa/plugins/remote/proxy.c | 1555 ------------------ 25 files changed, 1950 insertions(+), 3858 deletions(-) rename {spa/lib => pinos/client}/control.c (90%) rename {spa/include/spa => pinos/client}/control.h (93%) create mode 100644 pinos/client/serialize.c create mode 100644 pinos/client/serialize.h delete mode 100644 spa/lib/buffer.c delete mode 100644 spa/lib/format.c delete mode 100644 spa/lib/port.c delete mode 100644 spa/plugins/remote/dbus-proxy.c delete mode 100644 spa/plugins/remote/meson.build delete mode 100644 spa/plugins/remote/plugin.c delete mode 100644 spa/plugins/remote/proxy.c diff --git a/spa/lib/control.c b/pinos/client/control.c similarity index 90% rename from spa/lib/control.c rename to pinos/client/control.c index dbdd1aa6a..dcf25ad68 100644 --- a/spa/lib/control.c +++ b/pinos/client/control.c @@ -25,8 +25,8 @@ #include #include -#include -#include +#include "control.h" +#include "serialize.h" #if 0 #define SPA_DEBUG_CONTROL(format,args...) fprintf(stderr,format,##args) @@ -34,12 +34,6 @@ #define SPA_DEBUG_CONTROL(format,args...) #endif -typedef struct { - uint32_t version; - uint32_t flags; - uint32_t length; -} SpaStackHeader; - typedef struct { void *data; size_t size; @@ -94,27 +88,6 @@ spa_control_init_data (SpaControl *control, return SPA_RESULT_OK; } -/** - * spa_control_get_version - * @control: a #SpaControl - * - * Get the control version - * - * Returns: the control version. - */ -uint32_t -spa_control_get_version (SpaControl *control) -{ - SpaStackControl *sc = SSC (control); - SpaStackHeader *hdr; - - if (!is_valid_control (control)) - return -1; - - hdr = sc->data; - return hdr->version; -} - /** * spa_control_get_fd: * @control: a #SpaControl @@ -180,7 +153,6 @@ spa_control_clear (SpaControl *control) */ struct stack_iter { size_t magic; - uint32_t version; SpaStackControl *control; size_t offset; @@ -202,9 +174,8 @@ struct stack_iter { * Initialize @iter to iterate the packets in @control. */ SpaResult -spa_control_iter_init_full (SpaControlIter *iter, - SpaControl *control, - uint32_t version) +spa_control_iter_init (SpaControlIter *iter, + SpaControl *control) { struct stack_iter *si = SCSI (iter); @@ -212,11 +183,10 @@ spa_control_iter_init_full (SpaControlIter *iter, return SPA_RESULT_INVALID_ARGUMENTS; si->magic = SCSI_MAGIC; - si->version = version; si->control = SSC (control); si->offset = 0; si->cmd = SPA_CONTROL_CMD_INVALID; - si->size = sizeof (SpaStackHeader); + si->size = 0; si->data = NULL; return SPA_RESULT_OK; @@ -272,6 +242,7 @@ spa_control_iter_next (SpaControlIter *iter) /* now read packet */ data = si->control->data; size = si->control->size; + if (si->offset >= size) return SPA_RESULT_ERROR; @@ -345,7 +316,7 @@ iter_parse_node_update (struct stack_iter *si, SpaControlCmdNodeUpdate *nu) { memcpy (nu, si->data, sizeof (SpaControlCmdNodeUpdate)); if (nu->props) - nu->props = spa_props_deserialize (si->data, SPA_PTR_TO_INT (nu->props)); + nu->props = spa_serialize_props_deserialize (si->data, SPA_PTR_TO_INT (nu->props)); } static void @@ -363,16 +334,16 @@ iter_parse_port_update (struct stack_iter *si, SpaControlCmdPortUpdate *pu) SPA_PTR_TO_INT (pu->possible_formats), SpaFormat *); for (i = 0; i < pu->n_possible_formats; i++) { if (pu->possible_formats[i]) { - pu->possible_formats[i] = spa_format_deserialize (p, + pu->possible_formats[i] = spa_serialize_format_deserialize (p, SPA_PTR_TO_INT (pu->possible_formats[i])); } } if (pu->format) - pu->format = spa_format_deserialize (p, SPA_PTR_TO_INT (pu->format)); + pu->format = spa_serialize_format_deserialize (p, SPA_PTR_TO_INT (pu->format)); if (pu->props) - pu->props = spa_props_deserialize (p, SPA_PTR_TO_INT (pu->props)); + pu->props = spa_serialize_props_deserialize (p, SPA_PTR_TO_INT (pu->props)); if (pu->info) - pu->info = spa_port_info_deserialize (p, SPA_PTR_TO_INT (pu->info)); + pu->info = spa_serialize_port_info_deserialize (p, SPA_PTR_TO_INT (pu->info)); } static void @@ -380,7 +351,7 @@ iter_parse_set_format (struct stack_iter *si, SpaControlCmdSetFormat *cmd) { memcpy (cmd, si->data, sizeof (SpaControlCmdSetFormat)); if (cmd->format) - cmd->format = spa_format_deserialize (si->data, SPA_PTR_TO_INT (cmd->format)); + cmd->format = spa_serialize_format_deserialize (si->data, SPA_PTR_TO_INT (cmd->format)); } static void @@ -526,7 +497,7 @@ spa_control_iter_parse_cmd (SpaControlIter *iter, struct stack_builder { size_t magic; - SpaStackHeader *sh; + void *data; SpaStackControl control; SpaControlCmd cmd; @@ -540,34 +511,31 @@ struct stack_builder { /** - * spa_control_builder_init_full: + * spa_control_builder_init_into: * @builder: a #SpaControlBuilder - * @version: a version * @data: data to build into or %NULL to allocate * @max_data: allocated size of @data * @fds: memory for fds * @max_fds: maximum number of fds in @fds * - * Initialize a stack allocated @builder and set the @version. + * Initialize a stack allocated @builder */ SpaResult -spa_control_builder_init_full (SpaControlBuilder *builder, - uint32_t version, +spa_control_builder_init_into (SpaControlBuilder *builder, void *data, size_t max_data, int *fds, unsigned int max_fds) { struct stack_builder *sb = SCSB (builder); - SpaStackHeader *sh; if (builder == NULL) return SPA_RESULT_INVALID_ARGUMENTS; sb->magic = SCSB_MAGIC; - if (max_data < sizeof (SpaStackHeader) || data == NULL) { - sb->control.max_size = sizeof (SpaStackHeader) + 128; + if (max_data < 8 || data == NULL) { + sb->control.max_size = 128; sb->control.data = malloc (sb->control.max_size); sb->control.free_data = sb->control.data; fprintf (stderr, "builder %p: alloc control memory %zd -> %zd\n", @@ -577,18 +545,13 @@ spa_control_builder_init_full (SpaControlBuilder *builder, sb->control.data = data; sb->control.free_data = NULL; } - sb->control.size = sizeof (SpaStackHeader); + sb->control.size = 0; sb->control.fds = fds; sb->control.max_fds = max_fds; sb->control.n_fds = 0; sb->control.free_fds = NULL; - sh = sb->sh = sb->control.data; - sh->version = version; - sh->flags = 0; - sh->length = 0; - sb->cmd = 0; sb->offset = 0; @@ -642,7 +605,6 @@ spa_control_builder_end (SpaControlBuilder *builder, return SPA_RESULT_INVALID_ARGUMENTS; sb->magic = 0; - sb->sh->length = sb->control.size - sizeof (SpaStackHeader); sc->magic = SSC_MAGIC; sc->data = sb->control.data; @@ -718,7 +680,7 @@ builder_ensure_size (struct stack_builder *sb, size_t size) } else { sb->control.free_data = realloc (sb->control.free_data, new_size); } - sb->sh = sb->control.data = sb->control.free_data; + sb->control.data = sb->control.free_data; } return (uint8_t *) sb->control.data + sb->control.size; } @@ -758,7 +720,7 @@ builder_add_node_update (struct stack_builder *sb, SpaControlCmdNodeUpdate *nu) /* calc len */ len = sizeof (SpaControlCmdNodeUpdate); - len += spa_props_get_size (nu->props); + len += spa_serialize_props_get_size (nu->props); p = builder_add_cmd (sb, SPA_CONTROL_CMD_NODE_UPDATE, len); memcpy (p, nu, sizeof (SpaControlCmdNodeUpdate)); @@ -766,7 +728,7 @@ builder_add_node_update (struct stack_builder *sb, SpaControlCmdNodeUpdate *nu) p = SPA_MEMBER (d, sizeof (SpaControlCmdNodeUpdate), void); if (nu->props) { - len = spa_props_serialize (p, nu->props); + len = spa_serialize_props_serialize (p, nu->props); d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); } else { d->props = 0; @@ -786,12 +748,12 @@ builder_add_port_update (struct stack_builder *sb, SpaControlCmdPortUpdate *pu) len = sizeof (SpaControlCmdPortUpdate); len += pu->n_possible_formats * sizeof (SpaFormat *); for (i = 0; i < pu->n_possible_formats; i++) { - len += spa_format_get_size (pu->possible_formats[i]); + len += spa_serialize_format_get_size (pu->possible_formats[i]); } - len += spa_format_get_size (pu->format); - len += spa_props_get_size (pu->props); + len += spa_serialize_format_get_size (pu->format); + len += spa_serialize_props_get_size (pu->props); if (pu->info) - len += spa_port_info_get_size (pu->info); + len += spa_serialize_port_info_get_size (pu->info); p = builder_add_cmd (sb, SPA_CONTROL_CMD_PORT_UPDATE, len); memcpy (p, pu, sizeof (SpaControlCmdPortUpdate)); @@ -807,26 +769,26 @@ builder_add_port_update (struct stack_builder *sb, SpaControlCmdPortUpdate *pu) p = SPA_MEMBER (p, sizeof (SpaFormat*) * pu->n_possible_formats, void); for (i = 0; i < pu->n_possible_formats; i++) { - len = spa_format_serialize (p, pu->possible_formats[i]); + len = spa_serialize_format_serialize (p, pu->possible_formats[i]); bfa[i] = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); p = SPA_MEMBER (p, len, void); } if (pu->format) { - len = spa_format_serialize (p, pu->format); + len = spa_serialize_format_serialize (p, pu->format); d->format = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); p = SPA_MEMBER (p, len, void); } else { d->format = 0; } if (pu->props) { - len = spa_props_serialize (p, pu->props); + len = spa_serialize_props_serialize (p, pu->props); d->props = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); p = SPA_MEMBER (p, len, void); } else { d->props = 0; } if (pu->info) { - len = spa_port_info_serialize (p, pu->info); + len = spa_serialize_port_info_serialize (p, pu->info); d->info = SPA_INT_TO_PTR (SPA_PTRDIFF (p, d)); p = SPA_MEMBER (p, len, void); } else { @@ -842,14 +804,14 @@ builder_add_set_format (struct stack_builder *sb, SpaControlCmdSetFormat *sf) /* calculate length */ /* port_id + format + mask */ - len = sizeof (SpaControlCmdSetFormat) + spa_format_get_size (sf->format); + len = sizeof (SpaControlCmdSetFormat) + spa_serialize_format_get_size (sf->format); p = builder_add_cmd (sb, SPA_CONTROL_CMD_SET_FORMAT, len); memcpy (p, sf, sizeof (SpaControlCmdSetFormat)); sf = p; p = SPA_MEMBER (sf, sizeof (SpaControlCmdSetFormat), void); if (sf->format) { - len = spa_format_serialize (p, sf->format); + len = spa_serialize_format_serialize (p, sf->format); sf->format = SPA_INT_TO_PTR (SPA_PTRDIFF (p, sf)); } else sf->format = 0; @@ -1040,9 +1002,7 @@ spa_control_read (SpaControl *control, unsigned int max_fds) { ssize_t len; - SpaStackHeader *hdr; SpaStackControl *sc = (SpaStackControl *) control; - size_t need; struct cmsghdr *cmsg; struct msghdr msg = {0}; struct iovec iov[1]; @@ -1056,11 +1016,10 @@ spa_control_read (SpaControl *control, sc->max_fds = max_fds; sc->n_fds = 0; sc->free_fds = NULL; - hdr = sc->data; /* read header and control messages first */ - iov[0].iov_base = hdr; - iov[0].iov_len = sizeof (SpaStackHeader);; + iov[0].iov_base = sc->data; + iov[0].iov_len = sc->max_size; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; @@ -1077,24 +1036,18 @@ spa_control_read (SpaControl *control, } break; } - if (len != sizeof (SpaStackHeader)) + + if (len < 4) return SPA_RESULT_ERROR; - /* now we know the total length */ - need = sizeof (SpaStackHeader) + hdr->length; - + sc->size = len; +#if 0 if (sc->max_size < need) { fprintf (stderr, "control: realloc receive memory %zd -> %zd\n", sc->max_size, need); sc->max_size = need; - if (sc->free_data == NULL) { - sc->free_data = malloc (need); - memcpy (sc->free_data, sc->data, len); - } else { - sc->free_data = realloc (sc->free_data, need); - } + sc->free_data = realloc (sc->free_data, need); hdr = sc->data = sc->free_data; } - sc->size = need; if (hdr->length > 0) { /* read data */ @@ -1111,6 +1064,7 @@ spa_control_read (SpaControl *control, if (len != hdr->length) goto wrong_length; } +#endif /* handle control messages */ for (cmsg = CMSG_FIRSTHDR (&msg); cmsg != NULL; cmsg = CMSG_NXTHDR (&msg, cmsg)) { @@ -1132,11 +1086,6 @@ recv_error: fprintf (stderr, "could not recvmsg: %s\n", strerror (errno)); return SPA_RESULT_ERROR; } -wrong_length: - { - fprintf (stderr, "wrong header length %zd != %u\n", len, hdr->length); - return SPA_RESULT_ERROR; - } } diff --git a/spa/include/spa/control.h b/pinos/client/control.h similarity index 93% rename from spa/include/spa/control.h rename to pinos/client/control.h index c13fcc84c..3b834908d 100644 --- a/spa/include/spa/control.h +++ b/pinos/client/control.h @@ -48,7 +48,6 @@ SpaResult spa_control_init_data (SpaControl *control, SpaResult spa_control_clear (SpaControl *control); -uint32_t spa_control_get_version (SpaControl *control); int spa_control_get_fd (SpaControl *control, unsigned int index, bool close); @@ -206,10 +205,8 @@ struct _SpaControlIter { size_t x[16]; }; -SpaResult spa_control_iter_init_full (SpaControlIter *iter, - SpaControl *control, - uint32_t version); -#define spa_control_iter_init(i,b) spa_control_iter_init_full(i,b, SPA_CONTROL_VERSION); +SpaResult spa_control_iter_init (SpaControlIter *iter, + SpaControl *control); SpaResult spa_control_iter_next (SpaControlIter *iter); SpaResult spa_control_iter_end (SpaControlIter *iter); @@ -232,13 +229,11 @@ struct _SpaControlBuilder { size_t x[16]; }; -SpaResult spa_control_builder_init_full (SpaControlBuilder *builder, - uint32_t version, +SpaResult spa_control_builder_init_into (SpaControlBuilder *builder, void *data, size_t max_data, int *fds, unsigned int max_fds); -#define spa_control_builder_init_into(b,d,md,f,mf) spa_control_builder_init_full(b, SPA_CONTROL_VERSION,d,md,f,mf); #define spa_control_builder_init(b) spa_control_builder_init_into(b, NULL, 0, NULL, 0); SpaResult spa_control_builder_clear (SpaControlBuilder *builder); diff --git a/pinos/client/format.c b/pinos/client/format.c index 9ace1f8e1..2a0decdf8 100644 --- a/pinos/client/format.c +++ b/pinos/client/format.c @@ -19,6 +19,7 @@ #include #include +#include static SpaFormat * format_copy (SpaFormat *format) @@ -29,9 +30,9 @@ format_copy (SpaFormat *format) if (format == NULL) return NULL; - size = spa_format_get_size (format); + size = spa_serialize_format_get_size (format); p = malloc (size); - return spa_format_copy_into (p, format); + return spa_serialize_format_copy_into (p, format); } static void diff --git a/pinos/client/meson.build b/pinos/client/meson.build index c3f842bf9..03c7358dc 100644 --- a/pinos/client/meson.build +++ b/pinos/client/meson.build @@ -12,10 +12,12 @@ pinos_headers = [ pinos_sources = [ 'context.c', + 'control.c', 'format.c', 'introspect.c', 'mainloop.c', 'properties.c', + 'serialize.c', 'stream.c', 'pinos.c', 'ringbuffer.c', diff --git a/pinos/client/serialize.c b/pinos/client/serialize.c new file mode 100644 index 000000000..21f77fc04 --- /dev/null +++ b/pinos/client/serialize.c @@ -0,0 +1,354 @@ +/* Simple Plugin API + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "serialize.h" + +size_t +spa_serialize_buffer_get_size (const SpaBuffer *buffer) +{ + size_t size; + unsigned int i; + + if (buffer == NULL) + return 0; + + size = sizeof (SpaBuffer); + for (i = 0; i < buffer->n_metas; i++) + size += sizeof (SpaMeta) + buffer->metas[i].size; + for (i = 0; i < buffer->n_datas; i++) + size += sizeof (SpaData); + return size; +} + +size_t +spa_serialize_buffer_serialize (void *dest, const SpaBuffer *buffer) +{ + SpaBuffer *tb; + SpaMeta *mp; + SpaData *dp; + void *p; + unsigned int i; + + if (buffer == NULL) + return 0; + + tb = dest; + memcpy (tb, buffer, sizeof (SpaBuffer)); + mp = SPA_MEMBER (tb, sizeof(SpaBuffer), SpaMeta); + dp = SPA_MEMBER (mp, sizeof(SpaMeta) * tb->n_metas, SpaData); + p = SPA_MEMBER (dp, sizeof(SpaData) * tb->n_datas, void); + + tb->metas = SPA_INT_TO_PTR (SPA_PTRDIFF (mp, tb)); + tb->datas = SPA_INT_TO_PTR (SPA_PTRDIFF (dp, tb)); + + for (i = 0; i < tb->n_metas; i++) { + memcpy (&mp[i], &buffer->metas[i], sizeof (SpaMeta)); + memcpy (p, mp[i].data, mp[i].size); + mp[i].data = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tb)); + p += mp[i].size; + } + for (i = 0; i < tb->n_datas; i++) + memcpy (&dp[i], &buffer->datas[i], sizeof (SpaData)); + + return SPA_PTRDIFF (p, tb); +} + +SpaBuffer * +spa_serialize_buffer_deserialize (void *src, off_t offset) +{ + SpaBuffer *b; + unsigned int i; + + b = SPA_MEMBER (src, offset, SpaBuffer); + if (b->metas) + b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); + for (i = 0; i < b->n_metas; i++) { + SpaMeta *m = &b->metas[i]; + if (m->data) + m->data = SPA_MEMBER (b, SPA_PTR_TO_INT (m->data), void); + } + if (b->datas) + b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); + + return b; +} + + +size_t +spa_serialize_format_get_size (const SpaFormat *format) +{ + if (format == NULL) + return 0; + + return spa_serialize_props_get_size (&format->props) - sizeof (SpaProps) + sizeof (SpaFormat); +} + +size_t +spa_serialize_format_serialize (void *dest, const SpaFormat *format) +{ + SpaFormat *tf; + size_t size; + + if (format == NULL) + return 0; + + tf = dest; + tf->media_type = format->media_type; + tf->media_subtype = format->media_subtype; + + dest = SPA_MEMBER (tf, offsetof (SpaFormat, props), void); + size = spa_serialize_props_serialize (dest, &format->props) - sizeof (SpaProps) + sizeof (SpaFormat); + + return size; +} + +SpaFormat * +spa_serialize_format_deserialize (void *src, off_t offset) +{ + SpaFormat *f; + + f = SPA_MEMBER (src, offset, SpaFormat); + spa_serialize_props_deserialize (f, offsetof (SpaFormat, props)); + + return f; +} + +SpaFormat * +spa_serialize_format_copy_into (void *dest, const SpaFormat *format) +{ + if (format == NULL) + return NULL; + + spa_serialize_format_serialize (dest, format); + return spa_serialize_format_deserialize (dest, 0); +} + +size_t +spa_serialize_port_info_get_size (const SpaPortInfo *info) +{ + size_t len; + unsigned int i; + + if (info == NULL) + return 0; + + len = sizeof (SpaPortInfo); + len += info->n_params * sizeof (SpaAllocParam *); + for (i = 0; i < info->n_params; i++) + len += info->params[i]->size; + + return len; +} + +size_t +spa_serialize_port_info_serialize (void *p, const SpaPortInfo *info) +{ + SpaPortInfo *pi; + SpaAllocParam **ap; + int i; + size_t len; + + if (info == NULL) + return 0; + + pi = p; + memcpy (pi, info, sizeof (SpaPortInfo)); + + ap = SPA_MEMBER (pi, sizeof (SpaPortInfo), SpaAllocParam *); + if (info->n_params) + pi->params = SPA_INT_TO_PTR (SPA_PTRDIFF (ap, pi)); + else + pi->params = 0; + pi->extra = 0; + + p = SPA_MEMBER (ap, sizeof (SpaAllocParam*) * info->n_params, void); + + for (i = 0; i < info->n_params; i++) { + len = info->params[i]->size; + memcpy (p, info->params[i], len); + ap[i] = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi)); + p = SPA_MEMBER (p, len, void); + } + return SPA_PTRDIFF (p, pi); +} + +SpaPortInfo * +spa_serialize_port_info_deserialize (void *p, off_t offset) +{ + SpaPortInfo *pi; + unsigned int i; + + pi = SPA_MEMBER (p, offset, SpaPortInfo); + if (pi->params) + pi->params = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->params), SpaAllocParam *); + for (i = 0; i < pi->n_params; i++) { + pi->params[i] = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->params[i]), SpaAllocParam); + } + return pi; +} + +SpaPortInfo * +spa_serialize_port_info_copy_into (void *dest, const SpaPortInfo *info) +{ + if (info == NULL) + return NULL; + + spa_serialize_port_info_serialize (dest, info); + return spa_serialize_port_info_deserialize (dest, 0); +} + +size_t +spa_serialize_props_get_size (const SpaProps *props) +{ + size_t len; + unsigned int i, j; + SpaPropInfo *pi; + SpaPropRangeInfo *ri; + + if (props == NULL) + return 0; + + len = sizeof (SpaProps); + for (i = 0; i < props->n_prop_info; i++) { + pi = (SpaPropInfo *) &props->prop_info[i]; + len += sizeof (SpaPropInfo); + len += pi->name ? strlen (pi->name) + 1 : 0; + /* for the value */ + len += pi->maxsize; + for (j = 0; j < pi->n_range_values; j++) { + ri = (SpaPropRangeInfo *)&pi->range_values[j]; + len += sizeof (SpaPropRangeInfo); + len += ri->name ? strlen (ri->name) + 1 : 0; + /* the size of the range value */ + len += ri->val.size; + } + } + return len; +} + +size_t +spa_serialize_props_serialize (void *p, const SpaProps *props) +{ + size_t len, slen; + unsigned int i, j, c; + SpaProps *tp; + SpaPropInfo *pi; + SpaPropRangeInfo *ri; + + if (props == NULL) + return 0; + + tp = p; + memcpy (tp, props, sizeof (SpaProps)); + pi = SPA_MEMBER (tp, sizeof(SpaProps), SpaPropInfo); + ri = SPA_MEMBER (pi, sizeof(SpaPropInfo) * tp->n_prop_info, SpaPropRangeInfo); + + tp->prop_info = SPA_INT_TO_PTR (SPA_PTRDIFF (pi, tp)); + + /* write propinfo array */ + for (i = 0, c = 0; i < tp->n_prop_info; i++) { + memcpy (&pi[i], &props->prop_info[i], sizeof (SpaPropInfo)); + pi[i].range_values = SPA_INT_TO_PTR (SPA_PTRDIFF (&ri[c], tp)); + for (j = 0; j < pi[i].n_range_values; j++, c++) { + memcpy (&ri[c], &props->prop_info[i].range_values[j], sizeof (SpaPropRangeInfo)); + } + } + p = &ri[c]; + /* strings and default values from props and ranges */ + for (i = 0, c = 0; i < tp->n_prop_info; i++) { + if (pi[i].name) { + slen = strlen (pi[i].name) + 1; + memcpy (p, pi[i].name, slen); + pi[i].name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); + p += slen; + } else { + pi[i].name = 0; + } + for (j = 0; j < pi[i].n_range_values; j++, c++) { + if (ri[c].name) { + slen = strlen (ri[c].name) + 1; + memcpy (p, ri[c].name, slen); + ri[c].name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); + p += slen; + } else { + ri[c].name = 0; + } + if (ri[c].val.size) { + memcpy (p, ri[c].val.value, ri[c].val.size); + ri[c].val.value = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); + p += ri[c].val.size; + } else { + ri[c].val.value = 0; + } + } + } + /* and the actual values */ + for (i = 0; i < tp->n_prop_info; i++) { + if (pi[i].offset) { + memcpy (p, SPA_MEMBER (props, pi[i].offset, void), pi[i].maxsize); + pi[i].offset = SPA_PTRDIFF (p, tp); + p += pi[i].maxsize; + } else { + pi[i].offset = 0; + } + } + len = SPA_PTRDIFF (p, tp); + + return len; +} + +SpaProps * +spa_serialize_props_deserialize (void *p, off_t offset) +{ + SpaProps *tp; + unsigned int i, j; + SpaPropInfo *pi; + SpaPropRangeInfo *ri; + + tp = SPA_MEMBER (p, offset, SpaProps); + if (tp->prop_info) + tp->prop_info = SPA_MEMBER (tp, SPA_PTR_TO_INT (tp->prop_info), SpaPropInfo); + /* now fix all the pointers */ + for (i = 0; i < tp->n_prop_info; i++) { + pi = (SpaPropInfo *) &tp->prop_info[i]; + if (pi->name) + pi->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->name), char); + if (pi->range_values) + pi->range_values = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->range_values), SpaPropRangeInfo); + + for (j = 0; j < pi->n_range_values; j++) { + ri = (SpaPropRangeInfo *) &pi->range_values[j]; + if (ri->name) + ri->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (ri->name), char); + if (ri->val.value) + ri->val.value = SPA_MEMBER (tp, SPA_PTR_TO_INT (ri->val.value), void); + } + } + return tp; +} + +SpaProps * +spa_serialize_props_copy_into (void *dest, const SpaProps *props) +{ + if (props == NULL) + return NULL; + + spa_serialize_props_serialize (dest, props); + return spa_serialize_props_deserialize (dest, 0); +} diff --git a/pinos/client/serialize.h b/pinos/client/serialize.h new file mode 100644 index 000000000..f97bb590e --- /dev/null +++ b/pinos/client/serialize.h @@ -0,0 +1,55 @@ +/* Simple Plugin API + * Copyright (C) 2016 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __SPA_SERIALIZE_H__ +#define __SPA_SERIALIZE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +size_t spa_serialize_buffer_get_size (const SpaBuffer *buffer); +size_t spa_serialize_buffer_serialize (void *dest, const SpaBuffer *buffer); +SpaBuffer * spa_serialize_buffer_deserialize (void *src, off_t offset); + +size_t spa_serialize_format_get_size (const SpaFormat *format); +size_t spa_serialize_format_serialize (void *dest, const SpaFormat *format); +SpaFormat * spa_serialize_format_deserialize (void *src, off_t offset); +SpaFormat * spa_serialize_format_copy_into (void *dest, const SpaFormat *format); + +size_t spa_serialize_port_info_get_size (const SpaPortInfo *info); +size_t spa_serialize_port_info_serialize (void *dest, const SpaPortInfo *info); +SpaPortInfo * spa_serialize_port_info_deserialize (void *src, off_t offset); +SpaPortInfo * spa_serialize_port_info_copy_into (void *dest, const SpaPortInfo *info); + +size_t spa_serialize_props_get_size (const SpaProps *props); +size_t spa_serialize_props_serialize (void *dest, const SpaProps *props); +SpaProps * spa_serialize_props_deserialize (void *src, off_t offset); +SpaProps * spa_serialize_props_copy_into (void *dest, const SpaProps *props); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_SERIALIZE_H__ */ diff --git a/pinos/client/stream.c b/pinos/client/stream.c index 8007749e6..ba20ac4fb 100644 --- a/pinos/client/stream.c +++ b/pinos/client/stream.c @@ -22,7 +22,6 @@ #include #include -#include "spa/include/spa/control.h" #include "spa/include/spa/debug.h" #include @@ -32,11 +31,13 @@ #include "pinos/dbus/org-pinos.h" #include "pinos/server/daemon.h" #include "pinos/client/pinos.h" +#include "pinos/client/control.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" #define MAX_BUFFER_SIZE 4096 #define MAX_FDS 32 @@ -1048,8 +1049,8 @@ parse_control (PinosStream *stream, if (priv->format) g_free (priv->format); - mem = malloc (spa_format_get_size (p.format)); - priv->format = spa_format_copy_into (mem, p.format); + mem = malloc (spa_serialize_format_get_size (p.format)); + priv->format = spa_serialize_format_copy_into (mem, p.format); spa_debug_format (p.format); priv->pending_seq = p.seq; diff --git a/pinos/server/client-node.c b/pinos/server/client-node.c index 6b950efe7..0402b030f 100644 --- a/pinos/server/client-node.c +++ b/pinos/server/client-node.c @@ -18,32 +18,110 @@ */ #include -#include +#include +#include #include -#include #include #include #include #include +#include +#include #include #include "pinos/client/pinos.h" #include "pinos/client/enumtypes.h" #include "pinos/client/private.h" +#include "pinos/client/control.h" +#include "pinos/client/serialize.h" #include "pinos/server/daemon.h" #include "pinos/server/client-node.h" -#include "spa/include/spa/control.h" +#include "spa/include/spa/node.h" +#include "spa/include/spa/queue.h" +#include "spa/lib/memfd-wrappers.h" +#define MAX_INPUTS 64 +#define MAX_OUTPUTS 64 + +#define MAX_BUFFERS 16 + +#define CHECK_IN_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS) +#define CHECK_OUT_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_OUTPUTS) +#define CHECK_PORT_ID(this,d,p) (CHECK_IN_PORT_ID(this,d,p) || CHECK_OUT_PORT_ID(this,d,p)) +#define CHECK_FREE_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && !(this)->in_ports[p].valid) +#define CHECK_FREE_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && !(this)->out_ports[p].valid) +#define CHECK_FREE_PORT(this,d,p) (CHECK_FREE_IN_PORT (this,d,p) || CHECK_FREE_OUT_PORT (this,d,p)) +#define CHECK_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p].valid) +#define CHECK_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p].valid) +#define CHECK_PORT(this,d,p) (CHECK_IN_PORT (this,d,p) || CHECK_OUT_PORT (this,d,p)) + +typedef struct _SpaProxy SpaProxy; +typedef struct _ProxyBuffer ProxyBuffer; + +struct _ProxyBuffer { + SpaBuffer *outbuf; + SpaBuffer buffer; + SpaMeta metas[4]; + SpaData datas[4]; + off_t offset; + size_t size; +}; + +typedef struct { + bool valid; + SpaPortInfo *info; + SpaFormat *format; + unsigned int n_formats; + SpaFormat **formats; + SpaPortStatus status; + + unsigned int n_buffers; + ProxyBuffer buffers[MAX_BUFFERS]; + + uint32_t buffer_mem_id; + int buffer_mem_fd; + size_t buffer_mem_size; + void *buffer_mem_ptr; + + uint32_t buffer_id; + SpaQueue ready; +} SpaProxyPort; + +struct _SpaProxy +{ + SpaNode node; + + SpaIDMap *map; + SpaLog *log; + SpaPoll *main_loop; + SpaPoll *data_loop; + + SpaNodeEventCallback event_cb; + void *user_data; + + SpaPollFd fds[1]; + SpaPollItem poll; + SpaPollFd rtfds[1]; + SpaPollItem rtpoll; + + unsigned int max_inputs; + unsigned int n_inputs; + unsigned int max_outputs; + unsigned int n_outputs; + SpaProxyPort in_ports[MAX_INPUTS]; + SpaProxyPort out_ports[MAX_OUTPUTS]; + + uint32_t seq; +}; struct _PinosClientNodePrivate { - int fd; - int rtfd; + SpaProxy *proxy; + GSocket *sockets[2]; GSocket *rtsockets[2]; - SpaHandle *handle; }; #define PINOS_CLIENT_NODE_GET_PRIVATE(obj) \ @@ -64,6 +142,1251 @@ enum //static guint signals[LAST_SIGNAL] = { 0 }; +static void +send_async_complete (SpaProxy *this, uint32_t seq, SpaResult res) +{ + SpaNodeEvent event; + SpaNodeEventAsyncComplete ac; + + event.type = SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE; + event.data = ∾ + event.size = sizeof (ac); + ac.seq = seq; + ac.res = res; + this->event_cb (&this->node, &event, this->user_data); +} + +static SpaResult +clear_buffers (SpaProxy *this, SpaProxyPort *port) +{ + if (port->n_buffers) { + spa_log_info (this->log, "proxy %p: clear buffers\n", this); + + munmap (port->buffer_mem_ptr, port->buffer_mem_size); + close (port->buffer_mem_fd); + + port->n_buffers = 0; + SPA_QUEUE_INIT (&port->ready); + } + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_get_props (SpaNode *node, + SpaProps **props) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_proxy_node_set_props (SpaNode *node, + const SpaProps *props) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_proxy_node_send_command (SpaNode *node, + SpaNodeCommand *command) +{ + SpaProxy *this; + SpaResult res = SPA_RESULT_OK; + + if (node == NULL || command == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + switch (command->type) { + case SPA_NODE_COMMAND_INVALID: + return SPA_RESULT_INVALID_COMMAND; + + case SPA_NODE_COMMAND_START: + case SPA_NODE_COMMAND_PAUSE: + case SPA_NODE_COMMAND_FLUSH: + case SPA_NODE_COMMAND_DRAIN: + case SPA_NODE_COMMAND_MARKER: + { + SpaControlBuilder builder; + SpaControl control; + uint8_t buf[128]; + SpaControlCmdNodeCommand cnc; + + /* send start */ + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + cnc.seq = this->seq++; + cnc.command = command; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); + + spa_control_clear (&control); + + res = SPA_RESULT_RETURN_ASYNC (cnc.seq); + break; + } + + case SPA_NODE_COMMAND_CLOCK_UPDATE: + { + SpaControlBuilder builder; + SpaControl control; + uint8_t buf[128]; + SpaControlCmdNodeCommand cnc; + + /* send start */ + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + cnc.command = command; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); + + spa_control_clear (&control); + break; + } + } + return res; +} + +static SpaResult +spa_proxy_node_set_event_callback (SpaNode *node, + SpaNodeEventCallback event, + void *user_data) +{ + SpaProxy *this; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + this->event_cb = event; + this->user_data = user_data; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_get_n_ports (SpaNode *node, + unsigned int *n_input_ports, + unsigned int *max_input_ports, + unsigned int *n_output_ports, + unsigned int *max_output_ports) +{ + SpaProxy *this; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (n_input_ports) + *n_input_ports = this->n_inputs; + if (max_input_ports) + *max_input_ports = this->max_inputs; + if (n_output_ports) + *n_output_ports = this->n_outputs; + if (max_output_ports) + *max_output_ports = this->max_outputs; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_get_port_ids (SpaNode *node, + unsigned int n_input_ports, + uint32_t *input_ids, + unsigned int n_output_ports, + uint32_t *output_ids) +{ + SpaProxy *this; + int c, i; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (input_ids) { + for (c = 0, i = 0; i < MAX_INPUTS && c < n_input_ports; i++) { + if (this->in_ports[i].valid) + input_ids[c++] = i; + } + } + if (output_ids) { + for (c = 0, i = 0; i < MAX_OUTPUTS && c < n_output_ports; i++) { + if (this->out_ports[i].valid) + output_ids[c++] = i; + } + } + return SPA_RESULT_OK; +} + +static void +do_update_port (SpaProxy *this, + SpaControlCmdPortUpdate *pu) +{ + SpaProxyPort *port; + unsigned int i; + size_t size; + + if (pu->direction == SPA_DIRECTION_INPUT) { + port = &this->in_ports[pu->port_id]; + } else { + port = &this->out_ports[pu->port_id]; + } + + if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS) { + for (i = 0; i < port->n_formats; i++) + free (port->formats[i]); + port->n_formats = pu->n_possible_formats; + port->formats = realloc (port->formats, port->n_formats * sizeof (SpaFormat *)); + for (i = 0; i < port->n_formats; i++) { + size = spa_serialize_format_get_size (pu->possible_formats[i]); + port->formats[i] = spa_serialize_format_copy_into (malloc (size), pu->possible_formats[i]); + } + } + if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_FORMAT) { + if (port->format) + free (port->format); + size = spa_serialize_format_get_size (pu->format); + port->format = spa_serialize_format_copy_into (malloc (size), pu->format); + } + + if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) { + } + + if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_INFO && pu->info) { + if (port->info) + free (port->info); + size = spa_serialize_port_info_get_size (pu->info); + port->info = spa_serialize_port_info_copy_into (malloc (size), pu->info); + } + + if (!port->valid) { + spa_log_info (this->log, "proxy %p: adding port %d\n", this, pu->port_id); + port->format = NULL; + port->valid = true; + + if (pu->direction == SPA_DIRECTION_INPUT) + this->n_inputs++; + else + this->n_outputs++; + } +} + +static void +clear_port (SpaProxy *this, + SpaProxyPort *port, + SpaDirection direction, + uint32_t port_id) +{ + SpaControlCmdPortUpdate pu; + + pu.change_mask = SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS | + SPA_CONTROL_CMD_PORT_UPDATE_FORMAT | + SPA_CONTROL_CMD_PORT_UPDATE_PROPS | + SPA_CONTROL_CMD_PORT_UPDATE_INFO; + pu.direction = direction; + pu.port_id = port_id; + pu.n_possible_formats = 0; + pu.possible_formats = NULL; + pu.format = NULL; + pu.props = NULL; + pu.info = NULL; + do_update_port (this, &pu); + clear_buffers (this, port); +} + +static void +do_uninit_port (SpaProxy *this, + SpaDirection direction, + uint32_t port_id) +{ + SpaProxyPort *port; + + spa_log_info (this->log, "proxy %p: removing port %d\n", this, port_id); + if (direction == SPA_DIRECTION_INPUT) { + port = &this->in_ports[port_id]; + this->n_inputs--; + } else { + port = &this->out_ports[port_id]; + this->n_outputs--; + } + clear_port (this, port, direction, port_id); + port->valid = false; +} + +static SpaResult +spa_proxy_node_add_port (SpaNode *node, + SpaDirection direction, + uint32_t port_id) +{ + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_FREE_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + clear_port (this, port, direction, port_id); + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_remove_port (SpaNode *node, + SpaDirection direction, + uint32_t port_id) +{ + SpaProxy *this; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + do_uninit_port (this, direction, port_id); + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_enum_formats (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaFormat **format, + const SpaFormat *filter, + void **state) +{ + SpaProxy *this; + SpaProxyPort *port; + int index; + + if (node == NULL || format == NULL || state == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + index = (*state == NULL ? 0 : *(int*)state); + + if (index >= port->n_formats) + return SPA_RESULT_ENUM_END; + + *format = port->formats[index]; + *(int*)state = ++index; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_set_format (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaPortFormatFlags flags, + const SpaFormat *format) +{ + SpaProxy *this; + SpaControl control; + SpaControlBuilder builder; + SpaControlCmdSetFormat sf; + uint8_t buf[128]; + SpaResult res; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + sf.seq = this->seq++; + sf.direction = direction; + sf.port_id = port_id; + sf.flags = flags; + sf.format = (SpaFormat *) format; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf); + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_RETURN_ASYNC (sf.seq); +} + +static SpaResult +spa_proxy_node_port_get_format (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + const SpaFormat **format) +{ + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || format == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + if (!port->format) + return SPA_RESULT_NO_FORMAT; + + *format = port->format; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_get_info (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + const SpaPortInfo **info) +{ + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || info == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + *info = port->info; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_get_props (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaProps **props) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_proxy_node_port_set_props (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + const SpaProps *props) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +spa_proxy_node_port_get_status (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + const SpaPortStatus **status) +{ + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || status == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + if (!port->format) + return SPA_RESULT_NO_FORMAT; + + *status = &port->status; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_use_buffers (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaBuffer **buffers, + uint32_t n_buffers) +{ + SpaProxy *this; + SpaProxyPort *port; + unsigned int i, j; + SpaControl control; + SpaControlBuilder builder; + uint8_t buf[4096]; + int fds[32]; + SpaResult res; + SpaControlCmdAddMem am; + SpaControlCmdUseBuffers ub; + size_t size, n_mem; + SpaControlMemRef *memref; + void *p; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + spa_log_info (this->log, "proxy %p: use buffers %p %u\n", this, buffers, n_buffers); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + if (!port->format) + return SPA_RESULT_NO_FORMAT; + + clear_buffers (this, port); + + spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, SPA_N_ELEMENTS (fds)); + + /* find size to store buffers */ + size = 0; + n_mem = 0; + for (i = 0; i < n_buffers; i++) { + ProxyBuffer *b = &port->buffers[i]; + + b->outbuf = buffers[i]; + memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); + b->buffer.datas = b->datas; + b->buffer.metas = b->metas; + + b->size = spa_serialize_buffer_get_size (buffers[i]); + b->offset = size; + + for (j = 0; j < buffers[i]->n_metas; j++) { + memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta)); + } + + for (j = 0; j < buffers[i]->n_datas; j++) { + SpaData *d = &buffers[i]->datas[j]; + + memcpy (&b->buffer.datas[j], d, sizeof (SpaData)); + + switch (d->type) { + case SPA_DATA_TYPE_DMABUF: + case SPA_DATA_TYPE_MEMFD: + am.direction = direction; + am.port_id = port_id; + am.mem_id = n_mem; + am.type = d->type; + am.fd_index = spa_control_builder_add_fd (&builder, d->fd, false); + am.flags = d->flags; + am.offset = d->offset; + am.size = d->maxsize; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); + + b->buffer.datas[j].type = SPA_DATA_TYPE_ID; + b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem); + n_mem++; + break; + case SPA_DATA_TYPE_MEMPTR: + b->buffer.datas[j].data = SPA_INT_TO_PTR (b->size); + b->size += d->size; + break; + default: + b->buffer.datas[j].type = SPA_DATA_TYPE_INVALID; + b->buffer.datas[j].data = 0; + spa_log_error (this->log, "invalid memory type %d\n", d->type); + break; + } + } + size += b->size; + } + + if (n_buffers > 0) { + /* make mem for the buffers */ + port->buffer_mem_id = n_mem++; + port->buffer_mem_size = size; + port->buffer_mem_fd = memfd_create ("spa-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); + + if (ftruncate (port->buffer_mem_fd, size) < 0) { + spa_log_error (this->log, "Failed to truncate temporary file: %s\n", strerror (errno)); + close (port->buffer_mem_fd); + return SPA_RESULT_ERROR; + } +#if 0 + { + unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; + if (fcntl (port->buffer_mem_fd, F_ADD_SEALS, seals) == -1) { + spa_log_error (this->log, "Failed to add seals: %s\n", strerror (errno)); + } + } +#endif + p = port->buffer_mem_ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, port->buffer_mem_fd, 0); + + for (i = 0; i < n_buffers; i++) { + ProxyBuffer *b = &port->buffers[i]; + SpaBuffer *sb; + SpaMeta *sbm; + SpaData *sbd; + + spa_serialize_buffer_serialize (p, &b->buffer); + + sb = p; + b->buffer.datas = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); + sbm = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->metas), SpaMeta); + sbd = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); + + for (j = 0; j < b->buffer.n_metas; j++) + b->metas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbm[j].data), void); + + for (j = 0; j < b->buffer.n_datas; j++) { + if (b->datas[j].type == SPA_DATA_TYPE_MEMPTR) + b->datas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbd[j].data), void); + } + p += b->size; + } + + am.direction = direction; + am.port_id = port_id; + am.mem_id = port->buffer_mem_id; + am.type = SPA_DATA_TYPE_MEMFD; + am.fd_index = spa_control_builder_add_fd (&builder, port->buffer_mem_fd, false); + am.flags = 0; + am.offset = 0; + am.size = size; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); + + memref = alloca (n_buffers * sizeof (SpaControlMemRef)); + for (i = 0; i < n_buffers; i++) { + memref[i].mem_id = port->buffer_mem_id; + memref[i].offset = port->buffers[i].offset; + memref[i].size = port->buffers[i].size; + } + } else { + memref = NULL; + } + port->n_buffers = n_buffers; + + ub.seq = this->seq++; + ub.direction = direction; + ub.port_id = port_id; + ub.n_buffers = n_buffers; + ub.buffers = memref; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_USE_BUFFERS, &ub); + + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_RETURN_ASYNC (ub.seq); +} + +static SpaResult +spa_proxy_node_port_alloc_buffers (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaAllocParam **params, + uint32_t n_params, + SpaBuffer **buffers, + uint32_t *n_buffers) +{ + SpaProxy *this; + SpaProxyPort *port; + + if (node == NULL || buffers == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_PORT (this, direction, port_id)) + return SPA_RESULT_INVALID_PORT; + + port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; + + if (!port->format) + return SPA_RESULT_NO_FORMAT; + + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static void +copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) +{ + ProxyBuffer *b = &port->buffers[buffer_id]; + unsigned int i; + + for (i = 0; i < b->outbuf->n_metas; i++) { + SpaMeta *sm = &b->metas[i]; + SpaMeta *dm = &b->outbuf->metas[i]; + memcpy (dm->data, sm->data, dm->size); + } + for (i = 0; i < b->outbuf->n_datas; i++) { + b->outbuf->datas[i].size = b->buffer.datas[i].size; + if (b->outbuf->datas[i].type == SPA_DATA_TYPE_MEMPTR) { + spa_log_info (this->log, "memcpy in %zd\n", b->buffer.datas[i].size); + memcpy (b->outbuf->datas[i].data, b->datas[i].data, b->buffer.datas[i].size); + } + } +} + +static void +copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) +{ + ProxyBuffer *b = &port->buffers[buffer_id]; + unsigned int i; + + for (i = 0; i < b->outbuf->n_metas; i++) { + SpaMeta *sm = &b->outbuf->metas[i]; + SpaMeta *dm = &b->buffer.metas[i]; + memcpy (dm->data, sm->data, dm->size); + } + for (i = 0; i < b->outbuf->n_datas; i++) { + b->buffer.datas[i].size = b->outbuf->datas[i].size; + if (b->datas[i].type == SPA_DATA_TYPE_MEMPTR) { + spa_log_info (this->log, "memcpy out %zd\n", b->outbuf->datas[i].size); + memcpy (b->datas[i].data, b->outbuf->datas[i].data, b->outbuf->datas[i].size); + } + } +} + +static SpaResult +spa_proxy_node_port_push_input (SpaNode *node, + unsigned int n_info, + SpaPortInputInfo *info) +{ + SpaProxy *this; + SpaProxyPort *port; + unsigned int i; + bool have_error = false; + bool have_enough = false; + SpaControl control; + SpaControlBuilder builder; + SpaControlCmdProcessBuffer pb; + uint8_t buf[64]; + SpaResult res; + + if (node == NULL || n_info == 0 || info == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + spa_control_builder_init_into (&builder, buf, sizeof(buf), NULL, 0); + + for (i = 0; i < n_info; i++) { + if (!CHECK_IN_PORT (this, SPA_DIRECTION_INPUT, info[i].port_id)) { + spa_log_warn (this->log, "invalid port %d\n", info[i].port_id); + info[i].status = SPA_RESULT_INVALID_PORT; + have_error = true; + continue; + } + port = &this->in_ports[info[i].port_id]; + + if (!port->format) { + info[i].status = SPA_RESULT_NO_FORMAT; + have_error = true; + continue; + } + if (info[i].buffer_id >= port->n_buffers) { + if (port->n_buffers == 0) + info[i].status = SPA_RESULT_NO_BUFFERS; + else + info[i].status = SPA_RESULT_INVALID_BUFFER_ID; + have_error = true; + continue; + } + + copy_meta_out (this, port, info[i].buffer_id); + + pb.direction = SPA_DIRECTION_INPUT; + pb.port_id = info[i].port_id; + pb.buffer_id = info[i].buffer_id; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); + + info[i].status = SPA_RESULT_OK; + } + spa_control_builder_end (&builder, &control); + + if (have_error) + return SPA_RESULT_ERROR; + if (have_enough) + return SPA_RESULT_HAVE_ENOUGH_INPUT; + + if ((res = spa_control_write (&control, this->rtfds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control\n", this); + + spa_control_clear (&control); + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_pull_output (SpaNode *node, + unsigned int n_info, + SpaPortOutputInfo *info) +{ + SpaProxy *this; + SpaProxyPort *port; + unsigned int i; + bool have_error = false; + bool need_more = false; + + if (node == NULL || n_info == 0 || info == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + for (i = 0; i < n_info; i++) { + if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, info[i].port_id)) { + spa_log_warn (this->log, "invalid port %u\n", info[i].port_id); + info[i].status = SPA_RESULT_INVALID_PORT; + have_error = true; + continue; + } + + port = &this->out_ports[info[i].port_id]; + + if (!port->format) { + info[i].status = SPA_RESULT_NO_FORMAT; + have_error = true; + continue; + } + + info[i].buffer_id = port->buffer_id; + info[i].status = SPA_RESULT_OK; + + port->buffer_id = SPA_ID_INVALID; + } + if (have_error) + return SPA_RESULT_ERROR; + if (need_more) + return SPA_RESULT_NEED_MORE_INPUT; + + return SPA_RESULT_OK; +} + +static SpaResult +spa_proxy_node_port_reuse_buffer (SpaNode *node, + uint32_t port_id, + uint32_t buffer_id) +{ + SpaProxy *this; + SpaControlBuilder builder; + SpaControl control; + uint8_t buf[128]; + SpaResult res; + SpaControlCmdNodeEvent cne; + SpaNodeEvent ne; + SpaNodeEventReuseBuffer rb; + + if (node == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, port_id)) + return SPA_RESULT_INVALID_PORT; + + /* send start */ + spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); + cne.event = ≠ + ne.type = SPA_NODE_EVENT_TYPE_REUSE_BUFFER; + ne.data = &rb; + ne.size = sizeof (rb); + rb.port_id = port_id; + rb.buffer_id = buffer_id; + spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_EVENT, &cne); + spa_control_builder_end (&builder, &control); + + if ((res = spa_control_write (&control, this->rtfds[0].fd)) < 0) + spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); + + spa_control_clear (&control); + + return res; +} + +static SpaResult +spa_proxy_node_port_push_event (SpaNode *node, + SpaDirection direction, + uint32_t port_id, + SpaNodeEvent *event) +{ + SpaProxy *this; + + if (node == NULL || event == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + + this = SPA_CONTAINER_OF (node, SpaProxy, node); + + switch (event->type) { + default: + spa_log_warn (this->log, "unhandled event %d\n", event->type); + break; + } + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static SpaResult +handle_node_event (SpaProxy *this, + SpaNodeEvent *event) +{ + switch (event->type) { + case SPA_NODE_EVENT_TYPE_INVALID: + break; + + case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE: + case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: + case SPA_NODE_EVENT_TYPE_NEED_INPUT: + case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: + case SPA_NODE_EVENT_TYPE_DRAINED: + case SPA_NODE_EVENT_TYPE_MARKER: + 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: + this->event_cb (&this->node, event, this->user_data); + break; + } + + return SPA_RESULT_OK; +} + +static SpaResult +parse_control (SpaProxy *this, + SpaControl *ctrl) +{ + SpaControlIter it; + + spa_control_iter_init (&it, ctrl); + while (spa_control_iter_next (&it) == SPA_RESULT_OK) { + SpaControlCmd cmd = spa_control_iter_get_cmd (&it); + + switch (cmd) { + case SPA_CONTROL_CMD_INVALID: + case SPA_CONTROL_CMD_ADD_PORT: + case SPA_CONTROL_CMD_REMOVE_PORT: + case SPA_CONTROL_CMD_SET_FORMAT: + case SPA_CONTROL_CMD_SET_PROPERTY: + case SPA_CONTROL_CMD_NODE_COMMAND: + case SPA_CONTROL_CMD_PROCESS_BUFFER: + spa_log_error (this->log, "proxy %p: got unexpected control %d\n", this, cmd); + break; + + case SPA_CONTROL_CMD_NODE_UPDATE: + { + SpaControlCmdNodeUpdate nu; + + if (spa_control_iter_parse_cmd (&it, &nu) < 0) + break; + + if (nu.change_mask & SPA_CONTROL_CMD_NODE_UPDATE_MAX_INPUTS) + this->max_inputs = nu.max_input_ports; + if (nu.change_mask & SPA_CONTROL_CMD_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\n", this, cmd, + this->max_inputs, this->max_outputs); + + break; + } + + case SPA_CONTROL_CMD_PORT_UPDATE: + { + SpaControlCmdPortUpdate pu; + bool remove; + + spa_log_info (this->log, "proxy %p: got port update %d\n", this, cmd); + if (spa_control_iter_parse_cmd (&it, &pu) < 0) + break; + + if (!CHECK_PORT_ID (this, pu.direction, pu.port_id)) + break; + + remove = (pu.change_mask == 0); + + if (remove) { + do_uninit_port (this, pu.direction, pu.port_id); + } else { + do_update_port (this, &pu); + } + break; + } + + case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: + { + spa_log_warn (this->log, "proxy %p: command not implemented %d\n", this, cmd); + break; + } + + case SPA_CONTROL_CMD_NODE_STATE_CHANGE: + { + SpaControlCmdNodeStateChange sc; + SpaNodeState old = this->node.state; + + if (spa_control_iter_parse_cmd (&it, &sc) < 0) + break; + + spa_log_info (this->log, "proxy %p: got node state change %d -> %d\n", 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 SPA_CONTROL_CMD_ADD_MEM: + break; + case SPA_CONTROL_CMD_REMOVE_MEM: + break; + case SPA_CONTROL_CMD_USE_BUFFERS: + break; + + case SPA_CONTROL_CMD_NODE_EVENT: + { + SpaControlCmdNodeEvent cne; + + if (spa_control_iter_parse_cmd (&it, &cne) < 0) + break; + + handle_node_event (this, cne.event); + break; + } + } + } + spa_control_iter_end (&it); + + return SPA_RESULT_OK; +} + +static SpaResult +parse_rtcontrol (SpaProxy *this, + SpaControl *ctrl) +{ + SpaControlIter it; + + spa_control_iter_init (&it, ctrl); + while (spa_control_iter_next (&it) == SPA_RESULT_OK) { + SpaControlCmd cmd = spa_control_iter_get_cmd (&it); + + switch (cmd) { + case SPA_CONTROL_CMD_INVALID: + case SPA_CONTROL_CMD_NODE_UPDATE: + case SPA_CONTROL_CMD_PORT_UPDATE: + case SPA_CONTROL_CMD_NODE_STATE_CHANGE: + case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: + case SPA_CONTROL_CMD_ADD_PORT: + case SPA_CONTROL_CMD_REMOVE_PORT: + case SPA_CONTROL_CMD_SET_FORMAT: + case SPA_CONTROL_CMD_SET_PROPERTY: + case SPA_CONTROL_CMD_NODE_COMMAND: + case SPA_CONTROL_CMD_ADD_MEM: + case SPA_CONTROL_CMD_REMOVE_MEM: + case SPA_CONTROL_CMD_USE_BUFFERS: + spa_log_error (this->log, "proxy %p: got unexpected control %d\n", this, cmd); + break; + + case SPA_CONTROL_CMD_PROCESS_BUFFER: + { + SpaControlCmdProcessBuffer cmd; + SpaProxyPort *port; + + if (spa_control_iter_parse_cmd (&it, &cmd) < 0) + break; + + if (!CHECK_PORT (this, cmd.direction, cmd.port_id)) + break; + + port = cmd.direction == SPA_DIRECTION_INPUT ? &this->in_ports[cmd.port_id] : &this->out_ports[cmd.port_id]; + + if (port->buffer_id != SPA_ID_INVALID) + spa_log_warn (this->log, "proxy %p: unprocessed buffer: %d\n", this, port->buffer_id); + + copy_meta_in (this, port, cmd.buffer_id); + + port->buffer_id = cmd.buffer_id; + break; + } + case SPA_CONTROL_CMD_NODE_EVENT: + { + SpaControlCmdNodeEvent cne; + + if (spa_control_iter_parse_cmd (&it, &cne) < 0) + break; + + handle_node_event (this, cne.event); + break; + } + } + } + spa_control_iter_end (&it); + + return SPA_RESULT_OK; +} + +static int +proxy_on_fd_events (SpaPollNotifyData *data) +{ + SpaProxy *this = data->user_data; + SpaResult res; + + if (data->fds[0].revents & POLLIN) { + SpaControl control; + uint8_t buf[1024]; + int fds[16]; + + if ((res = spa_control_read (&control, data->fds[0].fd, buf, sizeof (buf), fds, 16)) < 0) { + spa_log_error (this->log, "proxy %p: failed to read control: %d\n", this, res); + return 0; + } + parse_control (this, &control); + spa_control_clear (&control); + } + return 0; +} + +static int +proxy_on_rtfd_events (SpaPollNotifyData *data) +{ + SpaProxy *this = data->user_data; + SpaResult res; + + if (data->fds[0].revents & POLLIN) { + SpaControl control; + uint8_t buf[1024]; + + if ((res = spa_control_read (&control, data->fds[0].fd, buf, sizeof (buf), NULL, 0)) < 0) { + spa_log_error (this->log, "proxy %p: failed to read control: %d\n", this, res); + return 0; + } + parse_rtcontrol (this, &control); + spa_control_clear (&control); + } + return 0; +} + +static const SpaNode proxy_node = { + sizeof (SpaNode), + NULL, + SPA_NODE_STATE_INIT, + spa_proxy_node_get_props, + spa_proxy_node_set_props, + spa_proxy_node_send_command, + spa_proxy_node_set_event_callback, + spa_proxy_node_get_n_ports, + spa_proxy_node_get_port_ids, + spa_proxy_node_add_port, + spa_proxy_node_remove_port, + spa_proxy_node_port_enum_formats, + spa_proxy_node_port_set_format, + spa_proxy_node_port_get_format, + spa_proxy_node_port_get_info, + spa_proxy_node_port_get_props, + spa_proxy_node_port_set_props, + spa_proxy_node_port_use_buffers, + spa_proxy_node_port_alloc_buffers, + spa_proxy_node_port_get_status, + spa_proxy_node_port_push_input, + spa_proxy_node_port_pull_output, + spa_proxy_node_port_reuse_buffer, + spa_proxy_node_port_push_event, +}; + +static SpaResult +proxy_init (SpaProxy *this, + SpaDict *info, + const SpaSupport *support, + unsigned int n_support) +{ + unsigned int i; + + for (i = 0; i < n_support; i++) { + if (strcmp (support[i].uri, SPA_LOG_URI) == 0) + this->log = support[i].data; + else if (strcmp (support[i].uri, SPA_POLL__MainLoop) == 0) + this->main_loop = support[i].data; + else if (strcmp (support[i].uri, SPA_POLL__DataLoop) == 0) + this->data_loop = support[i].data; + } + if (this->data_loop == NULL) { + spa_log_error (this->log, "a main-loop is needed"); + } + if (this->data_loop == NULL) { + spa_log_error (this->log, "a data-loop is needed"); + } + + this->node = proxy_node; + + this->fds[0].fd = -1; + this->fds[0].events = POLLIN | POLLPRI | POLLERR; + this->fds[0].revents = 0; + this->poll.id = 0; + this->poll.enabled = true; + this->poll.fds = this->fds; + this->poll.n_fds = 1; + this->poll.idle_cb = NULL; + this->poll.before_cb = NULL; + this->poll.after_cb = proxy_on_fd_events; + this->poll.user_data = this; + + this->rtfds[0].fd = -1; + this->rtfds[0].events = POLLIN | POLLPRI | POLLERR; + this->rtfds[0].revents = 0; + this->rtpoll.id = 0; + this->rtpoll.enabled = true; + this->rtpoll.fds = this->rtfds; + this->rtpoll.n_fds = 1; + this->rtpoll.idle_cb = NULL; + this->rtpoll.before_cb = NULL; + this->rtpoll.after_cb = proxy_on_rtfd_events; + this->rtpoll.user_data = this; + + return SPA_RESULT_OK; +} + +static SpaResult +proxy_clear (SpaProxy *this) +{ + unsigned int i; + + for (i = 0; i < MAX_INPUTS; i++) { + if (this->in_ports[i].valid) + clear_port (this, &this->in_ports[i], SPA_DIRECTION_INPUT, i); + } + for (i = 0; i < MAX_OUTPUTS; i++) { + if (this->out_ports[i].valid) + clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i); + } + if (this->fds[0].fd != -1) + spa_poll_remove_item (this->main_loop, &this->poll); + if (this->rtfds[0].fd != -1) + spa_poll_remove_item (this->data_loop, &this->rtpoll); + + return SPA_RESULT_OK; +} + static void pinos_client_node_get_property (GObject *_object, guint prop_id, @@ -94,6 +1417,107 @@ pinos_client_node_set_property (GObject *_object, } } +static void +pinos_client_node_dispose (GObject * object) +{ + PinosClientNode *this = PINOS_CLIENT_NODE (object); + PinosClientNodePrivate *priv = this->priv; + + g_debug ("client-node %p: dispose", this); + + proxy_clear (priv->proxy); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->dispose (object); +} + +static void +pinos_client_node_finalize (GObject * object) +{ + PinosClientNode *this = PINOS_CLIENT_NODE (object); + PinosClientNodePrivate *priv = this->priv; + + g_debug ("client-node %p: finalize", this); + + g_clear_object (&priv->sockets[0]); + g_clear_object (&priv->sockets[1]); + g_clear_object (&priv->rtsockets[0]); + g_clear_object (&priv->rtsockets[1]); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->finalize (object); +} + +static void +pinos_client_node_constructed (GObject * object) +{ + PinosClientNode *this = PINOS_CLIENT_NODE (object); + PinosClientNodePrivate *priv = this->priv; + + g_debug ("client-node %p: constructed", this); + + G_OBJECT_CLASS (pinos_client_node_parent_class)->constructed (object); + + + priv->proxy = (SpaProxy *) PINOS_NODE (this)->node; +} + +static void +pinos_client_node_class_init (PinosClientNodeClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (PinosClientNodePrivate)); + + gobject_class->constructed = pinos_client_node_constructed; + gobject_class->dispose = pinos_client_node_dispose; + gobject_class->finalize = pinos_client_node_finalize; + gobject_class->set_property = pinos_client_node_set_property; + gobject_class->get_property = pinos_client_node_get_property; +} + +static void +pinos_client_node_init (PinosClientNode * node) +{ + node->priv = PINOS_CLIENT_NODE_GET_PRIVATE (node); + + g_debug ("client-node %p: new", node); +} + +/** + * pinos_client_node_new: + * @daemon: a #PinosDaemon + * @client: the client owner + * @name: a name + * @properties: extra properties + * + * Create a new #PinosNode. + * + * Returns: a new #PinosNode + */ +PinosNode * +pinos_client_node_new (PinosDaemon *daemon, + PinosClient *client, + const gchar *name, + PinosProperties *properties) +{ + PinosNode *node; + SpaProxy *p; + + g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL); + + p = g_malloc0 (sizeof (SpaProxy)); + proxy_init (p, NULL, daemon->support, daemon->n_support); + + node = g_object_new (PINOS_TYPE_CLIENT_NODE, + "daemon", daemon, + "client", client, + "name", name, + "properties", properties, + "node", p, + NULL); + + return node; +} + /** * pinos_client_node_get_socket_pair: * @node: a #PinosClientNode @@ -106,18 +1530,14 @@ pinos_client_node_set_property (GObject *_object, */ GSocket * pinos_client_node_get_socket_pair (PinosClientNode *this, - GError **error) + GError **error) { - PinosNode *node; PinosClientNodePrivate *priv; g_return_val_if_fail (PINOS_IS_CLIENT_NODE (this), FALSE); - node = PINOS_NODE (this); priv = this->priv; if (priv->sockets[1] == NULL) { - SpaProps *props; - SpaPropValue value; int fd[2]; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0) @@ -131,13 +1551,8 @@ pinos_client_node_get_socket_pair (PinosClientNode *this, if (priv->sockets[1] == NULL) goto create_failed; - priv->fd = g_socket_get_fd (priv->sockets[0]); - - spa_node_get_props (node->node, &props); - value.value = &priv->fd; - value.size = sizeof (int); - spa_props_set_value (props, spa_props_index_for_name (props, "socket"), &value); - spa_node_set_props (node->node, props); + priv->proxy->fds[0].fd = g_socket_get_fd (priv->sockets[0]); + spa_poll_add_item (priv->proxy->main_loop, &priv->proxy->poll); } return g_object_ref (priv->sockets[1]); @@ -172,16 +1587,12 @@ GSocket * pinos_client_node_get_rtsocket_pair (PinosClientNode *this, GError **error) { - PinosNode *node; PinosClientNodePrivate *priv; g_return_val_if_fail (PINOS_IS_CLIENT_NODE (this), FALSE); - node = PINOS_NODE (this); priv = this->priv; if (priv->rtsockets[1] == NULL) { - SpaProps *props; - SpaPropValue value; int fd[2]; if (socketpair (AF_UNIX, SOCK_STREAM, 0, fd) != 0) @@ -195,13 +1606,8 @@ pinos_client_node_get_rtsocket_pair (PinosClientNode *this, if (priv->rtsockets[1] == NULL) goto create_failed; - priv->rtfd = g_socket_get_fd (priv->rtsockets[0]); - - spa_node_get_props (node->node, &props); - value.value = &priv->rtfd; - value.size = sizeof (int); - spa_props_set_value (props, spa_props_index_for_name (props, "rt-socket"), &value); - spa_node_set_props (node->node, props); + priv->proxy->rtfds[0].fd = g_socket_get_fd (priv->rtsockets[0]); + spa_poll_add_item (priv->proxy->data_loop, &priv->proxy->rtpoll); } return g_object_ref (priv->rtsockets[1]); @@ -221,169 +1627,3 @@ create_failed: return NULL; } } - -static void -pinos_client_node_dispose (GObject * object) -{ - PinosClientNode *this = PINOS_CLIENT_NODE (object); - PinosNode *node = PINOS_NODE (this); - SpaProps *props; - SpaPropValue value; - int fd = -1; - - g_debug ("client-node %p: dispose", this); - - spa_node_get_props (node->node, &props); - value.value = &fd; - value.size = sizeof (int); - spa_props_set_value (props, spa_props_index_for_name (props, "socket"), &value); - spa_props_set_value (props, spa_props_index_for_name (props, "rt-socket"), &value); - spa_node_set_props (node->node, props); - - G_OBJECT_CLASS (pinos_client_node_parent_class)->dispose (object); -} - -static void -pinos_client_node_finalize (GObject * object) -{ - PinosClientNode *this = PINOS_CLIENT_NODE (object); - PinosClientNodePrivate *priv = this->priv; - - g_debug ("client-node %p: finalize", this); - - g_clear_object (&priv->sockets[0]); - g_clear_object (&priv->sockets[1]); - g_clear_object (&priv->rtsockets[0]); - g_clear_object (&priv->rtsockets[1]); - spa_handle_clear (priv->handle); - g_free (priv->handle); - - G_OBJECT_CLASS (pinos_client_node_parent_class)->finalize (object); -} - -static void -pinos_client_node_constructed (GObject * object) -{ - PinosClientNode *this = PINOS_CLIENT_NODE (object); - - g_debug ("client-node %p: constructed", this); - - G_OBJECT_CLASS (pinos_client_node_parent_class)->constructed (object); -} - -static void -pinos_client_node_class_init (PinosClientNodeClass * klass) -{ - GObjectClass *gobject_class = G_OBJECT_CLASS (klass); - - g_type_class_add_private (klass, sizeof (PinosClientNodePrivate)); - - gobject_class->constructed = pinos_client_node_constructed; - gobject_class->dispose = pinos_client_node_dispose; - gobject_class->finalize = pinos_client_node_finalize; - gobject_class->set_property = pinos_client_node_set_property; - gobject_class->get_property = pinos_client_node_get_property; -} - -static void -pinos_client_node_init (PinosClientNode * node) -{ - node->priv = PINOS_CLIENT_NODE_GET_PRIVATE (node); - - g_debug ("client-node %p: new", node); -} - -static SpaResult -make_node (PinosDaemon *daemon, SpaHandle **handle, SpaNode **node, const char *lib, const char *name) -{ - SpaResult res; - void *hnd, *state = NULL; - SpaEnumHandleFactoryFunc enum_func; - - if ((hnd = dlopen (lib, RTLD_NOW)) == NULL) { - g_error ("can't load %s: %s", lib, dlerror()); - return SPA_RESULT_ERROR; - } - if ((enum_func = dlsym (hnd, "spa_enum_handle_factory")) == NULL) { - g_error ("can't find enum function"); - return SPA_RESULT_ERROR; - } - - while (true) { - const SpaHandleFactory *factory; - void *iface; - - if ((res = enum_func (&factory, &state)) < 0) { - if (res != SPA_RESULT_ENUM_END) - g_error ("can't enumerate factories: %d", res); - break; - } - if (strcmp (factory->name, name)) - continue; - - *handle = calloc (1, factory->size); - if ((res = factory->init (factory, - *handle, - NULL, - daemon->support, - daemon->n_support)) < 0) { - g_error ("can't make factory instance: %d", res); - return res; - } - if ((res = spa_handle_get_interface (*handle, - spa_id_map_get_id (daemon->map, SPA_NODE_URI), - &iface)) < 0) { - g_error ("can't get interface %d", res); - return res; - } - *node = iface; - return SPA_RESULT_OK; - } - return SPA_RESULT_ERROR; -} - -/** - * pinos_client_node_new: - * @daemon: a #PinosDaemon - * @client: the client owner - * @name: a name - * @properties: extra properties - * - * Create a new #PinosNode. - * - * Returns: a new #PinosNode - */ -PinosNode * -pinos_client_node_new (PinosDaemon *daemon, - PinosClient *client, - const gchar *name, - PinosProperties *properties) -{ - SpaNode *n; - SpaResult res; - SpaHandle *handle; - PinosNode *node; - - g_return_val_if_fail (PINOS_IS_DAEMON (daemon), NULL); - - if ((res = make_node (daemon, - &handle, - &n, - "build/spa/plugins/remote/libspa-remote.so", - "proxy")) < 0) { - g_error ("can't create proxy: %d", res); - return NULL; - } - - node = g_object_new (PINOS_TYPE_CLIENT_NODE, - "daemon", daemon, - "client", client, - "name", name, - "properties", properties, - "node", n, - NULL); - - PINOS_CLIENT_NODE (node)->priv->handle = handle; - - return node; -} diff --git a/pinos/server/dbus-client-node.c b/pinos/server/dbus-client-node.c index 1458f2f49..de8a6bff4 100644 --- a/pinos/server/dbus-client-node.c +++ b/pinos/server/dbus-client-node.c @@ -36,9 +36,6 @@ #include "pinos/dbus/org-pinos.h" -#include "spa/include/spa/control.h" - - struct _PinosDBusClientNodePrivate { int fd; diff --git a/spa/include/spa/buffer.h b/spa/include/spa/buffer.h index 1af514800..7bc05600c 100644 --- a/spa/include/spa/buffer.h +++ b/spa/include/spa/buffer.h @@ -174,7 +174,7 @@ struct _SpaBuffer { SpaData *datas; }; -inline void * +static inline void * spa_buffer_find_meta (SpaBuffer *b, SpaMetaType type) { unsigned int i; @@ -185,11 +185,20 @@ spa_buffer_find_meta (SpaBuffer *b, SpaMetaType type) return NULL; } -size_t spa_buffer_get_size (const SpaBuffer *buffer); -size_t spa_buffer_serialize (void *dest, const SpaBuffer *buffer); -SpaBuffer * spa_buffer_deserialize (void *src, off_t offset); - -size_t spa_meta_type_get_size (SpaMetaType type); +static inline size_t +spa_meta_type_get_size (SpaMetaType type) +{ + static const size_t header_sizes[] = { + 0, + sizeof (SpaMetaHeader), + sizeof (SpaMetaPointer), + sizeof (SpaMetaVideoCrop), + sizeof (SpaMetaRingbuffer), + }; + if (type <= 0 || type >= SPA_N_ELEMENTS (header_sizes)) + return 0; + return header_sizes[type]; +} #ifdef __cplusplus } /* extern "C" */ diff --git a/spa/include/spa/format.h b/spa/include/spa/format.h index bb5983ae3..abb4919b1 100644 --- a/spa/include/spa/format.h +++ b/spa/include/spa/format.h @@ -98,14 +98,15 @@ typedef enum { } SpaFormatProps; -SpaResult spa_format_fixate (SpaFormat *format); - -size_t spa_format_get_size (const SpaFormat *format); -size_t spa_format_serialize (void *dest, const SpaFormat *format); -SpaFormat * spa_format_deserialize (void *src, off_t offset); - -SpaFormat * spa_format_copy_into (void *dest, const SpaFormat *format); +static inline SpaResult +spa_format_fixate (SpaFormat *format) +{ + if (format == NULL) + return SPA_RESULT_INVALID_ARGUMENTS; + format->props.unset_mask = 0; + return SPA_RESULT_OK; +} #ifdef __cplusplus } /* extern "C" */ diff --git a/spa/include/spa/log.h b/spa/include/spa/log.h index 8c72fdc07..8bd3f726a 100644 --- a/spa/include/spa/log.h +++ b/spa/include/spa/log.h @@ -107,6 +107,8 @@ struct _SpaLog { va_list args) SPA_PRINTF_FUNC(6, 0); }; +#define spa_log_level_enabled(l,lev) ((l) && (l)->level >= (lev)) + #if __STDC_VERSION__ >= 199901L #define spa_log_log(l,lev,...) \ @@ -124,7 +126,7 @@ struct _SpaLog { #define SPA_LOG_FUNC(name,lev) \ static inline void spa_log_##name (SpaLog *l, const char *format, ...) \ { \ - if ((l) && (l)->level >= lev) { \ + if (spa_log_level_enabled (l, lev)) { \ va_list varargs; \ va_start (varargs, format); \ (l)->logv((l),lev,__FILE__,__LINE__,__func__,format,varargs); \ diff --git a/spa/include/spa/port.h b/spa/include/spa/port.h index a78969d4a..5d5f2ee61 100644 --- a/spa/include/spa/port.h +++ b/spa/include/spa/port.h @@ -124,12 +124,6 @@ typedef struct { } SpaPortInfo; -size_t spa_port_info_get_size (const SpaPortInfo *info); -size_t spa_port_info_serialize (void *dest, const SpaPortInfo *info); -SpaPortInfo * spa_port_info_deserialize (void *src, off_t offset); - -SpaPortInfo * spa_port_info_copy_into (void *dest, const SpaPortInfo *info); - /** * SpaPortStatusFlags: * @SPA_PORT_STATUS_FLAG_NONE: no status flags diff --git a/spa/include/spa/props.h b/spa/include/spa/props.h index 5b4622fbc..f83a9771b 100644 --- a/spa/include/spa/props.h +++ b/spa/include/spa/props.h @@ -235,13 +235,6 @@ SpaResult spa_props_copy_values (const SpaProps *src, SpaProps *dest); -size_t spa_props_get_size (const SpaProps *props); -size_t spa_props_serialize (void *dest, const SpaProps *props); -SpaProps * spa_props_deserialize (void *src, off_t offset); - -SpaProps * spa_props_copy_into (void *dest, const SpaProps *props); - - #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/spa/lib/buffer.c b/spa/lib/buffer.c deleted file mode 100644 index 79abc054b..000000000 --- a/spa/lib/buffer.c +++ /dev/null @@ -1,113 +0,0 @@ -/* Simple Plugin API - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include -#include - -static const size_t header_sizes[] = { - 0, - sizeof (SpaMetaHeader), - sizeof (SpaMetaPointer), - sizeof (SpaMetaVideoCrop), - sizeof (SpaMetaRingbuffer), -}; - -size_t -spa_meta_type_get_size (SpaMetaType type) -{ - if (type <= 0 || type >= SPA_N_ELEMENTS (header_sizes)) - return 0; - - return header_sizes[type]; -} - -size_t -spa_buffer_get_size (const SpaBuffer *buffer) -{ - size_t size; - unsigned int i; - - if (buffer == NULL) - return 0; - - size = sizeof (SpaBuffer); - for (i = 0; i < buffer->n_metas; i++) - size += sizeof (SpaMeta) + buffer->metas[i].size; - for (i = 0; i < buffer->n_datas; i++) - size += sizeof (SpaData); - return size; -} - -size_t -spa_buffer_serialize (void *dest, const SpaBuffer *buffer) -{ - SpaBuffer *tb; - SpaMeta *mp; - SpaData *dp; - void *p; - unsigned int i; - - if (buffer == NULL) - return 0; - - tb = dest; - memcpy (tb, buffer, sizeof (SpaBuffer)); - mp = SPA_MEMBER (tb, sizeof(SpaBuffer), SpaMeta); - dp = SPA_MEMBER (mp, sizeof(SpaMeta) * tb->n_metas, SpaData); - p = SPA_MEMBER (dp, sizeof(SpaData) * tb->n_datas, void); - - tb->metas = SPA_INT_TO_PTR (SPA_PTRDIFF (mp, tb)); - tb->datas = SPA_INT_TO_PTR (SPA_PTRDIFF (dp, tb)); - - for (i = 0; i < tb->n_metas; i++) { - memcpy (&mp[i], &buffer->metas[i], sizeof (SpaMeta)); - memcpy (p, mp[i].data, mp[i].size); - mp[i].data = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tb)); - p += mp[i].size; - } - for (i = 0; i < tb->n_datas; i++) - memcpy (&dp[i], &buffer->datas[i], sizeof (SpaData)); - - return SPA_PTRDIFF (p, tb); -} - -SpaBuffer * -spa_buffer_deserialize (void *src, off_t offset) -{ - SpaBuffer *b; - unsigned int i; - - b = SPA_MEMBER (src, offset, SpaBuffer); - if (b->metas) - b->metas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->metas), SpaMeta); - for (i = 0; i < b->n_metas; i++) { - SpaMeta *m = &b->metas[i]; - if (m->data) - m->data = SPA_MEMBER (b, SPA_PTR_TO_INT (m->data), void); - } - if (b->datas) - b->datas = SPA_MEMBER (b, SPA_PTR_TO_INT (b->datas), SpaData); - - return b; -} diff --git a/spa/lib/format.c b/spa/lib/format.c deleted file mode 100644 index f312bc2a0..000000000 --- a/spa/lib/format.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Simple Plugin API - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include -#include - - -SpaResult -spa_format_fixate (SpaFormat *format) -{ - if (format == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - format->props.unset_mask = 0; - - return SPA_RESULT_OK; -} - -size_t -spa_format_get_size (const SpaFormat *format) -{ - if (format == NULL) - return 0; - - return spa_props_get_size (&format->props) - sizeof (SpaProps) + sizeof (SpaFormat); -} - -size_t -spa_format_serialize (void *dest, const SpaFormat *format) -{ - SpaFormat *tf; - size_t size; - - if (format == NULL) - return 0; - - tf = dest; - tf->media_type = format->media_type; - tf->media_subtype = format->media_subtype; - - dest = SPA_MEMBER (tf, offsetof (SpaFormat, props), void); - size = spa_props_serialize (dest, &format->props) - sizeof (SpaProps) + sizeof (SpaFormat); - - return size; -} - -SpaFormat * -spa_format_deserialize (void *src, off_t offset) -{ - SpaFormat *f; - - f = SPA_MEMBER (src, offset, SpaFormat); - spa_props_deserialize (f, offsetof (SpaFormat, props)); - - return f; -} - -SpaFormat * -spa_format_copy_into (void *dest, const SpaFormat *format) -{ - if (format == NULL) - return NULL; - - spa_format_serialize (dest, format); - return spa_format_deserialize (dest, 0); -} diff --git a/spa/lib/mapper.c b/spa/lib/mapper.c index df0cb054a..bdc31efef 100644 --- a/spa/lib/mapper.c +++ b/spa/lib/mapper.c @@ -38,54 +38,53 @@ #include #include -static const char *uris[] = { - NULL, - SPA_ID_MAP_URI, - SPA_LOG_URI, - SPA_BUFFER_URI, - SPA_CLOCK_URI, - SPA_MONITOR_URI, - SPA_NODE_URI, - SPA_NODE_COMMAND_URI, - SPA_NODE_EVENT_URI, - SPA_ALLOC_PARAM_URI, - SPA_PROPS_URI, - SPA_QUEUE_URI, - SPA_RINGBUFFER_URI, - SPA_POLL__MainLoop, - SPA_POLL__DataLoop, -}; +#define MAX_URIS 4096 + +typedef struct { + SpaIDMap map; + char *uris[MAX_URIS]; + unsigned int n_uris; +} IDMap; static uint32_t id_map_get_id (SpaIDMap *map, const char *uri) { + IDMap *this = SPA_CONTAINER_OF (map, IDMap, map); + unsigned int i = 0; + if (uri != NULL) { - unsigned int i; - for (i = 1; i < SPA_N_ELEMENTS (uris); i++) { - if (strcmp (uris[i], uri) == 0) + for (i = 1; i <= this->n_uris; i++) { + if (strcmp (this->uris[i], uri) == 0) return i; } + this->uris[i] = (char *)uri; + this->n_uris++; } - return 0; + return i; } static const char * id_map_get_uri (SpaIDMap *map, uint32_t id) { - if (id < SPA_N_ELEMENTS (uris)) - return uris[id]; + IDMap *this = SPA_CONTAINER_OF (map, IDMap, map); + + if (id < this->n_uris) + return this->uris[id]; return 0; } -static const SpaIDMap default_map = { - sizeof (SpaIDMap), - NULL, - id_map_get_id, - id_map_get_uri, +static IDMap default_id_map = { + { sizeof (SpaIDMap), + NULL, + id_map_get_id, + id_map_get_uri, + }, + { NULL, }, + 0 }; SpaIDMap * spa_id_map_get_default (void) { - return (SpaIDMap *) &default_map; + return &default_id_map.map; } diff --git a/spa/lib/meson.build b/spa/lib/meson.build index 7205ac954..d1f5b66fb 100644 --- a/spa/lib/meson.build +++ b/spa/lib/meson.build @@ -1,10 +1,6 @@ spalib_sources = ['audio-raw.c', - 'buffer.c', - 'control.c', 'debug.c', - 'format.c', 'mapper.c', - 'port.c', 'props.c', 'video-raw.c'] diff --git a/spa/lib/port.c b/spa/lib/port.c deleted file mode 100644 index a1d0a0273..000000000 --- a/spa/lib/port.c +++ /dev/null @@ -1,101 +0,0 @@ -/* Simple Plugin API - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include - -#include -#include - - -size_t -spa_port_info_get_size (const SpaPortInfo *info) -{ - size_t len; - unsigned int i; - - if (info == NULL) - return 0; - - len = sizeof (SpaPortInfo); - len += info->n_params * sizeof (SpaAllocParam *); - for (i = 0; i < info->n_params; i++) - len += info->params[i]->size; - - return len; -} - -size_t -spa_port_info_serialize (void *p, const SpaPortInfo *info) -{ - SpaPortInfo *pi; - SpaAllocParam **ap; - int i; - size_t len; - - if (info == NULL) - return 0; - - pi = p; - memcpy (pi, info, sizeof (SpaPortInfo)); - - ap = SPA_MEMBER (pi, sizeof (SpaPortInfo), SpaAllocParam *); - if (info->n_params) - pi->params = SPA_INT_TO_PTR (SPA_PTRDIFF (ap, pi)); - else - pi->params = 0; - pi->extra = 0; - - p = SPA_MEMBER (ap, sizeof (SpaAllocParam*) * info->n_params, void); - - for (i = 0; i < info->n_params; i++) { - len = info->params[i]->size; - memcpy (p, info->params[i], len); - ap[i] = SPA_INT_TO_PTR (SPA_PTRDIFF (p, pi)); - p = SPA_MEMBER (p, len, void); - } - return SPA_PTRDIFF (p, pi); -} - -SpaPortInfo * -spa_port_info_deserialize (void *p, off_t offset) -{ - SpaPortInfo *pi; - unsigned int i; - - pi = SPA_MEMBER (p, offset, SpaPortInfo); - if (pi->params) - pi->params = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->params), SpaAllocParam *); - for (i = 0; i < pi->n_params; i++) { - pi->params[i] = SPA_MEMBER (pi, SPA_PTR_TO_INT (pi->params[i]), SpaAllocParam); - } - return pi; -} - -SpaPortInfo * -spa_port_info_copy_into (void *dest, const SpaPortInfo *info) -{ - if (info == NULL) - return NULL; - - spa_port_info_serialize (dest, info); - return spa_port_info_deserialize (dest, 0); -} diff --git a/spa/lib/props.c b/spa/lib/props.c index 128c03259..ac3301b3d 100644 --- a/spa/lib/props.c +++ b/spa/lib/props.c @@ -102,143 +102,3 @@ spa_props_copy_values (const SpaProps *src, } return SPA_RESULT_OK; } - -size_t -spa_props_get_size (const SpaProps *props) -{ - size_t len; - unsigned int i, j; - SpaPropInfo *pi; - SpaPropRangeInfo *ri; - - if (props == NULL) - return 0; - - len = sizeof (SpaProps); - for (i = 0; i < props->n_prop_info; i++) { - pi = (SpaPropInfo *) &props->prop_info[i]; - len += sizeof (SpaPropInfo); - len += pi->name ? strlen (pi->name) + 1 : 0; - /* for the value */ - len += pi->maxsize; - for (j = 0; j < pi->n_range_values; j++) { - ri = (SpaPropRangeInfo *)&pi->range_values[j]; - len += sizeof (SpaPropRangeInfo); - len += ri->name ? strlen (ri->name) + 1 : 0; - /* the size of the range value */ - len += ri->val.size; - } - } - return len; -} - -size_t -spa_props_serialize (void *p, const SpaProps *props) -{ - size_t len, slen; - unsigned int i, j, c; - SpaProps *tp; - SpaPropInfo *pi; - SpaPropRangeInfo *ri; - - if (props == NULL) - return 0; - - tp = p; - memcpy (tp, props, sizeof (SpaProps)); - pi = SPA_MEMBER (tp, sizeof(SpaProps), SpaPropInfo); - ri = SPA_MEMBER (pi, sizeof(SpaPropInfo) * tp->n_prop_info, SpaPropRangeInfo); - - tp->prop_info = SPA_INT_TO_PTR (SPA_PTRDIFF (pi, tp)); - - /* write propinfo array */ - for (i = 0, c = 0; i < tp->n_prop_info; i++) { - memcpy (&pi[i], &props->prop_info[i], sizeof (SpaPropInfo)); - pi[i].range_values = SPA_INT_TO_PTR (SPA_PTRDIFF (&ri[c], tp)); - for (j = 0; j < pi[i].n_range_values; j++, c++) { - memcpy (&ri[c], &props->prop_info[i].range_values[j], sizeof (SpaPropRangeInfo)); - } - } - p = &ri[c]; - /* strings and default values from props and ranges */ - for (i = 0, c = 0; i < tp->n_prop_info; i++) { - if (pi[i].name) { - slen = strlen (pi[i].name) + 1; - memcpy (p, pi[i].name, slen); - pi[i].name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); - p += slen; - } else { - pi[i].name = 0; - } - for (j = 0; j < pi[i].n_range_values; j++, c++) { - if (ri[c].name) { - slen = strlen (ri[c].name) + 1; - memcpy (p, ri[c].name, slen); - ri[c].name = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); - p += slen; - } else { - ri[c].name = 0; - } - if (ri[c].val.size) { - memcpy (p, ri[c].val.value, ri[c].val.size); - ri[c].val.value = SPA_INT_TO_PTR (SPA_PTRDIFF (p, tp)); - p += ri[c].val.size; - } else { - ri[c].val.value = 0; - } - } - } - /* and the actual values */ - for (i = 0; i < tp->n_prop_info; i++) { - if (pi[i].offset) { - memcpy (p, SPA_MEMBER (props, pi[i].offset, void), pi[i].maxsize); - pi[i].offset = SPA_PTRDIFF (p, tp); - p += pi[i].maxsize; - } else { - pi[i].offset = 0; - } - } - len = SPA_PTRDIFF (p, tp); - - return len; -} - -SpaProps * -spa_props_deserialize (void *p, off_t offset) -{ - SpaProps *tp; - unsigned int i, j; - SpaPropInfo *pi; - SpaPropRangeInfo *ri; - - tp = SPA_MEMBER (p, offset, SpaProps); - if (tp->prop_info) - tp->prop_info = SPA_MEMBER (tp, SPA_PTR_TO_INT (tp->prop_info), SpaPropInfo); - /* now fix all the pointers */ - for (i = 0; i < tp->n_prop_info; i++) { - pi = (SpaPropInfo *) &tp->prop_info[i]; - if (pi->name) - pi->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->name), char); - if (pi->range_values) - pi->range_values = SPA_MEMBER (tp, SPA_PTR_TO_INT (pi->range_values), SpaPropRangeInfo); - - for (j = 0; j < pi->n_range_values; j++) { - ri = (SpaPropRangeInfo *) &pi->range_values[j]; - if (ri->name) - ri->name = SPA_MEMBER (tp, SPA_PTR_TO_INT (ri->name), char); - if (ri->val.value) - ri->val.value = SPA_MEMBER (tp, SPA_PTR_TO_INT (ri->val.value), void); - } - } - return tp; -} - -SpaProps * -spa_props_copy_into (void *dest, const SpaProps *props) -{ - if (props == NULL) - return NULL; - - spa_props_serialize (dest, props); - return spa_props_deserialize (dest, 0); -} diff --git a/spa/plugins/meson.build b/spa/plugins/meson.build index ecba29c6d..89377a1b3 100644 --- a/spa/plugins/meson.build +++ b/spa/plugins/meson.build @@ -2,7 +2,6 @@ subdir('alsa') subdir('audiomixer') subdir('audiotestsrc') subdir('ffmpeg') -subdir('remote') #subdir('libva') subdir('videotestsrc') subdir('volume') diff --git a/spa/plugins/remote/dbus-proxy.c b/spa/plugins/remote/dbus-proxy.c deleted file mode 100644 index e6eeea1c6..000000000 --- a/spa/plugins/remote/dbus-proxy.c +++ /dev/null @@ -1,1439 +0,0 @@ -/* Spa - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include "../lib/memfd-wrappers.h" - -#define MAX_INPUTS 64 -#define MAX_OUTPUTS 64 - -#define MAX_BUFFERS 16 - -#define CHECK_IN_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS) -#define CHECK_OUT_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_OUTPUTS) -#define CHECK_PORT_ID(this,d,p) (CHECK_IN_PORT_ID(this,d,p) || CHECK_OUT_PORT_ID(this,d,p)) -#define CHECK_FREE_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && !(this)->in_ports[p].valid) -#define CHECK_FREE_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && !(this)->out_ports[p].valid) -#define CHECK_FREE_PORT(this,d,p) (CHECK_FREE_IN_PORT (this,d,p) || CHECK_FREE_OUT_PORT (this,d,p)) -#define CHECK_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p].valid) -#define CHECK_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p].valid) -#define CHECK_PORT(this,d,p) (CHECK_IN_PORT (this,d,p) || CHECK_OUT_PORT (this,d,p)) - - -typedef struct _SpaDBusProxy SpaDBusProxy; -typedef struct _ProxyBuffer ProxyBuffer; - -struct _ProxyBuffer { - SpaBuffer *outbuf; - SpaBuffer buffer; - SpaMeta metas[4]; - SpaData datas[4]; - off_t offset; - size_t size; -}; - -typedef struct { - SpaProps props; - int socketfd; -} SpaDBusProxyProps; - -typedef struct { - bool valid; - SpaPortInfo *info; - SpaFormat *format; - unsigned int n_formats; - SpaFormat **formats; - SpaPortStatus status; - - unsigned int n_buffers; - ProxyBuffer buffers[MAX_BUFFERS]; - - uint32_t buffer_mem_id; - int buffer_mem_fd; - size_t buffer_mem_size; - void *buffer_mem_ptr; - - uint32_t buffer_id; - SpaQueue ready; -} SpaDBusProxyPort; - -typedef struct { - uint32_t node; -} URI; - -struct _SpaDBusProxy { - SpaHandle handle; - SpaNode node; - - URI uri; - SpaIDMap *map; - SpaLog *log; - SpaPoll *data_loop; - - SpaDBusProxyProps props[2]; - - SpaNodeEventCallback event_cb; - void *user_data; - - SpaPollFd fds[1]; - SpaPollItem poll; - - unsigned int max_inputs; - unsigned int n_inputs; - unsigned int max_outputs; - unsigned int n_outputs; - SpaDBusProxyPort in_ports[MAX_INPUTS]; - SpaDBusProxyPort out_ports[MAX_OUTPUTS]; - - uint32_t seq; -}; - -enum { - PROP_ID_SOCKET, - PROP_ID_LAST, -}; - -static const SpaPropInfo prop_info[PROP_ID_LAST] = -{ - { PROP_ID_SOCKET, offsetof (SpaDBusProxyProps, socketfd), - "socket", - SPA_PROP_FLAG_READWRITE, - SPA_PROP_TYPE_INT, sizeof (int), - SPA_PROP_RANGE_TYPE_NONE, 0, NULL, - NULL }, -}; - -static void -reset_proxy_props (SpaDBusProxyProps *props) -{ - props->socketfd = -1; -} - -static SpaResult -update_poll (SpaDBusProxy *this, int socketfd) -{ - SpaDBusProxyProps *p; - SpaResult res = SPA_RESULT_OK; - - p = &this->props[1]; - - if (p->socketfd != -1) { - spa_poll_remove_item (this->data_loop, &this->poll); - } - p->socketfd = socketfd; - - if (p->socketfd != -1) { - this->fds[0].fd = p->socketfd; - spa_poll_add_item (this->data_loop, &this->poll); - } - return res; -} - -static void -send_async_complete (SpaDBusProxy *this, uint32_t seq, SpaResult res) -{ - SpaNodeEvent event; - SpaNodeEventAsyncComplete ac; - - event.type = SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE; - event.data = ∾ - event.size = sizeof (ac); - ac.seq = seq; - ac.res = res; - this->event_cb (&this->node, &event, this->user_data); -} - -static SpaResult -clear_buffers (SpaDBusProxy *this, SpaDBusProxyPort *port) -{ - if (port->n_buffers) { - spa_log_info (this->log, "proxy %p: clear buffers\n", this); - - munmap (port->buffer_mem_ptr, port->buffer_mem_size); - close (port->buffer_mem_fd); - - port->n_buffers = 0; - SPA_QUEUE_INIT (&port->ready); - } - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_props (SpaNode *node, - SpaProps **props) -{ - SpaDBusProxy *this; - - if (node == NULL || props == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - memcpy (&this->props[0], &this->props[1], sizeof (this->props[1])); - *props = &this->props[0].props; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_set_props (SpaNode *node, - const SpaProps *props) -{ - SpaDBusProxy *this; - SpaDBusProxyProps *op, *np; - SpaResult res; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - op = &this->props[1]; - np = &this->props[0]; - - if (props == NULL) { - reset_proxy_props (np); - props = &np->props; - } - - /* copy new properties */ - res = spa_props_copy_values (props, &np->props); - - /* compare changes */ - if (op->socketfd != np->socketfd) - res = update_poll (this, np->socketfd); - - /* commit changes */ - memcpy (op, np, sizeof (*np)); - - return res; -} - -static SpaResult -spa_proxy_node_send_command (SpaNode *node, - SpaNodeCommand *command) -{ - SpaDBusProxy *this; - SpaResult res = SPA_RESULT_OK; - - if (node == NULL || command == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - switch (command->type) { - case SPA_NODE_COMMAND_INVALID: - return SPA_RESULT_INVALID_COMMAND; - - case SPA_NODE_COMMAND_START: - case SPA_NODE_COMMAND_PAUSE: - case SPA_NODE_COMMAND_FLUSH: - case SPA_NODE_COMMAND_DRAIN: - case SPA_NODE_COMMAND_MARKER: - { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaControlCmdNodeCommand cnc; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cnc.seq = this->seq++; - cnc.command = command; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - - res = SPA_RESULT_RETURN_ASYNC (cnc.seq); - break; - } - - case SPA_NODE_COMMAND_CLOCK_UPDATE: - { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaControlCmdNodeCommand cnc; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cnc.command = command; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - break; - } - } - return res; -} - -static SpaResult -spa_proxy_node_set_event_callback (SpaNode *node, - SpaNodeEventCallback event, - void *user_data) -{ - SpaDBusProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - this->event_cb = event; - this->user_data = user_data; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_n_ports (SpaNode *node, - unsigned int *n_input_ports, - unsigned int *max_input_ports, - unsigned int *n_output_ports, - unsigned int *max_output_ports) -{ - SpaDBusProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (n_input_ports) - *n_input_ports = this->n_inputs; - if (max_input_ports) - *max_input_ports = this->max_inputs; - if (n_output_ports) - *n_output_ports = this->n_outputs; - if (max_output_ports) - *max_output_ports = this->max_outputs; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_port_ids (SpaNode *node, - unsigned int n_input_ports, - uint32_t *input_ids, - unsigned int n_output_ports, - uint32_t *output_ids) -{ - SpaDBusProxy *this; - int c, i; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (input_ids) { - for (c = 0, i = 0; i < MAX_INPUTS && c < n_input_ports; i++) { - if (this->in_ports[i].valid) - input_ids[c++] = i; - } - } - if (output_ids) { - for (c = 0, i = 0; i < MAX_OUTPUTS && c < n_output_ports; i++) { - if (this->out_ports[i].valid) - output_ids[c++] = i; - } - } - return SPA_RESULT_OK; -} - -static void -do_update_port (SpaDBusProxy *this, - SpaControlCmdPortUpdate *pu) -{ - SpaDBusProxyPort *port; - unsigned int i; - size_t size; - - if (pu->direction == SPA_DIRECTION_INPUT) { - port = &this->in_ports[pu->port_id]; - } else { - port = &this->out_ports[pu->port_id]; - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS) { - for (i = 0; i < port->n_formats; i++) - free (port->formats[i]); - port->n_formats = pu->n_possible_formats; - port->formats = realloc (port->formats, port->n_formats * sizeof (SpaFormat *)); - for (i = 0; i < port->n_formats; i++) { - size = spa_format_get_size (pu->possible_formats[i]); - port->formats[i] = spa_format_copy_into (malloc (size), pu->possible_formats[i]); - spa_debug_format (port->formats[i]); - } - } - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_FORMAT) { - if (port->format) - free (port->format); - size = spa_format_get_size (pu->format); - port->format = spa_format_copy_into (malloc (size), pu->format); - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) { - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_INFO && pu->info) { - if (port->info) - free (port->info); - size = spa_port_info_get_size (pu->info); - port->info = spa_port_info_copy_into (malloc (size), pu->info); - spa_debug_port_info (port->info); - } - - if (!port->valid) { - spa_log_info (this->log, "proxy %p: adding port %d\n", this, pu->port_id); - port->format = NULL; - port->valid = true; - - if (pu->direction == SPA_DIRECTION_INPUT) - this->n_inputs++; - else - this->n_outputs++; - } -} - -static void -clear_port (SpaDBusProxy *this, - SpaDBusProxyPort *port, - SpaDirection direction, - uint32_t port_id) -{ - SpaControlCmdPortUpdate pu; - - pu.change_mask = SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS | - SPA_CONTROL_CMD_PORT_UPDATE_FORMAT | - SPA_CONTROL_CMD_PORT_UPDATE_PROPS | - SPA_CONTROL_CMD_PORT_UPDATE_INFO; - pu.direction = direction; - pu.port_id = port_id; - pu.n_possible_formats = 0; - pu.possible_formats = NULL; - pu.format = NULL; - pu.props = NULL; - pu.info = NULL; - do_update_port (this, &pu); - clear_buffers (this, port); -} - -static void -do_uninit_port (SpaDBusProxy *this, - SpaDirection direction, - uint32_t port_id) -{ - SpaDBusProxyPort *port; - - spa_log_info (this->log, "proxy %p: removing port %d\n", this, port_id); - if (direction == SPA_DIRECTION_INPUT) { - port = &this->in_ports[port_id]; - this->n_inputs--; - } else { - port = &this->out_ports[port_id]; - this->n_outputs--; - } - clear_port (this, port, direction, port_id); - port->valid = false; -} - -static SpaResult -spa_proxy_node_add_port (SpaNode *node, - SpaDirection direction, - uint32_t port_id) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_FREE_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - clear_port (this, port, direction, port_id); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_remove_port (SpaNode *node, - SpaDirection direction, - uint32_t port_id) -{ - SpaDBusProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - do_uninit_port (this, direction, port_id); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_enum_formats (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaFormat **format, - const SpaFormat *filter, - void **state) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - int index; - - if (node == NULL || format == NULL || state == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - index = (*state == NULL ? 0 : *(int*)state); - - if (index >= port->n_formats) - return SPA_RESULT_ENUM_END; - - *format = port->formats[index]; - *(int*)state = ++index; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_set_format (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaPortFormatFlags flags, - const SpaFormat *format) -{ - SpaDBusProxy *this; - SpaControl control; - SpaControlBuilder builder; - SpaControlCmdSetFormat sf; - uint8_t buf[128]; - SpaResult res; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - sf.seq = this->seq++; - sf.direction = direction; - sf.port_id = port_id; - sf.flags = flags; - sf.format = (SpaFormat *) format; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_RETURN_ASYNC (sf.seq); -} - -static SpaResult -spa_proxy_node_port_get_format (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaFormat **format) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - - if (node == NULL || format == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - *format = port->format; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_get_info (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaPortInfo **info) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - - if (node == NULL || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - *info = port->info; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_get_props (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaProps **props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_proxy_node_port_set_props (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaProps *props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_proxy_node_port_get_status (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaPortStatus **status) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - - if (node == NULL || status == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - *status = &port->status; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_use_buffers (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - unsigned int i, j; - SpaControl control; - SpaControlBuilder builder; - uint8_t buf[4096]; - int fds[32]; - SpaResult res; - SpaControlCmdAddMem am; - SpaControlCmdUseBuffers ub; - size_t size, n_mem; - SpaControlMemRef *memref; - void *p; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - spa_log_info (this->log, "proxy %p: use buffers %p %u\n", this, buffers, n_buffers); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - clear_buffers (this, port); - - spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, SPA_N_ELEMENTS (fds)); - - /* find size to store buffers */ - size = 0; - n_mem = 0; - for (i = 0; i < n_buffers; i++) { - ProxyBuffer *b = &port->buffers[i]; - - b->outbuf = buffers[i]; - memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); - b->buffer.datas = b->datas; - b->buffer.metas = b->metas; - - b->size = spa_buffer_get_size (buffers[i]); - b->offset = size; - - for (j = 0; j < buffers[i]->n_metas; j++) { - memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta)); - } - - for (j = 0; j < buffers[i]->n_datas; j++) { - SpaData *d = &buffers[i]->datas[j]; - - memcpy (&b->buffer.datas[j], d, sizeof (SpaData)); - - switch (d->type) { - case SPA_DATA_TYPE_DMABUF: - case SPA_DATA_TYPE_MEMFD: - am.direction = direction; - am.port_id = port_id; - am.mem_id = n_mem; - am.type = d->type; - am.fd_index = spa_control_builder_add_fd (&builder, d->fd, false); - am.flags = d->flags; - am.offset = d->offset; - am.size = d->maxsize; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - b->buffer.datas[j].type = SPA_DATA_TYPE_ID; - b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem); - n_mem++; - break; - case SPA_DATA_TYPE_MEMPTR: - b->buffer.datas[j].data = SPA_INT_TO_PTR (b->size); - b->size += d->size; - break; - default: - b->buffer.datas[j].type = SPA_DATA_TYPE_INVALID; - b->buffer.datas[j].data = 0; - spa_log_error (this->log, "invalid memory type %d\n", d->type); - break; - } - } - size += b->size; - } - - /* make mem for the buffers */ - port->buffer_mem_id = n_mem++; - port->buffer_mem_size = size; - port->buffer_mem_fd = memfd_create ("spa-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); - - if (ftruncate (port->buffer_mem_fd, size) < 0) { - spa_log_error (this->log, "Failed to truncate temporary file: %s\n", strerror (errno)); - close (port->buffer_mem_fd); - return SPA_RESULT_ERROR; - } -#if 0 - { - unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; - if (fcntl (port->buffer_mem_fd, F_ADD_SEALS, seals) == -1) { - spa_log_error (this->log, "Failed to add seals: %s\n", strerror (errno)); - } - } -#endif - p = port->buffer_mem_ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, port->buffer_mem_fd, 0); - - for (i = 0; i < n_buffers; i++) { - ProxyBuffer *b = &port->buffers[i]; - SpaBuffer *sb; - SpaMeta *sbm; - SpaData *sbd; - - spa_buffer_serialize (p, &b->buffer); - - sb = p; - b->buffer.datas = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); - sbm = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->metas), SpaMeta); - sbd = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); - - for (j = 0; j < b->buffer.n_metas; j++) - b->metas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbm[j].data), void); - - for (j = 0; j < b->buffer.n_datas; j++) { - if (b->datas[j].type == SPA_DATA_TYPE_MEMPTR) - b->datas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbd[j].data), void); - } - p += b->size; - } - - am.direction = direction; - am.port_id = port_id; - am.mem_id = port->buffer_mem_id; - am.type = SPA_DATA_TYPE_MEMFD; - am.fd_index = spa_control_builder_add_fd (&builder, port->buffer_mem_fd, false); - am.flags = 0; - am.offset = 0; - am.size = size; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - memref = alloca (n_buffers * sizeof (SpaControlMemRef)); - for (i = 0; i < n_buffers; i++) { - memref[i].mem_id = port->buffer_mem_id; - memref[i].offset = port->buffers[i].offset; - memref[i].size = port->buffers[i].size; - } - port->n_buffers = n_buffers; - - ub.seq = this->seq++; - ub.direction = direction; - ub.port_id = port_id; - ub.n_buffers = n_buffers; - ub.buffers = memref; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_USE_BUFFERS, &ub); - - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_RETURN_ASYNC (ub.seq); -} - -static SpaResult -spa_proxy_node_port_alloc_buffers (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - - if (node == NULL || buffers == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static void -copy_meta_in (SpaDBusProxy *this, SpaDBusProxyPort *port, uint32_t buffer_id) -{ - ProxyBuffer *b = &port->buffers[buffer_id]; - unsigned int i; - - for (i = 0; i < b->outbuf->n_metas; i++) { - SpaMeta *sm = &b->metas[i]; - SpaMeta *dm = &b->outbuf->metas[i]; - memcpy (dm->data, sm->data, dm->size); - } - for (i = 0; i < b->outbuf->n_datas; i++) { - b->outbuf->datas[i].size = b->buffer.datas[i].size; - if (b->outbuf->datas[i].type == SPA_DATA_TYPE_MEMPTR) { - spa_log_info (this->log, "memcpy in %zd\n", b->buffer.datas[i].size); - memcpy (b->outbuf->datas[i].data, b->datas[i].data, b->buffer.datas[i].size); - } - } -} - -static void -copy_meta_out (SpaDBusProxy *this, SpaDBusProxyPort *port, uint32_t buffer_id) -{ - ProxyBuffer *b = &port->buffers[buffer_id]; - unsigned int i; - - for (i = 0; i < b->outbuf->n_metas; i++) { - SpaMeta *sm = &b->outbuf->metas[i]; - SpaMeta *dm = &b->buffer.metas[i]; - memcpy (dm->data, sm->data, dm->size); - } - for (i = 0; i < b->outbuf->n_datas; i++) { - b->buffer.datas[i].size = b->outbuf->datas[i].size; - if (b->datas[i].type == SPA_DATA_TYPE_MEMPTR) { - spa_log_info (this->log, "memcpy out %zd\n", b->outbuf->datas[i].size); - memcpy (b->datas[i].data, b->outbuf->datas[i].data, b->outbuf->datas[i].size); - } - } -} - -static SpaResult -spa_proxy_node_port_push_input (SpaNode *node, - unsigned int n_info, - SpaPortInputInfo *info) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - unsigned int i; - bool have_error = false; - bool have_enough = false; - SpaControl control; - SpaControlBuilder builder; - SpaControlCmdProcessBuffer pb; - uint8_t buf[64]; - SpaResult res; - - if (node == NULL || n_info == 0 || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - spa_control_builder_init_into (&builder, buf, sizeof(buf), NULL, 0); - - for (i = 0; i < n_info; i++) { - if (!CHECK_IN_PORT (this, SPA_DIRECTION_INPUT, info[i].port_id)) { - spa_log_warn (this->log, "invalid port %d\n", info[i].port_id); - info[i].status = SPA_RESULT_INVALID_PORT; - have_error = true; - continue; - } - port = &this->in_ports[info[i].port_id]; - - if (!port->format) { - info[i].status = SPA_RESULT_NO_FORMAT; - have_error = true; - continue; - } - if (info[i].buffer_id >= port->n_buffers) { - if (port->n_buffers == 0) - info[i].status = SPA_RESULT_NO_BUFFERS; - else - info[i].status = SPA_RESULT_INVALID_BUFFER_ID; - have_error = true; - continue; - } - - copy_meta_out (this, port, info[i].buffer_id); - - pb.direction = SPA_DIRECTION_INPUT; - pb.port_id = info[i].port_id; - pb.buffer_id = info[i].buffer_id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); - - info[i].status = SPA_RESULT_OK; - } - spa_control_builder_end (&builder, &control); - - if (have_error) - return SPA_RESULT_ERROR; - if (have_enough) - return SPA_RESULT_HAVE_ENOUGH_INPUT; - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_pull_output (SpaNode *node, - unsigned int n_info, - SpaPortOutputInfo *info) -{ - SpaDBusProxy *this; - SpaDBusProxyPort *port; - unsigned int i; - bool have_error = false; - bool need_more = false; - - if (node == NULL || n_info == 0 || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - for (i = 0; i < n_info; i++) { - if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, info[i].port_id)) { - spa_log_warn (this->log, "invalid port %u\n", info[i].port_id); - info[i].status = SPA_RESULT_INVALID_PORT; - have_error = true; - continue; - } - - port = &this->out_ports[info[i].port_id]; - - if (!port->format) { - info[i].status = SPA_RESULT_NO_FORMAT; - have_error = true; - continue; - } - - info[i].buffer_id = port->buffer_id; - info[i].status = SPA_RESULT_OK; - - port->buffer_id = SPA_ID_INVALID; - } - if (have_error) - return SPA_RESULT_ERROR; - if (need_more) - return SPA_RESULT_NEED_MORE_INPUT; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_reuse_buffer (SpaNode *node, - uint32_t port_id, - uint32_t buffer_id) -{ - SpaDBusProxy *this; - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaResult res; - SpaControlCmdNodeEvent cne; - SpaNodeEvent ne; - SpaNodeEventReuseBuffer rb; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, port_id)) - return SPA_RESULT_INVALID_PORT; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cne.event = ≠ - ne.type = SPA_NODE_EVENT_TYPE_REUSE_BUFFER; - ne.data = &rb; - ne.size = sizeof (rb); - rb.port_id = port_id; - rb.buffer_id = buffer_id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_EVENT, &cne); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - - return res; -} - -static SpaResult -spa_proxy_node_port_push_event (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaNodeEvent *event) -{ - SpaDBusProxy *this; - - if (node == NULL || event == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaDBusProxy, node); - - switch (event->type) { - default: - spa_log_warn (this->log, "unhandled event %d\n", event->type); - break; - } - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -handle_node_event (SpaDBusProxy *this, - SpaNodeEvent *event) -{ - switch (event->type) { - case SPA_NODE_EVENT_TYPE_INVALID: - break; - - case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE: - case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: - case SPA_NODE_EVENT_TYPE_NEED_INPUT: - case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: - case SPA_NODE_EVENT_TYPE_DRAINED: - case SPA_NODE_EVENT_TYPE_MARKER: - 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: - this->event_cb (&this->node, event, this->user_data); - break; - } - - return SPA_RESULT_OK; -} - -static SpaResult -parse_control (SpaDBusProxy *this, - SpaControl *ctrl) -{ - SpaControlIter it; - - spa_control_iter_init (&it, ctrl); - while (spa_control_iter_next (&it) == SPA_RESULT_OK) { - SpaControlCmd cmd = spa_control_iter_get_cmd (&it); - - switch (cmd) { - case SPA_CONTROL_CMD_INVALID: - case SPA_CONTROL_CMD_ADD_PORT: - case SPA_CONTROL_CMD_REMOVE_PORT: - case SPA_CONTROL_CMD_SET_FORMAT: - case SPA_CONTROL_CMD_SET_PROPERTY: - case SPA_CONTROL_CMD_NODE_COMMAND: - spa_log_error (this->log, "proxy %p: got unexpected control %d\n", this, cmd); - break; - - case SPA_CONTROL_CMD_NODE_UPDATE: - { - SpaControlCmdNodeUpdate nu; - - if (spa_control_iter_parse_cmd (&it, &nu) < 0) - break; - - if (nu.change_mask & SPA_CONTROL_CMD_NODE_UPDATE_MAX_INPUTS) - this->max_inputs = nu.max_input_ports; - if (nu.change_mask & SPA_CONTROL_CMD_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\n", this, cmd, - this->max_inputs, this->max_outputs); - - break; - } - - case SPA_CONTROL_CMD_PORT_UPDATE: - { - SpaControlCmdPortUpdate pu; - bool remove; - - spa_log_info (this->log, "proxy %p: got port update %d\n", this, cmd); - if (spa_control_iter_parse_cmd (&it, &pu) < 0) - break; - - if (!CHECK_PORT_ID (this, pu.direction, pu.port_id)) - break; - - remove = (pu.change_mask == 0); - - if (remove) { - do_uninit_port (this, pu.direction, pu.port_id); - } else { - do_update_port (this, &pu); - } - break; - } - - case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - { - spa_log_warn (this->log, "proxy %p: command not implemented %d\n", this, cmd); - break; - } - - case SPA_CONTROL_CMD_NODE_STATE_CHANGE: - { - SpaControlCmdNodeStateChange sc; - SpaNodeState old = this->node.state; - - if (spa_control_iter_parse_cmd (&it, &sc) < 0) - break; - - spa_log_info (this->log, "proxy %p: got node state change %d -> %d\n", 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 SPA_CONTROL_CMD_ADD_MEM: - break; - case SPA_CONTROL_CMD_REMOVE_MEM: - break; - case SPA_CONTROL_CMD_USE_BUFFERS: - break; - - case SPA_CONTROL_CMD_PROCESS_BUFFER: - { - SpaControlCmdProcessBuffer cmd; - SpaDBusProxyPort *port; - - if (spa_control_iter_parse_cmd (&it, &cmd) < 0) - break; - - if (!CHECK_PORT (this, cmd.direction, cmd.port_id)) - break; - - port = cmd.direction == SPA_DIRECTION_INPUT ? &this->in_ports[cmd.port_id] : &this->out_ports[cmd.port_id]; - - if (port->buffer_id != SPA_ID_INVALID) - spa_log_warn (this->log, "proxy %p: unprocessed buffer: %d\n", this, port->buffer_id); - - copy_meta_in (this, port, cmd.buffer_id); - - port->buffer_id = cmd.buffer_id; - break; - } - case SPA_CONTROL_CMD_NODE_EVENT: - { - SpaControlCmdNodeEvent cne; - - if (spa_control_iter_parse_cmd (&it, &cne) < 0) - break; - - handle_node_event (this, cne.event); - break; - } - } - } - spa_control_iter_end (&it); - - return SPA_RESULT_OK; -} - -static int -proxy_on_fd_events (SpaPollNotifyData *data) -{ - SpaDBusProxy *this = data->user_data; - SpaResult res; - - if (data->fds[0].revents & POLLIN) { - SpaControl control; - uint8_t buf[1024]; - int fds[16]; - - if ((res = spa_control_read (&control, data->fds[0].fd, buf, 1024, fds, 16)) < 0) { - spa_log_error (this->log, "proxy %p: failed to read control: %d\n", this, res); - return 0; - } - parse_control (this, &control); - spa_control_clear (&control); - } - return 0; -} - -static const SpaNode proxy_node = { - sizeof (SpaNode), - NULL, - SPA_NODE_STATE_INIT, - spa_proxy_node_get_props, - spa_proxy_node_set_props, - spa_proxy_node_send_command, - spa_proxy_node_set_event_callback, - spa_proxy_node_get_n_ports, - spa_proxy_node_get_port_ids, - spa_proxy_node_add_port, - spa_proxy_node_remove_port, - spa_proxy_node_port_enum_formats, - spa_proxy_node_port_set_format, - spa_proxy_node_port_get_format, - spa_proxy_node_port_get_info, - spa_proxy_node_port_get_props, - spa_proxy_node_port_set_props, - spa_proxy_node_port_use_buffers, - spa_proxy_node_port_alloc_buffers, - spa_proxy_node_port_get_status, - spa_proxy_node_port_push_input, - spa_proxy_node_port_pull_output, - spa_proxy_node_port_reuse_buffer, - spa_proxy_node_port_push_event, -}; - -static SpaResult -spa_proxy_get_interface (SpaHandle *handle, - uint32_t interface_id, - void **interface) -{ - SpaDBusProxy *this = (SpaDBusProxy *) handle; - - if (handle == NULL || interface == 0) - return SPA_RESULT_INVALID_ARGUMENTS; - - if (interface_id == this->uri.node) - *interface = &this->node; - else - return SPA_RESULT_UNKNOWN_INTERFACE; - - return SPA_RESULT_OK; -} - -static SpaResult -proxy_clear (SpaHandle *handle) -{ - SpaDBusProxy *this; - unsigned int i; - - if (handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = (SpaDBusProxy *) handle; - - for (i = 0; i < MAX_INPUTS; i++) { - if (this->in_ports[i].valid) - clear_port (this, &this->in_ports[i], SPA_DIRECTION_INPUT, i); - } - for (i = 0; i < MAX_OUTPUTS; i++) { - if (this->out_ports[i].valid) - clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i); - } - - return SPA_RESULT_OK; -} - -static SpaResult -proxy_init (const SpaHandleFactory *factory, - SpaHandle *handle, - const SpaDict *info, - const SpaSupport *support, - unsigned int n_support) -{ - SpaDBusProxy *this; - unsigned int i; - - if (factory == NULL || handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - handle->get_interface = spa_proxy_get_interface; - handle->clear = proxy_clear; - - this = (SpaDBusProxy *) handle; - - for (i = 0; i < n_support; i++) { - if (strcmp (support[i].uri, SPA_ID_MAP_URI) == 0) - this->map = support[i].data; - else if (strcmp (support[i].uri, SPA_LOG_URI) == 0) - this->log = support[i].data; - else if (strcmp (support[i].uri, SPA_POLL__DataLoop) == 0) - this->data_loop = support[i].data; - } - if (this->map == NULL) { - spa_log_error (this->log, "an id-map is needed"); - return SPA_RESULT_ERROR; - } - if (this->data_loop == NULL) { - spa_log_error (this->log, "a data-loop is needed"); - return SPA_RESULT_ERROR; - } - this->uri.node = spa_id_map_get_id (this->map, SPA_NODE_URI); - - this->node = proxy_node; - this->props[1].props.n_prop_info = PROP_ID_LAST; - this->props[1].props.prop_info = prop_info; - reset_proxy_props (&this->props[1]); - memcpy (&this->props[0], &this->props[1], sizeof (this->props[1])); - - this->fds[0].fd = -1; - this->fds[0].events = POLLIN | POLLPRI | POLLERR; - this->fds[0].revents = 0; - this->poll.id = 0; - this->poll.enabled = true; - this->poll.fds = this->fds; - this->poll.n_fds = 1; - this->poll.idle_cb = NULL; - this->poll.before_cb = NULL; - this->poll.after_cb = proxy_on_fd_events; - this->poll.user_data = this; - - return SPA_RESULT_RETURN_ASYNC (this->seq++); -} - -static const SpaInterfaceInfo proxy_interfaces[] = -{ - { SPA_NODE_URI, }, -}; - -static SpaResult -proxy_enum_interface_info (const SpaHandleFactory *factory, - const SpaInterfaceInfo **info, - void **state) -{ - int index; - - if (factory == NULL || info == NULL || state == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - index = (*state == NULL ? 0 : *(int*)state); - - switch (index) { - case 0: - *info = &proxy_interfaces[index]; - break; - default: - return SPA_RESULT_ENUM_END; - } - *(int*)state = ++index; - - return SPA_RESULT_OK; -} - -const SpaHandleFactory spa_dbus_proxy_factory = -{ "dbus-proxy", - NULL, - sizeof (SpaDBusProxy), - proxy_init, - proxy_enum_interface_info, -}; diff --git a/spa/plugins/remote/meson.build b/spa/plugins/remote/meson.build deleted file mode 100644 index a0a110a20..000000000 --- a/spa/plugins/remote/meson.build +++ /dev/null @@ -1,10 +0,0 @@ -remote_sources = ['proxy.c', - 'dbus-proxy.c', - 'plugin.c'] - -remotelib = shared_library('spa-remote', - remote_sources, - include_directories : spa_inc, - link_with : spalib, - install : true, - install_dir : '@0@/spa'.format(get_option('libdir'))) diff --git a/spa/plugins/remote/plugin.c b/spa/plugins/remote/plugin.c deleted file mode 100644 index 4c150cf94..000000000 --- a/spa/plugins/remote/plugin.c +++ /dev/null @@ -1,50 +0,0 @@ -/* Spa Volume plugin - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include - -extern const SpaHandleFactory spa_proxy_factory; -extern const SpaHandleFactory spa_dbus_proxy_factory; - -SpaResult -spa_enum_handle_factory (const SpaHandleFactory **factory, - void **state) -{ - int index; - - if (factory == NULL || state == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - index = (*state == NULL ? 0 : *(int*)state); - - switch (index) { - case 0: - *factory = &spa_proxy_factory; - break; - case 1: - *factory = &spa_dbus_proxy_factory; - break; - default: - return SPA_RESULT_ENUM_END; - } - *(int*)state = ++index; - - return SPA_RESULT_OK; -} diff --git a/spa/plugins/remote/proxy.c b/spa/plugins/remote/proxy.c deleted file mode 100644 index e5b40e1b9..000000000 --- a/spa/plugins/remote/proxy.c +++ /dev/null @@ -1,1555 +0,0 @@ -/* Spa - * Copyright (C) 2016 Wim Taymans - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include -#include -#include -#include -#include -#include -#include "../lib/memfd-wrappers.h" - -#define MAX_INPUTS 64 -#define MAX_OUTPUTS 64 - -#define MAX_BUFFERS 16 - -#define CHECK_IN_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_INPUT && (p) < MAX_INPUTS) -#define CHECK_OUT_PORT_ID(this,d,p) ((d) == SPA_DIRECTION_OUTPUT && (p) < MAX_OUTPUTS) -#define CHECK_PORT_ID(this,d,p) (CHECK_IN_PORT_ID(this,d,p) || CHECK_OUT_PORT_ID(this,d,p)) -#define CHECK_FREE_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && !(this)->in_ports[p].valid) -#define CHECK_FREE_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && !(this)->out_ports[p].valid) -#define CHECK_FREE_PORT(this,d,p) (CHECK_FREE_IN_PORT (this,d,p) || CHECK_FREE_OUT_PORT (this,d,p)) -#define CHECK_IN_PORT(this,d,p) (CHECK_IN_PORT_ID(this,d,p) && (this)->in_ports[p].valid) -#define CHECK_OUT_PORT(this,d,p) (CHECK_OUT_PORT_ID(this,d,p) && (this)->out_ports[p].valid) -#define CHECK_PORT(this,d,p) (CHECK_IN_PORT (this,d,p) || CHECK_OUT_PORT (this,d,p)) - - -typedef struct _SpaProxy SpaProxy; -typedef struct _ProxyBuffer ProxyBuffer; - -struct _ProxyBuffer { - SpaBuffer *outbuf; - SpaBuffer buffer; - SpaMeta metas[4]; - SpaData datas[4]; - off_t offset; - size_t size; -}; - -typedef struct { - SpaProps props; - int socketfd; - int rtsocketfd; -} SpaProxyProps; - -typedef struct { - bool valid; - SpaPortInfo *info; - SpaFormat *format; - unsigned int n_formats; - SpaFormat **formats; - SpaPortStatus status; - - unsigned int n_buffers; - ProxyBuffer buffers[MAX_BUFFERS]; - - uint32_t buffer_mem_id; - int buffer_mem_fd; - size_t buffer_mem_size; - void *buffer_mem_ptr; - - uint32_t buffer_id; - SpaQueue ready; -} SpaProxyPort; - -typedef struct { - uint32_t node; -} URI; - -struct _SpaProxy { - SpaHandle handle; - SpaNode node; - - URI uri; - SpaIDMap *map; - SpaLog *log; - SpaPoll *main_loop; - SpaPoll *data_loop; - - SpaProxyProps props[2]; - - SpaNodeEventCallback event_cb; - void *user_data; - - SpaPollFd fds[1]; - SpaPollItem poll; - SpaPollFd rtfds[1]; - SpaPollItem rtpoll; - - unsigned int max_inputs; - unsigned int n_inputs; - unsigned int max_outputs; - unsigned int n_outputs; - SpaProxyPort in_ports[MAX_INPUTS]; - SpaProxyPort out_ports[MAX_OUTPUTS]; - - uint32_t seq; -}; - -enum { - PROP_ID_SOCKET, - PROP_ID_RT_SOCKET, - PROP_ID_LAST, -}; - -static const SpaPropInfo prop_info[PROP_ID_LAST] = -{ - { PROP_ID_SOCKET, offsetof (SpaProxyProps, socketfd), - "socket", - SPA_PROP_FLAG_READWRITE, - SPA_PROP_TYPE_INT, sizeof (int), - SPA_PROP_RANGE_TYPE_NONE, 0, NULL, - NULL }, - { PROP_ID_RT_SOCKET, offsetof (SpaProxyProps, rtsocketfd), - "rt-socket", - SPA_PROP_FLAG_READWRITE, - SPA_PROP_TYPE_INT, sizeof (int), - SPA_PROP_RANGE_TYPE_NONE, 0, NULL, - NULL }, -}; - -static void -reset_proxy_props (SpaProxyProps *props) -{ - props->socketfd = -1; - props->rtsocketfd = -1; -} - -static SpaResult -update_poll (SpaProxy *this, int socketfd) -{ - SpaProxyProps *p; - SpaResult res = SPA_RESULT_OK; - - p = &this->props[1]; - - if (p->socketfd != -1) - spa_poll_remove_item (this->main_loop, &this->poll); - p->socketfd = socketfd; - - if (p->socketfd != -1) { - this->fds[0].fd = p->socketfd; - spa_poll_add_item (this->main_loop, &this->poll); - } - return res; -} - -static SpaResult -update_rtpoll (SpaProxy *this, int rtsocketfd) -{ - SpaProxyProps *p; - SpaResult res = SPA_RESULT_OK; - - p = &this->props[1]; - - if (p->rtsocketfd != -1) - spa_poll_remove_item (this->data_loop, &this->rtpoll); - p->rtsocketfd = rtsocketfd; - - if (p->rtsocketfd != -1) { - this->rtfds[0].fd = p->rtsocketfd; - spa_poll_add_item (this->data_loop, &this->rtpoll); - } - return res; -} - -static void -send_async_complete (SpaProxy *this, uint32_t seq, SpaResult res) -{ - SpaNodeEvent event; - SpaNodeEventAsyncComplete ac; - - event.type = SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE; - event.data = ∾ - event.size = sizeof (ac); - ac.seq = seq; - ac.res = res; - this->event_cb (&this->node, &event, this->user_data); -} - -static SpaResult -clear_buffers (SpaProxy *this, SpaProxyPort *port) -{ - if (port->n_buffers) { - spa_log_info (this->log, "proxy %p: clear buffers\n", this); - - munmap (port->buffer_mem_ptr, port->buffer_mem_size); - close (port->buffer_mem_fd); - - port->n_buffers = 0; - SPA_QUEUE_INIT (&port->ready); - } - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_props (SpaNode *node, - SpaProps **props) -{ - SpaProxy *this; - - if (node == NULL || props == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - memcpy (&this->props[0], &this->props[1], sizeof (this->props[1])); - *props = &this->props[0].props; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_set_props (SpaNode *node, - const SpaProps *props) -{ - SpaProxy *this; - SpaProxyProps *op, *np; - SpaResult res; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - op = &this->props[1]; - np = &this->props[0]; - - if (props == NULL) { - reset_proxy_props (np); - props = &np->props; - } - - /* copy new properties */ - res = spa_props_copy_values (props, &np->props); - - /* compare changes */ - - if (op->socketfd != np->socketfd) - res = update_poll (this, np->socketfd); - if (op->rtsocketfd != np->rtsocketfd) - res = update_rtpoll (this, np->rtsocketfd); - - /* commit changes */ - memcpy (op, np, sizeof (*np)); - - return res; -} - -static SpaResult -spa_proxy_node_send_command (SpaNode *node, - SpaNodeCommand *command) -{ - SpaProxy *this; - SpaResult res = SPA_RESULT_OK; - - if (node == NULL || command == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - switch (command->type) { - case SPA_NODE_COMMAND_INVALID: - return SPA_RESULT_INVALID_COMMAND; - - case SPA_NODE_COMMAND_START: - case SPA_NODE_COMMAND_PAUSE: - case SPA_NODE_COMMAND_FLUSH: - case SPA_NODE_COMMAND_DRAIN: - case SPA_NODE_COMMAND_MARKER: - { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaControlCmdNodeCommand cnc; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cnc.seq = this->seq++; - cnc.command = command; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - - res = SPA_RESULT_RETURN_ASYNC (cnc.seq); - break; - } - - case SPA_NODE_COMMAND_CLOCK_UPDATE: - { - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaControlCmdNodeCommand cnc; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cnc.command = command; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_COMMAND, &cnc); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - break; - } - } - return res; -} - -static SpaResult -spa_proxy_node_set_event_callback (SpaNode *node, - SpaNodeEventCallback event, - void *user_data) -{ - SpaProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - this->event_cb = event; - this->user_data = user_data; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_n_ports (SpaNode *node, - unsigned int *n_input_ports, - unsigned int *max_input_ports, - unsigned int *n_output_ports, - unsigned int *max_output_ports) -{ - SpaProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (n_input_ports) - *n_input_ports = this->n_inputs; - if (max_input_ports) - *max_input_ports = this->max_inputs; - if (n_output_ports) - *n_output_ports = this->n_outputs; - if (max_output_ports) - *max_output_ports = this->max_outputs; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_get_port_ids (SpaNode *node, - unsigned int n_input_ports, - uint32_t *input_ids, - unsigned int n_output_ports, - uint32_t *output_ids) -{ - SpaProxy *this; - int c, i; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (input_ids) { - for (c = 0, i = 0; i < MAX_INPUTS && c < n_input_ports; i++) { - if (this->in_ports[i].valid) - input_ids[c++] = i; - } - } - if (output_ids) { - for (c = 0, i = 0; i < MAX_OUTPUTS && c < n_output_ports; i++) { - if (this->out_ports[i].valid) - output_ids[c++] = i; - } - } - return SPA_RESULT_OK; -} - -static void -do_update_port (SpaProxy *this, - SpaControlCmdPortUpdate *pu) -{ - SpaProxyPort *port; - unsigned int i; - size_t size; - - if (pu->direction == SPA_DIRECTION_INPUT) { - port = &this->in_ports[pu->port_id]; - } else { - port = &this->out_ports[pu->port_id]; - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS) { - for (i = 0; i < port->n_formats; i++) - free (port->formats[i]); - port->n_formats = pu->n_possible_formats; - port->formats = realloc (port->formats, port->n_formats * sizeof (SpaFormat *)); - for (i = 0; i < port->n_formats; i++) { - size = spa_format_get_size (pu->possible_formats[i]); - port->formats[i] = spa_format_copy_into (malloc (size), pu->possible_formats[i]); - spa_debug_format (port->formats[i]); - } - } - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_FORMAT) { - if (port->format) - free (port->format); - size = spa_format_get_size (pu->format); - port->format = spa_format_copy_into (malloc (size), pu->format); - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_PROPS) { - } - - if (pu->change_mask & SPA_CONTROL_CMD_PORT_UPDATE_INFO && pu->info) { - if (port->info) - free (port->info); - size = spa_port_info_get_size (pu->info); - port->info = spa_port_info_copy_into (malloc (size), pu->info); - spa_debug_port_info (port->info); - } - - if (!port->valid) { - spa_log_info (this->log, "proxy %p: adding port %d\n", this, pu->port_id); - port->format = NULL; - port->valid = true; - - if (pu->direction == SPA_DIRECTION_INPUT) - this->n_inputs++; - else - this->n_outputs++; - } -} - -static void -clear_port (SpaProxy *this, - SpaProxyPort *port, - SpaDirection direction, - uint32_t port_id) -{ - SpaControlCmdPortUpdate pu; - - pu.change_mask = SPA_CONTROL_CMD_PORT_UPDATE_POSSIBLE_FORMATS | - SPA_CONTROL_CMD_PORT_UPDATE_FORMAT | - SPA_CONTROL_CMD_PORT_UPDATE_PROPS | - SPA_CONTROL_CMD_PORT_UPDATE_INFO; - pu.direction = direction; - pu.port_id = port_id; - pu.n_possible_formats = 0; - pu.possible_formats = NULL; - pu.format = NULL; - pu.props = NULL; - pu.info = NULL; - do_update_port (this, &pu); - clear_buffers (this, port); -} - -static void -do_uninit_port (SpaProxy *this, - SpaDirection direction, - uint32_t port_id) -{ - SpaProxyPort *port; - - spa_log_info (this->log, "proxy %p: removing port %d\n", this, port_id); - if (direction == SPA_DIRECTION_INPUT) { - port = &this->in_ports[port_id]; - this->n_inputs--; - } else { - port = &this->out_ports[port_id]; - this->n_outputs--; - } - clear_port (this, port, direction, port_id); - port->valid = false; -} - -static SpaResult -spa_proxy_node_add_port (SpaNode *node, - SpaDirection direction, - uint32_t port_id) -{ - SpaProxy *this; - SpaProxyPort *port; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_FREE_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - clear_port (this, port, direction, port_id); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_remove_port (SpaNode *node, - SpaDirection direction, - uint32_t port_id) -{ - SpaProxy *this; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - do_uninit_port (this, direction, port_id); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_enum_formats (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaFormat **format, - const SpaFormat *filter, - void **state) -{ - SpaProxy *this; - SpaProxyPort *port; - int index; - - if (node == NULL || format == NULL || state == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - index = (*state == NULL ? 0 : *(int*)state); - - if (index >= port->n_formats) - return SPA_RESULT_ENUM_END; - - *format = port->formats[index]; - *(int*)state = ++index; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_set_format (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaPortFormatFlags flags, - const SpaFormat *format) -{ - SpaProxy *this; - SpaControl control; - SpaControlBuilder builder; - SpaControlCmdSetFormat sf; - uint8_t buf[128]; - SpaResult res; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - sf.seq = this->seq++; - sf.direction = direction; - sf.port_id = port_id; - sf.flags = flags; - sf.format = (SpaFormat *) format; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_SET_FORMAT, &sf); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_RETURN_ASYNC (sf.seq); -} - -static SpaResult -spa_proxy_node_port_get_format (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaFormat **format) -{ - SpaProxy *this; - SpaProxyPort *port; - - if (node == NULL || format == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - *format = port->format; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_get_info (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaPortInfo **info) -{ - SpaProxy *this; - SpaProxyPort *port; - - if (node == NULL || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - *info = port->info; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_get_props (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaProps **props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_proxy_node_port_set_props (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaProps *props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -spa_proxy_node_port_get_status (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - const SpaPortStatus **status) -{ - SpaProxy *this; - SpaProxyPort *port; - - if (node == NULL || status == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - *status = &port->status; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_use_buffers (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaBuffer **buffers, - uint32_t n_buffers) -{ - SpaProxy *this; - SpaProxyPort *port; - unsigned int i, j; - SpaControl control; - SpaControlBuilder builder; - uint8_t buf[4096]; - int fds[32]; - SpaResult res; - SpaControlCmdAddMem am; - SpaControlCmdUseBuffers ub; - size_t size, n_mem; - SpaControlMemRef *memref; - void *p; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - spa_log_info (this->log, "proxy %p: use buffers %p %u\n", this, buffers, n_buffers); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - clear_buffers (this, port); - - spa_control_builder_init_into (&builder, buf, sizeof (buf), fds, SPA_N_ELEMENTS (fds)); - - /* find size to store buffers */ - size = 0; - n_mem = 0; - for (i = 0; i < n_buffers; i++) { - ProxyBuffer *b = &port->buffers[i]; - - b->outbuf = buffers[i]; - memcpy (&b->buffer, buffers[i], sizeof (SpaBuffer)); - b->buffer.datas = b->datas; - b->buffer.metas = b->metas; - - b->size = spa_buffer_get_size (buffers[i]); - b->offset = size; - - for (j = 0; j < buffers[i]->n_metas; j++) { - memcpy (&b->buffer.metas[j], &buffers[i]->metas[j], sizeof (SpaMeta)); - } - - for (j = 0; j < buffers[i]->n_datas; j++) { - SpaData *d = &buffers[i]->datas[j]; - - memcpy (&b->buffer.datas[j], d, sizeof (SpaData)); - - switch (d->type) { - case SPA_DATA_TYPE_DMABUF: - case SPA_DATA_TYPE_MEMFD: - am.direction = direction; - am.port_id = port_id; - am.mem_id = n_mem; - am.type = d->type; - am.fd_index = spa_control_builder_add_fd (&builder, d->fd, false); - am.flags = d->flags; - am.offset = d->offset; - am.size = d->maxsize; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - b->buffer.datas[j].type = SPA_DATA_TYPE_ID; - b->buffer.datas[j].data = SPA_UINT32_TO_PTR (n_mem); - n_mem++; - break; - case SPA_DATA_TYPE_MEMPTR: - b->buffer.datas[j].data = SPA_INT_TO_PTR (b->size); - b->size += d->size; - break; - default: - b->buffer.datas[j].type = SPA_DATA_TYPE_INVALID; - b->buffer.datas[j].data = 0; - spa_log_error (this->log, "invalid memory type %d\n", d->type); - break; - } - } - size += b->size; - } - - if (n_buffers > 0) { - /* make mem for the buffers */ - port->buffer_mem_id = n_mem++; - port->buffer_mem_size = size; - port->buffer_mem_fd = memfd_create ("spa-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING); - - if (ftruncate (port->buffer_mem_fd, size) < 0) { - spa_log_error (this->log, "Failed to truncate temporary file: %s\n", strerror (errno)); - close (port->buffer_mem_fd); - return SPA_RESULT_ERROR; - } -#if 0 - { - unsigned int seals = F_SEAL_GROW | F_SEAL_SHRINK | F_SEAL_SEAL; - if (fcntl (port->buffer_mem_fd, F_ADD_SEALS, seals) == -1) { - spa_log_error (this->log, "Failed to add seals: %s\n", strerror (errno)); - } - } -#endif - p = port->buffer_mem_ptr = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, port->buffer_mem_fd, 0); - - for (i = 0; i < n_buffers; i++) { - ProxyBuffer *b = &port->buffers[i]; - SpaBuffer *sb; - SpaMeta *sbm; - SpaData *sbd; - - spa_buffer_serialize (p, &b->buffer); - - sb = p; - b->buffer.datas = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); - sbm = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->metas), SpaMeta); - sbd = SPA_MEMBER (sb, SPA_PTR_TO_INT (sb->datas), SpaData); - - for (j = 0; j < b->buffer.n_metas; j++) - b->metas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbm[j].data), void); - - for (j = 0; j < b->buffer.n_datas; j++) { - if (b->datas[j].type == SPA_DATA_TYPE_MEMPTR) - b->datas[j].data = SPA_MEMBER (sb, SPA_PTR_TO_INT (sbd[j].data), void); - } - p += b->size; - } - - am.direction = direction; - am.port_id = port_id; - am.mem_id = port->buffer_mem_id; - am.type = SPA_DATA_TYPE_MEMFD; - am.fd_index = spa_control_builder_add_fd (&builder, port->buffer_mem_fd, false); - am.flags = 0; - am.offset = 0; - am.size = size; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_ADD_MEM, &am); - - memref = alloca (n_buffers * sizeof (SpaControlMemRef)); - for (i = 0; i < n_buffers; i++) { - memref[i].mem_id = port->buffer_mem_id; - memref[i].offset = port->buffers[i].offset; - memref[i].size = port->buffers[i].size; - } - } else { - memref = NULL; - } - port->n_buffers = n_buffers; - - ub.seq = this->seq++; - ub.direction = direction; - ub.port_id = port_id; - ub.n_buffers = n_buffers; - ub.buffers = memref; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_USE_BUFFERS, &ub); - - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->fds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_RETURN_ASYNC (ub.seq); -} - -static SpaResult -spa_proxy_node_port_alloc_buffers (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaAllocParam **params, - uint32_t n_params, - SpaBuffer **buffers, - uint32_t *n_buffers) -{ - SpaProxy *this; - SpaProxyPort *port; - - if (node == NULL || buffers == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_PORT (this, direction, port_id)) - return SPA_RESULT_INVALID_PORT; - - port = direction == SPA_DIRECTION_INPUT ? &this->in_ports[port_id] : &this->out_ports[port_id]; - - if (!port->format) - return SPA_RESULT_NO_FORMAT; - - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static void -copy_meta_in (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) -{ - ProxyBuffer *b = &port->buffers[buffer_id]; - unsigned int i; - - for (i = 0; i < b->outbuf->n_metas; i++) { - SpaMeta *sm = &b->metas[i]; - SpaMeta *dm = &b->outbuf->metas[i]; - memcpy (dm->data, sm->data, dm->size); - } - for (i = 0; i < b->outbuf->n_datas; i++) { - b->outbuf->datas[i].size = b->buffer.datas[i].size; - if (b->outbuf->datas[i].type == SPA_DATA_TYPE_MEMPTR) { - spa_log_info (this->log, "memcpy in %zd\n", b->buffer.datas[i].size); - memcpy (b->outbuf->datas[i].data, b->datas[i].data, b->buffer.datas[i].size); - } - } -} - -static void -copy_meta_out (SpaProxy *this, SpaProxyPort *port, uint32_t buffer_id) -{ - ProxyBuffer *b = &port->buffers[buffer_id]; - unsigned int i; - - for (i = 0; i < b->outbuf->n_metas; i++) { - SpaMeta *sm = &b->outbuf->metas[i]; - SpaMeta *dm = &b->buffer.metas[i]; - memcpy (dm->data, sm->data, dm->size); - } - for (i = 0; i < b->outbuf->n_datas; i++) { - b->buffer.datas[i].size = b->outbuf->datas[i].size; - if (b->datas[i].type == SPA_DATA_TYPE_MEMPTR) { - spa_log_info (this->log, "memcpy out %zd\n", b->outbuf->datas[i].size); - memcpy (b->datas[i].data, b->outbuf->datas[i].data, b->outbuf->datas[i].size); - } - } -} - -static SpaResult -spa_proxy_node_port_push_input (SpaNode *node, - unsigned int n_info, - SpaPortInputInfo *info) -{ - SpaProxy *this; - SpaProxyPort *port; - unsigned int i; - bool have_error = false; - bool have_enough = false; - SpaControl control; - SpaControlBuilder builder; - SpaControlCmdProcessBuffer pb; - uint8_t buf[64]; - SpaResult res; - - if (node == NULL || n_info == 0 || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - spa_control_builder_init_into (&builder, buf, sizeof(buf), NULL, 0); - - for (i = 0; i < n_info; i++) { - if (!CHECK_IN_PORT (this, SPA_DIRECTION_INPUT, info[i].port_id)) { - spa_log_warn (this->log, "invalid port %d\n", info[i].port_id); - info[i].status = SPA_RESULT_INVALID_PORT; - have_error = true; - continue; - } - port = &this->in_ports[info[i].port_id]; - - if (!port->format) { - info[i].status = SPA_RESULT_NO_FORMAT; - have_error = true; - continue; - } - if (info[i].buffer_id >= port->n_buffers) { - if (port->n_buffers == 0) - info[i].status = SPA_RESULT_NO_BUFFERS; - else - info[i].status = SPA_RESULT_INVALID_BUFFER_ID; - have_error = true; - continue; - } - - copy_meta_out (this, port, info[i].buffer_id); - - pb.direction = SPA_DIRECTION_INPUT; - pb.port_id = info[i].port_id; - pb.buffer_id = info[i].buffer_id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_PROCESS_BUFFER, &pb); - - info[i].status = SPA_RESULT_OK; - } - spa_control_builder_end (&builder, &control); - - if (have_error) - return SPA_RESULT_ERROR; - if (have_enough) - return SPA_RESULT_HAVE_ENOUGH_INPUT; - - if ((res = spa_control_write (&control, this->rtfds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control\n", this); - - spa_control_clear (&control); - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_pull_output (SpaNode *node, - unsigned int n_info, - SpaPortOutputInfo *info) -{ - SpaProxy *this; - SpaProxyPort *port; - unsigned int i; - bool have_error = false; - bool need_more = false; - - if (node == NULL || n_info == 0 || info == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - for (i = 0; i < n_info; i++) { - if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, info[i].port_id)) { - spa_log_warn (this->log, "invalid port %u\n", info[i].port_id); - info[i].status = SPA_RESULT_INVALID_PORT; - have_error = true; - continue; - } - - port = &this->out_ports[info[i].port_id]; - - if (!port->format) { - info[i].status = SPA_RESULT_NO_FORMAT; - have_error = true; - continue; - } - - info[i].buffer_id = port->buffer_id; - info[i].status = SPA_RESULT_OK; - - port->buffer_id = SPA_ID_INVALID; - } - if (have_error) - return SPA_RESULT_ERROR; - if (need_more) - return SPA_RESULT_NEED_MORE_INPUT; - - return SPA_RESULT_OK; -} - -static SpaResult -spa_proxy_node_port_reuse_buffer (SpaNode *node, - uint32_t port_id, - uint32_t buffer_id) -{ - SpaProxy *this; - SpaControlBuilder builder; - SpaControl control; - uint8_t buf[128]; - SpaResult res; - SpaControlCmdNodeEvent cne; - SpaNodeEvent ne; - SpaNodeEventReuseBuffer rb; - - if (node == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - if (!CHECK_OUT_PORT (this, SPA_DIRECTION_OUTPUT, port_id)) - return SPA_RESULT_INVALID_PORT; - - /* send start */ - spa_control_builder_init_into (&builder, buf, sizeof (buf), NULL, 0); - cne.event = ≠ - ne.type = SPA_NODE_EVENT_TYPE_REUSE_BUFFER; - ne.data = &rb; - ne.size = sizeof (rb); - rb.port_id = port_id; - rb.buffer_id = buffer_id; - spa_control_builder_add_cmd (&builder, SPA_CONTROL_CMD_NODE_EVENT, &cne); - spa_control_builder_end (&builder, &control); - - if ((res = spa_control_write (&control, this->rtfds[0].fd)) < 0) - spa_log_error (this->log, "proxy %p: error writing control %d\n", this, res); - - spa_control_clear (&control); - - return res; -} - -static SpaResult -spa_proxy_node_port_push_event (SpaNode *node, - SpaDirection direction, - uint32_t port_id, - SpaNodeEvent *event) -{ - SpaProxy *this; - - if (node == NULL || event == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = SPA_CONTAINER_OF (node, SpaProxy, node); - - switch (event->type) { - default: - spa_log_warn (this->log, "unhandled event %d\n", event->type); - break; - } - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static SpaResult -handle_node_event (SpaProxy *this, - SpaNodeEvent *event) -{ - switch (event->type) { - case SPA_NODE_EVENT_TYPE_INVALID: - break; - - case SPA_NODE_EVENT_TYPE_ASYNC_COMPLETE: - case SPA_NODE_EVENT_TYPE_HAVE_OUTPUT: - case SPA_NODE_EVENT_TYPE_NEED_INPUT: - case SPA_NODE_EVENT_TYPE_REUSE_BUFFER: - case SPA_NODE_EVENT_TYPE_DRAINED: - case SPA_NODE_EVENT_TYPE_MARKER: - 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: - this->event_cb (&this->node, event, this->user_data); - break; - } - - return SPA_RESULT_OK; -} - -static SpaResult -parse_control (SpaProxy *this, - SpaControl *ctrl) -{ - SpaControlIter it; - - spa_control_iter_init (&it, ctrl); - while (spa_control_iter_next (&it) == SPA_RESULT_OK) { - SpaControlCmd cmd = spa_control_iter_get_cmd (&it); - - switch (cmd) { - case SPA_CONTROL_CMD_INVALID: - case SPA_CONTROL_CMD_ADD_PORT: - case SPA_CONTROL_CMD_REMOVE_PORT: - case SPA_CONTROL_CMD_SET_FORMAT: - case SPA_CONTROL_CMD_SET_PROPERTY: - case SPA_CONTROL_CMD_NODE_COMMAND: - case SPA_CONTROL_CMD_PROCESS_BUFFER: - spa_log_error (this->log, "proxy %p: got unexpected control %d\n", this, cmd); - break; - - case SPA_CONTROL_CMD_NODE_UPDATE: - { - SpaControlCmdNodeUpdate nu; - - if (spa_control_iter_parse_cmd (&it, &nu) < 0) - break; - - if (nu.change_mask & SPA_CONTROL_CMD_NODE_UPDATE_MAX_INPUTS) - this->max_inputs = nu.max_input_ports; - if (nu.change_mask & SPA_CONTROL_CMD_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\n", this, cmd, - this->max_inputs, this->max_outputs); - - break; - } - - case SPA_CONTROL_CMD_PORT_UPDATE: - { - SpaControlCmdPortUpdate pu; - bool remove; - - spa_log_info (this->log, "proxy %p: got port update %d\n", this, cmd); - if (spa_control_iter_parse_cmd (&it, &pu) < 0) - break; - - if (!CHECK_PORT_ID (this, pu.direction, pu.port_id)) - break; - - remove = (pu.change_mask == 0); - - if (remove) { - do_uninit_port (this, pu.direction, pu.port_id); - } else { - do_update_port (this, &pu); - } - break; - } - - case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - { - spa_log_warn (this->log, "proxy %p: command not implemented %d\n", this, cmd); - break; - } - - case SPA_CONTROL_CMD_NODE_STATE_CHANGE: - { - SpaControlCmdNodeStateChange sc; - SpaNodeState old = this->node.state; - - if (spa_control_iter_parse_cmd (&it, &sc) < 0) - break; - - spa_log_info (this->log, "proxy %p: got node state change %d -> %d\n", 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 SPA_CONTROL_CMD_ADD_MEM: - break; - case SPA_CONTROL_CMD_REMOVE_MEM: - break; - case SPA_CONTROL_CMD_USE_BUFFERS: - break; - - case SPA_CONTROL_CMD_NODE_EVENT: - { - SpaControlCmdNodeEvent cne; - - if (spa_control_iter_parse_cmd (&it, &cne) < 0) - break; - - handle_node_event (this, cne.event); - break; - } - } - } - spa_control_iter_end (&it); - - return SPA_RESULT_OK; -} - -static SpaResult -parse_rtcontrol (SpaProxy *this, - SpaControl *ctrl) -{ - SpaControlIter it; - - spa_control_iter_init (&it, ctrl); - while (spa_control_iter_next (&it) == SPA_RESULT_OK) { - SpaControlCmd cmd = spa_control_iter_get_cmd (&it); - - switch (cmd) { - case SPA_CONTROL_CMD_INVALID: - case SPA_CONTROL_CMD_NODE_UPDATE: - case SPA_CONTROL_CMD_PORT_UPDATE: - case SPA_CONTROL_CMD_NODE_STATE_CHANGE: - case SPA_CONTROL_CMD_PORT_STATUS_CHANGE: - case SPA_CONTROL_CMD_ADD_PORT: - case SPA_CONTROL_CMD_REMOVE_PORT: - case SPA_CONTROL_CMD_SET_FORMAT: - case SPA_CONTROL_CMD_SET_PROPERTY: - case SPA_CONTROL_CMD_NODE_COMMAND: - case SPA_CONTROL_CMD_ADD_MEM: - case SPA_CONTROL_CMD_REMOVE_MEM: - case SPA_CONTROL_CMD_USE_BUFFERS: - spa_log_error (this->log, "proxy %p: got unexpected control %d\n", this, cmd); - break; - - case SPA_CONTROL_CMD_PROCESS_BUFFER: - { - SpaControlCmdProcessBuffer cmd; - SpaProxyPort *port; - - if (spa_control_iter_parse_cmd (&it, &cmd) < 0) - break; - - if (!CHECK_PORT (this, cmd.direction, cmd.port_id)) - break; - - port = cmd.direction == SPA_DIRECTION_INPUT ? &this->in_ports[cmd.port_id] : &this->out_ports[cmd.port_id]; - - if (port->buffer_id != SPA_ID_INVALID) - spa_log_warn (this->log, "proxy %p: unprocessed buffer: %d\n", this, port->buffer_id); - - copy_meta_in (this, port, cmd.buffer_id); - - port->buffer_id = cmd.buffer_id; - break; - } - case SPA_CONTROL_CMD_NODE_EVENT: - { - SpaControlCmdNodeEvent cne; - - if (spa_control_iter_parse_cmd (&it, &cne) < 0) - break; - - handle_node_event (this, cne.event); - break; - } - } - } - spa_control_iter_end (&it); - - return SPA_RESULT_OK; -} - -static int -proxy_on_fd_events (SpaPollNotifyData *data) -{ - SpaProxy *this = data->user_data; - SpaResult res; - - if (data->fds[0].revents & POLLIN) { - SpaControl control; - uint8_t buf[1024]; - int fds[16]; - - if ((res = spa_control_read (&control, data->fds[0].fd, buf, sizeof (buf), fds, 16)) < 0) { - spa_log_error (this->log, "proxy %p: failed to read control: %d\n", this, res); - return 0; - } - parse_control (this, &control); - spa_control_clear (&control); - } - return 0; -} - -static int -proxy_on_rtfd_events (SpaPollNotifyData *data) -{ - SpaProxy *this = data->user_data; - SpaResult res; - - if (data->fds[0].revents & POLLIN) { - SpaControl control; - uint8_t buf[1024]; - - if ((res = spa_control_read (&control, data->fds[0].fd, buf, sizeof (buf), NULL, 0)) < 0) { - spa_log_error (this->log, "proxy %p: failed to read control: %d\n", this, res); - return 0; - } - parse_rtcontrol (this, &control); - spa_control_clear (&control); - } - return 0; -} - -static const SpaNode proxy_node = { - sizeof (SpaNode), - NULL, - SPA_NODE_STATE_INIT, - spa_proxy_node_get_props, - spa_proxy_node_set_props, - spa_proxy_node_send_command, - spa_proxy_node_set_event_callback, - spa_proxy_node_get_n_ports, - spa_proxy_node_get_port_ids, - spa_proxy_node_add_port, - spa_proxy_node_remove_port, - spa_proxy_node_port_enum_formats, - spa_proxy_node_port_set_format, - spa_proxy_node_port_get_format, - spa_proxy_node_port_get_info, - spa_proxy_node_port_get_props, - spa_proxy_node_port_set_props, - spa_proxy_node_port_use_buffers, - spa_proxy_node_port_alloc_buffers, - spa_proxy_node_port_get_status, - spa_proxy_node_port_push_input, - spa_proxy_node_port_pull_output, - spa_proxy_node_port_reuse_buffer, - spa_proxy_node_port_push_event, -}; - -static SpaResult -spa_proxy_get_interface (SpaHandle *handle, - uint32_t interface_id, - void **interface) -{ - SpaProxy *this = (SpaProxy *) handle; - - if (handle == NULL || interface == 0) - return SPA_RESULT_INVALID_ARGUMENTS; - - if (interface_id == this->uri.node) - *interface = &this->node; - else - return SPA_RESULT_UNKNOWN_INTERFACE; - - return SPA_RESULT_OK; -} - -static SpaResult -proxy_clear (SpaHandle *handle) -{ - SpaProxy *this; - unsigned int i; - - if (handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - this = (SpaProxy *) handle; - - for (i = 0; i < MAX_INPUTS; i++) { - if (this->in_ports[i].valid) - clear_port (this, &this->in_ports[i], SPA_DIRECTION_INPUT, i); - } - for (i = 0; i < MAX_OUTPUTS; i++) { - if (this->out_ports[i].valid) - clear_port (this, &this->out_ports[i], SPA_DIRECTION_OUTPUT, i); - } - - return SPA_RESULT_OK; -} - -static SpaResult -proxy_init (const SpaHandleFactory *factory, - SpaHandle *handle, - const SpaDict *info, - const SpaSupport *support, - unsigned int n_support) -{ - SpaProxy *this; - unsigned int i; - - if (factory == NULL || handle == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - handle->get_interface = spa_proxy_get_interface; - handle->clear = proxy_clear; - - this = (SpaProxy *) handle; - - for (i = 0; i < n_support; i++) { - if (strcmp (support[i].uri, SPA_ID_MAP_URI) == 0) - this->map = support[i].data; - else if (strcmp (support[i].uri, SPA_LOG_URI) == 0) - this->log = support[i].data; - else if (strcmp (support[i].uri, SPA_POLL__MainLoop) == 0) - this->main_loop = support[i].data; - else if (strcmp (support[i].uri, SPA_POLL__DataLoop) == 0) - this->data_loop = support[i].data; - } - if (this->map == NULL) { - spa_log_error (this->log, "an id-map is needed"); - return SPA_RESULT_ERROR; - } - if (this->data_loop == NULL) { - spa_log_error (this->log, "a data-loop is needed"); - return SPA_RESULT_ERROR; - } - this->uri.node = spa_id_map_get_id (this->map, SPA_NODE_URI); - - this->node = proxy_node; - this->props[1].props.n_prop_info = PROP_ID_LAST; - this->props[1].props.prop_info = prop_info; - reset_proxy_props (&this->props[1]); - memcpy (&this->props[0], &this->props[1], sizeof (this->props[1])); - - this->fds[0].fd = -1; - this->fds[0].events = POLLIN | POLLPRI | POLLERR; - this->fds[0].revents = 0; - this->poll.id = 0; - this->poll.enabled = true; - this->poll.fds = this->fds; - this->poll.n_fds = 1; - this->poll.idle_cb = NULL; - this->poll.before_cb = NULL; - this->poll.after_cb = proxy_on_fd_events; - this->poll.user_data = this; - - this->rtfds[0].fd = -1; - this->rtfds[0].events = POLLIN | POLLPRI | POLLERR; - this->rtfds[0].revents = 0; - this->rtpoll.id = 0; - this->rtpoll.enabled = true; - this->rtpoll.fds = this->rtfds; - this->rtpoll.n_fds = 1; - this->rtpoll.idle_cb = NULL; - this->rtpoll.before_cb = NULL; - this->rtpoll.after_cb = proxy_on_rtfd_events; - this->rtpoll.user_data = this; - - return SPA_RESULT_RETURN_ASYNC (this->seq++); -} - -static const SpaInterfaceInfo proxy_interfaces[] = -{ - { SPA_NODE_URI, }, -}; - -static SpaResult -proxy_enum_interface_info (const SpaHandleFactory *factory, - const SpaInterfaceInfo **info, - void **state) -{ - int index; - - if (factory == NULL || info == NULL || state == NULL) - return SPA_RESULT_INVALID_ARGUMENTS; - - index = (*state == NULL ? 0 : *(int*)state); - - switch (index) { - case 0: - *info = &proxy_interfaces[index]; - break; - default: - return SPA_RESULT_ENUM_END; - } - *(int*)state = ++index; - - return SPA_RESULT_OK; -} - -const SpaHandleFactory spa_proxy_factory = -{ "proxy", - NULL, - sizeof (SpaProxy), - proxy_init, - proxy_enum_interface_info, -};