From d1e2f69324d174be0d1caf42a65de627df57bd9c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Jun 2018 12:59:08 +0200 Subject: [PATCH 001/155] connection: reset number of fds --- src/modules/module-protocol-native/connection.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/modules/module-protocol-native/connection.c b/src/modules/module-protocol-native/connection.c index 881669735..817e5b56a 100644 --- a/src/modules/module-protocol-native/connection.c +++ b/src/modules/module-protocol-native/connection.c @@ -158,6 +158,7 @@ static bool refill_buffer(struct pw_protocol_native_connection *conn, struct buf buf->buffer_size += len; /* handle control messages */ + buf->n_fds = 0; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) continue; From c208511f533276acfe3c81442cb9754ee0a865f7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 15 Jun 2018 13:01:08 +0200 Subject: [PATCH 002/155] proxy: reuse id when server removed it When we destroy the proxy, just clear the id. We then remove the id completely when the server sends a remove_id request. This avoid reusing the proxy id before the server has finished with it. --- src/pipewire/proxy.c | 2 +- src/pipewire/remote.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pipewire/proxy.c b/src/pipewire/proxy.c index d7c91e2b9..4a87b07be 100644 --- a/src/pipewire/proxy.c +++ b/src/pipewire/proxy.c @@ -121,7 +121,7 @@ void pw_proxy_destroy(struct pw_proxy *proxy) pw_log_debug("proxy %p: destroy %u", proxy, proxy->id); spa_hook_list_call(&proxy->listener_list, struct pw_proxy_events, destroy); - pw_map_remove(&proxy->remote->objects, proxy->id); + pw_map_insert_at(&proxy->remote->objects, proxy->id, NULL); spa_list_remove(&proxy->link); free(impl); diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index dbaeaaf5b..6d162817d 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -188,6 +188,7 @@ static void core_event_remove_id(void *data, uint32_t id) pw_log_debug("remote %p: object remove %u", this, id); pw_proxy_destroy(proxy); } + pw_map_remove(&this->objects, id); } static void From d619b774253ad8aa32f379847e42357878fc0d3a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Apr 2018 20:02:06 +0200 Subject: [PATCH 003/155] monitor: safely remove pending requests --- src/tools/pipewire-monitor.c | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index f92f4e32d..3bfeba24d 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -75,15 +75,22 @@ static void add_pending(struct proxy_data *pd) pw_core_proxy_sync(d->core_proxy, pd->pending_seq); } +static void remove_pending(struct proxy_data *pd) +{ + if (pd->pending_seq != SPA_ID_INVALID) { + spa_list_remove(&pd->pending_link); + pd->pending_seq = SPA_ID_INVALID; + } +} + static void on_sync_reply(void *data, uint32_t seq) { struct data *d = data; - struct proxy_data *pd; + struct proxy_data *pd, *t; - spa_list_for_each(pd, &d->pending_list, pending_link) { + spa_list_for_each_safe(pd, t, &d->pending_list, pending_link) { if (pd->pending_seq == seq) { - spa_list_remove(&pd->pending_link); - pd->pending_seq = SPA_ID_INVALID; + remove_pending(pd); pd->print_func(pd); } } @@ -439,16 +446,17 @@ static const struct pw_link_proxy_events link_events = { static void destroy_proxy (void *data) { - struct proxy_data *user_data = data; + struct proxy_data *pd = data; - clear_params(user_data); + clear_params(pd); + remove_pending(pd); - if (user_data->info == NULL) + if (pd->info == NULL) return; - if (user_data->destroy) - user_data->destroy(user_data->info); - user_data->info = NULL; + if (pd->destroy) + pd->destroy(pd->info); + pd->info = NULL; } static const struct pw_proxy_events proxy_events = { From c42d495771369e8463a7b04dd387c2146652d44d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Apr 2018 22:01:18 +0200 Subject: [PATCH 004/155] loop: blocking wait Release the locks before waiting. --- spa/plugins/support/loop.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 62d5b0cfe..95c1979ea 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -248,10 +248,15 @@ loop_invoke(struct spa_loop *loop, if (block) { uint64_t count = 1; + + spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, before); + if (read(impl->ack_fd, &count, sizeof(uint64_t)) != sizeof(uint64_t)) spa_log_warn(impl->log, NAME " %p: failed to read event fd: %s", impl, strerror(errno)); + spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, after); + res = item->res; } else { @@ -728,7 +733,7 @@ impl_init(const struct spa_handle_factory *factory, spa_ringbuffer_init(&impl->buffer); impl->wakeup = spa_loop_utils_add_event(&impl->utils, wakeup_func, impl); - impl->ack_fd = eventfd(0, EFD_CLOEXEC); + impl->ack_fd = eventfd(0, EFD_SEMAPHORE | EFD_CLOEXEC); spa_log_debug(impl->log, NAME " %p: initialized", impl); From 70bdb7285717101b725210ba86b5c84bd13419c0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Apr 2018 16:28:47 +0200 Subject: [PATCH 005/155] loop: add back the destroy loop We need to keep the sources around until all sources are dispatched. If not: source A and B are active after poll, A is dispatched first and removes B, when B is then dispatched, the memory is gone. We don't free the source but simply mark the fd invalid and move it do a destroy list. After all sources are dispatched we destroy. This is safe because removing a source is either done from the poll context (with invoke) or when holding the right locks. --- spa/plugins/support/loop.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 95c1979ea..a476868c2 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -79,6 +79,7 @@ struct impl { struct spa_type_map *map; struct spa_list source_list; + struct spa_list destroy_list; struct spa_hook_list hooks_list; int epoll_fd; @@ -319,6 +320,14 @@ static void loop_leave(struct spa_loop_control *ctrl) impl->thread = 0; } +static void process_destroy(struct impl *impl) +{ + struct source_impl *source, *tmp; + spa_list_for_each_safe(source, tmp, &impl->destroy_list, link) + free(source); + spa_list_init(&impl->destroy_list); +} + static int loop_iterate(struct spa_loop_control *ctrl, int timeout) { struct impl *impl = SPA_CONTAINER_OF(ctrl, struct impl, control); @@ -348,6 +357,8 @@ static int loop_iterate(struct spa_loop_control *ctrl, int timeout) if (s->rmask && s->fd != -1 && s->loop == loop) s->func(s); } + process_destroy(impl); + return 0; } @@ -617,7 +628,7 @@ static void loop_destroy_source(struct spa_source *source) close(source->fd); source->fd = -1; } - free(impl); + spa_list_insert(&impl->impl->destroy_list, &impl->link); } static const struct spa_loop impl_loop = { @@ -684,6 +695,8 @@ static int impl_clear(struct spa_handle *handle) spa_list_for_each_safe(source, tmp, &impl->source_list, link) loop_destroy_source(&source->source); + process_destroy(impl); + close(impl->ack_fd); close(impl->epoll_fd); @@ -728,6 +741,7 @@ impl_init(const struct spa_handle_factory *factory, return errno; spa_list_init(&impl->source_list); + spa_list_init(&impl->destroy_list); spa_hook_list_init(&impl->hooks_list); spa_ringbuffer_init(&impl->buffer); From 85f81ab4e2178db9aab31887835faab65c4adbb8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 14 May 2018 13:07:55 +0200 Subject: [PATCH 006/155] config: fail when something fails --- src/daemon/daemon-config.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/daemon/daemon-config.c b/src/daemon/daemon-config.c index ae805591a..a2bccf988 100644 --- a/src/daemon/daemon-config.c +++ b/src/daemon/daemon-config.c @@ -190,6 +190,7 @@ int pw_daemon_config_run_commands(struct pw_daemon_config *config, struct pw_cor if ((ret = pw_command_run(command, core, &err)) < 0) { pw_log_warn("could not run command %s: %s", command->args[0], err); free(err); + break; } } From 1e54d9e00bd29369abd6b96536304d370a777960 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 17 May 2018 17:21:30 +0200 Subject: [PATCH 007/155] hook: make safer Also protect against removal of the next hook by using a cursor. --- spa/include/spa/utils/hook.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index 97bda8594..8fddc2525 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -80,20 +80,28 @@ static inline void spa_hook_remove(struct spa_hook *hook) /** Call all hooks in a list, starting from the given one and optionally stopping * after calling the first non-NULL function, returns the number of methods * called */ -#define spa_hook_list_do_call(l,start,type,method,once,...) ({ \ +#define spa_hook_list_do_call(l,start,type,method,once,...) \ +({ \ struct spa_hook_list *list = l; \ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \ - struct spa_hook *ci, *t; \ + struct spa_hook cursor = { 0, }; \ + struct spa_hook *ci; \ int count = 0; \ - spa_list_for_each_safe_next(ci, t, &list->list, s, link) { \ + spa_list_prepend(s, &cursor.link); \ + for(ci = spa_list_first(&cursor.link, struct spa_hook, link); \ + &ci->link != s; \ + ci = spa_list_next(&cursor, link)) { \ const type *cb = ci->funcs; \ - if (cb->method) { \ + spa_list_remove(&ci->link); \ + spa_list_append(&cursor.link, &ci->link); \ + if (cb && cb->method) { \ cb->method(ci->data, ## __VA_ARGS__); \ count++; \ if (once) \ break; \ } \ } \ + spa_list_remove(&cursor.link); \ count; \ }) From 4574adcd2ef2b7d9463b1ddf64e9dcb25277cd73 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 17 May 2018 17:30:30 +0200 Subject: [PATCH 008/155] clean up listeners --- src/modules/module-client-node/client-node.c | 1 + src/modules/spa/module-node-factory.c | 1 + src/modules/spa/spa-node.c | 1 + 3 files changed, 3 insertions(+) diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index 8502a735f..eeab73abf 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -1187,6 +1187,7 @@ static void client_node_resource_destroy(void *data) pw_log_debug("client-node %p: destroy", impl); impl->node.resource = this->resource = NULL; + spa_hook_remove(&impl->resource_listener); if (node->data_source.fd != -1) { spa_loop_invoke(node->data_loop, diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index 2c76ffbd9..9e2129d9d 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -52,6 +52,7 @@ static void node_destroy(void *data) { struct node_data *nd = data; spa_list_remove(&nd->link); + spa_hook_remove(&nd->node_listener); } static const struct pw_node_events node_events = { diff --git a/src/modules/spa/spa-node.c b/src/modules/spa/spa-node.c index 1d2e7bdf8..c6dc70241 100644 --- a/src/modules/spa/spa-node.c +++ b/src/modules/spa/spa-node.c @@ -62,6 +62,7 @@ static void pw_spa_node_destroy(void *data) pw_log_debug("spa-node %p: destroy", node); + spa_hook_remove(&impl->node_listener); if (impl->handle) { spa_handle_clear(impl->handle); free(impl->handle); From 67e567b9c7c4c96fe55996062a83b5b907282035 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Sun, 8 Jul 2018 14:47:43 +0200 Subject: [PATCH 009/155] stream: API break Add pw_buffer Add queue/dequeue methods, remove old methods Add get and set for properties Update gst elements and examples Update the API to work branch which is more future proof --- src/examples/video-play.c | 16 +- src/examples/video-src.c | 38 ++--- src/gst/gstpipewireclock.c | 6 +- src/gst/gstpipewirepool.c | 98 ++++++++++-- src/gst/gstpipewirepool.h | 25 ++- src/gst/gstpipewiresink.c | 155 ++++-------------- src/gst/gstpipewiresink.h | 2 - src/gst/gstpipewiresrc.c | 180 +++++++-------------- src/gst/gstpipewiresrc.h | 5 +- src/pipewire/stream.c | 317 ++++++++++++++++++------------------- src/pipewire/stream.h | 139 ++++++++-------- 11 files changed, 454 insertions(+), 527 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index bd7920da7..17c7f1433 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -139,19 +139,19 @@ do_render(struct spa_loop *loop, bool async, uint32_t seq, } static void -on_stream_new_buffer(void *_data, uint32_t id) +on_stream_process(void *_data) { struct data *data = _data; struct pw_stream *stream = data->stream; - struct spa_buffer *buf; + struct pw_buffer *buf; - buf = pw_stream_peek_buffer(stream, id); + buf = pw_stream_dequeue_buffer(stream); pw_loop_invoke(pw_main_loop_get_loop(data->loop), do_render, - SPA_ID_INVALID, &buf, sizeof(struct spa_buffer *), + SPA_ID_INVALID, &buf->buffer, sizeof(struct spa_buffer *), true, data); - pw_stream_recycle_buffer(stream, id); + pw_stream_queue_buffer(stream, buf); } static void on_stream_state_changed(void *_data, enum pw_stream_state old, @@ -239,14 +239,14 @@ static Uint32 id_to_sdl_format(struct data *data, uint32_t id) } static void -on_stream_format_changed(void *_data, struct spa_pod *format) +on_stream_format_changed(void *_data, const struct spa_pod *format) { struct data *data = _data; struct pw_stream *stream = data->stream; struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - struct spa_pod *params[2]; + const struct spa_pod *params[2]; Uint32 sdl_format; void *d; @@ -291,7 +291,7 @@ static const struct pw_stream_events stream_events = { PW_VERSION_STREAM_EVENTS, .state_changed = on_stream_state_changed, .format_changed = on_stream_format_changed, - .new_buffer = on_stream_new_buffer, + .process = on_stream_process, }; static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) diff --git a/src/examples/video-src.c b/src/examples/video-src.c index e440d5f9c..7a4415cec 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -71,35 +71,35 @@ struct data { static void on_timeout(void *userdata, uint64_t expirations) { struct data *data = userdata; - uint32_t id; - struct spa_buffer *buf; int i, j; uint8_t *p, *map; struct spa_meta_header *h; + struct pw_buffer *buf; + struct spa_buffer *b; - id = pw_stream_get_empty_buffer(data->stream); - if (id == SPA_ID_INVALID) + buf = pw_stream_dequeue_buffer(data->stream); + if (buf == NULL) return; - buf = pw_stream_peek_buffer(data->stream, id); + b = buf->buffer; - if (buf->datas[0].type == data->t->data.MemFd || - buf->datas[0].type == data->t->data.DmaBuf) { + if (b->datas[0].type == data->t->data.MemFd || + b->datas[0].type == data->t->data.DmaBuf) { map = - mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, - PROT_READ | PROT_WRITE, MAP_SHARED, buf->datas[0].fd, 0); + mmap(NULL, b->datas[0].maxsize + b->datas[0].mapoffset, + PROT_READ | PROT_WRITE, MAP_SHARED, b->datas[0].fd, 0); if (map == MAP_FAILED) { printf("failed to mmap: %s\n", strerror(errno)); return; } - p = SPA_MEMBER(map, buf->datas[0].mapoffset, uint8_t); - } else if (buf->datas[0].type == data->t->data.MemPtr) { + p = SPA_MEMBER(map, b->datas[0].mapoffset, uint8_t); + } else if (b->datas[0].type == data->t->data.MemPtr) { map = NULL; - p = buf->datas[0].data; + p = b->datas[0].data; } else return; - if ((h = spa_buffer_find_meta(buf, data->t->meta.Header))) { + if ((h = spa_buffer_find_meta(b, data->t->meta.Header))) { #if 0 struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -116,16 +116,16 @@ static void on_timeout(void *userdata, uint64_t expirations) for (j = 0; j < data->format.size.width * BPP; j++) { p[j] = data->counter + j * i; } - p += buf->datas[0].chunk->stride; + p += b->datas[0].chunk->stride; data->counter += 13; } if (map) - munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset); + munmap(map, b->datas[0].maxsize + b->datas[0].mapoffset); - buf->datas[0].chunk->size = buf->datas[0].maxsize; + b->datas[0].chunk->size = b->datas[0].maxsize; - pw_stream_send_buffer(data->stream, id); + pw_stream_queue_buffer(data->stream, buf); } static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum pw_stream_state state, @@ -157,14 +157,14 @@ static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum } static void -on_stream_format_changed(void *_data, struct spa_pod *format) +on_stream_format_changed(void *_data, const struct spa_pod *format) { struct data *data = _data; struct pw_stream *stream = data->stream; struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - struct spa_pod *params[2]; + const struct spa_pod *params[2]; if (format == NULL) { pw_stream_finish_format(stream, 0, NULL, 0); diff --git a/src/gst/gstpipewireclock.c b/src/gst/gstpipewireclock.c index a82631efe..4c4e47889 100644 --- a/src/gst/gstpipewireclock.c +++ b/src/gst/gstpipewireclock.c @@ -50,12 +50,12 @@ gst_pipewire_clock_get_internal_time (GstClock * clock) pw_stream_get_time (pclock->stream, &t); - if (t.rate) - result = gst_util_uint64_scale_int (t.ticks, GST_SECOND, t.rate); + if (t.rate.denom) + result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.num, t.rate.denom); else result = GST_CLOCK_TIME_NONE; - GST_DEBUG ("%"PRId64", %d %"PRId64, t.ticks, t.rate, result); + GST_DEBUG ("%"PRId64", %d %"PRId64, t.ticks, t.rate.denom, result); return result; } diff --git a/src/gst/gstpipewirepool.c b/src/gst/gstpipewirepool.c index eb36f957f..b75ff5563 100644 --- a/src/gst/gstpipewirepool.c +++ b/src/gst/gstpipewirepool.c @@ -21,8 +21,13 @@ #include "config.h" #endif +#include + #include +#include +#include + #include "gstpipewirepool.h" GST_DEBUG_CATEGORY_STATIC (gst_pipewire_pool_debug_category); @@ -40,6 +45,8 @@ enum static guint pool_signals[LAST_SIGNAL] = { 0 }; +static GQuark pool_data_quark; + GstPipeWirePool * gst_pipewire_pool_new (void) { @@ -50,6 +57,74 @@ gst_pipewire_pool_new (void) return pool; } +static void +pool_data_destroy (gpointer user_data) +{ + GstPipeWirePoolData *data = user_data; + + gst_object_unref (data->pool); + g_slice_free (GstPipeWirePoolData, data); +} + +void gst_pipewire_pool_wrap_buffer (GstPipeWirePool *pool, struct pw_buffer *b) +{ + GstBuffer *buf; + uint32_t i; + GstPipeWirePoolData *data; + struct pw_type *t = pool->t; + + GST_LOG_OBJECT (pool, "wrap buffer"); + + data = g_slice_new (GstPipeWirePoolData); + + buf = gst_buffer_new (); + + for (i = 0; i < b->buffer->n_datas; i++) { + struct spa_data *d = &b->buffer->datas[i]; + GstMemory *gmem = NULL; + + GST_LOG_OBJECT (pool, "wrap buffer %d %d", d->mapoffset, d->maxsize); + if (d->type == t->data.MemFd) { + gmem = gst_fd_allocator_alloc (pool->fd_allocator, dup (d->fd), + d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE); + gst_memory_resize (gmem, d->mapoffset, d->maxsize); + data->offset = d->mapoffset; + } + else if(d->type == t->data.DmaBuf) { + gmem = gst_dmabuf_allocator_alloc (pool->dmabuf_allocator, dup (d->fd), + d->mapoffset + d->maxsize); + gst_memory_resize (gmem, d->mapoffset, d->maxsize); + data->offset = d->mapoffset; + } + else if (d->type == t->data.MemPtr) { + gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, 0, + d->maxsize, NULL, NULL); + data->offset = 0; + } + if (gmem) + gst_buffer_append_memory (buf, gmem); + } + + data->pool = gst_object_ref (pool); + data->owner = NULL; + data->header = spa_buffer_find_meta (b->buffer, t->meta.Header); + data->flags = GST_BUFFER_FLAGS (buf); + data->b = b; + data->buf = buf; + + gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), + pool_data_quark, + data, + pool_data_destroy); + b->user_data = data; +} + +GstPipeWirePoolData *gst_pipewire_pool_get_data (GstBuffer *buffer) +{ + return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), pool_data_quark); +} + +#if 0 gboolean gst_pipewire_pool_add_buffer (GstPipeWirePool *pool, GstBuffer *buffer) { @@ -78,25 +153,31 @@ gst_pipewire_pool_remove_buffer (GstPipeWirePool *pool, GstBuffer *buffer) return res; } +#endif static GstFlowReturn acquire_buffer (GstBufferPool * pool, GstBuffer ** buffer, GstBufferPoolAcquireParams * params) { GstPipeWirePool *p = GST_PIPEWIRE_POOL (pool); + GstPipeWirePoolData *data; + struct pw_buffer *b; GST_OBJECT_LOCK (pool); while (TRUE) { if (G_UNLIKELY (GST_BUFFER_POOL_IS_FLUSHING (pool))) goto flushing; - if (p->available.length > 0) + if ((b = pw_stream_dequeue_buffer(p->stream))) break; GST_WARNING ("queue empty"); g_cond_wait (&p->cond, GST_OBJECT_GET_LOCK (pool)); } - *buffer = g_queue_pop_head (&p->available); + + data = b->user_data; + *buffer = data->buf; + GST_OBJECT_UNLOCK (pool); GST_DEBUG ("acquire buffer %p", *buffer); @@ -123,13 +204,7 @@ flush_start (GstBufferPool * pool) static void release_buffer (GstBufferPool * pool, GstBuffer *buffer) { - GstPipeWirePool *p = GST_PIPEWIRE_POOL (pool); - GST_DEBUG ("release buffer %p", buffer); - GST_OBJECT_LOCK (pool); - g_queue_push_tail (&p->available, buffer); - g_cond_signal (&p->cond); - GST_OBJECT_UNLOCK (pool); } static gboolean @@ -145,6 +220,8 @@ gst_pipewire_pool_finalize (GObject * object) GstPipeWirePool *pool = GST_PIPEWIRE_POOL (object); GST_DEBUG_OBJECT (pool, "finalize"); + g_object_unref (pool->fd_allocator); + g_object_unref (pool->dmabuf_allocator); G_OBJECT_CLASS (gst_pipewire_pool_parent_class)->finalize (object); } @@ -168,11 +245,14 @@ gst_pipewire_pool_class_init (GstPipeWirePoolClass * klass) GST_DEBUG_CATEGORY_INIT (gst_pipewire_pool_debug_category, "pipewirepool", 0, "debug category for pipewirepool object"); + + pool_data_quark = g_quark_from_static_string ("GstPipeWirePoolDataQuark"); } static void gst_pipewire_pool_init (GstPipeWirePool * pool) { + pool->fd_allocator = gst_fd_allocator_new (); + pool->dmabuf_allocator = gst_dmabuf_allocator_new (); g_cond_init (&pool->cond); - g_queue_init (&pool->available); } diff --git a/src/gst/gstpipewirepool.h b/src/gst/gstpipewirepool.h index 80188f71c..4ed62d79a 100644 --- a/src/gst/gstpipewirepool.h +++ b/src/gst/gstpipewirepool.h @@ -39,14 +39,29 @@ G_BEGIN_DECLS #define GST_PIPEWIRE_POOL_GET_CLASS(klass) \ (G_TYPE_INSTANCE_GET_CLASS ((klass), GST_TYPE_PIPEWIRE_POOL, GstPipeWirePoolClass)) +typedef struct _GstPipeWirePoolData GstPipeWirePoolData; typedef struct _GstPipeWirePool GstPipeWirePool; typedef struct _GstPipeWirePoolClass GstPipeWirePoolClass; +struct _GstPipeWirePoolData { + GstPipeWirePool *pool; + void *owner; + struct spa_meta_header *header; + guint flags; + goffset offset; + struct pw_buffer *b; + GstBuffer *buf; +}; + struct _GstPipeWirePool { GstBufferPool parent; struct pw_stream *stream; - GQueue available; + struct pw_type *t; + + GstAllocator *fd_allocator; + GstAllocator *dmabuf_allocator; + GCond cond; }; @@ -58,8 +73,12 @@ GType gst_pipewire_pool_get_type (void); GstPipeWirePool * gst_pipewire_pool_new (void); -gboolean gst_pipewire_pool_add_buffer (GstPipeWirePool *pool, GstBuffer *buffer); -gboolean gst_pipewire_pool_remove_buffer (GstPipeWirePool *pool, GstBuffer *buffer); +void gst_pipewire_pool_wrap_buffer (GstPipeWirePool *pool, struct pw_buffer *buffer); + +GstPipeWirePoolData *gst_pipewire_pool_get_data (GstBuffer *buffer); + +//gboolean gst_pipewire_pool_add_buffer (GstPipeWirePool *pool, GstBuffer *buffer); +//gboolean gst_pipewire_pool_remove_buffer (GstPipeWirePool *pool, GstBuffer *buffer); G_END_DECLS diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c index 498ef8153..ea4b3eb3e 100644 --- a/src/gst/gstpipewiresink.c +++ b/src/gst/gstpipewiresink.c @@ -37,14 +37,9 @@ #include #include #include -#include - -#include #include "gstpipewireformat.h" -static GQuark process_mem_data_quark; - GST_DEBUG_CATEGORY_STATIC (pipewire_sink_debug); #define GST_CAT_DEFAULT pipewire_sink_debug @@ -123,10 +118,8 @@ gst_pipewire_sink_finalize (GObject * object) if (pwsink->properties) gst_structure_free (pwsink->properties); - g_object_unref (pwsink->allocator); g_free (pwsink->path); g_free (pwsink->client_name); - g_hash_table_unref (pwsink->buf_ids); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -219,8 +212,6 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass) GST_DEBUG_CATEGORY_INIT (pipewire_sink_debug, "pipewiresink", 0, "PipeWire Sink"); - - process_mem_data_quark = g_quark_from_static_string ("GstPipeWireSinkProcessMemQuark"); } #define PROP_RANGE(min,max) 2,min,max @@ -234,7 +225,7 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) guint size; guint min_buffers; guint max_buffers; - struct spa_pod *port_params[2]; + const struct spa_pod *port_params[2]; struct spa_pod_builder b = { NULL }; uint8_t buffer[1024]; @@ -273,7 +264,6 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) static void gst_pipewire_sink_init (GstPipeWireSink * sink) { - sink->allocator = gst_fd_allocator_new (); sink->pool = gst_pipewire_pool_new (); sink->client_name = pw_get_client_name(); sink->mode = DEFAULT_PROP_MODE; @@ -281,15 +271,13 @@ gst_pipewire_sink_init (GstPipeWireSink * sink) g_signal_connect (sink->pool, "activated", G_CALLBACK (pool_activated), sink); - sink->buf_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, - (GDestroyNotify) gst_buffer_unref); - g_queue_init (&sink->queue); sink->loop = pw_loop_new (NULL); sink->main_loop = pw_thread_loop_new (sink->loop, "pipewire-sink-loop"); sink->core = pw_core_new (sink->loop, NULL); sink->type = pw_core_get_type (sink->core); + sink->pool->t = sink->type; GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop); } @@ -407,126 +395,35 @@ gst_pipewire_sink_get_property (GObject * object, guint prop_id, } } -typedef struct { - GstPipeWireSink *sink; - guint id; - struct spa_buffer *buf; - struct spa_meta_header *header; - guint flags; - goffset offset; -} ProcessMemData; - static void -process_mem_data_destroy (gpointer user_data) -{ - ProcessMemData *data = user_data; - - gst_object_unref (data->sink); - g_slice_free (ProcessMemData, data); -} - -static void -on_add_buffer (void *_data, - uint32_t id) +on_add_buffer (void *_data, struct pw_buffer *b) { GstPipeWireSink *pwsink = _data; - struct spa_buffer *b; - GstBuffer *buf; - uint32_t i; - ProcessMemData data; - struct pw_type *t = pwsink->type; - - GST_LOG_OBJECT (pwsink, "add buffer"); - - if (!(b = pw_stream_peek_buffer (pwsink->stream, id))) { - g_warning ("failed to peek buffer"); - return; - } - - buf = gst_buffer_new (); - - data.sink = gst_object_ref (pwsink); - data.id = id; - data.buf = b; - data.header = spa_buffer_find_meta (b, t->meta.Header); - - for (i = 0; i < b->n_datas; i++) { - struct spa_data *d = &b->datas[i]; - GstMemory *gmem = NULL; - - if (d->type == t->data.MemFd || - d->type == t->data.DmaBuf) { - gmem = gst_fd_allocator_alloc (pwsink->allocator, dup (d->fd), - d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE); - gst_memory_resize (gmem, d->mapoffset, d->maxsize); - data.offset = d->mapoffset; - } - else if (d->type == t->data.MemPtr) { - gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, 0, - d->maxsize, NULL, NULL); - data.offset = 0; - } - if (gmem) - gst_buffer_append_memory (buf, gmem); - } - data.flags = GST_BUFFER_FLAGS (buf); - gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), - process_mem_data_quark, - g_slice_dup (ProcessMemData, &data), - process_mem_data_destroy); - - gst_pipewire_pool_add_buffer (pwsink->pool, buf); - g_hash_table_insert (pwsink->buf_ids, GINT_TO_POINTER (id), buf); - + gst_pipewire_pool_wrap_buffer (pwsink->pool, b); pw_thread_loop_signal (pwsink->main_loop, FALSE); } static void -on_remove_buffer (void *data, - uint32_t id) +on_remove_buffer (void *_data, struct pw_buffer *b) { - GstPipeWireSink *pwsink = data; - GstBuffer *buf; + GstPipeWireSink *pwsink = _data; + GstPipeWirePoolData *data = b->user_data; GST_LOG_OBJECT (pwsink, "remove buffer"); - buf = g_hash_table_lookup (pwsink->buf_ids, GINT_TO_POINTER (id)); - if (buf) { - GST_MINI_OBJECT_CAST (buf)->dispose = NULL; - if (!gst_pipewire_pool_remove_buffer (pwsink->pool, buf)) - gst_buffer_ref (buf); - if (g_queue_remove (&pwsink->queue, buf)) - gst_buffer_unref (buf); - g_hash_table_remove (pwsink->buf_ids, GINT_TO_POINTER (id)); - } -} -static void -on_new_buffer (void *data, - uint32_t id) -{ - GstPipeWireSink *pwsink = data; - GstBuffer *buf; - - GST_LOG_OBJECT (pwsink, "got new buffer %u", id); - if (pwsink->stream == NULL) { - GST_LOG_OBJECT (pwsink, "no stream"); - return; - } - buf = g_hash_table_lookup (pwsink->buf_ids, GINT_TO_POINTER (id)); - - if (buf) { - gst_buffer_unref (buf); - pw_thread_loop_signal (pwsink->main_loop, FALSE); - } + if (g_queue_remove (&pwsink->queue, data->buf)) + gst_buffer_unref (data->buf); + gst_buffer_unref (data->buf); } static void do_send_buffer (GstPipeWireSink *pwsink) { GstBuffer *buffer; - ProcessMemData *data; + GstPipeWirePoolData *data; gboolean res; guint i; + struct spa_buffer *b; buffer = g_queue_pop_head (&pwsink->queue); if (buffer == NULL) { @@ -534,23 +431,24 @@ do_send_buffer (GstPipeWireSink *pwsink) return; } - data = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buffer), - process_mem_data_quark); + data = gst_pipewire_pool_get_data(buffer); + + b = data->b->buffer; if (data->header) { data->header->seq = GST_BUFFER_OFFSET (buffer); data->header->pts = GST_BUFFER_PTS (buffer); data->header->dts_offset = GST_BUFFER_DTS (buffer); } - for (i = 0; i < data->buf->n_datas; i++) { - struct spa_data *d = &data->buf->datas[i]; + for (i = 0; i < b->n_datas; i++) { + struct spa_data *d = &b->datas[i]; GstMemory *mem = gst_buffer_peek_memory (buffer, i); d->chunk->offset = mem->offset - data->offset; d->chunk->size = mem->size; } - if (!(res = pw_stream_send_buffer (pwsink->stream, data->id))) { - g_warning ("can't send buffer"); + if ((res = pw_stream_queue_buffer (pwsink->stream, data->b)) < 0) { + g_warning ("can't send buffer %s", spa_strerror(res)); pw_thread_loop_signal (pwsink->main_loop, FALSE); } else pwsink->need_ready--; @@ -558,9 +456,17 @@ do_send_buffer (GstPipeWireSink *pwsink) static void -on_need_buffer (void *data) +on_process (void *data) { GstPipeWireSink *pwsink = data; + + if (pwsink->stream == NULL) { + GST_LOG_OBJECT (pwsink, "no stream"); + return; + } + + g_cond_signal (&pwsink->pool->cond); + pwsink->need_ready++; GST_DEBUG ("need buffer %u", pwsink->need_ready); do_send_buffer (pwsink); @@ -590,7 +496,7 @@ on_state_changed (void *data, enum pw_stream_state old, enum pw_stream_state sta } static void -on_format_changed (void *data, struct spa_pod *format) +on_format_changed (void *data, const struct spa_pod *format) { GstPipeWireSink *pwsink = data; @@ -733,8 +639,7 @@ static const struct pw_stream_events stream_events = { .format_changed = on_format_changed, .add_buffer = on_add_buffer, .remove_buffer = on_remove_buffer, - .new_buffer = on_new_buffer, - .need_buffer = on_need_buffer, + .process = on_process, }; static gboolean diff --git a/src/gst/gstpipewiresink.h b/src/gst/gstpipewiresink.h index c746cf358..5ff61f2e4 100644 --- a/src/gst/gstpipewiresink.h +++ b/src/gst/gstpipewiresink.h @@ -89,12 +89,10 @@ struct _GstPipeWireSink { struct pw_stream *stream; struct spa_hook stream_listener; - GstAllocator *allocator; GstStructure *properties; GstPipeWireSinkMode mode; GstPipeWirePool *pool; - GHashTable *buf_ids; GQueue queue; guint need_ready; }; diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 86770f1a0..568ebfa9b 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -211,13 +211,10 @@ gst_pipewire_src_finalize (GObject * object) if (pwsrc->properties) gst_structure_free (pwsrc->properties); - g_object_unref (pwsrc->fd_allocator); - g_object_unref (pwsrc->dmabuf_allocator); if (pwsrc->clock) gst_object_unref (pwsrc->clock); g_free (pwsrc->path); g_free (pwsrc->client_name); - g_hash_table_unref (pwsrc->buf_ids); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -322,163 +319,94 @@ gst_pipewire_src_init (GstPipeWireSrc * src) g_queue_init (&src->queue); - src->fd_allocator = gst_fd_allocator_new (); - src->dmabuf_allocator = gst_dmabuf_allocator_new (); src->client_name = pw_get_client_name (); - src->buf_ids = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) gst_buffer_unref); + src->pool = gst_pipewire_pool_new (); src->loop = pw_loop_new (NULL); src->main_loop = pw_thread_loop_new (src->loop, "pipewire-main-loop"); src->core = pw_core_new (src->loop, NULL); src->type = pw_core_get_type (src->core); + src->pool->t = src->type; GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop); } -typedef struct { - GstPipeWireSrc *src; - guint id; - struct spa_buffer *buf; - struct spa_meta_header *header; - guint flags; - goffset offset; -} ProcessMemData; - -static void -process_mem_data_destroy (gpointer user_data) -{ - ProcessMemData *data = user_data; - - gst_object_unref (data->src); - g_slice_free (ProcessMemData, data); -} - static gboolean buffer_recycle (GstMiniObject *obj) { - ProcessMemData *data; GstPipeWireSrc *src; + GstPipeWirePoolData *data; gst_mini_object_ref (obj); - data = gst_mini_object_get_qdata (obj, - process_mem_data_quark); + data = gst_pipewire_pool_get_data (GST_BUFFER_CAST(obj)); + GST_BUFFER_FLAGS (obj) = data->flags; - src = data->src; + src = data->owner; GST_LOG_OBJECT (obj, "recycle buffer"); pw_thread_loop_lock (src->main_loop); - pw_stream_recycle_buffer (src->stream, data->id); + pw_stream_queue_buffer (src->stream, data->b); pw_thread_loop_unlock (src->main_loop); return FALSE; } static void -on_add_buffer (void *_data, guint id) +on_add_buffer (void *_data, struct pw_buffer *b) { GstPipeWireSrc *pwsrc = _data; - struct spa_buffer *b; - GstBuffer *buf; - uint32_t i; - ProcessMemData data; - struct pw_core *core = pwsrc->core; - struct pw_type *t = pw_core_get_type(core); + GstPipeWirePoolData *data; GST_LOG_OBJECT (pwsrc, "add buffer"); - - if (!(b = pw_stream_peek_buffer (pwsrc->stream, id))) { - g_warning ("failed to peek buffer"); - return; - } - - buf = gst_buffer_new (); - GST_MINI_OBJECT_CAST (buf)->dispose = buffer_recycle; - - data.src = gst_object_ref (pwsrc); - data.id = id; - data.buf = b; - data.header = spa_buffer_find_meta (b, t->meta.Header); - - for (i = 0; i < b->n_datas; i++) { - struct spa_data *d = &b->datas[i]; - GstMemory *gmem = NULL; - - if (d->type == t->data.MemFd) { - gmem = gst_fd_allocator_alloc (pwsrc->fd_allocator, dup (d->fd), - d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE); - gst_memory_resize (gmem, d->mapoffset, d->maxsize); - data.offset = d->mapoffset; - } - else if(d->type == t->data.DmaBuf) { - gmem = gst_dmabuf_allocator_alloc (pwsrc->dmabuf_allocator, dup (d->fd), - d->mapoffset + d->maxsize); - gst_memory_resize (gmem, d->mapoffset, d->maxsize); - data.offset = d->mapoffset; - } - else if (d->type == t->data.MemPtr) { - gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, 0, - d->maxsize, NULL, NULL); - data.offset = 0; - } - if (gmem) - gst_buffer_append_memory (buf, gmem); - } - data.flags = GST_BUFFER_FLAGS (buf); - gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (buf), - process_mem_data_quark, - g_slice_dup (ProcessMemData, &data), - process_mem_data_destroy); - - g_hash_table_insert (pwsrc->buf_ids, GINT_TO_POINTER (id), buf); + gst_pipewire_pool_wrap_buffer (pwsrc->pool, b); + data = b->user_data; + data->owner = pwsrc; + GST_MINI_OBJECT_CAST (data->buf)->dispose = buffer_recycle; } static void -on_remove_buffer (void *data, - guint id) -{ - GstPipeWireSrc *pwsrc = data; - GstBuffer *buf; - - GST_LOG_OBJECT (pwsrc, "remove buffer"); - buf = g_hash_table_lookup (pwsrc->buf_ids, GINT_TO_POINTER (id)); - if (buf) { - GList *walk; - - GST_MINI_OBJECT_CAST (buf)->dispose = NULL; - - walk = pwsrc->queue.head; - while (walk) { - GList *next = walk->next; - - if (walk->data == buf) { - gst_buffer_unref (buf); - g_queue_delete_link (&pwsrc->queue, walk); - } - walk = next; - } - g_hash_table_remove (pwsrc->buf_ids, GINT_TO_POINTER (id)); - } -} - -static void -on_new_buffer (void *_data, - guint id) +on_remove_buffer (void *_data, struct pw_buffer *b) { GstPipeWireSrc *pwsrc = _data; + GstPipeWirePoolData *data = b->user_data; + GstBuffer *buf = data->buf; + GList *walk; + + GST_LOG_OBJECT (pwsrc, "remove buffer"); + + GST_MINI_OBJECT_CAST (buf)->dispose = NULL; + + walk = pwsrc->queue.head; + while (walk) { + GList *next = walk->next; + + if (walk->data == buf) { + gst_buffer_unref (buf); + g_queue_delete_link (&pwsrc->queue, walk); + } + walk = next; + } +} + +static void +on_process (void *_data) +{ + GstPipeWireSrc *pwsrc = _data; + struct pw_buffer *b; GstBuffer *buf; - ProcessMemData *data; + GstPipeWirePoolData *data; struct spa_meta_header *h; guint i; - buf = g_hash_table_lookup (pwsrc->buf_ids, GINT_TO_POINTER (id)); - if (buf == NULL) { - g_warning ("unknown buffer %d", id); - return; - } + b = pw_stream_dequeue_buffer (pwsrc->stream); + if (b == NULL) + return; + + data = b->user_data; + buf = data->buf; + GST_LOG_OBJECT (pwsrc, "got new buffer %p", buf); - data = gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (buf), - process_mem_data_quark); h = data->header; if (h) { GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, h->pts, h->dts_offset); @@ -490,8 +418,8 @@ on_new_buffer (void *_data, } GST_BUFFER_OFFSET (buf) = h->seq; } - for (i = 0; i < data->buf->n_datas; i++) { - struct spa_data *d = &data->buf->datas[i]; + for (i = 0; i < b->buffer->n_datas; i++) { + struct spa_data *d = &b->buffer->datas[i]; GstMemory *mem = gst_buffer_peek_memory (buf, i); mem->offset = SPA_MIN(d->chunk->offset, d->maxsize); mem->size = SPA_MIN(d->chunk->size, d->maxsize - mem->offset); @@ -690,7 +618,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) pw_stream_connect (pwsrc->stream, PW_DIRECTION_INPUT, pwsrc->path, - PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_CLOCK_UPDATE, + PW_STREAM_FLAG_AUTOCONNECT, (const struct spa_pod **)possible->pdata, possible->len); g_ptr_array_free (possible, TRUE); @@ -754,8 +682,8 @@ connect_error: #define SPA_PROP_RANGE(min,max) 2,min,max static void -on_format_changed (void *data, - struct spa_pod *format) +on_format_changed (void *data, + const struct spa_pod *format) { GstPipeWireSrc *pwsrc = data; GstCaps *caps; @@ -775,7 +703,7 @@ on_format_changed (void *data, gst_caps_unref (caps); if (res) { - struct spa_pod *params[2]; + const struct spa_pod *params[2]; struct spa_pod_builder b = { NULL }; uint8_t buffer[512]; @@ -1041,7 +969,7 @@ static const struct pw_stream_events stream_events = { .format_changed = on_format_changed, .add_buffer = on_add_buffer, .remove_buffer = on_remove_buffer, - .new_buffer = on_new_buffer, + .process = on_process, }; static gboolean diff --git a/src/gst/gstpipewiresrc.h b/src/gst/gstpipewiresrc.h index 5769c02dc..c8f718b91 100644 --- a/src/gst/gstpipewiresrc.h +++ b/src/gst/gstpipewiresrc.h @@ -24,6 +24,7 @@ #include #include +#include G_BEGIN_DECLS @@ -76,11 +77,9 @@ struct _GstPipeWireSrc { struct pw_stream *stream; struct spa_hook stream_listener; - GstAllocator *fd_allocator; - GstAllocator *dmabuf_allocator; GstStructure *properties; - GHashTable *buf_ids; + GstPipeWirePool *pool; GQueue queue; GstClock *clock; }; diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index dfbef3df9..cb3d351f9 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -42,7 +42,7 @@ #define MAX_INPUTS 64 #define MAX_OUTPUTS 64 -struct mem_id { +struct mem { uint32_t id; int fd; uint32_t flags; @@ -51,15 +51,14 @@ struct mem_id { void *ptr; }; -struct buffer_id { +struct buffer { + struct pw_buffer buffer; struct spa_list link; - uint32_t id; - bool used; - struct spa_buffer *buf; + bool queued; void *ptr; struct pw_map_range map; uint32_t n_mem; - struct mem_id **mem; + struct mem **mem; }; struct stream { @@ -101,9 +100,8 @@ struct stream { bool client_reuse; - struct spa_list free; - bool in_need_buffer; - bool in_new_buffer; + struct spa_list queue; + bool in_process; int64_t last_ticks; int32_t last_rate; @@ -111,19 +109,19 @@ struct stream { }; /** \endcond */ -static struct mem_id *find_mem(struct pw_stream *stream, uint32_t id) +static struct mem *find_mem(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct mem_id *mid; + struct mem *m; - pw_array_for_each(mid, &impl->mem_ids) { - if (mid->id == id) - return mid; + pw_array_for_each(m, &impl->mem_ids) { + if (m->id == id) + return m; } return NULL; } -static void *mem_map(struct pw_stream *stream, struct mem_id *m, uint32_t offset, uint32_t size) +static void *mem_map(struct pw_stream *stream, struct mem *m, uint32_t offset, uint32_t size) { if (m->ptr == NULL) { pw_map_range_init(&m->map, offset, size, stream->remote->core->sc_pagesize); @@ -140,7 +138,7 @@ static void *mem_map(struct pw_stream *stream, struct mem_id *m, uint32_t offset return SPA_MEMBER(m->ptr, m->map.start, void); } -static void mem_unmap(struct stream *impl, struct mem_id *m) +static void mem_unmap(struct stream *impl, struct mem *m) { if (m->ptr != NULL) { if (munmap(m->ptr, m->map.size) < 0) @@ -149,15 +147,15 @@ static void mem_unmap(struct stream *impl, struct mem_id *m) } } -static void clear_memid(struct stream *impl, struct mem_id *mid) +static void clear_mem(struct stream *impl, struct mem *m) { - if (mid->fd != -1) { + if (m->fd != -1) { bool has_ref = false; - struct mem_id *m2; + struct mem *m2; int fd; - fd = mid->fd; - mid->fd = -1; + fd = m->fd; + m->fd = -1; pw_array_for_each(m2, &impl->mem_ids) { if (m2->fd == fd) { @@ -166,7 +164,7 @@ static void clear_memid(struct stream *impl, struct mem_id *mid) } } if (!has_ref) { - mem_unmap(impl, mid); + mem_unmap(impl, m); close(fd); } } @@ -175,33 +173,33 @@ static void clear_memid(struct stream *impl, struct mem_id *mid) static void clear_mems(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct mem_id *mid; + struct mem *m; - pw_array_for_each(mid, &impl->mem_ids) - clear_memid(impl, mid); + pw_array_for_each(m, &impl->mem_ids) + clear_mem(impl, m); impl->mem_ids.size = 0; } static void clear_buffers(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct buffer_id *bid; + struct buffer *b; pw_log_debug("stream %p: clear buffers", stream); - pw_array_for_each(bid, &impl->buffer_ids) { - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, remove_buffer, bid->id); - if (bid->ptr != NULL) - if (munmap(bid->ptr, bid->map.size) < 0) + pw_array_for_each(b, &impl->buffer_ids) { + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, remove_buffer, &b->buffer); + if (b->ptr != NULL) + if (munmap(b->ptr, b->map.size) < 0) pw_log_warn("failed to unmap buffer: %m"); - bid->ptr = NULL; - free(bid->buf); - bid->buf = NULL; - bid->used = false; + b->ptr = NULL; + free(b->buffer.buffer); + b->buffer.buffer = NULL; + b->queued = false; } impl->buffer_ids.size = 0; impl->in_order = true; - spa_list_init(&impl->free); + spa_list_init(&impl->queue); } static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state state, char *error) @@ -282,11 +280,11 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, this->state = PW_STREAM_STATE_UNCONNECTED; pw_array_init(&impl->mem_ids, 64); - pw_array_ensure_size(&impl->mem_ids, sizeof(struct mem_id) * 64); + pw_array_ensure_size(&impl->mem_ids, sizeof(struct mem) * 64); pw_array_init(&impl->buffer_ids, 32); - pw_array_ensure_size(&impl->buffer_ids, sizeof(struct buffer_id) * 64); + pw_array_ensure_size(&impl->buffer_ids, sizeof(struct buffer) * 64); impl->pending_seq = SPA_ID_INVALID; - spa_list_init(&impl->free); + spa_list_init(&impl->queue); spa_list_append(&remote->stream_list, &this->link); @@ -374,7 +372,7 @@ set_init_params(struct pw_stream *stream, } } -static void set_params(struct pw_stream *stream, int n_params, struct spa_pod **params) +static void set_params(struct pw_stream *stream, int n_params, const struct spa_pod **params) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); int i; @@ -549,18 +547,18 @@ static void on_timeout(void *data, uint64_t expirations) add_request_clock_update(stream); } -static struct buffer_id *find_buffer(struct pw_stream *stream, uint32_t id) +static struct buffer *find_buffer(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - if (impl->in_order && pw_array_check_index(&impl->buffer_ids, id, struct buffer_id)) { - return pw_array_get_unchecked(&impl->buffer_ids, id, struct buffer_id); + if (impl->in_order && pw_array_check_index(&impl->buffer_ids, id, struct buffer)) { + return pw_array_get_unchecked(&impl->buffer_ids, id, struct buffer); } else { - struct buffer_id *bid; + struct buffer *b; - pw_array_for_each(bid, &impl->buffer_ids) { - if (bid->id == id) - return bid; + pw_array_for_each(b, &impl->buffer_ids) { + if (b->buffer.buffer->id == id) + return b; } } return NULL; @@ -569,15 +567,12 @@ static struct buffer_id *find_buffer(struct pw_stream *stream, uint32_t id) static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct buffer_id *bid; + struct buffer *b; - if ((bid = find_buffer(stream, id)) && bid->used) { + if ((b = find_buffer(stream, id)) && !b->queued) { pw_log_trace("stream %p: reuse buffer %u", stream, id); - bid->used = false; - spa_list_append(&impl->free, &bid->link); - impl->in_new_buffer = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, new_buffer, id); - impl->in_new_buffer = false; + spa_list_append(&impl->queue, &b->link); + b->queued = true; } } @@ -592,7 +587,7 @@ static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_nod for (i = 0; i < impl->trans->area->n_input_ports; i++) { struct spa_io_buffers *input = &impl->trans->inputs[i]; - struct buffer_id *bid; + struct buffer *b; uint32_t buffer_id; buffer_id = input->buffer_id; @@ -600,20 +595,20 @@ static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_nod pw_log_trace("stream %p: process input %d %d", stream, input->status, buffer_id); - if ((bid = find_buffer(stream, buffer_id)) == NULL) + if ((b = find_buffer(stream, buffer_id)) == NULL) continue; if (impl->client_reuse) input->buffer_id = SPA_ID_INVALID; if (input->status == SPA_STATUS_HAVE_BUFFER) { - bid->used = true; - impl->in_new_buffer = true; + spa_list_append(&impl->queue, &b->link); + b->queued = true; + impl->in_process = true; spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - new_buffer, buffer_id); - impl->in_new_buffer = false; + process); + impl->in_process = false; } - input->status = SPA_STATUS_NEED_BUFFER; } send_need_input(stream); @@ -633,9 +628,9 @@ static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_nod output->buffer_id = SPA_ID_INVALID; } pw_log_trace("stream %p: process output", stream); - impl->in_need_buffer = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, need_buffer); - impl->in_need_buffer = false; + impl->in_process = true; + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, process); + impl->in_process = false; break; } case PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER: @@ -695,12 +690,11 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, stream); - if (impl->flags & PW_STREAM_FLAG_CLOCK_UPDATE) { - impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); - interval.tv_sec = 0; - interval.tv_nsec = 100000000; - pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); - } + impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); + interval.tv_sec = 0; + interval.tv_nsec = 100000000; + pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); + return; } @@ -751,10 +745,10 @@ static void client_node_command(void *data, uint32_t seq, const struct spa_comma send_need_input(stream); } else { - impl->in_need_buffer = true; + impl->in_process = true; spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - need_buffer); - impl->in_need_buffer = false; + process); + impl->in_process = false; } stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL); } @@ -839,15 +833,15 @@ client_node_add_mem(void *data, { struct stream *impl = data; struct pw_stream *stream = &impl->this; - struct mem_id *m; + struct mem *m; m = find_mem(stream, mem_id); if (m) { pw_log_debug("update mem %u, fd %d, flags %d", mem_id, memfd, flags); - clear_memid(impl, m); + clear_mem(impl, m); } else { - m = pw_array_add(&impl->mem_ids, sizeof(struct mem_id)); + m = pw_array_add(&impl->mem_ids, sizeof(struct mem)); pw_log_debug("add mem %u, fd %d, flags %d", mem_id, memfd, flags); } @@ -868,7 +862,7 @@ client_node_port_use_buffers(void *data, struct pw_stream *stream = &impl->this; struct pw_core *core = stream->remote->core; struct pw_type *t = &core->type; - struct buffer_id *bid; + struct buffer *bid; uint32_t i, j, len; struct spa_buffer *b; int prot; @@ -881,29 +875,29 @@ client_node_port_use_buffers(void *data, for (i = 0; i < n_buffers; i++) { off_t offset; - struct mem_id *mid = find_mem(stream, buffers[i].mem_id); - if (mid == NULL) { + struct mem *m = find_mem(stream, buffers[i].mem_id); + if (m == NULL) { pw_log_warn("unknown memory id %u", buffers[i].mem_id); continue; } - len = pw_array_get_len(&impl->buffer_ids, struct buffer_id); - bid = pw_array_add(&impl->buffer_ids, sizeof(struct buffer_id)); + len = pw_array_get_len(&impl->buffer_ids, struct buffer); + bid = pw_array_add(&impl->buffer_ids, sizeof(struct buffer)); if (impl->direction == SPA_DIRECTION_OUTPUT) { - bid->used = false; - spa_list_append(&impl->free, &bid->link); + bid->queued = true; + spa_list_append(&impl->queue, &bid->link); } else { - bid->used = true; + bid->queued = false; } b = buffers[i].buffer; pw_map_range_init(&bid->map, buffers[i].offset, buffers[i].size, core->sc_pagesize); - bid->ptr = mmap(NULL, bid->map.size, prot, MAP_SHARED, mid->fd, bid->map.offset); + bid->ptr = mmap(NULL, bid->map.size, prot, MAP_SHARED, m->fd, bid->map.offset); if (bid->ptr == MAP_FAILED) { bid->ptr = NULL; - pw_log_warn("Failed to mmap memory %d %p: %s", bid->map.size, mid, + pw_log_warn("Failed to mmap memory %d %p: %s", bid->map.size, m, strerror(errno)); continue; } @@ -912,35 +906,34 @@ client_node_port_use_buffers(void *data, size_t size; size = sizeof(struct spa_buffer); - size += sizeof(struct mem_id *); + size += sizeof(struct mem *); for (j = 0; j < buffers[i].buffer->n_metas; j++) size += sizeof(struct spa_meta); for (j = 0; j < buffers[i].buffer->n_datas; j++) { size += sizeof(struct spa_data); - size += sizeof(struct mem_id *); + size += sizeof(struct mem *); } - b = bid->buf = malloc(size); + b = bid->buffer.buffer = malloc(size); memcpy(b, buffers[i].buffer, sizeof(struct spa_buffer)); b->metas = SPA_MEMBER(b, sizeof(struct spa_buffer), struct spa_meta); b->datas = SPA_MEMBER(b->metas, sizeof(struct spa_meta) * b->n_metas, struct spa_data); bid->mem = SPA_MEMBER(b->datas, sizeof(struct spa_data) * b->n_datas, - struct mem_id*); + struct mem*); bid->n_mem = 0; - mid->ref++; - bid->mem[bid->n_mem++] = mid; + m->ref++; + bid->mem[bid->n_mem++] = m; } - bid->id = b->id; - if (bid->id != len) { - pw_log_warn("unexpected id %u found, expected %u", bid->id, len); + if (b->id != len) { + pw_log_warn("unexpected id %u found, expected %u", b->id, len); impl->in_order = false; } - pw_log_debug("add buffer %d %d %u %u", mid->id, - bid->id, bid->map.offset, bid->map.size); + pw_log_debug("add buffer %d %d %u %u", m->id, + b->id, bid->map.offset, bid->map.size); offset = bid->map.start; for (j = 0; j < b->n_metas; j++) { @@ -959,22 +952,23 @@ client_node_port_use_buffers(void *data, struct spa_chunk); if (d->type == t->data.MemFd || d->type == t->data.DmaBuf) { - struct mem_id *bmid = find_mem(stream, SPA_PTR_TO_UINT32(d->data)); + struct mem *bm = find_mem(stream, SPA_PTR_TO_UINT32(d->data)); d->data = NULL; - d->fd = bmid->fd; - bmid->ref++; - bid->mem[bid->n_mem++] = bmid; - pw_log_debug(" data %d %u -> fd %d", j, bmid->id, bmid->fd); + d->fd = bm->fd; + bm->ref++; + bid->mem[bid->n_mem++] = bm; + pw_log_debug(" data %d %u -> fd %d", j, bm->id, bm->fd); } else if (d->type == t->data.MemPtr) { d->data = SPA_MEMBER(bid->ptr, bid->map.start + SPA_PTR_TO_INT(d->data), void); d->fd = -1; - pw_log_debug(" data %d %u -> mem %p", j, bid->id, d->data); + pw_log_debug(" data %d %u -> mem %p", j, b->id, d->data); } else { pw_log_warn("unknown buffer data type %d", d->type); } } - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, add_buffer, bid->id); + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, + add_buffer, &bid->buffer); } add_async_complete(stream, seq, 0); @@ -1029,7 +1023,7 @@ static void client_node_port_set_io(void *data, struct pw_stream *stream = &impl->this; struct pw_core *core = stream->remote->core; struct pw_type *t = &core->type; - struct mem_id *m; + struct mem *m; void *ptr; int res; @@ -1135,6 +1129,12 @@ pw_stream_connect(struct pw_stream *stream, return 0; } +struct pw_remote * +pw_stream_get_remote(struct pw_stream *stream) +{ + return stream->remote; +} + uint32_t pw_stream_get_node_id(struct pw_stream *stream) { @@ -1144,7 +1144,7 @@ pw_stream_get_node_id(struct pw_stream *stream) void pw_stream_finish_format(struct pw_stream *stream, int res, - struct spa_pod **params, + const struct spa_pod **params, uint32_t n_params) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1203,81 +1203,78 @@ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) elapsed = (time->now - impl->last_monotonic) / 1000; time->ticks = impl->last_ticks + (elapsed * impl->last_rate) / SPA_USEC_PER_SEC; - time->rate = impl->last_rate; + time->rate.num = 1; + time->rate.denom = impl->last_rate; return 0; } -uint32_t pw_stream_get_empty_buffer(struct pw_stream *stream) +int pw_stream_set_control(struct pw_stream *stream, const char *name, float value) { - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct buffer_id *bid; - - if (spa_list_is_empty(&impl->free)) - return SPA_ID_INVALID; - - bid = spa_list_first(&impl->free, struct buffer_id, link); - - return bid->id; + return -ENOTSUP; } -int pw_stream_recycle_buffer(struct pw_stream *stream, uint32_t id) +int pw_stream_get_control(struct pw_stream *stream, const char *name, float *value) +{ + return -ENOTSUP; +} + +struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct buffer_id *bid; + struct buffer *b; - if ((bid = find_buffer(stream, id)) == NULL || !bid->used) + if (spa_list_is_empty(&impl->queue)) + return NULL; + + b = spa_list_first(&impl->queue, struct buffer, link); + + b->queued = false; + spa_list_remove(&b->link); + + return &b->buffer; +} + +int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer) +{ + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct buffer *b; + uint32_t id; + + if ((b = find_buffer(stream, buffer->buffer->id)) == NULL) return -EINVAL; - bid->used = false; - spa_list_append(&impl->free, &bid->link); + if (b->queued) + return -EINVAL; - if (impl->in_new_buffer) { - int i; + id = buffer->buffer->id; - for (i = 0; i < impl->trans->area->n_input_ports; i++) { - struct spa_io_buffers *input = &impl->trans->inputs[i]; - input->buffer_id = id; + if (impl->direction == SPA_DIRECTION_OUTPUT) { + if (impl->trans->outputs[0].buffer_id != SPA_ID_INVALID) { + pw_log_debug("can't send %u, pending buffer %u", id, + impl->trans->outputs[0].buffer_id); + return -EIO; } - } else { - send_reuse_buffer(stream, id); - } - - return 0; -} - -struct spa_buffer *pw_stream_peek_buffer(struct pw_stream *stream, uint32_t id) -{ - struct buffer_id *bid; - - if ((bid = find_buffer(stream, id))) - return bid->buf; - - return NULL; -} - -int pw_stream_send_buffer(struct pw_stream *stream, uint32_t id) -{ - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct buffer_id *bid; - - if (impl->trans->outputs[0].buffer_id != SPA_ID_INVALID) { - pw_log_debug("can't send %u, pending buffer %u", id, - impl->trans->outputs[0].buffer_id); - return -EIO; - } - - if ((bid = find_buffer(stream, id)) && !bid->used) { - bid->used = true; - spa_list_remove(&bid->link); impl->trans->outputs[0].buffer_id = id; impl->trans->outputs[0].status = SPA_STATUS_HAVE_BUFFER; pw_log_trace("stream %p: send buffer %d", stream, id); - if (!impl->in_need_buffer) + if (!impl->in_process) send_have_output(stream); - } else { - pw_log_debug("stream %p: output %u was used", stream, id); } + else { + b->queued = true; + spa_list_append(&impl->queue, &b->link); + if (impl->in_process) { + int i; + for (i = 0; i < impl->trans->area->n_input_ports; i++) { + struct spa_io_buffers *input = &impl->trans->inputs[i]; + input->buffer_id = id; + } + } + else { + send_reuse_buffer(stream, id); + } + } return 0; } diff --git a/src/pipewire/stream.h b/src/pipewire/stream.h index 5d99dab60..4d9ccc60d 100644 --- a/src/pipewire/stream.h +++ b/src/pipewire/stream.h @@ -59,18 +59,6 @@ extern "C" { * The stream is initially unconnected. To connect the stream, use * \ref pw_stream_connect(). Pass the desired direction as an argument. * - * \subsection ssec_stream_mode Stream modes - * - * The stream mode specifies how the data will be exchanged with PipeWire. - * The following stream modes are available - * - * \li \ref PW_STREAM_MODE_BUFFER: data is exchanged with fixed size - * buffers. This is ideal for video frames or equal sized audio - * frames. - * \li \ref PW_STREAM_MODE_RINGBUFFER: data is exhanged with a fixed - * size ringbuffer. This is ideal for variable sized audio packets - * or compressed media. - * * \subsection ssec_stream_target Stream target * * To make the newly connected stream automatically connect to an existing @@ -107,7 +95,8 @@ extern "C" { * between client and server. * * With the add_buffer event, a stream will be notified of a new buffer - * that can be used for data transport. + * that can be used for data transport. You can attach user_data to these + * buffers. * * Afer the buffers are negotiated, the stream will transition to the * \ref PW_STREAM_STATE_PAUSED state. @@ -124,28 +113,23 @@ extern "C" { * * \subsection ssec_consume Consume data * - * The new_buffer event is emited for each new buffer can can be + * The process event is emited for each new buffer that can can be * consumed. * - * \ref pw_stream_peek_buffer() should be used to get the data and metadata - * of the buffer. + * \ref pw_stream_dequeue_buffer() should be used to get the data and + * metadata of the buffer. * - * When the buffer is no longer in use, call \ref pw_stream_recycle_buffer() + * When the buffer is no longer in use, call \ref pw_stream_queue_buffer() * to let PipeWire reuse the buffer. * * \subsection ssec_produce Produce data * - * The need_buffer event is emited when PipeWire needs a new buffer for this - * stream. + * \ref pw_stream_dequeue_buffer() gives an empty buffer that can be filled. * - * \ref pw_stream_get_empty_buffer() gives the id of an empty buffer. - * Use \ref pw_stream_peek_buffer() to get the data and metadata that should - * be filled. + * Filled buffers should be queued with \ref pw_stream_queue_buffer(). * - * To send the filled buffer, use \ref pw_stream_send_buffer(). - * - * The new_buffer event is emited when PipeWire no longer uses the buffer - * and it can be safely reused. + * The process event is emited when PipeWire has emptied a buffer that + * can now be refilled. * * \section sec_stream_disconnect Disconnect * @@ -179,6 +163,11 @@ enum pw_stream_state { PW_STREAM_STATE_STREAMING = 5 /**< streaming */ }; +struct pw_buffer { + struct spa_buffer *buffer; /* the spa buffer */ + void *user_data; /* user data attached to the buffer */ +}; + /** Events for a stream */ struct pw_stream_events { #define PW_VERSION_STREAM_EVENTS 0 @@ -191,17 +180,18 @@ struct pw_stream_events { /** when the format changed. The listener should call * pw_stream_finish_format() from within this callback or later to complete * the format negotiation and start the buffer negotiation. */ - void (*format_changed) (void *data, struct spa_pod *format); + void (*format_changed) (void *data, const struct spa_pod *format); /** when a new buffer was created for this stream */ - void (*add_buffer) (void *data, uint32_t id); + void (*add_buffer) (void *data, struct pw_buffer *buffer); /** when a buffer was destroyed for this stream */ - void (*remove_buffer) (void *data, uint32_t id); - /** when a buffer can be reused (for playback streams) or - * is filled (for capture streams */ - void (*new_buffer) (void *data, uint32_t id); - /** when a buffer is needed (for playback streams) */ - void (*need_buffer) (void *data); + void (*remove_buffer) (void *data, struct pw_buffer *buffer); + + /** when a buffer can be queued (for playback streams) or + * dequeued (for capture streams). This is normally called from the + * mainloop but can also be called directly from the realtime data + * thread if the user is prepared to deal with this. */ + void (*process) (void *data); }; /** Convert a stream state to a readable string \memberof pw_stream */ @@ -212,16 +202,14 @@ enum pw_stream_flags { PW_STREAM_FLAG_NONE = 0, /**< no flags */ PW_STREAM_FLAG_AUTOCONNECT = (1 << 0), /**< try to automatically connect * this stream */ - PW_STREAM_FLAG_CLOCK_UPDATE = (1 << 1), /**< request periodic clock updates for - * this stream */ - PW_STREAM_FLAG_INACTIVE = (1 << 2), /**< start the stream inactive */ -}; - -/** A time structure \memberof pw_stream */ -struct pw_time { - int64_t now; /**< the monotonic time */ - int64_t ticks; /**< the ticks at \a now */ - int32_t rate; /**< the rate of \a ticks */ + PW_STREAM_FLAG_INACTIVE = (1 << 1), /**< start the stream inactive */ + PW_STREAM_FLAG_MAP_BUFFERS = (1 << 2), /**< mmap the buffers */ + PW_STREAM_FLAG_DRIVER = (1 << 3), /**< be a driver */ + PW_STREAM_FLAG_RT_PROCESS = (1 << 4), /**< call process from the realtime + * thread */ + PW_STREAM_FLAG_NO_CONVERT = (1 << 5), /**< don't convert format */ + PW_STREAM_FLAG_EXCLUSIVE = (1 << 6), /**< require exclusive access to the + * device */ }; /** Create a new unconneced \ref pw_stream \memberof pw_stream @@ -231,6 +219,13 @@ pw_stream_new(struct pw_remote *remote, /**< a \ref pw_remote */ const char *name, /**< a stream name */ struct pw_properties *props /**< stream properties, ownership is taken */); +struct pw_stream * +pw_stream_new_simple(struct pw_loop *loop, /**< a \ref pw_loop to use */ + const char *name, /**< a stream name */ + struct pw_properties *props,/**< stream properties, ownership is taken */ + const struct pw_stream_events *events, /**< stream events */ + void *data /**< data passed to events */); + /** Destroy a stream \memberof pw_stream */ void pw_stream_destroy(struct pw_stream *stream); @@ -243,6 +238,8 @@ enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char ** const char *pw_stream_get_name(struct pw_stream *stream); +struct pw_remote *pw_stream_get_remote(struct pw_stream *stream); + /** Indicates that the stream is live, boolean default false */ #define PW_STREAM_PROP_IS_LIVE "pipewire.latency.is-live" /** The minimum latency of the stream, int, default 0 */ @@ -255,9 +252,8 @@ const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream); /** Connect a stream for input or output on \a port_path. \memberof pw_stream * \return 0 on success < 0 on error. * - * When \a mode is \ref PW_STREAM_MODE_BUFFER, you should connect to the new-buffer - * event and use pw_stream_peek_buffer() to get the latest metadata and - * data. */ + * You should connect to the process event and use pw_stream_dequeue_buffer() + * to get the latest metadata and data. */ int pw_stream_connect(struct pw_stream *stream, /**< a \ref pw_stream */ enum pw_direction direction, /**< the stream direction */ @@ -286,40 +282,45 @@ int pw_stream_disconnect(struct pw_stream *stream); void pw_stream_finish_format(struct pw_stream *stream, /**< a \ref pw_stream */ int res, /**< a result code */ - struct spa_pod **params, /**< an array of params. The params should + const struct spa_pod **params, /**< an array of params. The params should * ideally contain parameters for doing * buffer allocation. */ uint32_t n_params /**< number of elements in \a params */); + +/** Audio controls */ +#define PW_STREAM_CONTROL_VOLUME "volume" + +/** Video controls */ +#define PW_STREAM_CONTROL_CONTRAST "contrast" +#define PW_STREAM_CONTROL_BRIGHTNESS "brightness" +#define PW_STREAM_CONTROL_HUE "hue" +#define PW_STREAM_CONTROL_SATURATION "saturation" + +/** Set a control value */ +int pw_stream_set_control(struct pw_stream *stream, const char *name, float value); +/** Get a control value */ +int pw_stream_get_control(struct pw_stream *stream, const char *name, float *value); + /** Activate or deactivate the stream \memberof pw_stream */ int pw_stream_set_active(struct pw_stream *stream, bool active); +/** A time structure \memberof pw_stream */ +struct pw_time { + int64_t now; /**< the monotonic time */ + int64_t ticks; /**< the ticks at \a now */ + struct spa_fraction rate; /**< the rate of \a ticks */ +}; /** Query the time on the stream \memberof pw_stream */ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time); -/** Get the id of an empty buffer that can be filled \memberof pw_stream - * \return the id of an empty buffer or \ref SPA_ID_INVALID when no buffer is - * available. */ -uint32_t pw_stream_get_empty_buffer(struct pw_stream *stream); +/** Get a buffer that can be filled for playback streams or consumed + * for capture streams. */ +struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream); -/** Recycle the buffer with \a id \memberof pw_stream - * \return 0 on success, < 0 when \a id is invalid or not a used buffer - * Let the PipeWire server know that it can reuse the buffer with \a id. */ -int pw_stream_recycle_buffer(struct pw_stream *stream, uint32_t id); +/** Submit a buffer for playback or recycle a buffer for capture. */ +int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer); -/** Get the buffer with \a id from \a stream \memberof pw_stream - * \return a \ref spa_buffer or NULL when there is no buffer - * - * This function should be called from the new-buffer event. */ -struct spa_buffer * -pw_stream_peek_buffer(struct pw_stream *stream, uint32_t id); - -/** Send a buffer with \a id to \a stream \memberof pw_stream - * \return 0 when \a id was handled, < 0 on error - * - * For provider or playback streams, this function should be called whenever - * there is a new buffer available. */ -int pw_stream_send_buffer(struct pw_stream *stream, uint32_t id); #ifdef __cplusplus } From bcddac6e2b08338170fc51c26676e95e2c29e19e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 11 Jul 2018 17:51:57 +0200 Subject: [PATCH 010/155] stream: schedule process from main thread when asked Use 2 lockfree queues so that we can queue and dequeue from different threads. Call the process function from the main thread when requested Rework the data push and pull logic to go through the queues Update the examples for this new feature, video-play does not need to schedule the process in the main thread anymore and block for it to complete, this avoid a deadlock between the data and mainloop when shutting down. --- src/examples/video-play.c | 58 +++--- src/examples/video-src.c | 3 +- src/pipewire/stream.c | 365 +++++++++++++++++++++++--------------- 3 files changed, 253 insertions(+), 173 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 17c7f1433..1327373b2 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -87,12 +87,13 @@ static void handle_events(struct data *data) } } -static int -do_render(struct spa_loop *loop, bool async, uint32_t seq, - const void *_data, size_t size, void *user_data) +static void +on_stream_process(void *_data) { - struct data *data = user_data; - struct spa_buffer *buf = ((struct spa_buffer **) _data)[0]; + struct data *data = _data; + struct pw_stream *stream = data->stream; + struct pw_buffer *buf; + struct spa_buffer *b; uint8_t *map; void *sdata, *ddata; int sstride, dstride, ostride; @@ -101,22 +102,28 @@ do_render(struct spa_loop *loop, bool async, uint32_t seq, handle_events(data); - if (buf->datas[0].type == data->t->data.MemFd || - buf->datas[0].type == data->t->data.DmaBuf) { - map = mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ, - MAP_PRIVATE, buf->datas[0].fd, 0); - sdata = SPA_MEMBER(map, buf->datas[0].mapoffset, uint8_t); - } else if (buf->datas[0].type == data->t->data.MemPtr) { + buf = pw_stream_dequeue_buffer(stream); + if (buf == NULL) + return; + + b = buf->buffer; + + if (b->datas[0].type == data->t->data.MemFd || + b->datas[0].type == data->t->data.DmaBuf) { + map = mmap(NULL, b->datas[0].maxsize + b->datas[0].mapoffset, PROT_READ, + MAP_PRIVATE, b->datas[0].fd, 0); + sdata = SPA_MEMBER(map, b->datas[0].mapoffset, uint8_t); + } else if (b->datas[0].type == data->t->data.MemPtr) { map = NULL; - sdata = buf->datas[0].data; + sdata = b->datas[0].data; } else - return -EINVAL; + return; if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); - return -EIO; + return; } - sstride = buf->datas[0].chunk->stride; + sstride = b->datas[0].chunk->stride; ostride = SPA_MIN(sstride, dstride); src = sdata; @@ -133,23 +140,7 @@ do_render(struct spa_loop *loop, bool async, uint32_t seq, SDL_RenderPresent(data->renderer); if (map) - munmap(map, buf->datas[0].maxsize + buf->datas[0].mapoffset); - - return 0; -} - -static void -on_stream_process(void *_data) -{ - struct data *data = _data; - struct pw_stream *stream = data->stream; - struct pw_buffer *buf; - - buf = pw_stream_dequeue_buffer(stream); - - pw_loop_invoke(pw_main_loop_get_loop(data->loop), do_render, - SPA_ID_INVALID, &buf->buffer, sizeof(struct spa_buffer *), - true, data); + munmap(map, b->datas[0].maxsize + b->datas[0].mapoffset); pw_stream_queue_buffer(stream, buf); } @@ -366,7 +357,8 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo pw_stream_connect(data->stream, PW_DIRECTION_INPUT, data->path, - PW_STREAM_FLAG_AUTOCONNECT | PW_STREAM_FLAG_INACTIVE, + PW_STREAM_FLAG_AUTOCONNECT | + PW_STREAM_FLAG_INACTIVE, params, 1); break; } diff --git a/src/examples/video-src.c b/src/examples/video-src.c index 7a4415cec..a4d199f25 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -235,7 +235,8 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo pw_stream_connect(data->stream, PW_DIRECTION_OUTPUT, - NULL, PW_STREAM_FLAG_NONE, + NULL, + PW_STREAM_FLAG_DRIVER, params, 1); break; } diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index cb3d351f9..ecb5db457 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -24,6 +24,7 @@ #include #include +#include "spa/utils/ringbuffer.h" #include "spa/lib/debug.h" #include "pipewire/pipewire.h" @@ -37,10 +38,11 @@ /** \cond */ -#define MAX_BUFFER_SIZE 4096 -#define MAX_FDS 32 -#define MAX_INPUTS 64 -#define MAX_OUTPUTS 64 +#define MAX_BUFFERS 64 +#define MASK_BUFFERS (MAX_BUFFERS-1) +#define MIN_QUEUED 1 + +#define MAX_PORTS 1 struct mem { uint32_t id; @@ -53,7 +55,7 @@ struct mem { struct buffer { struct pw_buffer buffer; - struct spa_list link; + uint32_t id; bool queued; void *ptr; struct pw_map_range map; @@ -61,6 +63,11 @@ struct buffer { struct mem **mem; }; +struct queue { + uint32_t ids[MAX_BUFFERS]; + struct spa_ringbuffer ring; +}; + struct stream { struct pw_stream this; @@ -94,15 +101,18 @@ struct stream { struct spa_source *timeout_source; struct pw_array mem_ids; - struct pw_array buffer_ids; - bool in_order; + struct spa_io_buffers *io; bool client_reuse; - - struct spa_list queue; + struct queue dequeue; + struct queue queue; bool in_process; + struct buffer buffers[MAX_BUFFERS]; + int n_buffers; + + int64_t last_ticks; int32_t last_rate; int64_t last_monotonic; @@ -184,11 +194,16 @@ static void clear_buffers(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; + int i; pw_log_debug("stream %p: clear buffers", stream); - pw_array_for_each(b, &impl->buffer_ids) { - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, remove_buffer, &b->buffer); + for (i = 0; i < impl->n_buffers; i++) { + b = &impl->buffers[i]; + + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, + remove_buffer, &b->buffer); + if (b->ptr != NULL) if (munmap(b->ptr, b->map.size) < 0) pw_log_warn("failed to unmap buffer: %m"); @@ -197,9 +212,48 @@ static void clear_buffers(struct pw_stream *stream) b->buffer.buffer = NULL; b->queued = false; } - impl->buffer_ids.size = 0; - impl->in_order = true; - spa_list_init(&impl->queue); + impl->n_buffers = 0; + spa_ringbuffer_init(&impl->queue.ring); + spa_ringbuffer_init(&impl->dequeue.ring); + +} + +static inline int push_queue(struct stream *stream, struct queue *queue, struct buffer *buffer) +{ + uint32_t index; + int32_t filled; + + if (buffer->queued) + return -EINVAL; + + filled = spa_ringbuffer_get_write_index(&queue->ring, &index); + buffer->queued = true; + queue->ids[index & MASK_BUFFERS] = buffer->id; + spa_ringbuffer_write_update(&queue->ring, index + 1); + + pw_log_trace("stream %p: queued buffer %d %d", stream, buffer->id, filled); + + return filled; +} + +static inline struct buffer *pop_queue(struct stream *stream, struct queue *queue) +{ + int32_t avail; + uint32_t index, id; + struct buffer *buffer; + + if ((avail = spa_ringbuffer_get_read_index(&queue->ring, &index)) < MIN_QUEUED) + return NULL; + + id = queue->ids[index & MASK_BUFFERS]; + spa_ringbuffer_read_update(&queue->ring, index + 1); + + buffer = &stream->buffers[id]; + buffer->queued = false; + + pw_log_trace("stream %p: dequeued buffer %d %d", stream, id, avail); + + return buffer; } static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state state, char *error) @@ -222,6 +276,37 @@ static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state stat return res; } +static struct buffer *get_buffer(struct pw_stream *stream, uint32_t id) +{ + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + if (id < impl->n_buffers) + return &impl->buffers[id]; + return NULL; +} + +static int +do_call_process(struct spa_loop *loop, + bool async, uint32_t seq, const void *data, size_t size, void *user_data) +{ + struct stream *impl = user_data; + struct pw_stream *stream = &impl->this; + impl->in_process = true; + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, process); + impl->in_process = false; + return 0; +} + +static void call_process(struct stream *impl) +{ + if (SPA_FLAG_CHECK(impl->flags, PW_STREAM_FLAG_RT_PROCESS)) { + do_call_process(NULL, false, 1, NULL, 0, impl); + } + else { + pw_loop_invoke(impl->this.remote->core->main_loop, + do_call_process, 1, NULL, 0, false, impl); + } +} + const char *pw_stream_state_as_string(enum pw_stream_state state) { switch (state) { @@ -281,10 +366,11 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, pw_array_init(&impl->mem_ids, 64); pw_array_ensure_size(&impl->mem_ids, sizeof(struct mem) * 64); - pw_array_init(&impl->buffer_ids, 32); - pw_array_ensure_size(&impl->buffer_ids, sizeof(struct buffer) * 64); + impl->pending_seq = SPA_ID_INVALID; - spa_list_init(&impl->queue); + + spa_ringbuffer_init(&impl->queue.ring); + spa_ringbuffer_init(&impl->dequeue.ring); spa_list_append(&remote->stream_list, &this->link); @@ -416,7 +502,6 @@ void pw_stream_destroy(struct pw_stream *stream) free(stream->error); clear_buffers(stream); - pw_array_clear(&impl->buffer_ids); clear_mems(stream); pw_array_clear(&impl->mem_ids); @@ -480,6 +565,7 @@ static inline void send_need_input(struct pw_stream *stream) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); uint64_t cmd = 1; + pw_log_trace("send"); pw_client_node_transport_add_message(impl->trans, &PW_CLIENT_NODE_MESSAGE_INIT(PW_CLIENT_NODE_MESSAGE_NEED_INPUT)); write(impl->rtwritefd, &cmd, 8); @@ -490,6 +576,7 @@ static inline void send_have_output(struct pw_stream *stream) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); uint64_t cmd = 1; + pw_log_trace("send"); pw_client_node_transport_add_message(impl->trans, &PW_CLIENT_NODE_MESSAGE_INIT(PW_CLIENT_NODE_MESSAGE_HAVE_OUTPUT)); write(impl->rtwritefd, &cmd, 8); @@ -500,6 +587,7 @@ static inline void send_reuse_buffer(struct pw_stream *stream, uint32_t id) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); uint64_t cmd = 1; + pw_log_trace("send"); pw_client_node_transport_add_message(impl->trans, (struct pw_client_node_message*) &PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER_INIT(impl->port_id, id)); write(impl->rtwritefd, &cmd, 8); @@ -547,92 +635,114 @@ static void on_timeout(void *data, uint64_t expirations) add_request_clock_update(stream); } -static struct buffer *find_buffer(struct pw_stream *stream, uint32_t id) -{ - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - - if (impl->in_order && pw_array_check_index(&impl->buffer_ids, id, struct buffer)) { - return pw_array_get_unchecked(&impl->buffer_ids, id, struct buffer); - } else { - struct buffer *b; - - pw_array_for_each(b, &impl->buffer_ids) { - if (b->buffer.buffer->id == id) - return b; - } - } - return NULL; -} - static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; - if ((b = find_buffer(stream, id)) && !b->queued) { + if ((b = get_buffer(stream, id)) && !b->queued) { pw_log_trace("stream %p: reuse buffer %u", stream, id); - spa_list_append(&impl->queue, &b->link); - b->queued = true; + push_queue(impl, &impl->dequeue, b); } } +static int process_input(struct pw_stream *stream) +{ + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + int i; + + for (i = 0; i < impl->trans->area->n_input_ports; i++) { + struct spa_io_buffers *input = &impl->trans->inputs[i]; + struct buffer *b; + uint32_t buffer_id; + int status; + + buffer_id = input->buffer_id; + status = input->status; + + pw_log_trace("stream %p: process input %d %d", stream, status, + buffer_id); + + if (status != SPA_STATUS_HAVE_BUFFER) + goto done; + + if ((b = get_buffer(stream, buffer_id)) == NULL) + goto done; + + if (push_queue(impl, &impl->dequeue, b) >= 0) + call_process(impl); + + done: + /* pop buffer to recycle if we can */ + b = pop_queue(impl, &impl->queue); + input->buffer_id = b ? b->id : SPA_ID_INVALID; + input->status = SPA_STATUS_NEED_BUFFER; + + pw_log_trace("stream %p: reuse %d", stream, input->buffer_id); + } + return SPA_STATUS_NEED_BUFFER; +} + +static int process_output(struct pw_stream *stream) +{ + int i, res = 0; + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + + for (i = 0; i < impl->trans->area->n_output_ports; i++) { + struct spa_io_buffers *io = &impl->trans->outputs[i]; + struct buffer *b; + uint32_t index; + + again: + pw_log_trace("stream %p: process out %d %d", stream, + io->status, io->buffer_id); + + if (io->status != SPA_STATUS_HAVE_BUFFER) { + /* recycle old buffer */ + if ((b = get_buffer(stream, io->buffer_id)) != NULL) + push_queue(impl, &impl->dequeue, b); + + /* pop new buffer */ + if ((b = pop_queue(impl, &impl->queue)) != NULL) { + io->buffer_id = b->id; + io->status = SPA_STATUS_HAVE_BUFFER; + pw_log_trace("stream %p: pop %d %p", stream, b->id, io); + } else { + io->buffer_id = SPA_ID_INVALID; + io->status = SPA_STATUS_NEED_BUFFER; + pw_log_trace("stream %p: no more buffers %p", stream, io); + } + } + + if (!SPA_FLAG_CHECK(impl->flags, PW_STREAM_FLAG_DRIVER)) { + call_process(impl); + if (spa_ringbuffer_get_read_index(&impl->queue.ring, &index) >= MIN_QUEUED && + io->status == SPA_STATUS_NEED_BUFFER) + goto again; + } + res = io->status; + } + return res; +} + + static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_node_message *message) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + pw_log_trace("stream %p: %d", stream, PW_CLIENT_NODE_MESSAGE_TYPE(message)); + switch (PW_CLIENT_NODE_MESSAGE_TYPE(message)) { case PW_CLIENT_NODE_MESSAGE_PROCESS_INPUT: - { - int i; - - for (i = 0; i < impl->trans->area->n_input_ports; i++) { - struct spa_io_buffers *input = &impl->trans->inputs[i]; - struct buffer *b; - uint32_t buffer_id; - - buffer_id = input->buffer_id; - - pw_log_trace("stream %p: process input %d %d", stream, input->status, - buffer_id); - - if ((b = find_buffer(stream, buffer_id)) == NULL) - continue; - - if (impl->client_reuse) - input->buffer_id = SPA_ID_INVALID; - - if (input->status == SPA_STATUS_HAVE_BUFFER) { - spa_list_append(&impl->queue, &b->link); - b->queued = true; - impl->in_process = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - process); - impl->in_process = false; - } - input->status = SPA_STATUS_NEED_BUFFER; - } - send_need_input(stream); + if (process_input(stream) == SPA_STATUS_NEED_BUFFER) + send_need_input(stream); break; - } + case PW_CLIENT_NODE_MESSAGE_PROCESS_OUTPUT: - { - int i; - - for (i = 0; i < impl->trans->area->n_output_ports; i++) { - struct spa_io_buffers *output = &impl->trans->outputs[i]; - - if (output->buffer_id == SPA_ID_INVALID) - continue; - - reuse_buffer(stream, output->buffer_id); - output->buffer_id = SPA_ID_INVALID; - } - pw_log_trace("stream %p: process output", stream); - impl->in_process = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, process); - impl->in_process = false; + if (process_output(stream) == SPA_STATUS_HAVE_BUFFER) + send_have_output(stream); break; - } + case PW_CLIENT_NODE_MESSAGE_PORT_REUSE_BUFFER: { struct pw_client_node_message_port_reuse_buffer *p = @@ -643,6 +753,7 @@ static void handle_rtnode_message(struct pw_stream *stream, struct pw_client_nod if (impl->direction != SPA_DIRECTION_OUTPUT) return; + reuse_buffer(stream, p->body.buffer_id.value); break; } @@ -690,10 +801,12 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, stream); + /* impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); interval.tv_sec = 0; interval.tv_nsec = 100000000; pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); + */ return; } @@ -745,10 +858,7 @@ static void client_node_command(void *data, uint32_t seq, const struct spa_comma send_need_input(stream); } else { - impl->in_process = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - process); - impl->in_process = false; + call_process(impl); } stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL); } @@ -863,7 +973,7 @@ client_node_port_use_buffers(void *data, struct pw_core *core = stream->remote->core; struct pw_type *t = &core->type; struct buffer *bid; - uint32_t i, j, len; + uint32_t i, j; struct spa_buffer *b; int prot; @@ -881,18 +991,13 @@ client_node_port_use_buffers(void *data, continue; } - len = pw_array_get_len(&impl->buffer_ids, struct buffer); - bid = pw_array_add(&impl->buffer_ids, sizeof(struct buffer)); - if (impl->direction == SPA_DIRECTION_OUTPUT) { - bid->queued = true; - spa_list_append(&impl->queue, &bid->link); - } else { - bid->queued = false; - } - + bid = &impl->buffers[i]; + bid->id = i; + bid->queued = false; b = buffers[i].buffer; - pw_map_range_init(&bid->map, buffers[i].offset, buffers[i].size, core->sc_pagesize); + pw_map_range_init(&bid->map, buffers[i].offset, buffers[i].size, + core->sc_pagesize); bid->ptr = mmap(NULL, bid->map.size, prot, MAP_SHARED, m->fd, bid->map.offset); if (bid->ptr == MAP_FAILED) { @@ -928,10 +1033,6 @@ client_node_port_use_buffers(void *data, bid->mem[bid->n_mem++] = m; } - if (b->id != len) { - pw_log_warn("unexpected id %u found, expected %u", b->id, len); - impl->in_order = false; - } pw_log_debug("add buffer %d %d %u %u", m->id, b->id, bid->map.offset, bid->map.size); @@ -967,12 +1068,17 @@ client_node_port_use_buffers(void *data, pw_log_warn("unknown buffer data type %d", d->type); } } + if (impl->direction == SPA_DIRECTION_OUTPUT) + push_queue(impl, &impl->dequeue, bid); + spa_hook_list_call(&stream->listener_list, struct pw_stream_events, add_buffer, &bid->buffer); } add_async_complete(stream, seq, 0); + impl->n_buffers = n_buffers; + if (n_buffers) stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL); else { @@ -1224,13 +1330,11 @@ struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; - if (spa_list_is_empty(&impl->queue)) + if ((b = pop_queue(impl, &impl->dequeue)) == NULL) { + pw_log_trace("stream %p: no more buffers", stream); return NULL; - - b = spa_list_first(&impl->queue, struct buffer, link); - - b->queued = false; - spa_list_remove(&b->link); + } + pw_log_trace("stream %p: dequeue buffer %d", stream, b->id); return &b->buffer; } @@ -1239,42 +1343,25 @@ int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; - uint32_t id; + int res; - if ((b = find_buffer(stream, buffer->buffer->id)) == NULL) + if ((b = get_buffer(stream, buffer->buffer->id)) == NULL) return -EINVAL; - if (b->queued) - return -EINVAL; - - id = buffer->buffer->id; + pw_log_trace("stream %p: queue buffer %d", stream, b->id); + if ((res = push_queue(impl, &impl->queue, b)) < 0) + return res; if (impl->direction == SPA_DIRECTION_OUTPUT) { - if (impl->trans->outputs[0].buffer_id != SPA_ID_INVALID) { - pw_log_debug("can't send %u, pending buffer %u", id, - impl->trans->outputs[0].buffer_id); - return -EIO; - } - impl->trans->outputs[0].buffer_id = id; - impl->trans->outputs[0].status = SPA_STATUS_HAVE_BUFFER; - pw_log_trace("stream %p: send buffer %d", stream, id); - if (!impl->in_process) + if (res == 0 && + SPA_FLAG_CHECK(impl->flags, PW_STREAM_FLAG_DRIVER) && + process_output(stream) == SPA_STATUS_HAVE_BUFFER) send_have_output(stream); } else { - b->queued = true; - spa_list_append(&impl->queue, &b->link); - - if (impl->in_process) { - int i; - for (i = 0; i < impl->trans->area->n_input_ports; i++) { - struct spa_io_buffers *input = &impl->trans->inputs[i]; - input->buffer_id = id; - } - } - else { - send_reuse_buffer(stream, id); - } + if (impl->client_reuse) + if ((b = pop_queue(impl, &impl->queue))) + send_reuse_buffer(stream, b->id); } return 0; } From b9171b5e57aaa5fe048f915823bfffac0428ec55 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 09:46:30 +0200 Subject: [PATCH 011/155] node: add Media/Category/Role properties --- src/pipewire/node.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/pipewire/node.h b/src/pipewire/node.h index dfa585b57..462777f62 100644 --- a/src/pipewire/node.h +++ b/src/pipewire/node.h @@ -91,6 +91,15 @@ struct pw_node_events { void (*reuse_buffer) (void *data, uint32_t port_id, uint32_t buffer_id); }; +/** Media type of the node, Audio, Video, Midi */ +#define PW_NODE_PROP_MEDIA "pipewire.media" +/** Category: Playback, Capture, Duplex, Sink, Source */ +#define PW_NODE_PROP_CATEGORY "pipewire.category" +/** Role: Movie, Music, Camera, Screen, Communication, Game, Notification, DSP, + * Production, Accessibility, Test */ +#define PW_NODE_PROP_ROLE "pipewire.role" +/** exclusive access to device */ +#define PW_NODE_PROP_EXCLUSIVE "pipewire.exclusive" /** Automatically connect this node to a compatible node */ #define PW_NODE_PROP_AUTOCONNECT "pipewire.autoconnect" /** Try to connect the node to this node id */ From d6f40cefa638661e1271a61609646ac60cee09e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 10:02:42 +0200 Subject: [PATCH 012/155] examples: improve examples --- src/examples/export-sink.c | 13 +++++++++---- src/examples/export-source.c | 13 +++++++------ src/examples/video-play.c | 11 +++++++++-- src/examples/video-src.c | 9 ++++++++- 4 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index db482df2f..dca809637 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -36,6 +36,8 @@ #define M_PI_M2 ( M_PI + M_PI ) +#define MAX_BUFFERS 16 + struct type { uint32_t prop_param; uint32_t io_prop_param; @@ -105,7 +107,7 @@ struct data { struct spa_param *params[2]; - struct spa_buffer *buffers[32]; + struct spa_buffer *buffers[MAX_BUFFERS]; uint32_t n_buffers; }; @@ -392,8 +394,8 @@ static int impl_port_enum_params(struct spa_node *node, id, t->param_buffers.Buffers, ":", t->param_buffers.size, "i", d->stride * d->format.size.height, ":", t->param_buffers.stride, "i", d->stride, - ":", t->param_buffers.buffers, "iru", 32, - SPA_POD_PROP_MIN_MAX(2, 32), + ":", t->param_buffers.buffers, "iru", 2, + SPA_POD_PROP_MIN_MAX(2, MAX_BUFFERS), ":", t->param_buffers.align, "i", 16); } else if (id == t->param.idMeta) { @@ -548,7 +550,7 @@ static int impl_node_process_input(struct spa_node *node) if (d->io->status != SPA_STATUS_HAVE_BUFFER) return SPA_STATUS_NEED_BUFFER; - if (d->io->buffer_id > d->n_buffers) + if (d->io->buffer_id >= d->n_buffers) return SPA_STATUS_NEED_BUFFER; buf = d->buffers[d->io->buffer_id]; @@ -584,6 +586,9 @@ static void make_node(struct data *data) props = pw_properties_new(PW_NODE_PROP_AUTOCONNECT, "1", NULL); if (data->path) pw_properties_set(props, PW_NODE_PROP_TARGET_NODE, data->path); + pw_properties_set(props, PW_NODE_PROP_MEDIA, "Video"); + pw_properties_set(props, PW_NODE_PROP_CATEGORY, "Capture"); + pw_properties_set(props, PW_NODE_PROP_ROLE, "Camera"); data->node = pw_node_new(data->core, "SDL-sink", props, 0); data->impl_node = impl_node; diff --git a/src/examples/export-source.c b/src/examples/export-source.c index 5dc20bb75..e6e3a8547 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -33,6 +33,9 @@ #define M_PI_M2 ( M_PI + M_PI ) +#define MAX_BUFFERS 16 +#define BUFFER_SAMPLES 48 + struct type { uint32_t prop_volume; uint32_t io_prop_volume; @@ -95,11 +98,9 @@ struct data { struct spa_pod_double *ctrl_volume; - uint8_t buffer[1024]; - struct spa_audio_info_raw format; - struct buffer buffers[32]; + struct buffer buffers[MAX_BUFFERS]; int n_buffers; struct spa_list empty; @@ -235,7 +236,7 @@ static int port_get_format(struct spa_node *node, d->t->param.idFormat, d->t->spa_format, "I", d->type.media_type.audio, "I", d->type.media_subtype.raw, - ":", d->type.format_audio.format, "I", d->format.format, + ":", d->type.format_audio.format, "I", d->format.format, ":", d->type.format_audio.channels, "i", d->format.channels, ":", d->type.format_audio.rate, "i", d->format.rate); @@ -282,11 +283,11 @@ static int impl_port_enum_params(struct spa_node *node, param = spa_pod_builder_object(builder, id, t->param_buffers.Buffers, - ":", t->param_buffers.size, "iru", 256, + ":", t->param_buffers.size, "iru", BUFFER_SAMPLES * sizeof(float), SPA_POD_PROP_MIN_MAX(32, 4096), ":", t->param_buffers.stride, "i", 0, ":", t->param_buffers.buffers, "iru", 1, - SPA_POD_PROP_MIN_MAX(1, 32), + SPA_POD_PROP_MIN_MAX(1, MAX_BUFFERS), ":", t->param_buffers.align, "i", 16); } else if (id == t->param.idMeta) { diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 1327373b2..aef95caf4 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -306,8 +306,15 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); - data->stream = pw_stream_new(remote, "video-play", - pw_properties_new("pipewire.client.reuse", "1", NULL)); + data->stream = pw_stream_new(remote, + "video-play", + pw_properties_new( + "pipewire.client.reuse", "1", + PW_NODE_PROP_MEDIA, "Video", + PW_NODE_PROP_CATEGORY, "Capture", + PW_NODE_PROP_ROLE, "Camera", + NULL)); + SDL_GetRendererInfo(data->renderer, &info); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index a4d199f25..6217d3d37 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -216,7 +216,14 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); - data->stream = pw_stream_new(remote, "video-src", NULL); + data->stream = pw_stream_new(remote, + "video-src", + pw_properties_new( + "media.class", "Video/Source", + PW_NODE_PROP_MEDIA, "Video", + PW_NODE_PROP_CATEGORY, "Source", + PW_NODE_PROP_ROLE, "Screen", + NULL)); params[0] = spa_pod_builder_object(&b, data->t->param.idEnumFormat, data->t->spa_format, From a2d2d75a2574831d41d1f8fc54e2274efcf897bb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 11:05:31 +0200 Subject: [PATCH 013/155] remote: call disconnect to make sure we free all memory --- src/pipewire/remote.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 6d162817d..1c1ce1188 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -431,7 +431,7 @@ int pw_remote_steal_fd(struct pw_remote *remote) int fd; fd = pw_protocol_client_steal_fd(remote->conn); - pw_remote_update_state(remote, PW_REMOTE_STATE_UNCONNECTED, NULL); + pw_remote_disconnect(remote); return fd; } From c362b1ccc50b52dbe4359820293befc8cdc3f641 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 11:05:53 +0200 Subject: [PATCH 014/155] stream: implement MAP_BUFFERS video-play let the stream map our buffers --- src/examples/video-play.c | 22 +++------ src/pipewire/stream.c | 100 +++++++++++++++++++++++++++++--------- 2 files changed, 83 insertions(+), 39 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index aef95caf4..49b9cd0cd 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -94,7 +94,6 @@ on_stream_process(void *_data) struct pw_stream *stream = data->stream; struct pw_buffer *buf; struct spa_buffer *b; - uint8_t *map; void *sdata, *ddata; int sstride, dstride, ostride; uint32_t i; @@ -108,20 +107,12 @@ on_stream_process(void *_data) b = buf->buffer; - if (b->datas[0].type == data->t->data.MemFd || - b->datas[0].type == data->t->data.DmaBuf) { - map = mmap(NULL, b->datas[0].maxsize + b->datas[0].mapoffset, PROT_READ, - MAP_PRIVATE, b->datas[0].fd, 0); - sdata = SPA_MEMBER(map, b->datas[0].mapoffset, uint8_t); - } else if (b->datas[0].type == data->t->data.MemPtr) { - map = NULL; - sdata = b->datas[0].data; - } else - return; + if ((sdata = b->datas[0].data) == NULL) + goto done; if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); - return; + goto done; } sstride = b->datas[0].chunk->stride; ostride = SPA_MIN(sstride, dstride); @@ -139,9 +130,7 @@ on_stream_process(void *_data) SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); SDL_RenderPresent(data->renderer); - if (map) - munmap(map, b->datas[0].maxsize + b->datas[0].mapoffset); - + done: pw_stream_queue_buffer(stream, buf); } @@ -365,7 +354,8 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo PW_DIRECTION_INPUT, data->path, PW_STREAM_FLAG_AUTOCONNECT | - PW_STREAM_FLAG_INACTIVE, + PW_STREAM_FLAG_INACTIVE | + PW_STREAM_FLAG_MAP_BUFFERS, params, 1); break; } diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index ecb5db457..9b1064cb3 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -56,7 +56,9 @@ struct mem { struct buffer { struct pw_buffer buffer; uint32_t id; - bool queued; +#define BUFFER_FLAG_MAPPED (1 << 0) +#define BUFFER_FLAG_QUEUED (1 << 1) + uint32_t flags; void *ptr; struct pw_map_range map; uint32_t n_mem; @@ -190,11 +192,45 @@ static void clear_mems(struct pw_stream *stream) impl->mem_ids.size = 0; } +static int map_data(struct stream *impl, struct spa_data *data, int prot) +{ + void *ptr; + struct pw_map_range range; + + pw_map_range_init(&range, data->mapoffset, data->maxsize, + impl->this.remote->core->sc_pagesize); + + ptr = mmap(NULL, range.size, prot, MAP_SHARED, data->fd, range.offset); + if (ptr == MAP_FAILED) { + pw_log_error("stream %p: failed to mmap buffer mem: %m", impl); + return -errno; + } + data->data = SPA_MEMBER(ptr, range.start, void); + pw_log_debug("stream %p: fd %d mapped %d %d %p", impl, data->fd, + range.offset, range.size, data->data); + return 0; +} + +static int unmap_data(struct stream *impl, struct spa_data *data) +{ + struct pw_map_range range; + + pw_map_range_init(&range, data->mapoffset, data->maxsize, + impl->this.remote->core->sc_pagesize); + + if (munmap(SPA_MEMBER(data->data, -range.start, void), range.size) < 0) + pw_log_warn("failed to unmap: %m"); + + pw_log_debug("stream %p: fd %d unmapped", impl, data->fd); + data->data = NULL; + return 0; +} + static void clear_buffers(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; - int i; + int i, j; pw_log_debug("stream %p: clear buffers", stream); @@ -204,13 +240,21 @@ static void clear_buffers(struct pw_stream *stream) spa_hook_list_call(&stream->listener_list, struct pw_stream_events, remove_buffer, &b->buffer); + if (SPA_FLAG_CHECK(b->flags, BUFFER_FLAG_MAPPED)) { + for (j = 0; j < b->buffer.buffer->n_datas; j++) { + struct spa_data *d = &b->buffer.buffer->datas[j]; + pw_log_debug("stream %p: clear buffer %d mem", + stream, b->id); + unmap_data(impl, d); + } + } + if (b->ptr != NULL) if (munmap(b->ptr, b->map.size) < 0) pw_log_warn("failed to unmap buffer: %m"); b->ptr = NULL; free(b->buffer.buffer); b->buffer.buffer = NULL; - b->queued = false; } impl->n_buffers = 0; spa_ringbuffer_init(&impl->queue.ring); @@ -223,11 +267,11 @@ static inline int push_queue(struct stream *stream, struct queue *queue, struct uint32_t index; int32_t filled; - if (buffer->queued) + if (SPA_FLAG_CHECK(buffer->flags, BUFFER_FLAG_QUEUED)) return -EINVAL; filled = spa_ringbuffer_get_write_index(&queue->ring, &index); - buffer->queued = true; + SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED); queue->ids[index & MASK_BUFFERS] = buffer->id; spa_ringbuffer_write_update(&queue->ring, index + 1); @@ -249,7 +293,7 @@ static inline struct buffer *pop_queue(struct stream *stream, struct queue *queu spa_ringbuffer_read_update(&queue->ring, index + 1); buffer = &stream->buffers[id]; - buffer->queued = false; + SPA_FLAG_UNSET(buffer->flags, BUFFER_FLAG_QUEUED); pw_log_trace("stream %p: dequeued buffer %d %d", stream, id, avail); @@ -593,18 +637,6 @@ static inline void send_reuse_buffer(struct pw_stream *stream, uint32_t id) write(impl->rtwritefd, &cmd, 8); } -static void add_request_clock_update(struct pw_stream *stream) -{ - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - - pw_client_node_proxy_event(impl->node_proxy, (struct spa_event *) - &SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->remote->core->type. - event_node. - RequestClockUpdate, - SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_TIME, - 0, 0)); -} - static void add_async_complete(struct pw_stream *stream, uint32_t seq, int res) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -629,18 +661,33 @@ static void do_node_init(struct pw_stream *stream) pw_client_node_proxy_set_active(impl->node_proxy, true); } +#if 0 +static void add_request_clock_update(struct pw_stream *stream) +{ + struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + + pw_client_node_proxy_event(impl->node_proxy, (struct spa_event *) + &SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->remote->core->type. + event_node. + RequestClockUpdate, + SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_TIME, + 0, 0)); +} + static void on_timeout(void *data, uint64_t expirations) { struct pw_stream *stream = data; add_request_clock_update(stream); } +#endif static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct buffer *b; - if ((b = get_buffer(stream, id)) && !b->queued) { + if ((b = get_buffer(stream, id)) && + !SPA_FLAG_CHECK(b->flags, BUFFER_FLAG_QUEUED)) { pw_log_trace("stream %p: reuse buffer %u", stream, id); push_queue(impl, &impl->dequeue, b); } @@ -793,7 +840,6 @@ on_rtsocket_condition(void *data, int fd, enum spa_io mask) static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct timespec interval; impl->rtwritefd = rtwritefd; impl->rtsocket_source = pw_loop_add_io(stream->remote->core->data_loop, @@ -801,12 +847,13 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, stream); - /* +#if 0 + struct timespec interval; impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); interval.tv_sec = 0; interval.tv_nsec = 100000000; pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); - */ +#endif return; } @@ -993,7 +1040,7 @@ client_node_port_use_buffers(void *data, bid = &impl->buffers[i]; bid->id = i; - bid->queued = false; + bid->flags = 0; b = buffers[i].buffer; pw_map_range_init(&bid->map, buffers[i].offset, buffers[i].size, @@ -1059,6 +1106,12 @@ client_node_port_use_buffers(void *data, bm->ref++; bid->mem[bid->n_mem++] = bm; pw_log_debug(" data %d %u -> fd %d", j, bm->id, bm->fd); + + if (SPA_FLAG_CHECK(impl->flags, PW_STREAM_FLAG_MAP_BUFFERS)) { + if (map_data(impl, d, prot) < 0) + return; + SPA_FLAG_SET(bid->flags, BUFFER_FLAG_MAPPED); + } } else if (d->type == t->data.MemPtr) { d->data = SPA_MEMBER(bid->ptr, bid->map.start + SPA_PTR_TO_INT(d->data), void); @@ -1068,6 +1121,7 @@ client_node_port_use_buffers(void *data, pw_log_warn("unknown buffer data type %d", d->type); } } + if (impl->direction == SPA_DIRECTION_OUTPUT) push_queue(impl, &impl->dequeue, bid); From 18bfa9ae6efac59afb05c1091c7b2189944d6731 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 11:08:07 +0200 Subject: [PATCH 015/155] stream: add empty new_simple --- src/pipewire/stream.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 9b1064cb3..1775d97b9 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -425,6 +425,13 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, return NULL; } +struct pw_stream * +pw_stream_new_simple(struct pw_loop *loop, const char *name, struct pw_properties *props, + const struct pw_stream_events *events, void *data) +{ + return NULL; +} + enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error) { if (error) From 8b919e89bd35b60a49065d7d6e8a6515dcd73ec4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 12 Jul 2018 11:10:59 +0200 Subject: [PATCH 016/155] video-src: let stream map buffers --- src/examples/video-src.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) diff --git a/src/examples/video-src.c b/src/examples/video-src.c index 6217d3d37..f61e4c895 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -72,7 +72,7 @@ static void on_timeout(void *userdata, uint64_t expirations) { struct data *data = userdata; int i, j; - uint8_t *p, *map; + uint8_t *p; struct spa_meta_header *h; struct pw_buffer *buf; struct spa_buffer *b; @@ -83,21 +83,8 @@ static void on_timeout(void *userdata, uint64_t expirations) b = buf->buffer; - if (b->datas[0].type == data->t->data.MemFd || - b->datas[0].type == data->t->data.DmaBuf) { - map = - mmap(NULL, b->datas[0].maxsize + b->datas[0].mapoffset, - PROT_READ | PROT_WRITE, MAP_SHARED, b->datas[0].fd, 0); - if (map == MAP_FAILED) { - printf("failed to mmap: %s\n", strerror(errno)); - return; - } - p = SPA_MEMBER(map, b->datas[0].mapoffset, uint8_t); - } else if (b->datas[0].type == data->t->data.MemPtr) { - map = NULL; - p = b->datas[0].data; - } else - return; + if ((p = b->datas[0].data) == NULL) + goto done; if ((h = spa_buffer_find_meta(b, data->t->meta.Header))) { #if 0 @@ -120,11 +107,9 @@ static void on_timeout(void *userdata, uint64_t expirations) data->counter += 13; } - if (map) - munmap(map, b->datas[0].maxsize + b->datas[0].mapoffset); - b->datas[0].chunk->size = b->datas[0].maxsize; + done: pw_stream_queue_buffer(data->stream, buf); } @@ -243,7 +228,8 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo pw_stream_connect(data->stream, PW_DIRECTION_OUTPUT, NULL, - PW_STREAM_FLAG_DRIVER, + PW_STREAM_FLAG_DRIVER | + PW_STREAM_FLAG_MAP_BUFFERS, params, 1); break; } From 36d883b8c87310913e8149b15e3aa8df0274d53a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Jul 2018 10:31:17 +0200 Subject: [PATCH 017/155] version: add version file --- src/pipewire/meson.build | 5 ++++ src/pipewire/pipewire.c | 11 +++++-- src/pipewire/pipewire.h | 1 + src/pipewire/version.h.in | 63 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 78 insertions(+), 2 deletions(-) create mode 100644 src/pipewire/version.h.in diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 9929d498e..8f149eb1c 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -61,6 +61,11 @@ pipewire_sources = [ 'work-queue.c', ] +configure_file(input : 'version.h.in', + output : 'version.h', + install_dir : 'include/pipewire', + configuration : cdata) + install_headers(pipewire_headers, subdir : 'pipewire') libpipewire_c_args = [ diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index ce9588968..b93008c0d 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -31,8 +31,9 @@ #include -#include "pipewire/pipewire.h" -#include "pipewire/private.h" +#include "pipewire.h" +#include "private.h" +#include "version.h" static char **categories = NULL; @@ -378,3 +379,9 @@ enum pw_direction pw_direction_reverse(enum pw_direction direction) return PW_DIRECTION_INPUT; return direction; } + +/** Get the currently running version */ +const char* pw_get_library_version(void) +{ + return pw_get_headers_version(); +} diff --git a/src/pipewire/pipewire.h b/src/pipewire/pipewire.h index 870f97462..dcf705ea8 100644 --- a/src/pipewire/pipewire.h +++ b/src/pipewire/pipewire.h @@ -46,6 +46,7 @@ extern "C" { #include #include #include +#include /** \mainpage * diff --git a/src/pipewire/version.h.in b/src/pipewire/version.h.in new file mode 100644 index 000000000..1e43bef92 --- /dev/null +++ b/src/pipewire/version.h.in @@ -0,0 +1,63 @@ +/* PipeWire + * Copyright (C) 2018 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 __PIPEWIRE_VERSION_H__ +#define __PIPEWIRE_VERSION_H__ + +/* WARNING: Make sure to edit the real source file version.h.in! */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Return the version of the header files. Keep in mind that this is +a macro and not a function, so it is impossible to get the pointer of +it. */ +#define pw_get_headers_version() ("@PIPEWIRE_VERSION_MAJOR@.@PIPEWIRE_VERSION_MINOR@.@PIPEWIRE_VERSION_MICRO@") + +/** Return the version of the library the current application is + * linked to. */ +const char* pw_get_library_version(void); + +/** The current API version. Versions prior to 0.2.0 have + * PW_API_VERSION undefined. Please note that this is only ever + * increased on incompatible API changes! */ +#define PW_API_VERSION @PIPEWIRE_API_VERSION@ + +/** The major version of PipeWire. \since 0.2.0 */ +#define PW_MAJOR @PIPEWIRE_VERSION_MAJOR@ + +/** The minor version of PipeWire. \since 0.2.0 */ +#define PW_MINOR @PIPEWIRE_VERSION_MINOR@ + +/** The micro version of PipeWire. \since 0.2.0 */ +#define PW_MICRO @PIPEWIRE_VERSION_MICRO@ + +/** Evaluates to TRUE if the PipeWire library version is equal or + * newer than the specified. \since 0.2.0 */ +#define PW_CHECK_VERSION(major,minor,micro) \ + ((PW_MAJOR > (major)) || \ + (PW_MAJOR == (major) && PW_MINOR > (minor)) || \ + (PW_MAJOR == (major) && PW_MINOR == (minor) && PW_MICRO >= (micro))) + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_VERION_H__ */ From 061f2c82b53b2f6632b7b7d583058f683d9cfb86 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 17 Jul 2018 10:32:52 +0200 Subject: [PATCH 018/155] bump version --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index 9247a21c1..8e636eecb 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.1.9', + version : '0.2.0', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 9e0bce4cb7363dc7faaa5b0af6cb8f5359e364c9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 19 Jul 2018 16:33:00 +0200 Subject: [PATCH 019/155] stream: update to latest API --- src/gst/gstpipewireclock.c | 4 ++-- src/pipewire/stream.c | 24 ++++++++++++++++++++---- src/pipewire/stream.h | 15 ++++++++++++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/src/gst/gstpipewireclock.c b/src/gst/gstpipewireclock.c index 4c4e47889..c13d91b1d 100644 --- a/src/gst/gstpipewireclock.c +++ b/src/gst/gstpipewireclock.c @@ -51,11 +51,11 @@ gst_pipewire_clock_get_internal_time (GstClock * clock) pw_stream_get_time (pclock->stream, &t); if (t.rate.denom) - result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.num, t.rate.denom); + result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.denom, t.rate.num); else result = GST_CLOCK_TIME_NONE; - GST_DEBUG ("%"PRId64", %d %"PRId64, t.ticks, t.rate.denom, result); + GST_DEBUG ("%"PRId64", %d/%d %"PRId64, t.ticks, t.rate.num, t.rate.denom, result); return result; } diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 1775d97b9..d0bf53eed 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -68,6 +68,8 @@ struct buffer { struct queue { uint32_t ids[MAX_BUFFERS]; struct spa_ringbuffer ring; + uint64_t incount; + uint64_t outcount; }; struct stream { @@ -114,7 +116,6 @@ struct stream { struct buffer buffers[MAX_BUFFERS]; int n_buffers; - int64_t last_ticks; int32_t last_rate; int64_t last_monotonic; @@ -270,8 +271,10 @@ static inline int push_queue(struct stream *stream, struct queue *queue, struct if (SPA_FLAG_CHECK(buffer->flags, BUFFER_FLAG_QUEUED)) return -EINVAL; - filled = spa_ringbuffer_get_write_index(&queue->ring, &index); SPA_FLAG_SET(buffer->flags, BUFFER_FLAG_QUEUED); + queue->incount += buffer->buffer.size; + + filled = spa_ringbuffer_get_write_index(&queue->ring, &index); queue->ids[index & MASK_BUFFERS] = buffer->id; spa_ringbuffer_write_update(&queue->ring, index + 1); @@ -293,6 +296,7 @@ static inline struct buffer *pop_queue(struct stream *stream, struct queue *queu spa_ringbuffer_read_update(&queue->ring, index + 1); buffer = &stream->buffers[id]; + queue->outcount += buffer->buffer.size; SPA_FLAG_UNSET(buffer->flags, BUFFER_FLAG_QUEUED); pw_log_trace("stream %p: dequeued buffer %d %d", stream, id, avail); @@ -1359,6 +1363,11 @@ int pw_stream_set_active(struct pw_stream *stream, bool active) return 0; } +static inline int64_t get_queue_size(struct queue *queue) +{ + return (int64_t)(queue->incount - queue->outcount); +} + int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1370,8 +1379,15 @@ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) elapsed = (time->now - impl->last_monotonic) / 1000; time->ticks = impl->last_ticks + (elapsed * impl->last_rate) / SPA_USEC_PER_SEC; - time->rate.num = 1; - time->rate.denom = impl->last_rate; + time->rate.num = impl->last_rate; + time->rate.denom = 1; + time->delay = 0; + if (impl->direction == SPA_DIRECTION_INPUT) + time->queued = get_queue_size(&impl->dequeue); + else + time->queued = get_queue_size(&impl->queue); + + pw_log_trace("%ld %d/%d %ld", time->ticks, time->rate.num, time->rate.denom, time->queued); return 0; } diff --git a/src/pipewire/stream.h b/src/pipewire/stream.h index 4d9ccc60d..26ab1d913 100644 --- a/src/pipewire/stream.h +++ b/src/pipewire/stream.h @@ -166,6 +166,11 @@ enum pw_stream_state { struct pw_buffer { struct spa_buffer *buffer; /* the spa buffer */ void *user_data; /* user data attached to the buffer */ + uint64_t size; /* For input streams, this field is set by pw_stream + with the duration of the buffer in ticks. + For output streams, this field is set by the user. + This field is added for all queued buffers and + returned in the time info. */ }; /** Events for a stream */ @@ -308,9 +313,17 @@ int pw_stream_set_active(struct pw_stream *stream, bool active); /** A time structure \memberof pw_stream */ struct pw_time { int64_t now; /**< the monotonic time */ - int64_t ticks; /**< the ticks at \a now */ struct spa_fraction rate; /**< the rate of \a ticks */ + uint64_t ticks; /**< the ticks at \a now. This is the current time that + the remote end is reading/writing. */ + uint64_t delay; /**< delay to device, add to ticks for INPUT streams and + subtract from ticks for OUTPUT streams to get the + time of the device. */ + uint64_t queued; /**< data queued in the stream, this is the sum + of the size fields in the pw_buffer that are + currently queued */ }; + /** Query the time on the stream \memberof pw_stream */ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time); From de766324b99d548822afeb5fbdc0d35438387670 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Jul 2018 10:35:31 +0200 Subject: [PATCH 020/155] hook: add private data for future expansion --- spa/include/spa/utils/hook.h | 1 + 1 file changed, 1 insertion(+) diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index 8fddc2525..e23200dac 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -43,6 +43,7 @@ struct spa_hook { struct spa_list link; const void *funcs; void *data; + void *priv[2]; /**< private data for the hook list */ }; /** Initialize a hook list */ From aa838eab94292eccc2d13c68ae342fe8bd7897cd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 20 Jul 2018 12:44:54 +0200 Subject: [PATCH 021/155] Release 0.2.1 --- NEWS | 29 ++++++++++++++++------------- meson.build | 2 +- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index dfa521620..4c30d8a61 100644 --- a/NEWS +++ b/NEWS @@ -1,14 +1,17 @@ -PipeWire 0.1.9 +PipeWire 0.2.1 -- Various build fixes -- Do more permission checks -- Add support for doing async connections. This can be used to - make connections through the portal later. -- Fix device creation from the GStreamer device monitor -- v4l2 experiment with controls -- move rtkit to a module to avoid dbus dependency -- use dmabuf allocator in gstreamer elements -- Add DSP module for pro audio cases, remove jack module. The - idea is to make a replacement jack client library that talks - pipewire directly instead of trying to emulate a jack server. -- Various memory handling improvements +- Various fixes to memory handling +- Fixes for shutdown +- v4l2 fix enumeration of frame intervals +- Make the daemon stop when the setup commands fail +- Improve safety of hooks +- Update stream API to more future proof version +- Add more options to stream API such as scheduling in the + main thread and automatic mapping of buffers +- Add version file and macros to check compile time and + runtime versions of pipewire +- Future proof some structs + +Work is ongoing in the work branch that features a completely new +scheduling method that will enable audio support. Some of these +API changes are backported in this branch. diff --git a/meson.build b/meson.build index 8e636eecb..0e982cca2 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.0', + version : '0.2.1', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 07411e09cb6f38e2ff59807e307a61d96bfc082d Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Mon, 23 Jul 2018 08:05:40 +0200 Subject: [PATCH 022/155] Bump apiversion and soversion for PW 0.2.x --- meson.build | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 0e982cca2..7751fd56e 100644 --- a/meson.build +++ b/meson.build @@ -17,8 +17,8 @@ else pipewire_version_nano = 0 endif -apiversion = '0.1' -soversion = 0 +apiversion = '0.2' +soversion = 1 libversion = '@0@.@1@.0'.format(soversion, pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int()) prefix = get_option('prefix') From 76ab7eb9fb67b6df51f6255d46136dff4b8bb8be Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Fri, 27 Jul 2018 09:42:39 +0200 Subject: [PATCH 023/155] Drop api version suffix from library name --- meson.build | 4 ++-- pkgconfig/libpipewire.pc.in | 2 +- pkgconfig/meson.build | 2 +- src/modules/spa/meson.build | 6 +++--- src/pipewire/meson.build | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index 7751fd56e..db8da1eb2 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ pipewire_libdir = join_paths(prefix, get_option('libdir')) pipewire_localedir = join_paths(prefix, get_option('localedir')) pipewire_sysconfdir = join_paths(prefix, get_option('sysconfdir')) -modules_install_dir = join_paths(get_option('libdir'), 'pipewire-@0@'.format(apiversion)) +modules_install_dir = join_paths(get_option('libdir'), 'pipewire') gnome = import('gnome') @@ -54,7 +54,7 @@ cdata.set('PACKAGE_STRING', '"PipeWire @0@"'.format(pipewire_version)) cdata.set('PACKAGE_TARNAME', '"pipewire"') cdata.set('PACKAGE_URL', '"http://pipewire.org"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(pipewire_version)) -cdata.set('MODULEDIR', '"@0@/pipewire-@1@"'.format(pipewire_libdir,apiversion)) +cdata.set('MODULEDIR', '"@0@/pipewire"'.format(pipewire_libdir)) cdata.set('PIPEWIRE_CONFIG_DIR', '"@0@/pipewire"'.format(pipewire_sysconfdir)) cdata.set('VERSION', '"@0@"'.format(pipewire_version)) cdata.set('PLUGINDIR', '"@0@/spa"'.format(pipewire_libdir)) diff --git a/pkgconfig/libpipewire.pc.in b/pkgconfig/libpipewire.pc.in index ca302fbea..b246a71fe 100644 --- a/pkgconfig/libpipewire.pc.in +++ b/pkgconfig/libpipewire.pc.in @@ -7,5 +7,5 @@ moduledir=@moduledir@ Name: libpipewire Description: PipeWire Interface Version: @VERSION@ -Libs: -L${libdir} -lpipewire-@PIPEWIRE_API_VERSION@ +Libs: -L${libdir} -lpipewire Cflags: -I${includedir} -D_REENTRANT diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index 9b448aa15..2bb89fd14 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -17,7 +17,7 @@ pkg_files = [ foreach p : pkg_files infile = p + '.pc.in' - outfile = p + '-0.1.pc' + outfile = p + '.pc' configure_file(input : infile, output : outfile, configuration : pkgconf, diff --git a/src/modules/spa/meson.build b/src/modules/spa/meson.build index af49555fb..66ef7d79b 100644 --- a/src/modules/spa/meson.build +++ b/src/modules/spa/meson.build @@ -9,7 +9,7 @@ pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : '@0@/pipewire'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -19,7 +19,7 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : '@0@/pipewire'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -29,6 +29,6 @@ pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-fact include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : '@0@/pipewire'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 8f149eb1c..4e3f2fca8 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -74,7 +74,7 @@ libpipewire_c_args = [ '-D_POSIX_C_SOURCE', ] -libpipewire = shared_library('pipewire-@0@'.format(apiversion), pipewire_sources, +libpipewire = shared_library('pipewire', pipewire_sources, version : libversion, soversion : soversion, c_args : libpipewire_c_args, From a223a35a5bf6131caa0e677ba7416fbf1cbd1135 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 27 Jul 2018 11:24:41 +0200 Subject: [PATCH 024/155] Revert "Drop api version suffix from library name" This reverts commit 76ab7eb9fb67b6df51f6255d46136dff4b8bb8be. --- meson.build | 4 ++-- pkgconfig/libpipewire.pc.in | 2 +- pkgconfig/meson.build | 2 +- src/modules/spa/meson.build | 6 +++--- src/pipewire/meson.build | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/meson.build b/meson.build index db8da1eb2..7751fd56e 100644 --- a/meson.build +++ b/meson.build @@ -28,7 +28,7 @@ pipewire_libdir = join_paths(prefix, get_option('libdir')) pipewire_localedir = join_paths(prefix, get_option('localedir')) pipewire_sysconfdir = join_paths(prefix, get_option('sysconfdir')) -modules_install_dir = join_paths(get_option('libdir'), 'pipewire') +modules_install_dir = join_paths(get_option('libdir'), 'pipewire-@0@'.format(apiversion)) gnome = import('gnome') @@ -54,7 +54,7 @@ cdata.set('PACKAGE_STRING', '"PipeWire @0@"'.format(pipewire_version)) cdata.set('PACKAGE_TARNAME', '"pipewire"') cdata.set('PACKAGE_URL', '"http://pipewire.org"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(pipewire_version)) -cdata.set('MODULEDIR', '"@0@/pipewire"'.format(pipewire_libdir)) +cdata.set('MODULEDIR', '"@0@/pipewire-@1@"'.format(pipewire_libdir,apiversion)) cdata.set('PIPEWIRE_CONFIG_DIR', '"@0@/pipewire"'.format(pipewire_sysconfdir)) cdata.set('VERSION', '"@0@"'.format(pipewire_version)) cdata.set('PLUGINDIR', '"@0@/spa"'.format(pipewire_libdir)) diff --git a/pkgconfig/libpipewire.pc.in b/pkgconfig/libpipewire.pc.in index b246a71fe..ca302fbea 100644 --- a/pkgconfig/libpipewire.pc.in +++ b/pkgconfig/libpipewire.pc.in @@ -7,5 +7,5 @@ moduledir=@moduledir@ Name: libpipewire Description: PipeWire Interface Version: @VERSION@ -Libs: -L${libdir} -lpipewire +Libs: -L${libdir} -lpipewire-@PIPEWIRE_API_VERSION@ Cflags: -I${includedir} -D_REENTRANT diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index 2bb89fd14..9b448aa15 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -17,7 +17,7 @@ pkg_files = [ foreach p : pkg_files infile = p + '.pc.in' - outfile = p + '.pc' + outfile = p + '-0.1.pc' configure_file(input : infile, output : outfile, configuration : pkgconf, diff --git a/src/modules/spa/meson.build b/src/modules/spa/meson.build index 66ef7d79b..af49555fb 100644 --- a/src/modules/spa/meson.build +++ b/src/modules/spa/meson.build @@ -9,7 +9,7 @@ pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire'.format(get_option('libdir')), + install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -19,7 +19,7 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire'.format(get_option('libdir')), + install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -29,6 +29,6 @@ pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-fact include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire'.format(get_option('libdir')), + install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep], ) diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 4e3f2fca8..8f149eb1c 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -74,7 +74,7 @@ libpipewire_c_args = [ '-D_POSIX_C_SOURCE', ] -libpipewire = shared_library('pipewire', pipewire_sources, +libpipewire = shared_library('pipewire-@0@'.format(apiversion), pipewire_sources, version : libversion, soversion : soversion, c_args : libpipewire_c_args, From 887b9550ce5cfc2f8bd2d46af683fda3286de71d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 31 Jul 2018 14:39:42 +0200 Subject: [PATCH 025/155] Release 0.2.2 --- NEWS | 3 ++- meson.build | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 4c30d8a61..f1671eb03 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -PipeWire 0.2.1 +PipeWire 0.2.2 - Various fixes to memory handling - Fixes for shutdown @@ -11,6 +11,7 @@ PipeWire 0.2.1 - Add version file and macros to check compile time and runtime versions of pipewire - Future proof some structs +- Increment API version and .so version Work is ongoing in the work branch that features a completely new scheduling method that will enable audio support. Some of these diff --git a/meson.build b/meson.build index 7751fd56e..d4b8b6e57 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.1', + version : '0.2.2', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From c5380162acb22390c6e7f16c4f1939979e82741f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 31 Jul 2018 14:56:34 +0200 Subject: [PATCH 026/155] build: fix module install directory --- src/modules/spa/meson.build | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/spa/meson.build b/src/modules/spa/meson.build index af49555fb..e0a37280c 100644 --- a/src/modules/spa/meson.build +++ b/src/modules/spa/meson.build @@ -9,7 +9,7 @@ pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -19,7 +19,7 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node', include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], ) @@ -29,6 +29,6 @@ pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-fact include_directories : [configinc, spa_inc], link_with : spalib, install : true, - install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], ) From 327ae5db6ef93724640c4c74664d693d7a530dbe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 31 Jul 2018 15:05:17 +0200 Subject: [PATCH 027/155] add apiversion to pkgconfig as well --- pkgconfig/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index 9b448aa15..babd28968 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -17,7 +17,7 @@ pkg_files = [ foreach p : pkg_files infile = p + '.pc.in' - outfile = p + '-0.1.pc' + outfile = p + '-@0@.pc'.format(apiversion) configure_file(input : infile, output : outfile, configuration : pkgconf, From 393917ac765a04982d44bea8c3c9b60ee6895681 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 3 Aug 2018 17:42:49 +0200 Subject: [PATCH 028/155] gstdeviceprovider: fix caps introspection Enum the node port params to get the caps of the devices. --- src/gst/gstpipewiredeviceprovider.c | 288 ++++++++++++++++++++-------- src/gst/gstpipewiredeviceprovider.h | 3 + 2 files changed, 206 insertions(+), 85 deletions(-) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index fefdb57be..ad712850e 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -192,39 +192,92 @@ enum PROP_LAST }; -static GstDevice * -new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info, uint32_t id) +struct pending { + struct spa_list link; + uint32_t seq; + void (*callback) (void *data); + void *data; +}; + +struct registry_data { + uint32_t seq; + GstPipeWireDeviceProvider *self; + struct pw_registry_proxy *registry; + struct spa_hook registry_listener; + struct spa_list nodes; + struct spa_list ports; +}; + +struct node_data { + struct spa_list link; + GstPipeWireDeviceProvider *self; + struct pw_node_proxy *proxy; + uint32_t id; + uint32_t parent_id; + struct spa_hook node_listener; + struct pw_node_info *info; + GstCaps *caps; + GstDevice *dev; + struct pending pending; +}; + +struct port_data { + struct spa_list link; + struct node_data *node_data; + struct pw_port_proxy *proxy; + uint32_t id; + struct spa_hook port_listener; + struct pw_port_info *info; + struct pending pending; + struct pending pending_param; +}; + +static struct node_data *find_node_data(struct registry_data *rd, uint32_t id) +{ + struct node_data *n; + spa_list_for_each(n, &rd->nodes, link) { + if (n->id == id) + return n; + } + return NULL; +} + +static void free_node_data(struct registry_data *rd, struct node_data *nd) +{ + GstPipeWireDeviceProvider *self = rd->self; + GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); + + if (nd->dev != NULL) { + gst_device_provider_device_remove (provider, GST_DEVICE (nd->dev)); + gst_object_unref (nd->dev); + } + if (nd->caps) { + gst_caps_unref(nd->caps); + } + if (nd->info) + pw_node_info_free(nd->info); + spa_list_remove(&nd->link); +} + +static GstDevice * +new_node (GstPipeWireDeviceProvider *self, struct node_data *data) { - GstCaps *caps = NULL; GstStructure *props; const gchar *klass = NULL; - const struct spa_dict_item *item; GstPipeWireDeviceType type; - - caps = gst_caps_new_empty (); -#if 0 - int i; - struct pw_type *t = self->type; - for (i = 0; i < info->n_params; i++) { - if (!spa_pod_is_object_id(info->params[i], t->param.idEnumFormat)) - continue; - GstCaps *c1 = gst_caps_from_format (info->params[i], t->map); - if (c1) - gst_caps_append (caps, c1); - } -#endif + const struct pw_node_info *info = data->info; if (info->max_input_ports > 0 && info->max_output_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SINK; } else if (info->max_output_ports > 0 && info->max_input_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE; } else { - gst_caps_unref(caps); return NULL; } props = gst_structure_new_empty ("pipewire-proplist"); if (info->props) { + const struct spa_dict_item *item; spa_dict_for_each (item, info->props) gst_structure_set (props, item->key, G_TYPE_STRING, item->value, NULL); @@ -233,32 +286,30 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info, uint if (klass == NULL) klass = "unknown/unknown"; - return gst_pipewire_device_new (id, + return gst_pipewire_device_new (data->id, info->name, - caps, + data->caps, klass, type, props); } -static GstPipeWireDevice * -find_device (GstDeviceProvider *provider, uint32_t id) +static void do_add_node(void *data) { - GList *item; - GstPipeWireDevice *dev = NULL; + struct port_data *p = data; + struct node_data *nd = p->node_data; + GstPipeWireDeviceProvider *self = nd->self; - GST_OBJECT_LOCK (provider); - for (item = provider->devices; item; item = item->next) { - dev = item->data; - if (dev->id == id) { - gst_object_ref (dev); - break; - } - dev = NULL; + if (nd->dev) + return; + + nd->dev = new_node (self, nd); + if (nd->dev) { + if(self->list_only) + *self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (nd->dev)); + else + gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), nd->dev); } - GST_OBJECT_UNLOCK (provider); - - return dev; } static void @@ -289,13 +340,38 @@ get_core_info (struct pw_remote *remote, } } +static void add_pending(GstPipeWireDeviceProvider *self, struct pending *p) +{ + spa_list_append(&self->pending, &p->link); + p->seq = ++self->seq; + pw_log_debug("add pending %d", p->seq); + pw_core_proxy_sync(self->core_proxy, p->seq); +} + +static void remove_pending(struct pending *p) +{ + if (p->seq != SPA_ID_INVALID) { + pw_log_debug("remove pending %d", p->seq); + spa_list_remove(&p->link); + p->seq = SPA_ID_INVALID; + } +} + static void on_sync_reply (void *data, uint32_t seq) { GstPipeWireDeviceProvider *self = data; - if (seq == 1) - pw_core_proxy_sync(self->core_proxy, 2); - else if (seq == 2) { + struct pending *p, *t; + + spa_list_for_each_safe(p, t, &self->pending, link) { + if (p->seq == seq) { + remove_pending(p); + if (p->callback) + p->callback(p->data); + } + } + pw_log_debug("check %d %d", seq, self->seq); + if (seq == self->seq) { self->end = true; if (self->main_loop) pw_thread_loop_signal (self->main_loop, FALSE); @@ -323,38 +399,47 @@ on_state_changed (void *data, enum pw_remote_state old, enum pw_remote_state sta pw_thread_loop_signal (self->main_loop, FALSE); } +static void port_event_info(void *data, struct pw_port_info *info) +{ + struct port_data *port_data = data; + struct node_data *node_data = port_data->node_data; + GstPipeWireDeviceProvider *self = node_data->self; + struct pw_type *t = node_data->self->type; -struct node_data { - GstPipeWireDeviceProvider *self; - struct pw_node_proxy *node; - uint32_t id; - uint32_t parent_id; - struct spa_hook node_listener; -}; + if (info->change_mask & PW_PORT_CHANGE_MASK_ENUM_PARAMS) { + pw_port_proxy_enum_params((struct pw_port_proxy*)port_data->proxy, + t->param.idEnumFormat, 0, 0, NULL); + port_data->pending_param.callback = do_add_node; + port_data->pending_param.data = port_data; + add_pending(self, &port_data->pending_param); + } +} -struct registry_data { - GstPipeWireDeviceProvider *self; - struct pw_registry_proxy *registry; - struct spa_hook registry_listener; +static void port_event_param(void *data, uint32_t id, uint32_t index, uint32_t next, + const struct spa_pod *param) +{ + struct port_data *port_data = data; + struct node_data *node_data = port_data->node_data; + GstPipeWireDeviceProvider *self = node_data->self; + struct pw_type *t = self->type; + GstCaps *c1; + + c1 = gst_caps_from_format (param, t->map); + if (c1 && node_data->caps) + gst_caps_append (node_data->caps, c1); + +} + +static const struct pw_port_proxy_events port_events = { + PW_VERSION_PORT_PROXY_EVENTS, + .info = port_event_info, + .param = port_event_param }; static void node_event_info(void *data, struct pw_node_info *info) { struct node_data *node_data = data; - GstPipeWireDeviceProvider *self = node_data->self; - GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); - GstDevice *dev; - - if (find_device (provider, node_data->id) != NULL) - return; - - dev = new_node (self, info, node_data->id); - if (dev) { - if(self->list_only) - *self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (dev)); - else - gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); - } + node_data->info = pw_node_info_update(node_data->info, info); } static const struct pw_node_proxy_events node_events = { @@ -369,22 +454,50 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, u { struct registry_data *rd = data; GstPipeWireDeviceProvider *self = rd->self; - struct pw_node_proxy *node; struct node_data *nd; - if (type != self->type->node) - return; + if (type == self->type->node) { + struct pw_node_proxy *node; - node = pw_registry_proxy_bind(rd->registry, id, self->type->node, PW_VERSION_NODE, sizeof(*nd)); - if (node == NULL) - goto no_mem; + node = pw_registry_proxy_bind(rd->registry, + id, self->type->node, + PW_VERSION_NODE, sizeof(*nd)); + if (node == NULL) + goto no_mem; - nd = pw_proxy_get_user_data((struct pw_proxy*)node); - nd->self = self; - nd->node = node; - nd->id = id; - nd->parent_id = parent_id; - pw_node_proxy_add_listener(node, &nd->node_listener, &node_events, nd); + nd = pw_proxy_get_user_data((struct pw_proxy*)node); + nd->self = self; + nd->proxy = node; + nd->id = id; + nd->parent_id = parent_id; + nd->caps = gst_caps_new_empty (); + spa_list_append(&rd->nodes, &nd->link); + pw_node_proxy_add_listener(node, &nd->node_listener, &node_events, nd); + nd->pending.callback = NULL; + add_pending(self, &nd->pending); + } + else if (type == self->type->port) { + struct pw_port_proxy *port; + struct port_data *pd; + + if ((nd = find_node_data(rd, parent_id)) == NULL) + return; + + port = pw_registry_proxy_bind(rd->registry, + id, self->type->port, + PW_VERSION_PORT, sizeof(*pd)); + if (port == NULL) + goto no_mem; + + pd = pw_proxy_get_user_data((struct pw_proxy*)port); + pd->node_data = nd; + pd->proxy = port; + pd->id = id; + spa_list_append(&rd->ports, &pd->link); + pw_port_proxy_add_listener(port, &pd->port_listener, &port_events, pd); + pd->pending.callback = NULL; + add_pending(self, &pd->pending); + } return; @@ -396,15 +509,12 @@ no_mem: static void registry_event_global_remove(void *data, uint32_t id) { struct registry_data *rd = data; - GstPipeWireDeviceProvider *self = rd->self; - GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); - GstPipeWireDevice *dev; + struct node_data *nd; - dev = find_device (provider, id); - if (dev != NULL) { - gst_device_provider_device_remove (provider, GST_DEVICE (dev)); - gst_object_unref (dev); - } + if ((nd = find_node_data(rd, id)) == NULL) + return; + + free_node_data(rd, nd); } static const struct pw_registry_proxy_events registry_events = { @@ -444,6 +554,8 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) if (!(r = pw_remote_new (c, NULL, 0))) goto failed; + spa_list_init(&self->pending); + self->seq = 1; pw_remote_add_listener(r, &listener, &remote_events, self); pw_remote_connect (r); @@ -479,8 +591,10 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) data = pw_proxy_get_user_data((struct pw_proxy*)reg); data->self = self; data->registry = reg; + spa_list_init(&data->nodes); + spa_list_init(&data->ports); pw_registry_proxy_add_listener(reg, &data->registry_listener, ®istry_events, data); - pw_core_proxy_sync(self->core_proxy, 1); + pw_core_proxy_sync(self->core_proxy, ++self->seq); for (;;) { if (pw_remote_get_state(r, NULL) <= 0) @@ -512,6 +626,8 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) self->loop = pw_loop_new (NULL); self->list_only = FALSE; + spa_list_init(&self->pending); + self->seq = 1; if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) { GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop"); @@ -566,9 +682,11 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) data = pw_proxy_get_user_data((struct pw_proxy*)self->registry); data->self = self; data->registry = self->registry; + spa_list_init(&data->nodes); + spa_list_init(&data->ports); pw_registry_proxy_add_listener(self->registry, &data->registry_listener, ®istry_events, data); - pw_core_proxy_sync(self->core_proxy, 1); + pw_core_proxy_sync(self->core_proxy, ++self->seq); for (;;) { if (self->end) diff --git a/src/gst/gstpipewiredeviceprovider.h b/src/gst/gstpipewiredeviceprovider.h index dd675d49d..816226052 100644 --- a/src/gst/gstpipewiredeviceprovider.h +++ b/src/gst/gstpipewiredeviceprovider.h @@ -91,6 +91,9 @@ struct _GstPipeWireDeviceProvider { struct spa_hook remote_listener; struct pw_core_proxy *core_proxy; + struct spa_list pending; + uint32_t seq; + struct pw_registry_proxy *registry; gboolean end; From e6b7dd1d0f5e25a7a527f0f3cd1e2cdffd33db23 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 12:07:05 +0200 Subject: [PATCH 029/155] pipewiresrc: fix refcounting of buffers --- src/gst/gstpipewiresrc.c | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 568ebfa9b..18ba270ac 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -215,6 +215,7 @@ gst_pipewire_src_finalize (GObject * object) gst_object_unref (pwsrc->clock); g_free (pwsrc->path); g_free (pwsrc->client_name); + g_object_unref(pwsrc->pool); G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -372,7 +373,7 @@ on_remove_buffer (void *_data, struct pw_buffer *b) GstBuffer *buf = data->buf; GList *walk; - GST_LOG_OBJECT (pwsrc, "remove buffer"); + GST_LOG_OBJECT (pwsrc, "remove buffer %p", buf); GST_MINI_OBJECT_CAST (buf)->dispose = NULL; @@ -386,6 +387,7 @@ on_remove_buffer (void *_data, struct pw_buffer *b) } walk = next; } + gst_buffer_unref (buf); } static void @@ -426,11 +428,8 @@ on_process (void *_data) mem->offset += data->offset; } - if (pwsrc->always_copy) - buf = gst_buffer_copy_deep (buf); - else - gst_buffer_ref (buf); + gst_buffer_ref (buf); g_queue_push_tail (&pwsrc->queue, buf); pw_thread_loop_signal (pwsrc->main_loop, FALSE); @@ -831,6 +830,7 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) GstPipeWireSrc *pwsrc; GstClockTime pts, dts, base_time; const char *error = NULL; + GstBuffer *buf; pwsrc = GST_PIPEWIRE_SRC (psrc); @@ -854,15 +854,24 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (state != PW_STREAM_STATE_STREAMING) goto streaming_stopped; - *buffer = g_queue_pop_head (&pwsrc->queue); - GST_DEBUG ("popped buffer %p", *buffer); - if (*buffer != NULL) + buf = g_queue_pop_head (&pwsrc->queue); + GST_DEBUG ("popped buffer %p", buf); + if (buf != NULL) break; pw_thread_loop_wait (pwsrc->main_loop); } pw_thread_loop_unlock (pwsrc->main_loop); + gst_buffer_unref (buf); + + if (pwsrc->always_copy) { + *buffer = gst_buffer_copy_deep (buf); + gst_buffer_unref (buf); + } + else + *buffer = buf; + if (pwsrc->is_live) base_time = GST_ELEMENT_CAST (psrc)->base_time; else @@ -884,8 +893,6 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) GST_BUFFER_PTS (*buffer) = pts; GST_BUFFER_DTS (*buffer) = dts; - buffer_recycle (GST_MINI_OBJECT_CAST (*buffer)); - return GST_FLOW_OK; not_negotiated: From 5a3883509b77a528a2ad96a449a55baae73af0cf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 14:28:25 +0200 Subject: [PATCH 030/155] stream: return error when no timing info yet --- src/pipewire/stream.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index d0bf53eed..abd1e4846 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -932,6 +932,8 @@ static void client_node_command(void *data, uint32_t seq, const struct spa_comma impl->last_ticks = cu->body.ticks.value; impl->last_rate = cu->body.rate.value; impl->last_monotonic = cu->body.monotonic_time.value; + pw_log_debug("clock update %ld %d %ld", impl->last_ticks, + impl->last_rate, impl->last_monotonic); } else { pw_log_warn("unhandled node command %d", SPA_COMMAND_TYPE(command)); add_async_complete(stream, seq, -ENOTSUP); @@ -1374,6 +1376,9 @@ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) int64_t elapsed; struct timespec ts; + if (impl->last_rate == 0) + return -EAGAIN; + clock_gettime(CLOCK_MONOTONIC, &ts); time->now = SPA_TIMESPEC_TO_TIME(&ts); elapsed = (time->now - impl->last_monotonic) / 1000; @@ -1387,7 +1392,8 @@ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) else time->queued = get_queue_size(&impl->queue); - pw_log_trace("%ld %d/%d %ld", time->ticks, time->rate.num, time->rate.denom, time->queued); + pw_log_trace("stream %p: %ld %d/%d %ld", stream, + time->ticks, time->rate.num, time->rate.denom, time->queued); return 0; } From a2cfb0882bf5f0b649c4ccb11c5825256b278db0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 15:19:20 +0200 Subject: [PATCH 031/155] gst: keep track of clock time Invalidate the clock when the stream is destroyed and let the new clock take the time of previous clock when no timing info is available. --- src/gst/gstpipewireclock.c | 13 +++++++------ src/gst/gstpipewireclock.h | 5 +++-- src/gst/gstpipewiresrc.c | 8 +++++++- src/gst/gstpipewiresrc.h | 1 + 4 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/gst/gstpipewireclock.c b/src/gst/gstpipewireclock.c index c13d91b1d..b5ec5027d 100644 --- a/src/gst/gstpipewireclock.c +++ b/src/gst/gstpipewireclock.c @@ -31,12 +31,13 @@ GST_DEBUG_CATEGORY_STATIC (gst_pipewire_clock_debug_category); G_DEFINE_TYPE (GstPipeWireClock, gst_pipewire_clock, GST_TYPE_SYSTEM_CLOCK); GstClock * -gst_pipewire_clock_new (struct pw_stream *stream) +gst_pipewire_clock_new (struct pw_stream *stream, GstClockTime last_time) { GstPipeWireClock *clock; clock = g_object_new (GST_TYPE_PIPEWIRE_CLOCK, NULL); clock->stream = stream; + clock->last_time = last_time; return GST_CLOCK_CAST (clock); } @@ -48,12 +49,12 @@ gst_pipewire_clock_get_internal_time (GstClock * clock) GstClockTime result; struct pw_time t; - pw_stream_get_time (pclock->stream, &t); + if (pclock->stream == NULL || + pw_stream_get_time (pclock->stream, &t) < 0 || + t.rate.num == 0) + return pclock->last_time; - if (t.rate.denom) - result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.denom, t.rate.num); - else - result = GST_CLOCK_TIME_NONE; + result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.denom, t.rate.num); GST_DEBUG ("%"PRId64", %d/%d %"PRId64, t.ticks, t.rate.num, t.rate.denom, result); diff --git a/src/gst/gstpipewireclock.h b/src/gst/gstpipewireclock.h index 3020c83c8..f847ce48b 100644 --- a/src/gst/gstpipewireclock.h +++ b/src/gst/gstpipewireclock.h @@ -46,6 +46,7 @@ struct _GstPipeWireClock { GstSystemClock parent; struct pw_stream *stream; + GstClockTime last_time; }; struct _GstPipeWireClockClass { @@ -54,8 +55,8 @@ struct _GstPipeWireClockClass { GType gst_pipewire_clock_get_type (void); -GstClock * gst_pipewire_clock_new (struct pw_stream *stream); - +GstClock * gst_pipewire_clock_new (struct pw_stream *stream, + GstClockTime last_time); G_END_DECLS diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 18ba270ac..145fd584c 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -1028,7 +1028,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) pwsrc); - pwsrc->clock = gst_pipewire_clock_new (pwsrc->stream); + pwsrc->clock = gst_pipewire_clock_new (pwsrc->stream, pwsrc->last_time); pw_thread_loop_unlock (pwsrc->main_loop); return TRUE; @@ -1071,7 +1071,13 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc) pw_remote_destroy (pwsrc->remote); pwsrc->remote = NULL; + pwsrc->last_time = gst_clock_get_time (pwsrc->clock); + + gst_element_post_message (GST_ELEMENT (pwsrc), + gst_message_new_clock_lost (GST_OBJECT_CAST (pwsrc), pwsrc->clock)); + GST_OBJECT_LOCK (pwsrc); + GST_PIPEWIRE_CLOCK (pwsrc->clock)->stream = NULL; g_clear_object (&pwsrc->clock); GST_OBJECT_UNLOCK (pwsrc); } diff --git a/src/gst/gstpipewiresrc.h b/src/gst/gstpipewiresrc.h index c8f718b91..613f888f0 100644 --- a/src/gst/gstpipewiresrc.h +++ b/src/gst/gstpipewiresrc.h @@ -82,6 +82,7 @@ struct _GstPipeWireSrc { GstPipeWirePool *pool; GQueue queue; GstClock *clock; + GstClockTime last_time; }; struct _GstPipeWireSrcClass { From d51fb8687b925895c064a9e1de5e0d0c00975125 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 15:20:25 +0200 Subject: [PATCH 032/155] deviceprovider: fix memory leaks Fix leaking of the node info and caps by tracking the proxy object and freeing our stuff when it is destroyed. --- src/gst/gstpipewiredeviceprovider.c | 192 ++++++++++++++-------------- 1 file changed, 97 insertions(+), 95 deletions(-) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index ad712850e..b6472d961 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -43,40 +43,6 @@ enum PROP_ID = 1, }; -static GstDevice * -gst_pipewire_device_new (uint32_t id, const gchar * device_name, - GstCaps * caps, const gchar *klass, - GstPipeWireDeviceType type, GstStructure *props) -{ - GstPipeWireDevice *gstdev; - const gchar *element = NULL; - - g_return_val_if_fail (device_name, NULL); - g_return_val_if_fail (caps, NULL); - - switch (type) { - case GST_PIPEWIRE_DEVICE_TYPE_SOURCE: - element = "pipewiresrc"; - break; - case GST_PIPEWIRE_DEVICE_TYPE_SINK: - element = "pipewiresink"; - break; - default: - g_assert_not_reached (); - break; - } - - gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE, - "display-name", device_name, "caps", caps, "device-class", klass, - "id", id, "properties", props, NULL); - - gstdev->id = id; - gstdev->type = type; - gstdev->element = element; - - return GST_DEVICE (gstdev); -} - static GstElement * gst_pipewire_device_create_element (GstDevice * device, const gchar * name) { @@ -199,7 +165,7 @@ struct pending { void *data; }; -struct registry_data { +struct remote_data { uint32_t seq; GstPipeWireDeviceProvider *self; struct pw_registry_proxy *registry; @@ -212,6 +178,7 @@ struct node_data { struct spa_list link; GstPipeWireDeviceProvider *self; struct pw_node_proxy *proxy; + struct spa_hook proxy_listener; uint32_t id; uint32_t parent_id; struct spa_hook node_listener; @@ -225,14 +192,14 @@ struct port_data { struct spa_list link; struct node_data *node_data; struct pw_port_proxy *proxy; + struct spa_hook proxy_listener; uint32_t id; struct spa_hook port_listener; - struct pw_port_info *info; struct pending pending; struct pending pending_param; }; -static struct node_data *find_node_data(struct registry_data *rd, uint32_t id) +static struct node_data *find_node_data(struct remote_data *rd, uint32_t id) { struct node_data *n; spa_list_for_each(n, &rd->nodes, link) { @@ -242,23 +209,6 @@ static struct node_data *find_node_data(struct registry_data *rd, uint32_t id) return NULL; } -static void free_node_data(struct registry_data *rd, struct node_data *nd) -{ - GstPipeWireDeviceProvider *self = rd->self; - GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); - - if (nd->dev != NULL) { - gst_device_provider_device_remove (provider, GST_DEVICE (nd->dev)); - gst_object_unref (nd->dev); - } - if (nd->caps) { - gst_caps_unref(nd->caps); - } - if (nd->info) - pw_node_info_free(nd->info); - spa_list_remove(&nd->link); -} - static GstDevice * new_node (GstPipeWireDeviceProvider *self, struct node_data *data) { @@ -266,11 +216,15 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data) const gchar *klass = NULL; GstPipeWireDeviceType type; const struct pw_node_info *info = data->info; + const gchar *element = NULL; + GstPipeWireDevice *gstdev; if (info->max_input_ports > 0 && info->max_output_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SINK; + element = "pipewiresink"; } else if (info->max_output_ports > 0 && info->max_input_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE; + element = "pipewiresrc"; } else { return NULL; } @@ -286,12 +240,17 @@ new_node (GstPipeWireDeviceProvider *self, struct node_data *data) if (klass == NULL) klass = "unknown/unknown"; - return gst_pipewire_device_new (data->id, - info->name, - data->caps, - klass, - type, - props); + gstdev = g_object_new (GST_TYPE_PIPEWIRE_DEVICE, + "display-name", info->name, "caps", data->caps, "device-class", klass, + "id", data->id, "properties", props, NULL); + + gstdev->id = data->id; + gstdev->type = type; + gstdev->element = element; + if (props) + gst_structure_free (props); + + return GST_DEVICE (gstdev); } static void do_add_node(void *data) @@ -340,9 +299,17 @@ get_core_info (struct pw_remote *remote, } } -static void add_pending(GstPipeWireDeviceProvider *self, struct pending *p) +static void init_pending(GstPipeWireDeviceProvider *self, struct pending *p) +{ + p->seq = SPA_ID_INVALID; +} + +static void add_pending(GstPipeWireDeviceProvider *self, struct pending *p, + void (*callback) (void *data), void *data) { spa_list_append(&self->pending, &p->link); + p->callback = callback; + p->data = data; p->seq = ++self->seq; pw_log_debug("add pending %d", p->seq); pw_core_proxy_sync(self->core_proxy, p->seq); @@ -406,12 +373,12 @@ static void port_event_info(void *data, struct pw_port_info *info) GstPipeWireDeviceProvider *self = node_data->self; struct pw_type *t = node_data->self->type; + pw_log_debug("%p", port_data); + if (info->change_mask & PW_PORT_CHANGE_MASK_ENUM_PARAMS) { pw_port_proxy_enum_params((struct pw_port_proxy*)port_data->proxy, t->param.idEnumFormat, 0, 0, NULL); - port_data->pending_param.callback = do_add_node; - port_data->pending_param.data = port_data; - add_pending(self, &port_data->pending_param); + add_pending(self, &port_data->pending_param, do_add_node, port_data); } } @@ -424,6 +391,8 @@ static void port_event_param(void *data, uint32_t id, uint32_t index, uint32_t n struct pw_type *t = self->type; GstCaps *c1; + pw_log_debug("%p", port_data); + c1 = gst_caps_from_format (param, t->map); if (c1 && node_data->caps) gst_caps_append (node_data->caps, c1); @@ -439,6 +408,7 @@ static const struct pw_port_proxy_events port_events = { static void node_event_info(void *data, struct pw_node_info *info) { struct node_data *node_data = data; + pw_log_debug("%p", node_data); node_data->info = pw_node_info_update(node_data->info, info); } @@ -447,12 +417,53 @@ static const struct pw_node_proxy_events node_events = { .info = node_event_info }; +static void +destroy_node_proxy (void *data) +{ + struct node_data *nd = data; + GstPipeWireDeviceProvider *self = nd->self; + GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); + + pw_log_debug("destroy %p", nd); + + remove_pending(&nd->pending); + + if (nd->dev != NULL) { + gst_device_provider_device_remove (provider, GST_DEVICE (nd->dev)); + } + if (nd->caps) + gst_caps_unref(nd->caps); + if (nd->info) + pw_node_info_free(nd->info); + + spa_list_remove(&nd->link); +} + +static const struct pw_proxy_events proxy_node_events = { + PW_VERSION_PROXY_EVENTS, + .destroy = destroy_node_proxy, +}; + +static void +destroy_port_proxy (void *data) +{ + struct port_data *pd = data; + pw_log_debug("destroy %p", pd); + remove_pending(&pd->pending); + remove_pending(&pd->pending_param); + spa_list_remove(&pd->link); +} + +static const struct pw_proxy_events proxy_port_events = { + PW_VERSION_PROXY_EVENTS, + .destroy = destroy_port_proxy, +}; static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version, const struct spa_dict *props) { - struct registry_data *rd = data; + struct remote_data *rd = data; GstPipeWireDeviceProvider *self = rd->self; struct node_data *nd; @@ -473,8 +484,8 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, u nd->caps = gst_caps_new_empty (); spa_list_append(&rd->nodes, &nd->link); pw_node_proxy_add_listener(node, &nd->node_listener, &node_events, nd); - nd->pending.callback = NULL; - add_pending(self, &nd->pending); + pw_proxy_add_listener((struct pw_proxy*)node, &nd->proxy_listener, &proxy_node_events, nd); + add_pending(self, &nd->pending, NULL, NULL); } else if (type == self->type->port) { struct pw_port_proxy *port; @@ -495,8 +506,9 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, u pd->id = id; spa_list_append(&rd->ports, &pd->link); pw_port_proxy_add_listener(port, &pd->port_listener, &port_events, pd); - pd->pending.callback = NULL; - add_pending(self, &pd->pending); + pw_proxy_add_listener((struct pw_proxy*)port, &pd->proxy_listener, &proxy_port_events, pd); + init_pending(self, &pd->pending_param); + add_pending(self, &pd->pending, NULL, NULL); } return; @@ -508,13 +520,6 @@ no_mem: static void registry_event_global_remove(void *data, uint32_t id) { - struct registry_data *rd = data; - struct node_data *nd; - - if ((nd = find_node_data(rd, id)) == NULL) - return; - - free_node_data(rd, nd); } static const struct pw_registry_proxy_events registry_events = { @@ -537,8 +542,7 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) struct pw_core *c = NULL; struct pw_type *t = NULL; struct pw_remote *r = NULL; - struct pw_registry_proxy *reg = NULL; - struct registry_data *data; + struct remote_data *data; struct spa_hook listener; GST_DEBUG_OBJECT (self, "starting probe"); @@ -551,9 +555,14 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) t = pw_core_get_type(c); - if (!(r = pw_remote_new (c, NULL, 0))) + if (!(r = pw_remote_new (c, NULL, sizeof(*data)))) goto failed; + data = pw_remote_get_user_data(r); + data->self = self; + spa_list_init(&data->nodes); + spa_list_init(&data->ports); + spa_list_init(&self->pending); self->seq = 1; pw_remote_add_listener(r, &listener, &remote_events, self); @@ -586,14 +595,8 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) self->devices = NULL; self->core_proxy = pw_remote_get_core_proxy(r); - reg = pw_core_proxy_get_registry(self->core_proxy, t->registry, PW_VERSION_REGISTRY, sizeof(*data)); - - data = pw_proxy_get_user_data((struct pw_proxy*)reg); - data->self = self; - data->registry = reg; - spa_list_init(&data->nodes); - spa_list_init(&data->ports); - pw_registry_proxy_add_listener(reg, &data->registry_listener, ®istry_events, data); + data->registry = pw_core_proxy_get_registry(self->core_proxy, t->registry, PW_VERSION_REGISTRY, 0); + pw_registry_proxy_add_listener(data->registry, &data->registry_listener, ®istry_events, data); pw_core_proxy_sync(self->core_proxy, ++self->seq); for (;;) { @@ -620,7 +623,7 @@ static gboolean gst_pipewire_device_provider_start (GstDeviceProvider * provider) { GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider); - struct registry_data *data; + struct remote_data *data; GST_DEBUG_OBJECT (self, "starting provider"); @@ -647,11 +650,14 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) pw_thread_loop_lock (self->main_loop); - if (!(self->remote = pw_remote_new (self->core, NULL, 0))) { + if (!(self->remote = pw_remote_new (self->core, NULL, sizeof(*data)))) { GST_ERROR_OBJECT (self, "Failed to create remote"); goto failed_remote; } - + data = pw_remote_get_user_data(self->remote); + data->self = self; + spa_list_init(&data->nodes); + spa_list_init(&data->ports); pw_remote_add_listener (self->remote, &self->remote_listener, &remote_events, self); pw_remote_connect (self->remote); @@ -677,13 +683,9 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) self->core_proxy = pw_remote_get_core_proxy(self->remote); self->registry = pw_core_proxy_get_registry(self->core_proxy, self->type->registry, - PW_VERSION_REGISTRY, sizeof(*data)); + PW_VERSION_REGISTRY, 0); - data = pw_proxy_get_user_data((struct pw_proxy*)self->registry); - data->self = self; data->registry = self->registry; - spa_list_init(&data->nodes); - spa_list_init(&data->ports); pw_registry_proxy_add_listener(self->registry, &data->registry_listener, ®istry_events, data); pw_core_proxy_sync(self->core_proxy, ++self->seq); From 6ba0ef7f2da61676471e150a132a9fc9a9c52707 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 15:46:28 +0200 Subject: [PATCH 033/155] stream: don't include stream.h twice Fixes #67 --- src/pipewire/stream.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index abd1e4846..a4d8b83f3 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -33,7 +33,6 @@ #include "pipewire/array.h" #include "pipewire/stream.h" #include "pipewire/utils.h" -#include "pipewire/stream.h" #include "extensions/client-node.h" /** \cond */ From 336fd190b4eb4642525991c2117418e64eb3f6b5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 15:46:48 +0200 Subject: [PATCH 034/155] pipewire: debug version in init --- src/pipewire/pipewire.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index b93008c0d..925e8af24 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -230,6 +230,7 @@ void pw_init(int *argc, char **argv[]) pw_log_set(iface); } } + pw_log_info("version %s", pw_get_library_version()); } /** Check if a debug category is enabled From d768a2d6dacbfab829e1369ace05d474a0a7d29e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 16:14:14 +0200 Subject: [PATCH 035/155] make spa-lib versioned Fixes #60 --- meson.build | 1 + pkgconfig/meson.build | 8 ++++---- spa/lib/meson.build | 2 +- spa/meson.build | 1 + 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/meson.build b/meson.build index d4b8b6e57..4a8714572 100644 --- a/meson.build +++ b/meson.build @@ -17,6 +17,7 @@ else pipewire_version_nano = 0 endif +spaversion = '0.1' apiversion = '0.2' soversion = 1 libversion = '@0@.@1@.0'.format(soversion, pipewire_version_minor.to_int() * 100 + pipewire_version_micro.to_int()) diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build index babd28968..9d5757846 100644 --- a/pkgconfig/meson.build +++ b/pkgconfig/meson.build @@ -11,13 +11,13 @@ pkgconf.set('VERSION', pipewire_version) pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) pkg_files = [ - 'libpipewire', - 'libspa', + [ 'libpipewire', apiversion ], + [ 'libspa', spaversion ], ] foreach p : pkg_files - infile = p + '.pc.in' - outfile = p + '-@0@.pc'.format(apiversion) + infile = p.get(0) + '.pc.in' + outfile = p.get(0) + '-@0@.pc'.format(p.get(1)) configure_file(input : infile, output : outfile, configuration : pkgconf, diff --git a/spa/lib/meson.build b/spa/lib/meson.build index 8f85ae484..7914759f8 100644 --- a/spa/lib/meson.build +++ b/spa/lib/meson.build @@ -8,7 +8,7 @@ install_headers(spalib_headers, subdir : 'spa/lib') spalib_sources = ['debug.c', 'pod.c' ] -spalib = shared_library('spa-lib', +spalib = shared_library('spa-lib-@0@'.format(spaversion), spalib_sources, version : libversion, soversion : soversion, diff --git a/spa/meson.build b/spa/meson.build index 74e92d2ba..6a76c275b 100644 --- a/spa/meson.build +++ b/spa/meson.build @@ -1,5 +1,6 @@ #project('spa', 'c') + alsa_dep = dependency('alsa') v4l2_dep = dependency('libv4l2') x11_dep = dependency('x11', required : false) From 872a1131fa4855938cceb062d73a4f8983782a1f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 17:17:23 +0200 Subject: [PATCH 036/155] pod: move compare and filter functions out of the library --- spa/include/spa/pod/compare.h | 167 +++++++++ spa/include/spa/pod/filter.h | 342 +++++++++++++++++++ spa/include/spa/pod/iter.h | 15 +- spa/lib/debug.c | 2 - spa/lib/meson.build | 4 +- spa/plugins/alsa/alsa-monitor.c | 3 +- spa/plugins/alsa/alsa-sink.c | 3 +- spa/plugins/alsa/alsa-source.c | 3 +- spa/plugins/alsa/alsa-utils.c | 3 +- spa/plugins/audiomixer/audiomixer.c | 3 +- spa/plugins/audiotestsrc/audiotestsrc.c | 3 +- spa/plugins/bluez5/a2dp-sink.c | 2 +- spa/plugins/bluez5/bluez5-monitor.c | 3 +- spa/plugins/ffmpeg/ffmpeg-dec.c | 3 +- spa/plugins/ffmpeg/ffmpeg-enc.c | 2 +- spa/plugins/test/fakesink.c | 3 +- spa/plugins/test/fakesrc.c | 3 +- spa/plugins/v4l2/v4l2-monitor.c | 3 +- spa/plugins/v4l2/v4l2-source.c | 4 +- spa/plugins/videotestsrc/videotestsrc.c | 3 +- spa/plugins/volume/volume.c | 3 +- src/modules/module-audio-dsp.c | 4 +- src/modules/module-client-node/client-node.c | 2 +- src/pipewire/global.c | 2 - src/pipewire/link.c | 2 +- src/pipewire/node.c | 1 - src/pipewire/remote.c | 1 - src/pipewire/stream.c | 1 - 28 files changed, 537 insertions(+), 53 deletions(-) create mode 100644 spa/include/spa/pod/compare.h create mode 100644 spa/include/spa/pod/filter.h diff --git a/spa/include/spa/pod/compare.h b/spa/include/spa/pod/compare.h new file mode 100644 index 000000000..23afe72cd --- /dev/null +++ b/spa/include/spa/pod/compare.h @@ -0,0 +1,167 @@ +/* Simple Plugin API + * Copyright (C) 2018 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 + +static inline int spa_pod_compare_value(enum spa_pod_type type, const void *r1, const void *r2) +{ + switch (type) { + case SPA_POD_TYPE_INVALID: + return 0; + case SPA_POD_TYPE_BOOL: + case SPA_POD_TYPE_ID: + return *(int32_t *) r1 == *(uint32_t *) r2 ? 0 : 1; + case SPA_POD_TYPE_INT: + return *(int32_t *) r1 - *(int32_t *) r2; + case SPA_POD_TYPE_LONG: + return *(int64_t *) r1 - *(int64_t *) r2; + case SPA_POD_TYPE_FLOAT: + return *(float *) r1 - *(float *) r2; + case SPA_POD_TYPE_DOUBLE: + return *(double *) r1 - *(double *) r2; + case SPA_POD_TYPE_STRING: + return strcmp(r1, r2); + case SPA_POD_TYPE_RECTANGLE: + { + const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1, + *rec2 = (struct spa_rectangle *) r2; + if (rec1->width == rec2->width && rec1->height == rec2->height) + return 0; + else if (rec1->width < rec2->width || rec1->height < rec2->height) + return -1; + else + return 1; + } + case SPA_POD_TYPE_FRACTION: + { + const struct spa_fraction *f1 = (struct spa_fraction *) r1, + *f2 = (struct spa_fraction *) r2; + int64_t n1, n2; + n1 = ((int64_t) f1->num) * f2->denom; + n2 = ((int64_t) f2->num) * f1->denom; + if (n1 < n2) + return -1; + else if (n1 > n2) + return 1; + else + return 0; + } + default: + break; + } + return 0; +} + +static inline int spa_pod_compare_part(const struct spa_pod *pod1, uint32_t pod1_size, + const struct spa_pod *pod2, uint32_t pod2_size) +{ + const struct spa_pod *p1, *p2; + int res; + + p2 = pod2; + + SPA_POD_FOREACH(pod1, pod1_size, p1) { + bool do_advance = true; + uint32_t recurse_offset = 0; + + if (p2 == NULL) + return -EINVAL; + + switch (SPA_POD_TYPE(p1)) { + case SPA_POD_TYPE_STRUCT: + case SPA_POD_TYPE_OBJECT: + if (SPA_POD_TYPE(p2) != SPA_POD_TYPE(p1)) + return -EINVAL; + + if (SPA_POD_TYPE(p1) == SPA_POD_TYPE_STRUCT) + recurse_offset = sizeof(struct spa_pod_struct); + else + recurse_offset = sizeof(struct spa_pod_object); + + do_advance = true; + break; + case SPA_POD_TYPE_PROP: + { + struct spa_pod_prop *pr1, *pr2; + void *a1, *a2; + + pr1 = (struct spa_pod_prop *) p1; + pr2 = spa_pod_contents_find_prop(pod2, pod2_size, pr1->body.key); + + if (pr2 == NULL) + return -EINVAL; + + /* incompatible property types */ + if (pr1->body.value.type != pr2->body.value.type) + return -EINVAL; + + if (pr1->body.flags & SPA_POD_PROP_FLAG_UNSET || + pr2->body.flags & SPA_POD_PROP_FLAG_UNSET) + return -EINVAL; + + a1 = SPA_MEMBER(pr1, sizeof(struct spa_pod_prop), void); + a2 = SPA_MEMBER(pr2, sizeof(struct spa_pod_prop), void); + + res = spa_pod_compare_value(pr1->body.value.type, a1, a2); + break; + } + default: + if (SPA_POD_TYPE(p1) != SPA_POD_TYPE(p2)) + return -EINVAL; + + res = spa_pod_compare_value(SPA_POD_TYPE(p1), SPA_POD_BODY(p1), SPA_POD_BODY(p2)); + do_advance = true; + break; + } + if (recurse_offset) { + res = spa_pod_compare_part(SPA_MEMBER(p1,recurse_offset,void), + SPA_POD_SIZE(p1) - recurse_offset, + SPA_MEMBER(p2,recurse_offset,void), + SPA_POD_SIZE(p2) - recurse_offset); + } + if (do_advance) { + p2 = spa_pod_next(p2); + if (!spa_pod_is_inside(pod2, pod2_size, p2)) + p2 = NULL; + } + if (res != 0) + return res; + } + if (p2 != NULL) + return -EINVAL; + + return 0; +} + +static inline int spa_pod_compare(const struct spa_pod *pod1, + const struct spa_pod *pod2) +{ + spa_return_val_if_fail(pod1 != NULL, -EINVAL); + spa_return_val_if_fail(pod2 != NULL, -EINVAL); + + return spa_pod_compare_part(pod1, SPA_POD_SIZE(pod1), pod2, SPA_POD_SIZE(pod2)); +} diff --git a/spa/include/spa/pod/filter.h b/spa/include/spa/pod/filter.h new file mode 100644 index 000000000..3aeb264ab --- /dev/null +++ b/spa/include/spa/pod/filter.h @@ -0,0 +1,342 @@ +/* Simple Plugin API + * Copyright (C) 2018 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 + +static inline void spa_pod_prop_fix_default(struct spa_pod_prop *prop) +{ + void *val = SPA_MEMBER(prop, sizeof(struct spa_pod_prop), void), + *alt = SPA_MEMBER(val, prop->body.value.size, void); + int i, nalt = SPA_POD_PROP_N_VALUES(prop) - 1; + + switch (prop->body.flags & SPA_POD_PROP_RANGE_MASK) { + case SPA_POD_PROP_RANGE_NONE: + break; + case SPA_POD_PROP_RANGE_MIN_MAX: + case SPA_POD_PROP_RANGE_STEP: + if (spa_pod_compare_value(prop->body.value.type, val, alt) < 0) + memcpy(val, alt, prop->body.value.size); + alt = SPA_MEMBER(alt, prop->body.value.size, void); + if (spa_pod_compare_value(prop->body.value.type, val, alt) > 0) + memcpy(val, alt, prop->body.value.size); + break; + case SPA_POD_PROP_RANGE_ENUM: + { + void *best = NULL; + + for (i = 0; i < nalt; i++) { + if (spa_pod_compare_value(prop->body.value.type, val, alt) == 0) { + best = alt; + break; + } + if (best == NULL) + best = alt; + alt = SPA_MEMBER(alt, prop->body.value.size, void); + } + if (best) + memcpy(val, best, prop->body.value.size); + + if (nalt <= 1) { + prop->body.flags &= ~SPA_POD_PROP_FLAG_UNSET; + prop->body.flags &= ~SPA_POD_PROP_RANGE_MASK; + prop->body.flags |= SPA_POD_PROP_RANGE_NONE; + } + break; + } + case SPA_POD_PROP_RANGE_FLAGS: + break; + } +} + +static inline int +spa_pod_filter_prop(struct spa_pod_builder *b, + const struct spa_pod_prop *p1, + const struct spa_pod_prop *p2) +{ + struct spa_pod_prop *np; + int nalt1, nalt2; + void *alt1, *alt2, *a1, *a2; + uint32_t rt1, rt2; + int j, k; + + /* incompatible property types */ + if (p1->body.value.type != p2->body.value.type) + return -EINVAL; + + rt1 = p1->body.flags & SPA_POD_PROP_RANGE_MASK; + rt2 = p2->body.flags & SPA_POD_PROP_RANGE_MASK; + + alt1 = SPA_MEMBER(p1, sizeof(struct spa_pod_prop), void); + nalt1 = SPA_POD_PROP_N_VALUES(p1); + alt2 = SPA_MEMBER(p2, sizeof(struct spa_pod_prop), void); + nalt2 = SPA_POD_PROP_N_VALUES(p2); + + if (p1->body.flags & SPA_POD_PROP_FLAG_UNSET) { + alt1 = SPA_MEMBER(alt1, p1->body.value.size, void); + nalt1--; + } else { + nalt1 = 1; + rt1 = SPA_POD_PROP_RANGE_NONE; + } + + if (p2->body.flags & SPA_POD_PROP_FLAG_UNSET) { + alt2 = SPA_MEMBER(alt2, p2->body.value.size, void); + nalt2--; + } else { + nalt2 = 1; + rt2 = SPA_POD_PROP_RANGE_NONE; + } + + /* start with copying the property */ + np = spa_pod_builder_deref(b, spa_pod_builder_push_prop(b, p1->body.key, 0)); + + /* default value */ + spa_pod_builder_raw(b, &p1->body.value, sizeof(p1->body.value) + p1->body.value.size); + + if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_NONE) || + (rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_ENUM) || + (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_NONE) || + (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_ENUM)) { + int n_copied = 0; + /* copy all equal values but don't copy the default value again */ + for (j = 0, a1 = alt1; j < nalt1; j++, a1 += p1->body.value.size) { + for (k = 0, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) { + if (spa_pod_compare_value(p1->body.value.type, a1, a2) == 0) { + if (rt1 == SPA_POD_PROP_RANGE_ENUM || j > 0) + spa_pod_builder_raw(b, a1, p1->body.value.size); + n_copied++; + } + } + } + if (n_copied == 0) + return -EINVAL; + np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; + } + + if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) || + (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_MIN_MAX)) { + int n_copied = 0; + /* copy all values inside the range */ + for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 += p1->body.value.size) { + if (spa_pod_compare_value(p1->body.value.type, a1, a2) < 0) + continue; + if (spa_pod_compare_value(p1->body.value.type, a1, a2 + p2->body.value.size) > 0) + continue; + spa_pod_builder_raw(b, a1, p1->body.value.size); + n_copied++; + } + if (n_copied == 0) + return -EINVAL; + np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; + } + + if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_STEP) || + (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_STEP)) { + return -ENOTSUP; + } + + if ((rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_NONE) || + (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_ENUM)) { + int n_copied = 0; + /* copy all values inside the range */ + for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) { + if (spa_pod_compare_value(p1->body.value.type, a2, a1) < 0) + continue; + if (spa_pod_compare_value(p1->body.value.type, a2, a1 + p1->body.value.size) > 0) + continue; + spa_pod_builder_raw(b, a2, p2->body.value.size); + n_copied++; + } + if (n_copied == 0) + return -EINVAL; + np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; + } + + if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) { + if (spa_pod_compare_value(p1->body.value.type, alt1, alt2) < 0) + spa_pod_builder_raw(b, alt2, p2->body.value.size); + else + spa_pod_builder_raw(b, alt1, p1->body.value.size); + + alt1 += p1->body.value.size; + alt2 += p2->body.value.size; + + if (spa_pod_compare_value(p1->body.value.type, alt1, alt2) < 0) + spa_pod_builder_raw(b, alt1, p1->body.value.size); + else + spa_pod_builder_raw(b, alt2, p2->body.value.size); + + np->body.flags |= SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET; + } + + if (rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_FLAGS) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_STEP) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_FLAGS) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_FLAGS) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_NONE) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_STEP) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_ENUM) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_FLAGS) + return -ENOTSUP; + + if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_NONE) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_STEP) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_ENUM) + return -ENOTSUP; + if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_FLAGS) + return -ENOTSUP; + + spa_pod_builder_pop(b); + spa_pod_prop_fix_default(np); + + return 0; +} + +static inline int spa_pod_filter_part(struct spa_pod_builder *b, + const struct spa_pod *pod, uint32_t pod_size, + const struct spa_pod *filter, uint32_t filter_size) +{ + const struct spa_pod *pp, *pf; + int res = 0; + + pf = filter; + + SPA_POD_FOREACH(pod, pod_size, pp) { + bool do_copy = false, do_advance = false; + uint32_t filter_offset = 0; + + switch (SPA_POD_TYPE(pp)) { + case SPA_POD_TYPE_STRUCT: + case SPA_POD_TYPE_OBJECT: + if (pf != NULL) { + if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp)) + return -EINVAL; + + if (SPA_POD_TYPE(pp) == SPA_POD_TYPE_STRUCT) { + filter_offset = sizeof(struct spa_pod_struct); + spa_pod_builder_push_struct(b); + } else { + struct spa_pod_object *p1 = (struct spa_pod_object *) pp; + filter_offset = sizeof(struct spa_pod_object); + spa_pod_builder_push_object(b, p1->body.id, p1->body.type); + } + do_advance = true; + } + else + do_copy = true; + break; + + case SPA_POD_TYPE_PROP: + { + struct spa_pod_prop *p1, *p2; + + p1 = (struct spa_pod_prop *) pp; + p2 = spa_pod_contents_find_prop(filter, filter_size, p1->body.key); + + if (p2 != NULL) + res = spa_pod_filter_prop(b, p1, p2); + else + do_copy = true; + break; + } + default: + if (pf != NULL) { + if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf)) + return -EINVAL; + if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0) + return -EINVAL; + do_advance = true; + } + do_copy = true; + break; + } + if (do_copy) + spa_pod_builder_raw_padded(b, pp, SPA_POD_SIZE(pp)); + else if (filter_offset) { + res = spa_pod_filter_part(b, + SPA_MEMBER(pp,filter_offset,void), + SPA_POD_SIZE(pp) - filter_offset, + SPA_MEMBER(pf,filter_offset,void), + SPA_POD_SIZE(pf) - filter_offset); + spa_pod_builder_pop(b); + } + if (do_advance) { + pf = spa_pod_next(pf); + if (!spa_pod_is_inside(filter, filter_size, pf)) + pf = NULL; + } + if (res < 0) + break; + } + return res; +} + +static inline int +spa_pod_filter(struct spa_pod_builder *b, + struct spa_pod **result, + const struct spa_pod *pod, + const struct spa_pod *filter) +{ + int res; + struct spa_pod_builder_state state; + + spa_return_val_if_fail(pod != NULL, -EINVAL); + spa_return_val_if_fail(b != NULL, -EINVAL); + + if (filter == NULL) { + *result = spa_pod_builder_deref(b, + spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod))); + return 0; + } + + spa_pod_builder_get_state(b, &state); + if ((res = spa_pod_filter_part(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter))) < 0) + spa_pod_builder_reset(b, &state); + else + *result = spa_pod_builder_deref(b, state.offset); + + return res; +} diff --git a/spa/include/spa/pod/iter.h b/spa/include/spa/pod/iter.h index 1e2bdeadd..ea0214074 100644 --- a/spa/include/spa/pod/iter.h +++ b/spa/include/spa/pod/iter.h @@ -74,9 +74,9 @@ static inline struct spa_pod *spa_pod_next(const struct spa_pod *iter) (iter) < SPA_MEMBER((body), (_size), __typeof__(*(iter))); \ (iter) = SPA_MEMBER((iter), (body)->child.size, __typeof__(*(iter)))) -#define SPA_POD_FOREACH(pod, size, iter) \ - for ((iter) = (pod); \ - spa_pod_is_inside(pod, size, iter); \ +#define SPA_POD_FOREACH(pod, size, iter) \ + for ((iter) = (pod); \ + spa_pod_is_inside(pod, size, iter); \ (iter) = spa_pod_next(iter)) #define SPA_POD_CONTENTS_FOREACH(pod, offset, iter) \ @@ -97,10 +97,10 @@ static inline struct spa_pod *spa_pod_next(const struct spa_pod *iter) (iter) = SPA_MEMBER((iter), (body)->value.size, __typeof__(*iter))) static inline struct spa_pod_prop *spa_pod_contents_find_prop(const struct spa_pod *pod, - uint32_t offset, uint32_t key) + uint32_t size, uint32_t key) { - struct spa_pod *res; - SPA_POD_CONTENTS_FOREACH(pod, offset, res) { + const struct spa_pod *res; + SPA_POD_FOREACH(pod, size, res) { if (res->type == SPA_POD_TYPE_PROP && ((struct spa_pod_prop *) res)->body.key == key) return (struct spa_pod_prop *) res; @@ -119,7 +119,8 @@ static inline struct spa_pod_prop *spa_pod_find_prop(const struct spa_pod *pod, else return NULL; - return spa_pod_contents_find_prop(pod, offset, key); + return spa_pod_contents_find_prop(SPA_MEMBER(pod, offset, const struct spa_pod), + SPA_POD_SIZE(pod) - offset, key); } static inline int spa_pod_fixate(struct spa_pod *pod) diff --git a/spa/lib/debug.c b/spa/lib/debug.c index c2665bac9..41759ce42 100644 --- a/spa/lib/debug.c +++ b/spa/lib/debug.c @@ -25,8 +25,6 @@ #include #include -#include - #include "debug.h" static const struct spa_type_map *map; diff --git a/spa/lib/meson.build b/spa/lib/meson.build index 7914759f8..81eb2dcce 100644 --- a/spa/lib/meson.build +++ b/spa/lib/meson.build @@ -1,12 +1,10 @@ spalib_headers = [ 'debug.h', - 'pod.h', ] install_headers(spalib_headers, subdir : 'spa/lib') -spalib_sources = ['debug.c', - 'pod.c' ] +spalib_sources = ['debug.c' ] spalib = shared_library('spa-lib-@0@'.format(spaversion), spalib_sources, diff --git a/spa/plugins/alsa/alsa-monitor.c b/spa/plugins/alsa/alsa-monitor.c index 08a4adfae..d8935cd75 100644 --- a/spa/plugins/alsa/alsa-monitor.c +++ b/spa/plugins/alsa/alsa-monitor.c @@ -30,10 +30,9 @@ #include #include #include +#include #include -#include - #define NAME "alsa-monitor" extern const struct spa_handle_factory spa_alsa_sink_factory; diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index fccd9b966..c31fe3e29 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -23,8 +23,7 @@ #include #include - -#include +#include #define NAME "alsa-sink" diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index 92f9a19c6..74bbb3c07 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -24,8 +24,7 @@ #include #include #include - -#include +#include #define NAME "alsa-source" diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c index dd3594613..1bc5aaa97 100644 --- a/spa/plugins/alsa/alsa-utils.c +++ b/spa/plugins/alsa/alsa-utils.c @@ -9,8 +9,7 @@ #include #include -#include -#include +#include #include "alsa-utils.h" diff --git a/spa/plugins/audiomixer/audiomixer.c b/spa/plugins/audiomixer/audiomixer.c index e61a40423..5c793ab75 100644 --- a/spa/plugins/audiomixer/audiomixer.c +++ b/spa/plugins/audiomixer/audiomixer.c @@ -30,8 +30,7 @@ #include #include #include - -#include +#include #include "mix-ops.h" diff --git a/spa/plugins/audiotestsrc/audiotestsrc.c b/spa/plugins/audiotestsrc/audiotestsrc.c index bf3d4b88f..7d527c04f 100644 --- a/spa/plugins/audiotestsrc/audiotestsrc.c +++ b/spa/plugins/audiotestsrc/audiotestsrc.c @@ -35,8 +35,7 @@ #include #include #include - -#include +#include #define NAME "audiotestsrc" diff --git a/spa/plugins/bluez5/a2dp-sink.c b/spa/plugins/bluez5/a2dp-sink.c index 1ff759797..2981dc4c9 100644 --- a/spa/plugins/bluez5/a2dp-sink.c +++ b/spa/plugins/bluez5/a2dp-sink.c @@ -36,8 +36,8 @@ #include #include #include +#include -#include #include #include "defs.h" diff --git a/spa/plugins/bluez5/bluez5-monitor.c b/spa/plugins/bluez5/bluez5-monitor.c index 2e65f1a1b..939aa70ed 100644 --- a/spa/plugins/bluez5/bluez5-monitor.c +++ b/spa/plugins/bluez5/bluez5-monitor.c @@ -33,10 +33,9 @@ #include #include #include +#include #include -#include - #include "a2dp-codecs.h" #include "defs.h" diff --git a/spa/plugins/ffmpeg/ffmpeg-dec.c b/spa/plugins/ffmpeg/ffmpeg-dec.c index 2b0a17585..74a571cda 100644 --- a/spa/plugins/ffmpeg/ffmpeg-dec.c +++ b/spa/plugins/ffmpeg/ffmpeg-dec.c @@ -28,8 +28,7 @@ #include #include #include - -#include +#include #define IS_VALID_PORT(this,d,id) ((id) == 0) #define GET_IN_PORT(this,p) (&this->in_ports[p]) diff --git a/spa/plugins/ffmpeg/ffmpeg-enc.c b/spa/plugins/ffmpeg/ffmpeg-enc.c index 62fa31cd5..899f6b4ee 100644 --- a/spa/plugins/ffmpeg/ffmpeg-enc.c +++ b/spa/plugins/ffmpeg/ffmpeg-enc.c @@ -28,8 +28,8 @@ #include #include #include +#include -#include #define IS_VALID_PORT(this,d,id) ((id) == 0) #define GET_IN_PORT(this,p) (&this->in_ports[p]) diff --git a/spa/plugins/test/fakesink.c b/spa/plugins/test/fakesink.c index b25b739cc..2ac51fe66 100644 --- a/spa/plugins/test/fakesink.c +++ b/spa/plugins/test/fakesink.c @@ -35,8 +35,7 @@ #include #include #include - -#include +#include #define NAME "fakesink" diff --git a/spa/plugins/test/fakesrc.c b/spa/plugins/test/fakesrc.c index dd8748c1c..c95bdd39c 100644 --- a/spa/plugins/test/fakesrc.c +++ b/spa/plugins/test/fakesrc.c @@ -35,8 +35,7 @@ #include #include #include - -#include +#include #define NAME "fakesrc" diff --git a/spa/plugins/v4l2/v4l2-monitor.c b/spa/plugins/v4l2/v4l2-monitor.c index 50789ff3a..cd0a97a1b 100644 --- a/spa/plugins/v4l2/v4l2-monitor.c +++ b/spa/plugins/v4l2/v4l2-monitor.c @@ -29,10 +29,9 @@ #include #include #include +#include #include -#include - #define NAME "v4l2-monitor" extern const struct spa_handle_factory spa_v4l2_source_factory; diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index 5835e3e03..f8a2b2732 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -35,9 +35,7 @@ #include #include #include - -#include -#include +#include #define NAME "v4l2-source" diff --git a/spa/plugins/videotestsrc/videotestsrc.c b/spa/plugins/videotestsrc/videotestsrc.c index fb5478958..f25e49831 100644 --- a/spa/plugins/videotestsrc/videotestsrc.c +++ b/spa/plugins/videotestsrc/videotestsrc.c @@ -35,8 +35,7 @@ #include #include #include - -#include +#include #define NAME "videotestsrc" diff --git a/spa/plugins/volume/volume.c b/spa/plugins/volume/volume.c index 7451c3ce3..578b4e18e 100644 --- a/spa/plugins/volume/volume.c +++ b/spa/plugins/volume/volume.c @@ -30,8 +30,7 @@ #include #include #include - -#include +#include #define NAME "volume" diff --git a/src/modules/module-audio-dsp.c b/src/modules/module-audio-dsp.c index 385906154..1b28c2d3b 100644 --- a/src/modules/module-audio-dsp.c +++ b/src/modules/module-audio-dsp.c @@ -27,9 +27,7 @@ #include #include #include - -#include -#include +#include #include "pipewire/core.h" #include "pipewire/link.h" diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index eeab73abf..27e703292 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -29,7 +29,7 @@ #include #include -#include +#include #include "pipewire/pipewire.h" #include "pipewire/interfaces.h" diff --git a/src/pipewire/global.c b/src/pipewire/global.c index 0e990247b..e349f67bf 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -22,8 +22,6 @@ #include #include -#include - #include #include #include diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 5862ef8a3..4654d09ad 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -22,10 +22,10 @@ #include #include +#include #include #include -#include #include "pipewire.h" #include "private.h" diff --git a/src/pipewire/node.c b/src/pipewire/node.c index d2ad2c2d5..425c94d67 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -23,7 +23,6 @@ #include #include -#include #include #include "pipewire/pipewire.h" diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 1c1ce1188..2ae8052de 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -25,7 +25,6 @@ #include #include -#include #include "pipewire/pipewire.h" #include "pipewire/private.h" diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index a4d8b83f3..b9ebbc9a8 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -25,7 +25,6 @@ #include #include "spa/utils/ringbuffer.h" -#include "spa/lib/debug.h" #include "pipewire/pipewire.h" #include "pipewire/private.h" From d3b9a52ec4eeab62daec515471471bc785b60ad2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 Aug 2018 17:22:55 +0200 Subject: [PATCH 037/155] don't link with spalib when we don't have to --- spa/plugins/alsa/meson.build | 1 - spa/plugins/audiomixer/meson.build | 1 - spa/plugins/audiotestsrc/meson.build | 1 - spa/plugins/bluez5/meson.build | 1 - spa/plugins/ffmpeg/meson.build | 1 - spa/plugins/test/meson.build | 1 - spa/plugins/v4l2/meson.build | 1 - spa/plugins/videotestsrc/meson.build | 1 - spa/plugins/volume/meson.build | 1 - src/modules/meson.build | 8 -------- src/modules/spa/meson.build | 3 --- 11 files changed, 20 deletions(-) diff --git a/spa/plugins/alsa/meson.build b/spa/plugins/alsa/meson.build index b6b38c059..c45160e45 100644 --- a/spa/plugins/alsa/meson.build +++ b/spa/plugins/alsa/meson.build @@ -8,6 +8,5 @@ spa_alsa = shared_library('spa-alsa', spa_alsa_sources, include_directories : [spa_inc, spa_libinc], dependencies : [ alsa_dep, libudev_dep ], - link_with : spalib, install : true, install_dir : '@0@/spa/alsa'.format(get_option('libdir'))) diff --git a/spa/plugins/audiomixer/meson.build b/spa/plugins/audiomixer/meson.build index a9c8dd316..444145ffb 100644 --- a/spa/plugins/audiomixer/meson.build +++ b/spa/plugins/audiomixer/meson.build @@ -3,6 +3,5 @@ audiomixer_sources = ['audiomixer.c', 'mix-ops.c', 'plugin.c'] audiomixerlib = shared_library('spa-audiomixer', audiomixer_sources, include_directories : [spa_inc, spa_libinc], - link_with : spalib, install : true, install_dir : '@0@/spa/audiomixer/'.format(get_option('libdir'))) diff --git a/spa/plugins/audiotestsrc/meson.build b/spa/plugins/audiotestsrc/meson.build index b68da31d6..8553511bf 100644 --- a/spa/plugins/audiotestsrc/meson.build +++ b/spa/plugins/audiotestsrc/meson.build @@ -4,6 +4,5 @@ audiotestsrclib = shared_library('spa-audiotestsrc', audiotestsrc_sources, include_directories : [spa_inc, spa_libinc], dependencies : mathlib, - link_with : spalib, install : true, install_dir : '@0@/spa/audiotestsrc'.format(get_option('libdir'))) diff --git a/spa/plugins/bluez5/meson.build b/spa/plugins/bluez5/meson.build index 53888285f..a96f60164 100644 --- a/spa/plugins/bluez5/meson.build +++ b/spa/plugins/bluez5/meson.build @@ -7,6 +7,5 @@ bluez5lib = shared_library('spa-bluez5', bluez5_sources, include_directories : [ spa_inc, spa_libinc ], dependencies : [ dbus_dep, sbc_dep ], - link_with : spalib, install : true, install_dir : '@0@/spa/bluez5'.format(get_option('libdir'))) diff --git a/spa/plugins/ffmpeg/meson.build b/spa/plugins/ffmpeg/meson.build index deacdf03d..9769c5df9 100644 --- a/spa/plugins/ffmpeg/meson.build +++ b/spa/plugins/ffmpeg/meson.build @@ -6,6 +6,5 @@ ffmpeglib = shared_library('spa-ffmpeg', ffmpeg_sources, include_directories : [spa_inc, spa_libinc], dependencies : [ avcodec_dep, avformat_dep ], - link_with : spalib, install : true, install_dir : '@0@/spa/ffmpeg'.format(get_option('libdir'))) diff --git a/spa/plugins/test/meson.build b/spa/plugins/test/meson.build index 0f1fc2b22..c3c1f3483 100644 --- a/spa/plugins/test/meson.build +++ b/spa/plugins/test/meson.build @@ -4,6 +4,5 @@ testlib = shared_library('spa-test', test_sources, include_directories : [ spa_inc, spa_libinc], dependencies : threads_dep, - link_with : spalib, install : true, install_dir : '@0@/spa/test'.format(get_option('libdir'))) diff --git a/spa/plugins/v4l2/meson.build b/spa/plugins/v4l2/meson.build index 1d82379cb..fadfafd57 100644 --- a/spa/plugins/v4l2/meson.build +++ b/spa/plugins/v4l2/meson.build @@ -6,6 +6,5 @@ v4l2lib = shared_library('spa-v4l2', v4l2_sources, include_directories : [ spa_inc, spa_libinc ], dependencies : [ v4l2_dep, libudev_dep ], - link_with : spalib, install : true, install_dir : '@0@/spa/v4l2'.format(get_option('libdir'))) diff --git a/spa/plugins/videotestsrc/meson.build b/spa/plugins/videotestsrc/meson.build index 1db13b449..134fdaa00 100644 --- a/spa/plugins/videotestsrc/meson.build +++ b/spa/plugins/videotestsrc/meson.build @@ -4,6 +4,5 @@ videotestsrclib = shared_library('spa-videotestsrc', videotestsrc_sources, include_directories : [ spa_inc, spa_libinc], dependencies : threads_dep, - link_with : spalib, install : true, install_dir : '@0@/spa/videotestsrc'.format(get_option('libdir'))) diff --git a/spa/plugins/volume/meson.build b/spa/plugins/volume/meson.build index f21d94ab6..dff1f2d47 100644 --- a/spa/plugins/volume/meson.build +++ b/spa/plugins/volume/meson.build @@ -3,6 +3,5 @@ volume_sources = ['volume.c', 'plugin.c'] volumelib = shared_library('spa-volume', volume_sources, include_directories : [spa_inc, spa_libinc], - link_with : spalib, install : true, install_dir : '@0@/spa/volume'.format(get_option('libdir'))) diff --git a/src/modules/meson.build b/src/modules/meson.build index 33db36407..e693545ef 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -9,7 +9,6 @@ if dbus_dep.found() pipewire_module_flatpak = shared_library('pipewire-module-flatpak', [ 'module-flatpak.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], @@ -18,7 +17,6 @@ pipewire_module_flatpak = shared_library('pipewire-module-flatpak', [ 'module-fl pipewire_module_rtkit = shared_library('pipewire-module-rtkit', [ 'module-rtkit.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [dbus_dep, mathlib, dl_lib, pipewire_dep], @@ -28,7 +26,6 @@ endif pipewire_module_autolink = shared_library('pipewire-module-autolink', [ 'module-autolink.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -38,7 +35,6 @@ pipewire_module_mixer = shared_library('pipewire-module-mixer', [ 'module-mixer.c', 'spa/spa-node.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -53,7 +49,6 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node', 'spa/spa-node.c', ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -63,7 +58,6 @@ pipewire_module_link_factory = shared_library('pipewire-module-link-factory', [ 'module-link-factory.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -96,7 +90,6 @@ pipewire_module_audio_dsp = shared_library('pipewire-module-audio-dsp', [ 'module-audio-dsp.c', 'spa/spa-node.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, rt_lib, pipewire_dep], @@ -105,7 +98,6 @@ pipewire_module_audio_dsp = shared_library('pipewire-module-audio-dsp', pipewire_module_suspend_on_idle = shared_library('pipewire-module-suspend-on-idle', [ 'module-suspend-on-idle.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], diff --git a/src/modules/spa/meson.build b/src/modules/spa/meson.build index e0a37280c..210a3bd3e 100644 --- a/src/modules/spa/meson.build +++ b/src/modules/spa/meson.build @@ -7,7 +7,6 @@ pipewire_module_spa_monitor = shared_library('pipewire-module-spa-monitor', [ 'module-monitor.c', 'spa-monitor.c', 'spa-node.c' ], c_args : pipewire_module_spa_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -17,7 +16,6 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node', [ 'module-node.c', 'spa-node.c' ], c_args : pipewire_module_spa_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], @@ -27,7 +25,6 @@ pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-fact [ 'module-node-factory.c', 'spa-node.c' ], c_args : pipewire_module_spa_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], From 9d36b85dd67d930477d6e09caf81812b55c8154b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Aug 2018 12:33:53 +0200 Subject: [PATCH 038/155] remove spalib --- pkgconfig/libspa.pc.in | 3 - spa/include/spa/debug/buffer.h | 91 ++++ spa/{lib/pod.h => include/spa/debug/dict.h} | 36 +- .../debug.h => include/spa/debug/format.h} | 34 +- spa/include/spa/debug/mem.h | 54 ++ spa/include/spa/debug/node.h | 52 ++ spa/include/spa/debug/pod.h | 206 ++++++++ spa/include/spa/support/log.h | 4 +- spa/lib/debug.c | 460 ---------------- spa/lib/meson.build | 18 - spa/lib/pod.c | 491 ------------------ spa/meson.build | 2 - spa/plugins/alsa/meson.build | 2 +- spa/plugins/audiomixer/meson.build | 2 +- spa/plugins/audiotestsrc/meson.build | 2 +- spa/plugins/bluez5/meson.build | 2 +- spa/plugins/ffmpeg/meson.build | 2 +- spa/plugins/support/meson.build | 4 +- spa/plugins/test/meson.build | 2 +- spa/plugins/v4l2/meson.build | 2 +- spa/plugins/videotestsrc/meson.build | 2 +- spa/plugins/volume/meson.build | 2 +- spa/tests/meson.build | 35 +- spa/tests/test-bluez5.c | 5 +- spa/tests/test-control.c | 10 +- spa/tests/test-graph.c | 10 +- spa/tests/test-props.c | 19 +- spa/tests/test-props2.c | 8 +- spa/tests/test-props5.c | 9 +- spa/tests/test-ringbuffer.c | 2 - spa/tests/test-v4l2.c | 2 - spa/tools/meson.build | 6 +- spa/tools/spa-inspect.c | 21 +- spa/tools/spa-monitor.c | 10 +- src/examples/export-sink.c | 6 +- src/examples/export-source.c | 5 +- src/examples/export-spa.c | 2 - src/examples/local-v4l2.c | 6 +- src/examples/video-play.c | 6 +- src/modules/meson.build | 2 - src/modules/module-protocol-native.c | 10 +- .../module-protocol-native/connection.c | 9 +- .../module-protocol-native/connection.h | 2 +- src/pipewire/core.c | 12 +- src/pipewire/link.c | 18 +- src/pipewire/log.h | 4 +- src/pipewire/meson.build | 3 +- src/tools/pipewire-cli.c | 16 +- src/tools/pipewire-monitor.c | 17 +- 49 files changed, 566 insertions(+), 1162 deletions(-) create mode 100644 spa/include/spa/debug/buffer.h rename spa/{lib/pod.h => include/spa/debug/dict.h} (61%) rename spa/{lib/debug.h => include/spa/debug/format.h} (58%) create mode 100644 spa/include/spa/debug/mem.h create mode 100644 spa/include/spa/debug/node.h create mode 100644 spa/include/spa/debug/pod.h delete mode 100644 spa/lib/debug.c delete mode 100644 spa/lib/meson.build delete mode 100644 spa/lib/pod.c diff --git a/pkgconfig/libspa.pc.in b/pkgconfig/libspa.pc.in index b327cf010..e5878d2d8 100644 --- a/pkgconfig/libspa.pc.in +++ b/pkgconfig/libspa.pc.in @@ -1,10 +1,7 @@ prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ includedir=@includedir@/ Name: libspa Description: Simple Plugin API Version: @VERSION@ -Libs: -L${libdir} -lspa-lib Cflags: -I${includedir} -D_REENTRANT diff --git a/spa/include/spa/debug/buffer.h b/spa/include/spa/debug/buffer.h new file mode 100644 index 000000000..f90a0cfef --- /dev/null +++ b/spa/include/spa/debug/buffer.h @@ -0,0 +1,91 @@ +/* Simple Plugin API + * Copyright (C) 2018 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_DEBUG_BUFFER_H__ +#define __SPA_DEBUG_BUFFER_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) +#endif + +static inline int spa_debug_buffer(int indent, + struct spa_type_map *map, const struct spa_buffer *buffer) +{ + int i; + + spa_debug("%*s" "struct spa_buffer %p:", indent, "", buffer); + spa_debug("%*s" " id: %08X", indent, "", buffer->id); + spa_debug("%*s" " n_metas: %u (at %p)", indent, "", buffer->n_metas, buffer->metas); + for (i = 0; i < buffer->n_metas; i++) { + struct spa_meta *m = &buffer->metas[i]; + const char *type_name; + + type_name = spa_type_map_get_type(map, m->type); + spa_debug("%*s" " meta %d: type %d (%s), data %p, size %d:", indent, "", i, m->type, + type_name, m->data, m->size); + + if (!strcmp(type_name, SPA_TYPE_META__Header)) { + struct spa_meta_header *h = m->data; + spa_debug("%*s" " struct spa_meta_header:", indent, ""); + spa_debug("%*s" " flags: %08x", indent, "", h->flags); + spa_debug("%*s" " seq: %u", indent, "", h->seq); + spa_debug("%*s" " pts: %" PRIi64, indent, "", h->pts); + spa_debug("%*s" " dts_offset: %" PRIi64, indent, "", h->dts_offset); + } else if (!strcmp(type_name, SPA_TYPE_META__VideoCrop)) { + struct spa_meta_video_crop *h = m->data; + spa_debug("%*s" " struct spa_meta_video_crop:", indent, ""); + spa_debug("%*s" " x: %d", indent, "", h->x); + spa_debug("%*s" " y: %d", indent, "", h->y); + spa_debug("%*s" " width: %d", indent, "", h->width); + spa_debug("%*s" " height: %d", indent, "", h->height); + } else { + spa_debug("%*s" " Unknown:", indent, ""); + spa_debug_mem(5, m->data, m->size); + } + } + spa_debug("%*s" " n_datas: \t%u (at %p)", indent, "", buffer->n_datas, buffer->datas); + for (i = 0; i < buffer->n_datas; i++) { + struct spa_data *d = &buffer->datas[i]; + spa_debug("%*s" " type: %d (%s)", indent, "", d->type, + spa_type_map_get_type(map, d->type)); + spa_debug("%*s" " flags: %d", indent, "", d->flags); + spa_debug("%*s" " data: %p", indent, "", d->data); + spa_debug("%*s" " fd: %d", indent, "", d->fd); + spa_debug("%*s" " offset: %d", indent, "", d->mapoffset); + spa_debug("%*s" " maxsize: %u", indent, "", d->maxsize); + spa_debug("%*s" " chunk: %p", indent, "", d->chunk); + spa_debug("%*s" " offset: %d", indent, "", d->chunk->offset); + spa_debug("%*s" " size: %u", indent, "", d->chunk->size); + spa_debug("%*s" " stride: %d", indent, "", d->chunk->stride); + } + return 0; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_DEBUG_BUFFER_H__ */ diff --git a/spa/lib/pod.h b/spa/include/spa/debug/dict.h similarity index 61% rename from spa/lib/pod.h rename to spa/include/spa/debug/dict.h index b7cdecd59..18ebdb2a0 100644 --- a/spa/lib/pod.h +++ b/spa/include/spa/debug/dict.h @@ -1,5 +1,5 @@ /* Simple Plugin API - * Copyright (C) 2017 Wim Taymans + * Copyright (C) 2018 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,26 +17,30 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __SPA_LIBPOD_H__ -#define __SPA_LIBPOD_H__ +#ifndef __SPA_DEBUG_DICT_H__ +#define __SPA_DEBUG_DICT_H__ #ifdef __cplusplus extern "C" { #endif -#include -#include +#include -int spa_pod_filter(struct spa_pod_builder *b, - struct spa_pod **result, - const struct spa_pod *pod, - const struct spa_pod *filter); - -int spa_pod_compare(const struct spa_pod *pod1, - const struct spa_pod *pod2); - -#ifdef __cplusplus -} /* extern "C" */ +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) #endif -#endif /* __SPA_LIBPOD_H__ */ +static inline int spa_debug_dict(int indent, const struct spa_dict *dict) +{ + const struct spa_dict_item *item; + spa_dict_for_each(item, dict) { + spa_debug("%*s%s = \"%s\"", indent, "", item->key, item->value); + } + return 0; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_DEBUG_DICT_H__ */ diff --git a/spa/lib/debug.h b/spa/include/spa/debug/format.h similarity index 58% rename from spa/lib/debug.h rename to spa/include/spa/debug/format.h index 7ec6c97c2..ef57c7fec 100644 --- a/spa/lib/debug.h +++ b/spa/include/spa/debug/format.h @@ -1,5 +1,5 @@ /* Simple Plugin API - * Copyright (C) 2016 Wim Taymans + * Copyright (C) 2018 Wim Taymans * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -17,26 +17,32 @@ * Boston, MA 02110-1301, USA. */ -#ifndef __SPA_LIBDEBUG_H__ -#define __SPA_LIBDEBUG_H__ +#ifndef __SPA_DEBUG_FORMAT_H__ +#define __SPA_DEBUG_FORMAT_H__ #ifdef __cplusplus extern "C" { #endif -#include -#include +#include +#include +#include -void spa_debug_set_type_map(const struct spa_type_map *map); +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) +#endif -int spa_debug_port_info(const struct spa_port_info *info); -int spa_debug_buffer(const struct spa_buffer *buffer); -#define SPA_DEBUG_FLAG_FORMAT (1 << 0) -int spa_debug_pod(const struct spa_pod *pod, uint32_t flags); -int spa_debug_dump_mem(const void *data, size_t size); -int spa_debug_dict(const struct spa_dict *dict); +static inline int spa_debug_format(int indent, + struct spa_type_map *map, const struct spa_pod *pod) +{ + return spa_debug_pod_value(indent, map, + SPA_POD_TYPE(pod), + SPA_POD_BODY(pod), + SPA_POD_BODY_SIZE(pod)); +} #ifdef __cplusplus -} /* extern "C" */ +} /* extern "C" */ #endif -#endif /* __SPA_LIBDEBUG_H__ */ + +#endif /* __SPA_DEBUG_FORMAT_H__ */ diff --git a/spa/include/spa/debug/mem.h b/spa/include/spa/debug/mem.h new file mode 100644 index 000000000..f619e06e3 --- /dev/null +++ b/spa/include/spa/debug/mem.h @@ -0,0 +1,54 @@ +/* Simple Plugin API + * Copyright (C) 2018 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_DEBUG_MEM_H__ +#define __SPA_DEBUG_MEM_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) +#endif + +static inline int spa_debug_mem(int indent, const void *data, size_t size) +{ + const uint8_t *t = data; + char buffer[512]; + int i, pos = 0; + + for (i = 0; i < size; i++) { + if (i % 16 == 0) + pos = sprintf(buffer, "%p: ", &t[i]); + pos += sprintf(buffer + pos, "%02x ", t[i]); + if (i % 16 == 15 || i == size - 1) { + spa_debug("%*s" "%s", indent, "", buffer); + } + } + return 0; +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_DEBUG_MEM_H__ */ diff --git a/spa/include/spa/debug/node.h b/spa/include/spa/debug/node.h new file mode 100644 index 000000000..5038daa0e --- /dev/null +++ b/spa/include/spa/debug/node.h @@ -0,0 +1,52 @@ +/* Simple Plugin API + * Copyright (C) 2018 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_DEBUG_NODE_H__ +#define __SPA_DEBUG_NODE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) +#endif + +int spa_debug_port_info(int indent, const struct spa_port_info *info) +{ + spa_debug("%*s" "struct spa_port_info %p:", indent, "", info); + spa_debug("%*s" " flags: \t%08x", indent, "", info->flags); + spa_debug("%*s" " rate: \t%u", indent, "", info->rate); + spa_debug("%*s" " props:", indent, ""); + if (info->props) + spa_debug_dict(indent + 2, info->props); + else + spa_debug("%*s" " none", indent, ""); + return 0; +} + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_DEBUG_NODE_H__ */ diff --git a/spa/include/spa/debug/pod.h b/spa/include/spa/debug/pod.h new file mode 100644 index 000000000..5a2d4c9e9 --- /dev/null +++ b/spa/include/spa/debug/pod.h @@ -0,0 +1,206 @@ +/* Simple Plugin API + * Copyright (C) 2018 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_DEBUG_POD_H__ +#define __SPA_DEBUG_POD_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include +#include + +#ifndef spa_debug +#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) +#endif + +static inline int +spa_debug_pod_value(int indent, struct spa_type_map *map, + uint32_t type, void *body, uint32_t size) +{ + switch (type) { + case SPA_POD_TYPE_BOOL: + spa_debug("%*s" "Bool %d", indent, "", *(int32_t *) body); + break; + case SPA_POD_TYPE_ID: + spa_debug("%*s" "Id %d %s", indent, "", *(int32_t *) body, + spa_type_map_get_type(map, *(int32_t *) body)); + break; + case SPA_POD_TYPE_INT: + spa_debug("%*s" "Int %d", indent, "", *(int32_t *) body); + break; + case SPA_POD_TYPE_LONG: + spa_debug("%*s" "Long %" PRIi64 "", indent, "", *(int64_t *) body); + break; + case SPA_POD_TYPE_FLOAT: + spa_debug("%*s" "Float %f", indent, "", *(float *) body); + break; + case SPA_POD_TYPE_DOUBLE: + spa_debug("%*s" "Double %f", indent, "", *(double *) body); + break; + case SPA_POD_TYPE_STRING: + spa_debug("%*s" "String \"%s\"", indent, "", (char *) body); + break; + case SPA_POD_TYPE_FD: + spa_debug("%*s" "Fd %d", indent, "", *(int *) body); + break; + case SPA_POD_TYPE_POINTER: + { + struct spa_pod_pointer_body *b = body; + spa_debug("%*s" "Pointer %s %p", indent, "", + map ? spa_type_map_get_type(map, b->type) : "*no map*", b->value); + break; + } + case SPA_POD_TYPE_RECTANGLE: + { + struct spa_rectangle *r = body; + spa_debug("%*s" "Rectangle %dx%d", indent, "", r->width, r->height); + break; + } + case SPA_POD_TYPE_FRACTION: + { + struct spa_fraction *f = body; + spa_debug("%*s" "Fraction %d/%d", indent, "", f->num, f->denom); + break; + } + case SPA_POD_TYPE_BITMAP: + spa_debug("%*s" "Bitmap", indent, ""); + break; + case SPA_POD_TYPE_ARRAY: + { + struct spa_pod_array_body *b = body; + void *p; + spa_debug("%*s" "Array: child.size %d, child.type %d", indent, "", + b->child.size, b->child.type); + + SPA_POD_ARRAY_BODY_FOREACH(b, size, p) + spa_debug_pod_value(indent + 2, map, b->child.type, p, b->child.size); + break; + } + case SPA_POD_TYPE_STRUCT: + { + struct spa_pod *b = body, *p; + spa_debug("%*s" "Struct: size %d", indent, "", size); + SPA_POD_FOREACH(b, size, p) + spa_debug_pod_value(indent + 2, map, p->type, SPA_POD_BODY(p), p->size); + break; + } + case SPA_POD_TYPE_OBJECT: + { + struct spa_pod_object_body *b = body; + struct spa_pod *p; + + spa_debug("%*s" "Object: size %d, id %s, type %s", indent, "", size, + map ? spa_type_map_get_type(map, b->id) : "*no map*", + map ? spa_type_map_get_type(map, b->type) : "*no map*"); + SPA_POD_OBJECT_BODY_FOREACH(b, size, p) + spa_debug_pod_value(indent + 2, map, p->type, SPA_POD_BODY(p), p->size); + break; + } + case SPA_POD_TYPE_PROP: + { + struct spa_pod_prop_body *b = body; + void *alt; + int i; + + spa_debug("%*s" "Prop: key %s, flags %d", indent, "", + map ? spa_type_map_get_type(map, b->key) : "*no map*", b->flags); + if (b->flags & SPA_POD_PROP_FLAG_UNSET) + spa_debug("%*s" "Unset (Default):", indent + 2, ""); + else + spa_debug("%*s" "Value: size %u", indent + 2, "", b->value.size); + spa_debug_pod_value(indent + 4, map, b->value.type, SPA_POD_BODY(&b->value), + b->value.size); + + i = 0; + switch (b->flags & SPA_POD_PROP_RANGE_MASK) { + case SPA_POD_PROP_RANGE_NONE: + break; + case SPA_POD_PROP_RANGE_MIN_MAX: + SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { + if (i == 0) + spa_debug("%*s" "Min: ", indent + 2, ""); + else if (i == 1) + spa_debug("%*s" "Max: ", indent + 2, ""); + else + break; + spa_debug_pod_value(indent + 4, map, b->value.type, alt, b->value.size); + i++; + } + break; + case SPA_POD_PROP_RANGE_STEP: + SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { + if (i == 0) + spa_debug("%*s" "Min: ", indent + 2, ""); + else if (i == 1) + spa_debug("%*s" "Max: ", indent + 2, ""); + else if (i == 2) + spa_debug("%*s" "Step: ", indent + 2, ""); + else + break; + spa_debug_pod_value(indent + 4, map, b->value.type, alt, b->value.size); + i++; + } + break; + case SPA_POD_PROP_RANGE_ENUM: + SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { + if (i == 0) { + spa_debug("%*s" "Enum:", indent + 2, ""); + } + spa_debug_pod_value(indent + 4, map, b->value.type, alt, b->value.size); + i++; + } + break; + case SPA_POD_PROP_RANGE_FLAGS: + break; + } + break; + } + case SPA_POD_TYPE_BYTES: + spa_debug("%*s" "Bytes", indent, ""); + spa_debug_mem(indent + 2, body, size); + break; + case SPA_POD_TYPE_NONE: + spa_debug("%*s" "None", indent, ""); + spa_debug_mem(indent + 2, body, size); + break; + default: + spa_debug("%*s" "unhandled POD type %d", indent, "", type); + break; + } + return 0; +} + +static inline int spa_debug_pod(int indent, + struct spa_type_map *map, const struct spa_pod *pod) +{ + return spa_debug_pod_value(indent, map, + SPA_POD_TYPE(pod), + SPA_POD_BODY(pod), + SPA_POD_BODY_SIZE(pod)); +} + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* __SPA_DEBUG_POD_H__ */ diff --git a/spa/include/spa/support/log.h b/spa/include/spa/support/log.h index 57e2b01f1..ec4b5d1b9 100644 --- a/spa/include/spa/support/log.h +++ b/spa/include/spa/support/log.h @@ -102,8 +102,10 @@ struct spa_log { (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define spa_log_log(l,lev,...) \ +({ \ if (SPA_UNLIKELY (spa_log_level_enabled (l, lev))) \ - (l)->log((l),lev,__VA_ARGS__) + (l)->log((l),lev,__VA_ARGS__); \ +}) #define spa_log_error(l,...) spa_log_log(l,SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__) #define spa_log_warn(l,...) spa_log_log(l,SPA_LOG_LEVEL_WARN,__FILE__,__LINE__,__func__,__VA_ARGS__) diff --git a/spa/lib/debug.c b/spa/lib/debug.c deleted file mode 100644 index 41759ce42..000000000 --- a/spa/lib/debug.c +++ /dev/null @@ -1,460 +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 - -#include "debug.h" - -static const struct spa_type_map *map; - -void spa_debug_set_type_map(const struct spa_type_map *m) -{ - map = m; -} - -int spa_debug_port_info(const struct spa_port_info *info) -{ - if (info == NULL) - return -EINVAL; - - fprintf(stderr, "struct spa_port_info %p:\n", info); - fprintf(stderr, " flags: \t%08x\n", info->flags); - - return 0; -} - -int spa_debug_buffer(const struct spa_buffer *buffer) -{ - int i; - - if (buffer == NULL) - return -EINVAL; - - fprintf(stderr, "spa_buffer %p:\n", buffer); - fprintf(stderr, " id: %08X\n", buffer->id); - fprintf(stderr, " n_metas: %u (at %p)\n", buffer->n_metas, buffer->metas); - for (i = 0; i < buffer->n_metas; i++) { - struct spa_meta *m = &buffer->metas[i]; - const char *type_name; - - type_name = spa_type_map_get_type(map, m->type); - fprintf(stderr, " meta %d: type %d (%s), data %p, size %d:\n", i, m->type, - type_name, m->data, m->size); - - if (!strcmp(type_name, SPA_TYPE_META__Header)) { - struct spa_meta_header *h = m->data; - fprintf(stderr, " struct spa_meta_header:\n"); - fprintf(stderr, " flags: %08x\n", h->flags); - fprintf(stderr, " seq: %u\n", h->seq); - fprintf(stderr, " pts: %" PRIi64 "\n", h->pts); - fprintf(stderr, " dts_offset: %" PRIi64 "\n", h->dts_offset); - } else if (!strcmp(type_name, SPA_TYPE_META__VideoCrop)) { - struct spa_meta_video_crop *h = m->data; - fprintf(stderr, " struct spa_meta_video_crop:\n"); - fprintf(stderr, " x: %d\n", h->x); - fprintf(stderr, " y: %d\n", h->y); - fprintf(stderr, " width: %d\n", h->width); - fprintf(stderr, " height: %d\n", h->height); - } else { - fprintf(stderr, " Unknown:\n"); - spa_debug_dump_mem(m->data, m->size); - } - } - fprintf(stderr, " n_datas: \t%u (at %p)\n", buffer->n_datas, buffer->datas); - for (i = 0; i < buffer->n_datas; i++) { - struct spa_data *d = &buffer->datas[i]; - fprintf(stderr, " type: %d (%s)\n", d->type, - spa_type_map_get_type(map, d->type)); - fprintf(stderr, " flags: %d\n", d->flags); - fprintf(stderr, " data: %p\n", d->data); - fprintf(stderr, " fd: %d\n", d->fd); - fprintf(stderr, " offset: %d\n", d->mapoffset); - fprintf(stderr, " maxsize: %u\n", d->maxsize); - fprintf(stderr, " chunk: %p\n", d->chunk); - fprintf(stderr, " offset: %d\n", d->chunk->offset); - fprintf(stderr, " size: %u\n", d->chunk->size); - fprintf(stderr, " stride: %d\n", d->chunk->stride); - } - return 0; -} - -int spa_debug_dump_mem(const void *mem, size_t size) -{ - const uint8_t *t = mem; - int i; - - if (mem == NULL) - return -EINVAL; - - for (i = 0; i < size; i++) { - if (i % 16 == 0) - fprintf(stderr,"%p: ", &t[i]); - fprintf(stderr,"%02x ", t[i]); - if (i % 16 == 15 || i == size - 1) - fprintf(stderr,"\n"); - } - return 0; -} - -static const char *pod_type_names[] = { - [SPA_POD_TYPE_INVALID] = "invalid", - [SPA_POD_TYPE_NONE] = "none", - [SPA_POD_TYPE_BOOL] = "bool", - [SPA_POD_TYPE_ID] = "id", - [SPA_POD_TYPE_INT] = "int", - [SPA_POD_TYPE_LONG] = "long", - [SPA_POD_TYPE_FLOAT] = "float", - [SPA_POD_TYPE_DOUBLE] = "double", - [SPA_POD_TYPE_STRING] = "string", - [SPA_POD_TYPE_BYTES] = "bytes", - [SPA_POD_TYPE_RECTANGLE] = "rectangle", - [SPA_POD_TYPE_FRACTION] = "fraction", - [SPA_POD_TYPE_BITMAP] = "bitmap", - [SPA_POD_TYPE_ARRAY] = "array", - [SPA_POD_TYPE_STRUCT] = "struct", - [SPA_POD_TYPE_OBJECT] = "object", - [SPA_POD_TYPE_POINTER] = "pointer", - [SPA_POD_TYPE_FD] = "fd", - [SPA_POD_TYPE_PROP] = "prop", - [SPA_POD_TYPE_POD] = "pod" -}; - -static void -print_pod_value(uint32_t size, uint32_t type, void *body, int prefix) -{ - switch (type) { - case SPA_POD_TYPE_BOOL: - fprintf(stderr,"%-*sBool %d\n", prefix, "", *(int32_t *) body); - break; - case SPA_POD_TYPE_ID: - fprintf(stderr,"%-*sId %d %s\n", prefix, "", *(int32_t *) body, - spa_type_map_get_type(map, *(int32_t *) body)); - break; - case SPA_POD_TYPE_INT: - fprintf(stderr,"%-*sInt %d\n", prefix, "", *(int32_t *) body); - break; - case SPA_POD_TYPE_LONG: - fprintf(stderr,"%-*sLong %" PRIi64 "\n", prefix, "", *(int64_t *) body); - break; - case SPA_POD_TYPE_FLOAT: - fprintf(stderr,"%-*sFloat %f\n", prefix, "", *(float *) body); - break; - case SPA_POD_TYPE_DOUBLE: - fprintf(stderr,"%-*sDouble %f\n", prefix, "", *(double *) body); - break; - case SPA_POD_TYPE_STRING: - fprintf(stderr,"%-*sString \"%s\"\n", prefix, "", (char *) body); - break; - case SPA_POD_TYPE_FD: - fprintf(stderr,"%-*sFd %d\n", prefix, "", *(int *) body); - break; - case SPA_POD_TYPE_POINTER: - { - struct spa_pod_pointer_body *b = body; - fprintf(stderr,"%-*sPointer %s %p\n", prefix, "", - map ? spa_type_map_get_type(map, b->type) : "*no map*", b->value); - break; - } - case SPA_POD_TYPE_RECTANGLE: - { - struct spa_rectangle *r = body; - fprintf(stderr,"%-*sRectangle %dx%d\n", prefix, "", r->width, r->height); - break; - } - case SPA_POD_TYPE_FRACTION: - { - struct spa_fraction *f = body; - fprintf(stderr,"%-*sFraction %d/%d\n", prefix, "", f->num, f->denom); - break; - } - case SPA_POD_TYPE_BITMAP: - fprintf(stderr,"%-*sBitmap\n", prefix, ""); - break; - case SPA_POD_TYPE_ARRAY: - { - struct spa_pod_array_body *b = body; - void *p; - fprintf(stderr,"%-*sArray: child.size %d, child.type %d\n", prefix, "", - b->child.size, b->child.type); - - SPA_POD_ARRAY_BODY_FOREACH(b, size, p) - print_pod_value(b->child.size, b->child.type, p, prefix + 2); - break; - } - case SPA_POD_TYPE_STRUCT: - { - struct spa_pod *b = body, *p; - fprintf(stderr,"%-*sStruct: size %d\n", prefix, "", size); - SPA_POD_FOREACH(b, size, p) - print_pod_value(p->size, p->type, SPA_POD_BODY(p), prefix + 2); - break; - } - case SPA_POD_TYPE_OBJECT: - { - struct spa_pod_object_body *b = body; - struct spa_pod *p; - - fprintf(stderr,"%-*sObject: size %d, id %s, type %s\n", prefix, "", size, - map ? spa_type_map_get_type(map, b->id) : "*no map*", - map ? spa_type_map_get_type(map, b->type) : "*no map*"); - SPA_POD_OBJECT_BODY_FOREACH(b, size, p) - print_pod_value(p->size, p->type, SPA_POD_BODY(p), prefix + 2); - break; - } - case SPA_POD_TYPE_PROP: - { - struct spa_pod_prop_body *b = body; - void *alt; - int i; - - fprintf(stderr,"%-*sProp: key %s, flags %d\n", prefix, "", - map ? spa_type_map_get_type(map, b->key) : "*no map*", b->flags); - if (b->flags & SPA_POD_PROP_FLAG_UNSET) - fprintf(stderr,"%-*sUnset (Default):\n", prefix + 2, ""); - else - fprintf(stderr,"%-*sValue: size %u\n", prefix + 2, "", b->value.size); - print_pod_value(b->value.size, b->value.type, SPA_POD_BODY(&b->value), - prefix + 4); - - i = 0; - switch (b->flags & SPA_POD_PROP_RANGE_MASK) { - case SPA_POD_PROP_RANGE_NONE: - break; - case SPA_POD_PROP_RANGE_MIN_MAX: - SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { - if (i == 0) - fprintf(stderr,"%-*sMin: ", prefix + 2, ""); - else if (i == 1) - fprintf(stderr,"%-*sMax: ", prefix + 2, ""); - else - break; - print_pod_value(b->value.size, b->value.type, alt, 0); - i++; - } - break; - case SPA_POD_PROP_RANGE_STEP: - SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { - if (i == 0) - fprintf(stderr,"%-*sMin: ", prefix + 2, ""); - else if (i == 1) - fprintf(stderr,"%-*sMax: ", prefix + 2, ""); - else if (i == 2) - fprintf(stderr,"%-*sStep: ", prefix + 2, ""); - else - break; - print_pod_value(b->value.size, b->value.type, alt, 0); - i++; - } - break; - case SPA_POD_PROP_RANGE_ENUM: - SPA_POD_PROP_ALTERNATIVE_FOREACH(b, size, alt) { - if (i == 0) - fprintf(stderr,"%-*sEnum:\n", prefix + 2, ""); - print_pod_value(b->value.size, b->value.type, alt, prefix + 4); - i++; - } - break; - case SPA_POD_PROP_RANGE_FLAGS: - break; - } - break; - } - case SPA_POD_TYPE_BYTES: - fprintf(stderr,"%-*sBytes\n", prefix, ""); - spa_debug_dump_mem(body, size); - break; - case SPA_POD_TYPE_NONE: - fprintf(stderr,"%-*sNone\n", prefix, ""); - spa_debug_dump_mem(body, size); - break; - default: - fprintf(stderr,"unhandled POD type %d\n", type); - break; - } -} - -static void -print_format_value(uint32_t size, uint32_t type, void *body) -{ - switch (type) { - case SPA_POD_TYPE_BOOL: - fprintf(stderr, "%s", *(int32_t *) body ? "true" : "false"); - break; - case SPA_POD_TYPE_ID: - { - const char *str = map ? spa_type_map_get_type(map, *(int32_t *) body) : NULL; - if (str) { - const char *h = rindex(str, ':'); - if (h) - str = h + 1; - } else { - str = "unknown"; - } - fprintf(stderr, "%s", str); - break; - } - case SPA_POD_TYPE_INT: - fprintf(stderr, "%" PRIi32, *(int32_t *) body); - break; - case SPA_POD_TYPE_LONG: - fprintf(stderr, "%" PRIi64, *(int64_t *) body); - break; - case SPA_POD_TYPE_FLOAT: - fprintf(stderr, "%f", *(float *) body); - break; - case SPA_POD_TYPE_DOUBLE: - fprintf(stderr, "%g", *(double *) body); - break; - case SPA_POD_TYPE_STRING: - fprintf(stderr, "%s", (char *) body); - break; - case SPA_POD_TYPE_RECTANGLE: - { - struct spa_rectangle *r = body; - fprintf(stderr, "%" PRIu32 "x%" PRIu32, r->width, r->height); - break; - } - case SPA_POD_TYPE_FRACTION: - { - struct spa_fraction *f = body; - fprintf(stderr, "%" PRIu32 "/%" PRIu32, f->num, f->denom); - break; - } - case SPA_POD_TYPE_BITMAP: - fprintf(stderr, "Bitmap"); - break; - case SPA_POD_TYPE_BYTES: - fprintf(stderr, "Bytes"); - break; - default: - break; - } -} - -static int spa_debug_format(const struct spa_pod *format) -{ - int i; - const char *media_type; - const char *media_subtype; - struct spa_pod *pod; - uint32_t mtype, mstype; - - if (format == NULL || SPA_POD_TYPE(format) != SPA_POD_TYPE_OBJECT) - return -EINVAL; - - if (spa_pod_object_parse(format, "I", &mtype, - "I", &mstype) < 0) - return -EINVAL; - - media_type = spa_type_map_get_type(map, mtype); - media_subtype = spa_type_map_get_type(map, mstype); - - fprintf(stderr, "%-6s %s/%s\n", "", rindex(media_type, ':') + 1, - rindex(media_subtype, ':') + 1); - - SPA_POD_OBJECT_FOREACH((struct spa_pod_object*)format, pod) { - struct spa_pod_prop *prop; - const char *key; - - if (pod->type != SPA_POD_TYPE_PROP) - continue; - - prop = (struct spa_pod_prop *)pod; - - if ((prop->body.flags & SPA_POD_PROP_FLAG_UNSET) && - (prop->body.flags & SPA_POD_PROP_FLAG_OPTIONAL)) - continue; - - key = spa_type_map_get_type(map, prop->body.key); - - fprintf(stderr, " %20s : (%s) ", rindex(key, ':') + 1, - pod_type_names[prop->body.value.type]); - - if (!(prop->body.flags & SPA_POD_PROP_FLAG_UNSET)) { - print_format_value(prop->body.value.size, - prop->body.value.type, SPA_POD_BODY(&prop->body.value)); - } else { - const char *ssep, *esep, *sep; - void *alt; - - switch (prop->body.flags & SPA_POD_PROP_RANGE_MASK) { - case SPA_POD_PROP_RANGE_MIN_MAX: - case SPA_POD_PROP_RANGE_STEP: - ssep = "[ "; - sep = ", "; - esep = " ]"; - break; - default: - case SPA_POD_PROP_RANGE_ENUM: - case SPA_POD_PROP_RANGE_FLAGS: - ssep = "{ "; - sep = ", "; - esep = " }"; - break; - } - - fprintf(stderr, "%s", ssep); - - i = 0; - SPA_POD_PROP_ALTERNATIVE_FOREACH(&prop->body, prop->pod.size, alt) { - if (i > 0) - fprintf(stderr, "%s", sep); - print_format_value(prop->body.value.size, - prop->body.value.type, alt); - i++; - } - fprintf(stderr, "%s", esep); - } - fprintf(stderr, "\n"); - } - return 0; -} - -int spa_debug_pod(const struct spa_pod *pod, uint32_t flags) -{ - int res = 0; - - if (flags & SPA_DEBUG_FLAG_FORMAT) - res = spa_debug_format(pod); - else - print_pod_value(pod->size, pod->type, SPA_POD_BODY(pod), 0); - - return res; -} - - -int spa_debug_dict(const struct spa_dict *dict) -{ - unsigned int i; - - if (dict == NULL) - return -EINVAL; - - for (i = 0; i < dict->n_items; i++) - fprintf(stderr, " %s = \"%s\"\n", dict->items[i].key, - dict->items[i].value); - - return 0; -} diff --git a/spa/lib/meson.build b/spa/lib/meson.build deleted file mode 100644 index 81eb2dcce..000000000 --- a/spa/lib/meson.build +++ /dev/null @@ -1,18 +0,0 @@ -spalib_headers = [ - 'debug.h', -] - -install_headers(spalib_headers, subdir : 'spa/lib') - -spalib_sources = ['debug.c' ] - -spalib = shared_library('spa-lib-@0@'.format(spaversion), - spalib_sources, - version : libversion, - soversion : soversion, - include_directories : [ spa_inc, spa_libinc ], - install : true) - -spalib_dep = declare_dependency(link_with : spalib, - include_directories : spa_inc, -) diff --git a/spa/lib/pod.c b/spa/lib/pod.c deleted file mode 100644 index 43967a98f..000000000 --- a/spa/lib/pod.c +++ /dev/null @@ -1,491 +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 -#include -#include - -static int compare_value(enum spa_pod_type type, const void *r1, const void *r2) -{ - switch (type) { - case SPA_POD_TYPE_INVALID: - return 0; - case SPA_POD_TYPE_BOOL: - case SPA_POD_TYPE_ID: - return *(int32_t *) r1 == *(uint32_t *) r2 ? 0 : 1; - case SPA_POD_TYPE_INT: - return *(int32_t *) r1 - *(int32_t *) r2; - case SPA_POD_TYPE_LONG: - return *(int64_t *) r1 - *(int64_t *) r2; - case SPA_POD_TYPE_FLOAT: - return *(float *) r1 - *(float *) r2; - case SPA_POD_TYPE_DOUBLE: - return *(double *) r1 - *(double *) r2; - case SPA_POD_TYPE_STRING: - return strcmp(r1, r2); - case SPA_POD_TYPE_RECTANGLE: - { - const struct spa_rectangle *rec1 = (struct spa_rectangle *) r1, - *rec2 = (struct spa_rectangle *) r2; - if (rec1->width == rec2->width && rec1->height == rec2->height) - return 0; - else if (rec1->width < rec2->width || rec1->height < rec2->height) - return -1; - else - return 1; - } - case SPA_POD_TYPE_FRACTION: - { - const struct spa_fraction *f1 = (struct spa_fraction *) r1, - *f2 = (struct spa_fraction *) r2; - int64_t n1, n2; - n1 = ((int64_t) f1->num) * f2->denom; - n2 = ((int64_t) f2->num) * f1->denom; - if (n1 < n2) - return -1; - else if (n1 > n2) - return 1; - else - return 0; - } - default: - break; - } - return 0; -} - -static void fix_default(struct spa_pod_prop *prop) -{ - void *val = SPA_MEMBER(prop, sizeof(struct spa_pod_prop), void), - *alt = SPA_MEMBER(val, prop->body.value.size, void); - int i, nalt = SPA_POD_PROP_N_VALUES(prop) - 1; - - switch (prop->body.flags & SPA_POD_PROP_RANGE_MASK) { - case SPA_POD_PROP_RANGE_NONE: - break; - case SPA_POD_PROP_RANGE_MIN_MAX: - case SPA_POD_PROP_RANGE_STEP: - if (compare_value(prop->body.value.type, val, alt) < 0) - memcpy(val, alt, prop->body.value.size); - alt = SPA_MEMBER(alt, prop->body.value.size, void); - if (compare_value(prop->body.value.type, val, alt) > 0) - memcpy(val, alt, prop->body.value.size); - break; - case SPA_POD_PROP_RANGE_ENUM: - { - void *best = NULL; - - for (i = 0; i < nalt; i++) { - if (compare_value(prop->body.value.type, val, alt) == 0) { - best = alt; - break; - } - if (best == NULL) - best = alt; - alt = SPA_MEMBER(alt, prop->body.value.size, void); - } - if (best) - memcpy(val, best, prop->body.value.size); - - if (nalt <= 1) { - prop->body.flags &= ~SPA_POD_PROP_FLAG_UNSET; - prop->body.flags &= ~SPA_POD_PROP_RANGE_MASK; - prop->body.flags |= SPA_POD_PROP_RANGE_NONE; - } - break; - } - case SPA_POD_PROP_RANGE_FLAGS: - break; - } -} - -static inline struct spa_pod_prop *find_prop(const struct spa_pod *pod, uint32_t size, uint32_t key) -{ - const struct spa_pod *res; - SPA_POD_FOREACH(pod, size, res) { - if (res->type == SPA_POD_TYPE_PROP - && ((struct spa_pod_prop *) res)->body.key == key) - return (struct spa_pod_prop *) res; - } - return NULL; -} - -static inline int -filter_prop(struct spa_pod_builder *b, - const struct spa_pod_prop *p1, - const struct spa_pod_prop *p2) -{ - struct spa_pod_prop *np; - int nalt1, nalt2; - void *alt1, *alt2, *a1, *a2; - uint32_t rt1, rt2; - int j, k; - - /* incompatible property types */ - if (p1->body.value.type != p2->body.value.type) - return -EINVAL; - - rt1 = p1->body.flags & SPA_POD_PROP_RANGE_MASK; - rt2 = p2->body.flags & SPA_POD_PROP_RANGE_MASK; - - alt1 = SPA_MEMBER(p1, sizeof(struct spa_pod_prop), void); - nalt1 = SPA_POD_PROP_N_VALUES(p1); - alt2 = SPA_MEMBER(p2, sizeof(struct spa_pod_prop), void); - nalt2 = SPA_POD_PROP_N_VALUES(p2); - - if (p1->body.flags & SPA_POD_PROP_FLAG_UNSET) { - alt1 = SPA_MEMBER(alt1, p1->body.value.size, void); - nalt1--; - } else { - nalt1 = 1; - rt1 = SPA_POD_PROP_RANGE_NONE; - } - - if (p2->body.flags & SPA_POD_PROP_FLAG_UNSET) { - alt2 = SPA_MEMBER(alt2, p2->body.value.size, void); - nalt2--; - } else { - nalt2 = 1; - rt2 = SPA_POD_PROP_RANGE_NONE; - } - - /* start with copying the property */ - np = spa_pod_builder_deref(b, spa_pod_builder_push_prop(b, p1->body.key, 0)); - - /* default value */ - spa_pod_builder_raw(b, &p1->body.value, sizeof(p1->body.value) + p1->body.value.size); - - if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_NONE) || - (rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_ENUM) || - (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_NONE) || - (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_ENUM)) { - int n_copied = 0; - /* copy all equal values but don't copy the default value again */ - for (j = 0, a1 = alt1; j < nalt1; j++, a1 += p1->body.value.size) { - for (k = 0, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) { - if (compare_value(p1->body.value.type, a1, a2) == 0) { - if (rt1 == SPA_POD_PROP_RANGE_ENUM || j > 0) - spa_pod_builder_raw(b, a1, p1->body.value.size); - n_copied++; - } - } - } - if (n_copied == 0) - return -EINVAL; - np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; - } - - if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) || - (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_MIN_MAX)) { - int n_copied = 0; - /* copy all values inside the range */ - for (j = 0, a1 = alt1, a2 = alt2; j < nalt1; j++, a1 += p1->body.value.size) { - if (compare_value(p1->body.value.type, a1, a2) < 0) - continue; - if (compare_value(p1->body.value.type, a1, a2 + p2->body.value.size) > 0) - continue; - spa_pod_builder_raw(b, a1, p1->body.value.size); - n_copied++; - } - if (n_copied == 0) - return -EINVAL; - np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; - } - - if ((rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_STEP) || - (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_STEP)) { - return -ENOTSUP; - } - - if ((rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_NONE) || - (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_ENUM)) { - int n_copied = 0; - /* copy all values inside the range */ - for (k = 0, a1 = alt1, a2 = alt2; k < nalt2; k++, a2 += p2->body.value.size) { - if (compare_value(p1->body.value.type, a2, a1) < 0) - continue; - if (compare_value(p1->body.value.type, a2, a1 + p1->body.value.size) > 0) - continue; - spa_pod_builder_raw(b, a2, p2->body.value.size); - n_copied++; - } - if (n_copied == 0) - return -EINVAL; - np->body.flags |= SPA_POD_PROP_RANGE_ENUM | SPA_POD_PROP_FLAG_UNSET; - } - - if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) { - if (compare_value(p1->body.value.type, alt1, alt2) < 0) - spa_pod_builder_raw(b, alt2, p2->body.value.size); - else - spa_pod_builder_raw(b, alt1, p1->body.value.size); - - alt1 += p1->body.value.size; - alt2 += p2->body.value.size; - - if (compare_value(p1->body.value.type, alt1, alt2) < 0) - spa_pod_builder_raw(b, alt1, p1->body.value.size); - else - spa_pod_builder_raw(b, alt2, p2->body.value.size); - - np->body.flags |= SPA_POD_PROP_RANGE_MIN_MAX | SPA_POD_PROP_FLAG_UNSET; - } - - if (rt1 == SPA_POD_PROP_RANGE_NONE && rt2 == SPA_POD_PROP_RANGE_FLAGS) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_STEP) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_MIN_MAX && rt2 == SPA_POD_PROP_RANGE_FLAGS) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_ENUM && rt2 == SPA_POD_PROP_RANGE_FLAGS) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_NONE) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_STEP) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_ENUM) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_STEP && rt2 == SPA_POD_PROP_RANGE_FLAGS) - return -ENOTSUP; - - if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_NONE) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_MIN_MAX) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_STEP) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_ENUM) - return -ENOTSUP; - if (rt1 == SPA_POD_PROP_RANGE_FLAGS && rt2 == SPA_POD_PROP_RANGE_FLAGS) - return -ENOTSUP; - - spa_pod_builder_pop(b); - fix_default(np); - - return 0; -} - -int pod_filter(struct spa_pod_builder *b, - const struct spa_pod *pod, uint32_t pod_size, - const struct spa_pod *filter, uint32_t filter_size) -{ - const struct spa_pod *pp, *pf; - int res = 0; - - pf = filter; - - SPA_POD_FOREACH(pod, pod_size, pp) { - bool do_copy = false, do_advance = false; - uint32_t filter_offset = 0; - - switch (SPA_POD_TYPE(pp)) { - case SPA_POD_TYPE_STRUCT: - case SPA_POD_TYPE_OBJECT: - if (pf != NULL) { - if (SPA_POD_TYPE(pf) != SPA_POD_TYPE(pp)) - return -EINVAL; - - if (SPA_POD_TYPE(pp) == SPA_POD_TYPE_STRUCT) { - filter_offset = sizeof(struct spa_pod_struct); - spa_pod_builder_push_struct(b); - } else { - struct spa_pod_object *p1 = (struct spa_pod_object *) pp; - filter_offset = sizeof(struct spa_pod_object); - spa_pod_builder_push_object(b, p1->body.id, p1->body.type); - } - do_advance = true; - } - else - do_copy = true; - break; - - case SPA_POD_TYPE_PROP: - { - struct spa_pod_prop *p1, *p2; - - p1 = (struct spa_pod_prop *) pp; - p2 = find_prop(filter, filter_size, p1->body.key); - - if (p2 != NULL) - res = filter_prop(b, p1, p2); - else - do_copy = true; - break; - } - default: - if (pf != NULL) { - if (SPA_POD_SIZE(pp) != SPA_POD_SIZE(pf)) - return -EINVAL; - if (memcmp(pp, pf, SPA_POD_SIZE(pp)) != 0) - return -EINVAL; - do_advance = true; - } - do_copy = true; - break; - } - if (do_copy) - spa_pod_builder_raw_padded(b, pp, SPA_POD_SIZE(pp)); - else if (filter_offset) { - res = pod_filter(b, - SPA_MEMBER(pp,filter_offset,void), - SPA_POD_SIZE(pp) - filter_offset, - SPA_MEMBER(pf,filter_offset,void), - SPA_POD_SIZE(pf) - filter_offset); - spa_pod_builder_pop(b); - } - if (do_advance) { - pf = spa_pod_next(pf); - if (!spa_pod_is_inside(filter, filter_size, pf)) - pf = NULL; - } - if (res < 0) - break; - } - return res; -} - -int -spa_pod_filter(struct spa_pod_builder *b, - struct spa_pod **result, - const struct spa_pod *pod, - const struct spa_pod *filter) -{ - int res; - struct spa_pod_builder_state state; - - spa_return_val_if_fail(pod != NULL, -EINVAL); - spa_return_val_if_fail(b != NULL, -EINVAL); - - if (filter == NULL) { - *result = spa_pod_builder_deref(b, - spa_pod_builder_raw_padded(b, pod, SPA_POD_SIZE(pod))); - return 0; - } - - spa_pod_builder_get_state(b, &state); - if ((res = pod_filter(b, pod, SPA_POD_SIZE(pod), filter, SPA_POD_SIZE(filter))) < 0) - spa_pod_builder_reset(b, &state); - else - *result = spa_pod_builder_deref(b, state.offset); - - return res; -} - -int pod_compare(const struct spa_pod *pod1, uint32_t pod1_size, - const struct spa_pod *pod2, uint32_t pod2_size) -{ - const struct spa_pod *p1, *p2; - int res; - - p2 = pod2; - - SPA_POD_FOREACH(pod1, pod1_size, p1) { - bool do_advance = true; - uint32_t recurse_offset = 0; - - if (p2 == NULL) - return -EINVAL; - - switch (SPA_POD_TYPE(p1)) { - case SPA_POD_TYPE_STRUCT: - case SPA_POD_TYPE_OBJECT: - if (SPA_POD_TYPE(p2) != SPA_POD_TYPE(p1)) - return -EINVAL; - - if (SPA_POD_TYPE(p1) == SPA_POD_TYPE_STRUCT) - recurse_offset = sizeof(struct spa_pod_struct); - else - recurse_offset = sizeof(struct spa_pod_object); - - do_advance = true; - break; - case SPA_POD_TYPE_PROP: - { - struct spa_pod_prop *pr1, *pr2; - void *a1, *a2; - - pr1 = (struct spa_pod_prop *) p1; - pr2 = find_prop(pod2, pod2_size, pr1->body.key); - - if (pr2 == NULL) - return -EINVAL; - - /* incompatible property types */ - if (pr1->body.value.type != pr2->body.value.type) - return -EINVAL; - - if (pr1->body.flags & SPA_POD_PROP_FLAG_UNSET || - pr2->body.flags & SPA_POD_PROP_FLAG_UNSET) - return -EINVAL; - - a1 = SPA_MEMBER(pr1, sizeof(struct spa_pod_prop), void); - a2 = SPA_MEMBER(pr2, sizeof(struct spa_pod_prop), void); - - res = compare_value(pr1->body.value.type, a1, a2); - break; - } - default: - if (SPA_POD_TYPE(p1) != SPA_POD_TYPE(p2)) - return -EINVAL; - - res = compare_value(SPA_POD_TYPE(p1), SPA_POD_BODY(p1), SPA_POD_BODY(p2)); - do_advance = true; - break; - } - if (recurse_offset) { - res = pod_compare(SPA_MEMBER(p1,recurse_offset,void), - SPA_POD_SIZE(p1) - recurse_offset, - SPA_MEMBER(p2,recurse_offset,void), - SPA_POD_SIZE(p2) - recurse_offset); - } - if (do_advance) { - p2 = spa_pod_next(p2); - if (!spa_pod_is_inside(pod2, pod2_size, p2)) - p2 = NULL; - } - if (res != 0) - return res; - } - if (p2 != NULL) - return -EINVAL; - - return 0; -} - -int spa_pod_compare(const struct spa_pod *pod1, - const struct spa_pod *pod2) -{ - spa_return_val_if_fail(pod1 != NULL, -EINVAL); - spa_return_val_if_fail(pod2 != NULL, -EINVAL); - - return pod_compare(pod1, SPA_POD_SIZE(pod1), pod2, SPA_POD_SIZE(pod2)); -} diff --git a/spa/meson.build b/spa/meson.build index 6a76c275b..09e1c2f08 100644 --- a/spa/meson.build +++ b/spa/meson.build @@ -19,10 +19,8 @@ threads_dep = dependency('threads') #mathlib = cc.find_library('m', required : false) spa_inc = include_directories('include') -spa_libinc = include_directories('.') subdir('include') -subdir('lib') subdir('plugins') subdir('tools') subdir('tests') diff --git a/spa/plugins/alsa/meson.build b/spa/plugins/alsa/meson.build index c45160e45..9a4ecb7f0 100644 --- a/spa/plugins/alsa/meson.build +++ b/spa/plugins/alsa/meson.build @@ -6,7 +6,7 @@ spa_alsa_sources = ['alsa.c', spa_alsa = shared_library('spa-alsa', spa_alsa_sources, - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], dependencies : [ alsa_dep, libudev_dep ], install : true, install_dir : '@0@/spa/alsa'.format(get_option('libdir'))) diff --git a/spa/plugins/audiomixer/meson.build b/spa/plugins/audiomixer/meson.build index 444145ffb..51840ac15 100644 --- a/spa/plugins/audiomixer/meson.build +++ b/spa/plugins/audiomixer/meson.build @@ -2,6 +2,6 @@ audiomixer_sources = ['audiomixer.c', 'mix-ops.c', 'plugin.c'] audiomixerlib = shared_library('spa-audiomixer', audiomixer_sources, - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], install : true, install_dir : '@0@/spa/audiomixer/'.format(get_option('libdir'))) diff --git a/spa/plugins/audiotestsrc/meson.build b/spa/plugins/audiotestsrc/meson.build index 8553511bf..1a3d14cea 100644 --- a/spa/plugins/audiotestsrc/meson.build +++ b/spa/plugins/audiotestsrc/meson.build @@ -2,7 +2,7 @@ audiotestsrc_sources = ['audiotestsrc.c', 'plugin.c'] audiotestsrclib = shared_library('spa-audiotestsrc', audiotestsrc_sources, - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], dependencies : mathlib, install : true, install_dir : '@0@/spa/audiotestsrc'.format(get_option('libdir'))) diff --git a/spa/plugins/bluez5/meson.build b/spa/plugins/bluez5/meson.build index a96f60164..158902384 100644 --- a/spa/plugins/bluez5/meson.build +++ b/spa/plugins/bluez5/meson.build @@ -5,7 +5,7 @@ bluez5_sources = ['plugin.c', bluez5lib = shared_library('spa-bluez5', bluez5_sources, - include_directories : [ spa_inc, spa_libinc ], + include_directories : [ spa_inc ], dependencies : [ dbus_dep, sbc_dep ], install : true, install_dir : '@0@/spa/bluez5'.format(get_option('libdir'))) diff --git a/spa/plugins/ffmpeg/meson.build b/spa/plugins/ffmpeg/meson.build index 9769c5df9..64789a1dd 100644 --- a/spa/plugins/ffmpeg/meson.build +++ b/spa/plugins/ffmpeg/meson.build @@ -4,7 +4,7 @@ ffmpeg_sources = ['ffmpeg.c', ffmpeglib = shared_library('spa-ffmpeg', ffmpeg_sources, - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], dependencies : [ avcodec_dep, avformat_dep ], install : true, install_dir : '@0@/spa/ffmpeg'.format(get_option('libdir'))) diff --git a/spa/plugins/support/meson.build b/spa/plugins/support/meson.build index 862769b25..475e295f2 100644 --- a/spa/plugins/support/meson.build +++ b/spa/plugins/support/meson.build @@ -5,7 +5,7 @@ spa_support_sources = ['mapper.c', spa_support_lib = shared_library('spa-support', spa_support_sources, - include_directories : [ spa_inc, spa_libinc], + include_directories : [ spa_inc], dependencies : threads_dep, install : true, install_dir : '@0@/spa/support'.format(get_option('libdir'))) @@ -14,7 +14,7 @@ spa_dbus_sources = ['dbus.c'] spa_dbus_lib = shared_library('spa-dbus', spa_dbus_sources, - include_directories : [ spa_inc, spa_libinc], + include_directories : [ spa_inc], dependencies : dbus_dep, install : true, install_dir : '@0@/spa/support'.format(get_option('libdir'))) diff --git a/spa/plugins/test/meson.build b/spa/plugins/test/meson.build index c3c1f3483..e9bb1f2b8 100644 --- a/spa/plugins/test/meson.build +++ b/spa/plugins/test/meson.build @@ -2,7 +2,7 @@ test_sources = ['fakesrc.c', 'fakesink.c', 'plugin.c'] testlib = shared_library('spa-test', test_sources, - include_directories : [ spa_inc, spa_libinc], + include_directories : [ spa_inc], dependencies : threads_dep, install : true, install_dir : '@0@/spa/test'.format(get_option('libdir'))) diff --git a/spa/plugins/v4l2/meson.build b/spa/plugins/v4l2/meson.build index fadfafd57..847adbcdc 100644 --- a/spa/plugins/v4l2/meson.build +++ b/spa/plugins/v4l2/meson.build @@ -4,7 +4,7 @@ v4l2_sources = ['v4l2.c', v4l2lib = shared_library('spa-v4l2', v4l2_sources, - include_directories : [ spa_inc, spa_libinc ], + include_directories : [ spa_inc ], dependencies : [ v4l2_dep, libudev_dep ], install : true, install_dir : '@0@/spa/v4l2'.format(get_option('libdir'))) diff --git a/spa/plugins/videotestsrc/meson.build b/spa/plugins/videotestsrc/meson.build index 134fdaa00..cb6652483 100644 --- a/spa/plugins/videotestsrc/meson.build +++ b/spa/plugins/videotestsrc/meson.build @@ -2,7 +2,7 @@ videotestsrc_sources = ['videotestsrc.c', 'plugin.c'] videotestsrclib = shared_library('spa-videotestsrc', videotestsrc_sources, - include_directories : [ spa_inc, spa_libinc], + include_directories : [ spa_inc], dependencies : threads_dep, install : true, install_dir : '@0@/spa/videotestsrc'.format(get_option('libdir'))) diff --git a/spa/plugins/volume/meson.build b/spa/plugins/volume/meson.build index dff1f2d47..9d85f14ce 100644 --- a/spa/plugins/volume/meson.build +++ b/spa/plugins/volume/meson.build @@ -2,6 +2,6 @@ volume_sources = ['volume.c', 'plugin.c'] volumelib = shared_library('spa-volume', volume_sources, - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], install : true, install_dir : '@0@/spa/volume'.format(get_option('libdir'))) diff --git a/spa/tests/meson.build b/spa/tests/meson.build index d03820033..9aca7121c 100644 --- a/spa/tests/meson.build +++ b/spa/tests/meson.build @@ -1,67 +1,54 @@ executable('test-mixer', 'test-mixer.c', include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib, mathlib], - link_with : spalib, install : false) executable('test-bluez5', 'test-bluez5.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib, mathlib, dbus_dep], - link_with : spalib, install : false) executable('test-ringbuffer', 'test-ringbuffer.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib], - link_with : spalib, install : false) executable('test-graph', 'test-graph.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib], - link_with : spalib, install : false) executable('test-graph2', 'test-graph2.c', include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib], - link_with : spalib, install : false) executable('test-perf', 'test-perf.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib], - link_with : spalib, install : false) executable('stress-ringbuffer', 'stress-ringbuffer.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib], - link_with : spalib, install : false) if sdl_dep.found() executable('test-v4l2', 'test-v4l2.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, sdl_dep, pthread_lib], - link_with : spalib, install : false) endif executable('test-props', 'test-props.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [], - link_with : spalib, install : false) executable('test-props2', 'test-props2.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [], - link_with : spalib, install : false) #executable('test-props4', 'test-props4.c', -# include_directories : [spa_inc, spa_libinc ], +# include_directories : [spa_inc ], # dependencies : [], -# link_with : spalib, # install : false) executable('test-props5', 'test-props5.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [], - link_with : spalib, install : false) executable('test-control', 'test-control.c', - include_directories : [spa_inc, spa_libinc ], + include_directories : [spa_inc ], dependencies : [dl_lib, pthread_lib, mathlib], - link_with : spalib, install : false) diff --git a/spa/tests/test-bluez5.c b/spa/tests/test-bluez5.c index 1043639bd..b29d535ed 100644 --- a/spa/tests/test-bluez5.c +++ b/spa/tests/test-bluez5.c @@ -50,7 +50,7 @@ static struct spa_log *logger; #include #include -#include +#include struct type { uint32_t log; @@ -133,7 +133,7 @@ struct data { static void inspect_item(struct data *data, struct spa_pod *item) { - spa_debug_pod(item, 0); + spa_debug_pod(0, data->map, item); } static void monitor_event(void *_data, struct spa_event *event) @@ -222,7 +222,6 @@ int main(int argc, char *argv[]) data.support[0].data = data.map; data.n_support = 1; init_type(&data.type, data.map); - spa_debug_set_type_map(data.map); if ((res = get_handle(&data, &handle, "build/spa/plugins/support/libspa-support.so", diff --git a/spa/tests/test-control.c b/spa/tests/test-control.c index 9cda5e89d..35b143448 100644 --- a/spa/tests/test-control.c +++ b/spa/tests/test-control.c @@ -49,7 +49,7 @@ static SPA_LOG_IMPL(default_log); #include #include -#include +#include struct type { uint32_t node; @@ -326,7 +326,7 @@ static int make_nodes(struct data *data, const char *device) ":", data->type.props_device, "s", device ? device : "hw:0", ":", data->type.props_min_latency, "i", MIN_LATENCY); - spa_debug_pod(props, 0); + spa_debug_pod(0, data->map, props); if ((res = spa_node_set_param(data->sink, data->type.param.idProps, 0, props)) < 0) printf("got set_props error %d\n", res); @@ -431,7 +431,7 @@ static int negotiate_formats(struct data *data) ":", data->type.format_audio.rate, "i", 44100, ":", data->type.format_audio.channels, "i", 2); - spa_debug_pod(filter, 0); + spa_debug_pod(0, data->map, filter); spa_log_debug(&default_log.log, "enum_params"); if ((res = spa_node_port_enum_params(data->sink, @@ -440,7 +440,7 @@ static int negotiate_formats(struct data *data) filter, &format, &b)) <= 0) return -EBADF; - spa_debug_pod(format, 0); + spa_debug_pod(0, data->map, format); spa_log_debug(&default_log.log, "sink set_param"); if ((res = spa_node_port_set_param(data->sink, @@ -574,8 +574,6 @@ int main(int argc, char *argv[]) data.data_loop.remove_source = do_remove_source; data.data_loop.invoke = do_invoke; - spa_debug_set_type_map(data.map); - if ((str = getenv("SPA_DEBUG"))) data.log->level = atoi(str); diff --git a/spa/tests/test-graph.c b/spa/tests/test-graph.c index 82cf7b6ac..abe0bc83b 100644 --- a/spa/tests/test-graph.c +++ b/spa/tests/test-graph.c @@ -44,7 +44,7 @@ static SPA_LOG_IMPL(default_log); #include #include -#include +#include struct type { uint32_t node; @@ -305,7 +305,7 @@ static int make_nodes(struct data *data, const char *device) ":", data->type.props_device, "s", device ? device : "hw:0", ":", data->type.props_min_latency, "i", MIN_LATENCY); - spa_debug_pod(props, 0); + spa_debug_pod(0, data->map, props); if ((res = spa_node_set_param(data->sink, data->type.param.idProps, 0, props)) < 0) printf("got set_props error %d\n", res); @@ -399,7 +399,7 @@ static int negotiate_formats(struct data *data) ":", data->type.format_audio.rate, "i", 44100, ":", data->type.format_audio.channels, "i", 2); - spa_debug_pod(filter, 0); + spa_debug_pod(0, data->map, filter); spa_log_debug(&default_log.log, "enum_params"); if ((res = spa_node_port_enum_params(data->sink, @@ -408,7 +408,7 @@ static int negotiate_formats(struct data *data) filter, &format, &b)) <= 0) return -EBADF; - spa_debug_pod(format, 0); + spa_debug_pod(0, data->map, format); spa_log_debug(&default_log.log, "sink set_param"); if ((res = spa_node_port_set_param(data->sink, @@ -566,8 +566,6 @@ int main(int argc, char *argv[]) data.data_loop.remove_source = do_remove_source; data.data_loop.invoke = do_invoke; - spa_debug_set_type_map(data.map); - if ((str = getenv("SPA_DEBUG"))) data.log->level = atoi(str); diff --git a/spa/tests/test-props.c b/spa/tests/test-props.c index dc6a40763..53b0c4c30 100644 --- a/spa/tests/test-props.c +++ b/spa/tests/test-props.c @@ -29,8 +29,8 @@ #include #include #include - -#include +#include +#include #if 0 /* { video/raw, @@ -250,8 +250,8 @@ static void do_static_struct(struct spa_type_map *map) } }; - spa_debug_pod(&test_format.fmt.pod, 0); - spa_debug_pod(&test_format.fmt.pod, SPA_DEBUG_FLAG_FORMAT); + spa_debug_pod(0, map, &test_format.fmt.pod); + spa_debug_format(0, map, &test_format.fmt.pod); { uint32_t format = -1; @@ -283,7 +283,6 @@ int main(int argc, char *argv[]) struct spa_type_map *map = &default_map.map; type_init(map); - spa_debug_set_type_map(map); spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -317,7 +316,7 @@ int main(int argc, char *argv[]) fmt = spa_pod_builder_pop(&b); - spa_debug_pod(&fmt->pod, 0); + spa_debug_pod(0, map, &fmt->pod); spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -335,8 +334,8 @@ int main(int argc, char *argv[]) 2, &SPA_FRACTION(0,1), &SPA_FRACTION(INT32_MAX,1)); - spa_debug_pod(&fmt->pod, 0); - spa_debug_pod(&fmt->pod, SPA_DEBUG_FLAG_FORMAT); + spa_debug_pod(0, map, &fmt->pod); + spa_debug_format(0, map, &fmt->pod); spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -365,8 +364,8 @@ int main(int argc, char *argv[]) &SPA_FRACTION(INT32_MAX,1), ">", NULL); - spa_debug_pod(&fmt->pod, 0); - spa_debug_pod(&fmt->pod, SPA_DEBUG_FLAG_FORMAT); + spa_debug_pod(0, map, &fmt->pod); + spa_debug_format(0, map, &fmt->pod); do_static_struct(map); diff --git a/spa/tests/test-props2.c b/spa/tests/test-props2.c index b2338c67d..692b95c52 100644 --- a/spa/tests/test-props2.c +++ b/spa/tests/test-props2.c @@ -30,7 +30,7 @@ #include #include -#include +#include static SPA_TYPE_MAP_IMPL(default_map, 4096); @@ -43,8 +43,6 @@ int main(int argc, char *argv[]) struct spa_pod_parser prs; struct spa_type_map *map = &default_map.map; - spa_debug_set_type_map(map); - b.data = buffer; b.size = 1024; @@ -86,11 +84,11 @@ int main(int argc, char *argv[]) spa_pod_builder_pop(&b); obj = spa_pod_builder_pop(&b); - spa_debug_pod(obj, 0); + spa_debug_pod(0, map, obj); struct spa_pod_prop *p = spa_pod_find_prop(obj, 4); printf("%d %d\n", p->body.key, p->body.flags); - spa_debug_pod(&p->body.value, 0); + spa_debug_pod(0, map, &p->body.value); obj = spa_pod_builder_deref(&b, ref); diff --git a/spa/tests/test-props5.c b/spa/tests/test-props5.c index a3da22c8b..b633fec74 100644 --- a/spa/tests/test-props5.c +++ b/spa/tests/test-props5.c @@ -24,8 +24,9 @@ #include #include +#include -#include +#include int main(int argc, char *argv[]) { @@ -52,7 +53,7 @@ int main(int argc, char *argv[]) 2, &SPA_FRACTION(0,1), &SPA_FRACTION(INT32_MAX, 1), ">", NULL); - spa_debug_pod(fmt, 0); + spa_debug_pod(0, NULL, fmt); spa_pod_parser_pod(&prs, fmt); res = spa_pod_parser_get(&prs, @@ -67,7 +68,7 @@ int main(int argc, char *argv[]) printf("media-type:%d media-subtype:%d\n", media_type, media_subtype); printf("framerate:\n"); if (pod) - spa_debug_pod(pod, 0); + spa_debug_pod(0, NULL, pod); printf("format: %d\n", fmt_value); spa_pod_builder_init(&b, buffer, sizeof(buffer)); @@ -76,7 +77,7 @@ int main(int argc, char *argv[]) " P", NULL, " [ i", 44, "i",45,"]" ">", NULL); - spa_debug_pod(pod, 0); + spa_debug_pod(0, NULL, pod); spa_pod_parser_pod(&prs, pod); res = spa_pod_parser_get(&prs, diff --git a/spa/tests/test-ringbuffer.c b/spa/tests/test-ringbuffer.c index 8ba40bb45..68e50d8b9 100644 --- a/spa/tests/test-ringbuffer.c +++ b/spa/tests/test-ringbuffer.c @@ -36,8 +36,6 @@ #include #include -#include - static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); diff --git a/spa/tests/test-v4l2.c b/spa/tests/test-v4l2.c index d7e8bdabe..98ba7f5ac 100644 --- a/spa/tests/test-v4l2.c +++ b/spa/tests/test-v4l2.c @@ -39,8 +39,6 @@ #include #include -#include - static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); diff --git a/spa/tools/meson.build b/spa/tools/meson.build index c03603541..fe4f2e7a1 100644 --- a/spa/tools/meson.build +++ b/spa/tools/meson.build @@ -1,11 +1,9 @@ executable('spa-inspect', 'spa-inspect.c', - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], dependencies : [dl_lib], - link_with : spalib, install : true) executable('spa-monitor', 'spa-monitor.c', - include_directories : [spa_inc, spa_libinc], + include_directories : [spa_inc], dependencies : [dl_lib], - link_with : spalib, install : true) diff --git a/spa/tools/spa-inspect.c b/spa/tools/spa-inspect.c index e25fbf12d..fe0d67f65 100644 --- a/spa/tools/spa-inspect.c +++ b/spa/tools/spa-inspect.c @@ -32,8 +32,8 @@ #include #include #include - -#include +#include +#include static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); @@ -82,8 +82,6 @@ inspect_node_params(struct data *data, struct spa_node *node) printf("enumerating: %s:\n", spa_type_map_get_type(data->map, id)); for (idx2 = 0;;) { - uint32_t flags = 0; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); if ((res = spa_node_enum_params(node, id, &idx2, @@ -92,7 +90,7 @@ inspect_node_params(struct data *data, struct spa_node *node) error(0, -res, "enum_params %d", id); break; } - spa_debug_pod(param, flags); + spa_debug_pod(0, data->map, param); } } } @@ -125,8 +123,6 @@ inspect_port_params(struct data *data, struct spa_node *node, printf("enumerating: %s:\n", spa_type_map_get_type(data->map, id)); for (idx2 = 0;;) { - uint32_t flags = 0; - spa_pod_builder_init(&b, buffer, sizeof(buffer)); if ((res = spa_node_port_enum_params(node, direction, port_id, @@ -138,8 +134,9 @@ inspect_port_params(struct data *data, struct spa_node *node, } if (spa_pod_is_object_type(param, data->type.format)) - flags |= SPA_DEBUG_FLAG_FORMAT; - spa_debug_pod(param, flags); + spa_debug_format(0, data->map, param); + else + spa_debug_pod(0, data->map, param); } } } @@ -152,7 +149,7 @@ static void inspect_node(struct data *data, struct spa_node *node) printf("node info:\n"); if (node->info) - spa_debug_dict(node->info); + spa_debug_dict(2, node->info); else printf(" none\n"); @@ -195,7 +192,7 @@ static void inspect_factory(struct data *data, const struct spa_handle_factory * printf("factory name:\t\t'%s'\n", factory->name); printf("factory info:\n"); if (factory->info) - spa_debug_dict(factory->info); + spa_debug_dict(2, factory->info); else printf(" none\n"); @@ -285,8 +282,6 @@ int main(int argc, char *argv[]) if ((str = getenv("SPA_DEBUG"))) data.log->level = atoi(str); - spa_debug_set_type_map(data.map); - data.support[0].type = SPA_TYPE__TypeMap; data.support[0].data = data.map; data.support[1].type = SPA_TYPE__Log; diff --git a/spa/tools/spa-monitor.c b/spa/tools/spa-monitor.c index d4afeafda..39e5c3831 100644 --- a/spa/tools/spa-monitor.c +++ b/spa/tools/spa-monitor.c @@ -28,9 +28,11 @@ #include #include #include +#include #include -#include +#include +#include static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); @@ -60,7 +62,7 @@ struct data { static void inspect_item(struct data *data, struct spa_pod *item) { - spa_debug_pod(item, 0); + spa_debug_pod(0, data->map, item); } static void on_monitor_event(void *_data, struct spa_event *event) @@ -110,7 +112,7 @@ static void handle_monitor(struct data *data, struct spa_monitor *monitor) uint32_t index; if (monitor->info) - spa_debug_dict(monitor->info); + spa_debug_dict(0, monitor->info); for (index = 0;;) { struct spa_pod *item; @@ -174,8 +176,6 @@ int main(int argc, char *argv[]) data.main_loop.update_source = do_update_source; data.main_loop.remove_source = do_remove_source; - spa_debug_set_type_map(data.map); - data.support[0].type = SPA_TYPE__TypeMap; data.support[0].data = data.map; data.support[1].type = SPA_TYPE__Log; diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index dca809637..0aa916324 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include @@ -445,7 +445,7 @@ static int port_set_format(struct spa_node *node, if (format == NULL) return 0; - spa_debug_pod(format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(0, d->t->map, format); spa_format_video_raw_parse(format, &d->format, &d->type.format_video); @@ -656,8 +656,6 @@ int main(int argc, char *argv[]) init_type(&data.type, data.t->map); reset_props(&data.props); - spa_debug_set_type_map(data.t->map); - if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("can't initialize SDL: %s\n", SDL_GetError()); return -1; diff --git a/src/examples/export-source.c b/src/examples/export-source.c index e6e3a8547..d137d7c3d 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include @@ -351,7 +351,7 @@ static int port_set_format(struct spa_node *node, return 0; } - spa_debug_pod(format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(0, d->t->map, format); if (spa_format_audio_raw_parse(format, &d->format, &d->type.format_audio) < 0) return -EINVAL; @@ -592,7 +592,6 @@ int main(int argc, char *argv[]) spa_list_init(&data.empty); init_type(&data.type, data.t->map); reset_props(&data.props); - spa_debug_set_type_map(data.t->map); pw_remote_add_listener(data.remote, &data.remote_listener, &remote_events, &data); diff --git a/src/examples/export-spa.c b/src/examples/export-spa.c index 6fb11913c..242c0180e 100644 --- a/src/examples/export-spa.c +++ b/src/examples/export-spa.c @@ -140,8 +140,6 @@ int main(int argc, char *argv[]) pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL, NULL, NULL, NULL); - spa_debug_set_type_map(data.t->map); - pw_remote_add_listener(data.remote, &data.remote_listener, &remote_events, &data); pw_remote_connect(data.remote); diff --git a/src/examples/local-v4l2.c b/src/examples/local-v4l2.c index b071af43a..f5915a71d 100644 --- a/src/examples/local-v4l2.c +++ b/src/examples/local-v4l2.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include @@ -337,7 +337,7 @@ static int port_set_format(struct spa_node *node, enum spa_direction direction, if (format == NULL) return 0; - spa_debug_pod(format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(0, d->t->map, format); spa_format_video_raw_parse(format, &d->format, &d->type.format_video); @@ -511,8 +511,6 @@ int main(int argc, char *argv[]) init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.t->map); - if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("can't initialize SDL: %s\n", SDL_GetError()); return -1; diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 49b9cd0cd..03a98819f 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include @@ -343,7 +343,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo params[0] = spa_pod_builder_pop(&b); printf("supported formats:\n"); - spa_debug_pod(params[0], SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, data->t->map, params[0]); pw_stream_add_listener(data->stream, &data->stream_listener, @@ -426,8 +426,6 @@ int main(int argc, char *argv[]) init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.t->map); - if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("can't initialize SDL: %s\n", SDL_GetError()); return -1; diff --git a/src/modules/meson.build b/src/modules/meson.build index e693545ef..2c5092df6 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -66,7 +66,6 @@ pipewire_module_link_factory = shared_library('pipewire-module-link-factory', #pipewire_module_protocol_dbus = shared_library('pipewire-module-protocol-dbus', [ 'module-protocol-dbus.c', gdbus_target ], # c_args : pipewire_module_c_args, # include_directories : [configinc, spa_inc], -# link_with : spalib, # install : true, # install_dir : modules_install_dir, # dependencies : [glib_dep, gio_dep, mathlib, dl_lib, pipewire_dep], @@ -80,7 +79,6 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ 'module-protocol-native/connection.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], - link_with : spalib, install : true, install_dir : modules_install_dir, dependencies : [mathlib, dl_lib, pipewire_dep], diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 912b842cd..f975947e4 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "config.h" @@ -227,7 +227,7 @@ process_messages(struct client_data *data) if (debug_messages) { printf("<<<<<<<<< in: %d %d %d\n", id, opcode, size); - spa_debug_pod((struct spa_pod *)message, 0); + spa_debug_pod(0, core->type.map, (struct spa_pod *)message); } if (demarshal[opcode].func(resource, message, size) < 0) goto invalid_message; @@ -338,7 +338,7 @@ static struct pw_client *client_new(struct server *s, int fd) if (this->source == NULL) goto no_source; - this->connection = pw_protocol_native_connection_new(fd); + this->connection = pw_protocol_native_connection_new(protocol->core, fd); if (this->connection == NULL) goto no_connection; @@ -561,7 +561,7 @@ on_remote_data(void *data, int fd, enum spa_io mask) } if (debug_messages) { printf("<<<<<<<<< in: %d %d %d\n", id, opcode, size); - spa_debug_pod((struct spa_pod *)message, 0); + spa_debug_pod(0, core->type.map, (struct spa_pod *)message); } if (demarshal[opcode].func(proxy, message, size) < 0) { pw_log_error ("protocol-native %p: invalid message received %u for %u", this, @@ -605,7 +605,7 @@ static int impl_connect_fd(struct pw_protocol_client *client, int fd) impl->disconnecting = false; - impl->connection = pw_protocol_native_connection_new(fd); + impl->connection = pw_protocol_native_connection_new(remote->core, fd); if (impl->connection == NULL) goto error_close; diff --git a/src/modules/module-protocol-native/connection.c b/src/modules/module-protocol-native/connection.c index 817e5b56a..b46de7428 100644 --- a/src/modules/module-protocol-native/connection.c +++ b/src/modules/module-protocol-native/connection.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -59,6 +59,8 @@ struct impl { uint32_t dest_id; uint8_t opcode; struct spa_pod_builder builder; + + struct pw_core *core; }; /** \endcond */ @@ -193,7 +195,7 @@ static void clear_buffer(struct buffer *buf) * * \memberof pw_protocol_native_connection */ -struct pw_protocol_native_connection *pw_protocol_native_connection_new(int fd) +struct pw_protocol_native_connection *pw_protocol_native_connection_new(struct pw_core *core, int fd) { struct impl *impl; struct pw_protocol_native_connection *this; @@ -216,6 +218,7 @@ struct pw_protocol_native_connection *pw_protocol_native_connection_new(int fd) impl->in.buffer_data = malloc(MAX_BUFFER_SIZE); impl->in.buffer_maxsize = MAX_BUFFER_SIZE; impl->in.update = true; + impl->core = core; if (impl->out.buffer_data == NULL || impl->in.buffer_data == NULL) goto no_mem; @@ -432,7 +435,7 @@ pw_protocol_native_connection_end(struct pw_protocol_native_connection *conn, if (debug_messages) { printf(">>>>>>>>> out: %d %d %d\n", impl->dest_id, impl->opcode, size); - spa_debug_pod((struct spa_pod *)p, 0); + spa_debug_pod(0, impl->core->type.map, (struct spa_pod *)p); } spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, need_flush); } diff --git a/src/modules/module-protocol-native/connection.h b/src/modules/module-protocol-native/connection.h index eed6bc56a..0a6572881 100644 --- a/src/modules/module-protocol-native/connection.h +++ b/src/modules/module-protocol-native/connection.h @@ -59,7 +59,7 @@ pw_protocol_native_connection_add_listener(struct pw_protocol_native_connection } struct pw_protocol_native_connection * -pw_protocol_native_connection_new(int fd); +pw_protocol_native_connection_new(struct pw_core *core, int fd); void pw_protocol_native_connection_destroy(struct pw_protocol_native_connection *conn); diff --git a/src/pipewire/core.c b/src/pipewire/core.c index da3a1ebf4..c15091521 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -21,10 +21,10 @@ #include #include -#define spa_debug pw_log_trace +#include -#include #include +#include #include #include @@ -33,6 +33,8 @@ #include #include +#undef spa_debug +#define spa_debug pw_log_trace #include /** \cond */ @@ -389,8 +391,6 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro spa_graph_init(&this->rt.graph); spa_graph_set_callbacks(&this->rt.graph, &spa_graph_impl_default, NULL); - spa_debug_set_type_map(this->type.map); - this->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, this->type.map); this->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop); this->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop); @@ -784,7 +784,7 @@ int pw_core_find_format(struct pw_core *core, } pw_log_debug("enum output %d with filter: %p", oidx, filter); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_pod(filter, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, core->type.map, filter); if ((res = spa_node_port_enum_params(output->node->node, output->direction, output->port_id, @@ -800,7 +800,7 @@ int pw_core_find_format(struct pw_core *core, pw_log_debug("Got filtered:"); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_pod(*format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, core->type.map, *format); } else { res = -EBADF; asprintf(error, "error node state"); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 4654d09ad..c330285e5 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -24,11 +24,11 @@ #include #include #include +#include +#include -#include - -#include "pipewire.h" #include "private.h" +#include "pipewire.h" #include "interfaces.h" #include "link.h" #include "work-queue.h" @@ -186,7 +186,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st pw_log_debug("link %p: doing set format %p", this, format); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_pod(format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, t->map, format); if (out_state == PW_PORT_STATE_CONFIGURE) { pw_log_debug("link %p: doing set format on output", this); @@ -459,7 +459,7 @@ param_filter(struct pw_link *this, } if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG) && iparam != NULL) - spa_debug_pod(iparam, 0); + spa_debug_pod(2, this->core->type.map, iparam); for (oidx = 0;;) { pw_log_debug("oparam %d", oidx); @@ -470,7 +470,7 @@ param_filter(struct pw_link *this, } if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_pod(oparam, 0); + spa_debug_pod(2, this->core->type.map, oparam); num++; } @@ -555,8 +555,8 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s } if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) { - spa_debug_port_info(oinfo); - spa_debug_port_info(iinfo); + spa_debug_port_info(2, oinfo); + spa_debug_port_info(2, iinfo); } if (output->allocation.n_buffers) { out_flags = 0; @@ -593,7 +593,7 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s spa_pod_fixate(params[i]); pw_log_debug("fixated param %d:", i); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_pod(params[i], 0); + spa_debug_pod(2, this->core->type.map, params[i]); offset += SPA_ROUND_UP_N(SPA_POD_SIZE(params[i]), 8); } diff --git a/src/pipewire/log.h b/src/pipewire/log.h index 43b97582f..8d2906f5b 100644 --- a/src/pipewire/log.h +++ b/src/pipewire/log.h @@ -65,8 +65,10 @@ pw_log_logv(enum spa_log_level level, (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) #define pw_log_logc(lev,...) \ +({ \ if (SPA_UNLIKELY(pw_log_level_enabled (lev))) \ - pw_log_log(lev,__VA_ARGS__) + pw_log_log(lev,__VA_ARGS__); \ +}) #define pw_log_error(...) pw_log_logc(SPA_LOG_LEVEL_ERROR,__FILE__,__LINE__,__func__,__VA_ARGS__) #define pw_log_warn(...) pw_log_logc(SPA_LOG_LEVEL_WARN,__FILE__,__LINE__,__func__,__VA_ARGS__) diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 8f149eb1c..7cd6f55c7 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -79,12 +79,11 @@ libpipewire = shared_library('pipewire-@0@'.format(apiversion), pipewire_sources soversion : soversion, c_args : libpipewire_c_args, include_directories : [pipewire_inc, configinc, spa_inc], - link_with : spalib, install : true, dependencies : [dl_lib, mathlib, pthread_lib], ) pipewire_dep = declare_dependency(link_with : libpipewire, include_directories : [pipewire_inc, configinc, spa_inc], - dependencies : [pthread_lib,spalib_dep], + dependencies : [pthread_lib], ) diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index 90f65920b..f23254a2e 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include @@ -596,7 +596,7 @@ static void info_link(struct proxy_data *pd) fprintf(stdout, "%c\tinput-port-id: %u\n", MARK_CHANGE(1), info->input_port_id); fprintf(stdout, "%c\tformat:\n", MARK_CHANGE(2)); if (info->format) - spa_debug_pod(info->format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, pd->rd->data->t->map, info->format); else fprintf(stdout, "\t\tnone\n"); print_properties(info->props, MARK_CHANGE(3), true); @@ -666,14 +666,14 @@ static void node_event_param(void *object, uint32_t id, uint32_t index, uint32_t struct proxy_data *data = object; struct remote_data *rd = data->rd; struct pw_type *t = rd->data->t; - uint32_t flags = 0; fprintf(stdout, "remote %d node %d param %d index %d\n", rd->id, data->global->id, id, index); if (spa_pod_is_object_type(param, t->spa_format)) - flags |= SPA_DEBUG_FLAG_FORMAT; - spa_debug_pod(param, flags); + spa_debug_format(2, t->map, param); + else + spa_debug_pod(2, t->map, param); } static const struct pw_node_proxy_events node_events = { @@ -704,14 +704,14 @@ static void port_event_param(void *object, uint32_t id, uint32_t index, uint32_t struct proxy_data *data = object; struct remote_data *rd = data->rd; struct pw_type *t = rd->data->t; - uint32_t flags = 0; fprintf(stdout, "remote %d port %d param %d index %d\n", rd->id, data->global->id, id, index); if (spa_pod_is_object_type(param, t->spa_format)) - flags |= SPA_DEBUG_FLAG_FORMAT; - spa_debug_pod(param, flags); + spa_debug_format(2, t->map, param); + else + spa_debug_pod(2, t->map, param); } static const struct pw_port_proxy_events port_events = { diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index 3bfeba24d..0c71745db 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -20,7 +20,7 @@ #include #include -#include +#include #include #include @@ -216,10 +216,10 @@ static void print_node(struct proxy_data *data) printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); printf("%c\tparams:\n", MARK_CHANGE(5)); for (i = 0; i < data->n_params; i++) { - uint32_t flags = 0; if (spa_pod_is_object_type(data->params[i], t->spa_format)) - flags |= SPA_DEBUG_FLAG_FORMAT; - spa_debug_pod(data->params[i], flags); + spa_debug_format(2, t->map, data->params[i]); + else + spa_debug_pod(2, t->map, data->params[i]); } printf("%c\tinput ports: %u/%u\n", MARK_CHANGE(1), info->n_input_ports, info->max_input_ports); @@ -293,10 +293,10 @@ static void print_port(struct proxy_data *data) printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); printf("%c\tparams:\n", MARK_CHANGE(2)); for (i = 0; i < data->n_params; i++) { - uint32_t flags = 0; if (spa_pod_is_object_type(data->params[i], t->spa_format)) - flags |= SPA_DEBUG_FLAG_FORMAT; - spa_debug_pod(data->params[i], flags); + spa_debug_format(2, t->map, data->params[i]); + else + spa_debug_pod(2, t->map, data->params[i]); } print_properties(info->props, MARK_CHANGE(1)); } @@ -404,6 +404,7 @@ static const struct pw_client_proxy_events client_events = { static void link_event_info(void *object, struct pw_link_info *info) { struct proxy_data *data = object; + struct pw_type *t = pw_core_get_type(data->data->core); bool print_all, print_mark; print_all = true; @@ -431,7 +432,7 @@ static void link_event_info(void *object, struct pw_link_info *info) printf("%c\tinput-port-id: %u\n", MARK_CHANGE(1), info->input_port_id); printf("%c\tformat:\n", MARK_CHANGE(2)); if (info->format) - spa_debug_pod(info->format, SPA_DEBUG_FLAG_FORMAT); + spa_debug_format(2, t->map, info->format); else printf("\t\tnone\n"); print_properties(info->props, MARK_CHANGE(3)); From 4eae1f0c6fb7ceb90159f3cd93565404b9bc7021 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Aug 2018 13:05:10 +0200 Subject: [PATCH 039/155] debug: add specific format debug --- spa/include/spa/debug/format.h | 172 +++++++++++++++++++++++++++++++-- spa/tools/spa-inspect.c | 1 + src/pipewire/link.c | 1 + src/tools/pipewire-cli.c | 1 + src/tools/pipewire-monitor.c | 1 + 5 files changed, 166 insertions(+), 10 deletions(-) diff --git a/spa/include/spa/debug/format.h b/spa/include/spa/debug/format.h index ef57c7fec..820240a6b 100644 --- a/spa/include/spa/debug/format.h +++ b/spa/include/spa/debug/format.h @@ -25,20 +25,172 @@ extern "C" { #endif #include -#include -#include +#include -#ifndef spa_debug -#define spa_debug(...) ({ fprintf(stderr, __VA_ARGS__);fputc('\n', stderr); }) -#endif +static inline int +spa_debug_format_value(struct spa_type_map *map, + uint32_t type, void *body, uint32_t size) +{ + switch (type) { + case SPA_POD_TYPE_BOOL: + fprintf(stderr, "%s", *(int32_t *) body ? "true" : "false"); + break; + case SPA_POD_TYPE_ID: + { + const char *str = map ? spa_type_map_get_type(map, *(int32_t *) body) : NULL; + if (str) { + const char *h = rindex(str, ':'); + if (h) + str = h + 1; + } else { + str = "unknown"; + } + fprintf(stderr, "%s", str); + break; + } + case SPA_POD_TYPE_INT: + fprintf(stderr, "%" PRIi32, *(int32_t *) body); + break; + case SPA_POD_TYPE_LONG: + fprintf(stderr, "%" PRIi64, *(int64_t *) body); + break; + case SPA_POD_TYPE_FLOAT: + fprintf(stderr, "%f", *(float *) body); + break; + case SPA_POD_TYPE_DOUBLE: + fprintf(stderr, "%g", *(double *) body); + break; + case SPA_POD_TYPE_STRING: + fprintf(stderr, "%s", (char *) body); + break; + case SPA_POD_TYPE_RECTANGLE: + { + struct spa_rectangle *r = body; + fprintf(stderr, "%" PRIu32 "x%" PRIu32, r->width, r->height); + break; + } + case SPA_POD_TYPE_FRACTION: + { + struct spa_fraction *f = body; + fprintf(stderr, "%" PRIu32 "/%" PRIu32, f->num, f->denom); + break; + } + case SPA_POD_TYPE_BITMAP: + fprintf(stderr, "Bitmap"); + break; + case SPA_POD_TYPE_BYTES: + fprintf(stderr, "Bytes"); + break; + default: + break; + } + return 0; +} static inline int spa_debug_format(int indent, - struct spa_type_map *map, const struct spa_pod *pod) + struct spa_type_map *map, const struct spa_pod *format) { - return spa_debug_pod_value(indent, map, - SPA_POD_TYPE(pod), - SPA_POD_BODY(pod), - SPA_POD_BODY_SIZE(pod)); + int i; + const char *media_type; + const char *media_subtype; + struct spa_pod *pod; + uint32_t mtype, mstype; + const char *pod_type_names[] = { + [SPA_POD_TYPE_INVALID] = "invalid", + [SPA_POD_TYPE_NONE] = "none", + [SPA_POD_TYPE_BOOL] = "bool", + [SPA_POD_TYPE_ID] = "id", + [SPA_POD_TYPE_INT] = "int", + [SPA_POD_TYPE_LONG] = "long", + [SPA_POD_TYPE_FLOAT] = "float", + [SPA_POD_TYPE_DOUBLE] = "double", + [SPA_POD_TYPE_STRING] = "string", + [SPA_POD_TYPE_BYTES] = "bytes", + [SPA_POD_TYPE_RECTANGLE] = "rectangle", + [SPA_POD_TYPE_FRACTION] = "fraction", + [SPA_POD_TYPE_BITMAP] = "bitmap", + [SPA_POD_TYPE_ARRAY] = "array", + [SPA_POD_TYPE_STRUCT] = "struct", + [SPA_POD_TYPE_OBJECT] = "object", + [SPA_POD_TYPE_POINTER] = "pointer", + [SPA_POD_TYPE_FD] = "fd", + [SPA_POD_TYPE_PROP] = "prop", + [SPA_POD_TYPE_POD] = "pod" + }; + + if (format == NULL || SPA_POD_TYPE(format) != SPA_POD_TYPE_OBJECT) + return -EINVAL; + + if (spa_pod_object_parse(format, "I", &mtype, + "I", &mstype) < 0) + return -EINVAL; + + media_type = spa_type_map_get_type(map, mtype); + media_subtype = spa_type_map_get_type(map, mstype); + + fprintf(stderr, "%-6s %s/%s\n", "", rindex(media_type, ':') + 1, + rindex(media_subtype, ':') + 1); + + SPA_POD_OBJECT_FOREACH((struct spa_pod_object*)format, pod) { + struct spa_pod_prop *prop; + const char *key; + + if (pod->type != SPA_POD_TYPE_PROP) + continue; + + prop = (struct spa_pod_prop *)pod; + + if ((prop->body.flags & SPA_POD_PROP_FLAG_UNSET) && + (prop->body.flags & SPA_POD_PROP_FLAG_OPTIONAL)) + continue; + + key = spa_type_map_get_type(map, prop->body.key); + + fprintf(stderr, " %20s : (%s) ", rindex(key, ':') + 1, + pod_type_names[prop->body.value.type]); + + if (!(prop->body.flags & SPA_POD_PROP_FLAG_UNSET)) { + spa_debug_format_value(map, + prop->body.value.type, + SPA_POD_BODY(&prop->body.value), + prop->body.value.size); + } else { + const char *ssep, *esep, *sep; + void *alt; + + switch (prop->body.flags & SPA_POD_PROP_RANGE_MASK) { + case SPA_POD_PROP_RANGE_MIN_MAX: + case SPA_POD_PROP_RANGE_STEP: + ssep = "[ "; + sep = ", "; + esep = " ]"; + break; + default: + case SPA_POD_PROP_RANGE_ENUM: + case SPA_POD_PROP_RANGE_FLAGS: + ssep = "{ "; + sep = ", "; + esep = " }"; + break; + } + + fprintf(stderr, "%s", ssep); + + i = 0; + SPA_POD_PROP_ALTERNATIVE_FOREACH(&prop->body, prop->pod.size, alt) { + if (i > 0) + fprintf(stderr, "%s", sep); + spa_debug_format_value(map, + prop->body.value.type, + alt, + prop->body.value.size); + i++; + } + fprintf(stderr, "%s", esep); + } + fprintf(stderr, "\n"); + } + return 0; } #ifdef __cplusplus diff --git a/spa/tools/spa-inspect.c b/spa/tools/spa-inspect.c index fe0d67f65..12b5cbb92 100644 --- a/spa/tools/spa-inspect.c +++ b/spa/tools/spa-inspect.c @@ -33,6 +33,7 @@ #include #include #include +#include #include static SPA_TYPE_MAP_IMPL(default_map, 4096); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index c330285e5..24bc18623 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include "private.h" diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index f23254a2e..bf5ec0c21 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -25,6 +25,7 @@ #include #include +#include #include #include diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index 0c71745db..7f73ecd35 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -20,6 +20,7 @@ #include #include +#include #include #include From d93afe7f9b41c6d9d9c17319224a56af47e138e2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Aug 2018 15:37:18 +0200 Subject: [PATCH 040/155] core: set version --- src/pipewire/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index c15091521..290e91819 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -427,7 +427,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro this->info.change_mask = 0; this->info.user_name = pw_get_user_name(); this->info.host_name = pw_get_host_name(); - this->info.version = SPA_STRINGIFY(PW_VERSION_CORE); + this->info.version = pw_get_library_version(); srandom(time(NULL)); this->info.cookie = random(); this->info.props = &properties->dict; From 813506a614f07f32bea25d41e86b2e7f88e0886c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 14 Aug 2018 16:57:34 +0200 Subject: [PATCH 041/155] map: use invalid value for empty list --- src/pipewire/map.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pipewire/map.h b/src/pipewire/map.h index 127add0ee..9cd277563 100644 --- a/src/pipewire/map.h +++ b/src/pipewire/map.h @@ -71,7 +71,7 @@ static inline void pw_map_init(struct pw_map *map, size_t size, size_t extend) { pw_array_init(&map->items, extend); pw_array_ensure_size(&map->items, size * sizeof(union pw_map_item)); - map->free_list = 0; + map->free_list = SPA_ID_INVALID; } /** Clear a map @@ -94,7 +94,7 @@ static inline uint32_t pw_map_insert_new(struct pw_map *map, void *data) union pw_map_item *start, *item; uint32_t id; - if (map->free_list) { + if (map->free_list != SPA_ID_INVALID) { start = (union pw_map_item *) map->items.data; item = &start[map->free_list >> 1]; map->free_list = item->next; From 2de7f9cc0362319eb78ff8f13137503e6eb26c7d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 11:17:12 +0200 Subject: [PATCH 042/155] list: add iteration with a cursor Iterating a list with a cursor is heavier but is safe against removal of any element in the list. Move the hook cursor iterator to list. --- spa/include/spa/utils/hook.h | 13 ++++--------- spa/include/spa/utils/list.h | 17 +++++++++++++++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index e23200dac..9fa44be13 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -85,16 +85,11 @@ static inline void spa_hook_remove(struct spa_hook *hook) ({ \ struct spa_hook_list *list = l; \ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \ - struct spa_hook cursor = { 0, }; \ - struct spa_hook *ci; \ + struct spa_hook cursor = { 0 }, *ci; \ int count = 0; \ - spa_list_prepend(s, &cursor.link); \ - for(ci = spa_list_first(&cursor.link, struct spa_hook, link); \ - &ci->link != s; \ - ci = spa_list_next(&cursor, link)) { \ + spa_list_cursor_start(cursor, s, link); \ + spa_list_for_each_cursor(ci, cursor, &list->list, link) { \ const type *cb = ci->funcs; \ - spa_list_remove(&ci->link); \ - spa_list_append(&cursor.link, &ci->link); \ if (cb && cb->method) { \ cb->method(ci->data, ## __VA_ARGS__); \ count++; \ @@ -102,7 +97,7 @@ static inline void spa_hook_remove(struct spa_hook *hook) break; \ } \ } \ - spa_list_remove(&cursor.link); \ + spa_list_cursor_end(cursor, link); \ count; \ }) diff --git a/spa/include/spa/utils/list.h b/spa/include/spa/utils/list.h index 16376f23e..18a06a523 100644 --- a/spa/include/spa/utils/list.h +++ b/spa/include/spa/utils/list.h @@ -84,7 +84,7 @@ static inline void spa_list_remove(struct spa_list *elem) pos = spa_list_next(pos, member)) #define spa_list_for_each(pos, head, member) \ - spa_list_for_each_next(pos, head, head, member) \ + spa_list_for_each_next(pos, head, head, member) #define spa_list_for_each_safe_next(pos, tmp, head, curr, member) \ for (pos = spa_list_first(curr, __typeof__(*pos), member), \ @@ -94,7 +94,20 @@ static inline void spa_list_remove(struct spa_list *elem) tmp = spa_list_next(pos, member)) #define spa_list_for_each_safe(pos, tmp, head, member) \ - spa_list_for_each_safe_next(pos, tmp, head, head, member) \ + spa_list_for_each_safe_next(pos, tmp, head, head, member) + +#define spa_list_cursor_start(cursor, head, member) \ + spa_list_prepend(head, &(cursor).member) + +#define spa_list_for_each_cursor(pos, cursor, head, member) \ + for(pos = spa_list_first(&(cursor).member, __typeof__(*(pos)), member); \ + spa_list_remove(&(pos)->member), \ + spa_list_append(&(cursor).member, &(pos)->member), \ + !spa_list_is_end(pos, head, member); \ + pos = spa_list_next(&cursor, member)) + +#define spa_list_cursor_end(cursor, member) \ + spa_list_remove(&(cursor).member) #ifdef __cplusplus } /* extern "C" */ From 150e30dfb959b0905f7a3532f8999795747ef905 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 11:18:55 +0200 Subject: [PATCH 043/155] map: make for_each use a return value Make it possible to stop pw_map_for_each by adding a return value to the callback. --- src/pipewire/client.c | 3 ++- src/pipewire/map.h | 13 ++++++++++--- src/tools/pipewire-cli.c | 15 +++++++++------ 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 711f1d86f..df92e3a05 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -279,10 +279,11 @@ void *pw_client_get_user_data(struct pw_client *client) return client->user_data; } -static void destroy_resource(void *object, void *data) +static int destroy_resource(void *object, void *data) { if (object) pw_resource_destroy(object); + return 0; } /** Destroy a client object diff --git a/src/pipewire/map.h b/src/pipewire/map.h index 9cd277563..4419383d4 100644 --- a/src/pipewire/map.h +++ b/src/pipewire/map.h @@ -161,18 +161,25 @@ static inline void *pw_map_lookup(struct pw_map *map, uint32_t id) /** Iterate all map items * \param map the map to iterate - * \param func the function to call for each item + * \param func the function to call for each item, the item data and \a data is + * passed to the function. When \a func returns a non-zero result, + * iteration ends and the result is returned. * \param data data to pass to \a func + * \return the result of the last call to \a func or 0 when all callbacks returned 0. * \memberof pw_map */ -static inline void pw_map_for_each(struct pw_map *map, void (*func) (void *, void *), void *data) +static inline int pw_map_for_each(struct pw_map *map, + int (*func) (void *item_data, void *data), void *data) { union pw_map_item *item; + int res = 0; pw_array_for_each(item, &map->items) { if (!pw_map_item_is_free(item)) - func(item->data, data); + if ((res = func(item->data, data)) != 0) + break; } + return res; } #ifdef __cplusplus diff --git a/src/tools/pipewire-cli.c b/src/tools/pipewire-cli.c index bf5ec0c21..bcfb3d769 100644 --- a/src/tools/pipewire-cli.c +++ b/src/tools/pipewire-cli.c @@ -259,13 +259,13 @@ static void on_sync_reply(void *_data, uint32_t seq) } } -static void print_global(void *obj, void *data) +static int print_global(void *obj, void *data) { struct global *global = obj; struct pw_type *t; if (global == NULL) - return; + return 0; t = global->rd->data->t; @@ -275,6 +275,7 @@ static void print_global(void *obj, void *data) if (global->properties) print_properties(&global->properties->dict, ' ', false); + return 0; } static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, @@ -303,17 +304,18 @@ static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, pw_map_insert_at(&rd->globals, id, global); } -static void destroy_global(void *obj, void *data) +static int destroy_global(void *obj, void *data) { struct global *global = obj; if (global == NULL) - return; + return 0; pw_map_remove(&global->rd->globals, global->id); if (global->properties) pw_properties_free(global->properties); free(global); + return 0; } static void registry_event_global_remove(void *data, uint32_t id) @@ -902,18 +904,19 @@ static bool do_global_info(struct global *global, char **error) } return true; } -static void do_global_info_all(void *obj, void *data) +static int do_global_info_all(void *obj, void *data) { struct global *global = obj; char *error; if (global == NULL) - return; + return 0; if (!do_global_info(global, &error)) { fprintf(stderr, "info: %s\n", error); free(error); } + return 0; } static bool do_info(struct data *data, const char *cmd, char *args, char **error) From d8525e3732c17bb7e6de116ad91391109824a4c0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 1 Aug 2018 21:41:25 +0200 Subject: [PATCH 044/155] hooks: enforce version on hook emission Pass the minimum required version to the hook emission and only call events when the handler is recent enough. Add some macros to make event emission easier to read. --- spa/include/spa/support/loop.h | 3 + spa/include/spa/utils/hook.h | 18 +-- spa/plugins/support/loop.c | 8 +- .../module-client-node/protocol-native.c | 34 +++--- .../module-protocol-native/connection.c | 7 +- .../module-protocol-native/connection.h | 2 + .../module-protocol-native/protocol-native.c | 52 ++++----- src/pipewire/client.c | 10 +- src/pipewire/control.c | 17 ++- src/pipewire/core.c | 7 +- src/pipewire/data-loop.c | 2 +- src/pipewire/factory.c | 2 +- src/pipewire/global.c | 11 +- src/pipewire/link.c | 19 ++-- src/pipewire/main-loop.c | 2 +- src/pipewire/module.c | 2 +- src/pipewire/node.c | 33 +++--- src/pipewire/port.c | 13 +-- src/pipewire/private.h | 103 ++++++++++++++++++ src/pipewire/protocol.c | 2 +- src/pipewire/proxy.c | 2 +- src/pipewire/proxy.h | 2 +- src/pipewire/remote.c | 10 +- src/pipewire/resource.c | 8 +- src/pipewire/resource.h | 6 +- src/pipewire/stream.c | 17 +-- src/pipewire/thread-loop.c | 5 +- 27 files changed, 249 insertions(+), 148 deletions(-) diff --git a/spa/include/spa/support/loop.h b/spa/include/spa/support/loop.h index 73fda8002..d6fa85b26 100644 --- a/spa/include/spa/support/loop.h +++ b/spa/include/spa/support/loop.h @@ -111,6 +111,9 @@ struct spa_loop_control_hooks { void (*after) (void *data); }; +#define spa_loop_control_hook_before(l) spa_hook_list_call(l, struct spa_loop_control_hooks, before, 0) +#define spa_loop_control_hook_after(l) spa_hook_list_call(l, struct spa_loop_control_hooks, after, 0) + /** * Control an event loop */ diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index 9fa44be13..bde20dc27 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -43,7 +43,9 @@ struct spa_hook { struct spa_list link; const void *funcs; void *data; - void *priv[2]; /**< private data for the hook list */ + void *priv; /**< private data for the hook list */ + void (*removed) (struct spa_hook *hook); + }; /** Initialize a hook list */ @@ -76,12 +78,14 @@ static inline void spa_hook_list_prepend(struct spa_hook_list *list, static inline void spa_hook_remove(struct spa_hook *hook) { spa_list_remove(&hook->link); + if (hook->removed) + hook->removed(hook); } /** Call all hooks in a list, starting from the given one and optionally stopping * after calling the first non-NULL function, returns the number of methods * called */ -#define spa_hook_list_do_call(l,start,type,method,once,...) \ +#define spa_hook_list_do_call(l,start,type,method,vers,once,...) \ ({ \ struct spa_hook_list *list = l; \ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \ @@ -90,7 +94,7 @@ static inline void spa_hook_remove(struct spa_hook *hook) spa_list_cursor_start(cursor, s, link); \ spa_list_for_each_cursor(ci, cursor, &list->list, link) { \ const type *cb = ci->funcs; \ - if (cb && cb->method) { \ + if (cb && cb->version >= vers && cb->method) { \ cb->method(ci->data, ## __VA_ARGS__); \ count++; \ if (once) \ @@ -101,11 +105,11 @@ static inline void spa_hook_remove(struct spa_hook *hook) count; \ }) -#define spa_hook_list_call(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,false,##__VA_ARGS__) -#define spa_hook_list_call_once(l,t,m,...) spa_hook_list_do_call(l,NULL,t,m,true,##__VA_ARGS__) +#define spa_hook_list_call(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,false,##__VA_ARGS__) +#define spa_hook_list_call_once(l,t,m,v,...) spa_hook_list_do_call(l,NULL,t,m,v,true,##__VA_ARGS__) -#define spa_hook_list_call_start(l,s,t,m,...) spa_hook_list_do_call(l,s,t,m,false,##__VA_ARGS__) -#define spa_hook_list_call_once_start(l,s,t,m,...) spa_hook_list_do_call(l,s,t,m,true,##__VA_ARGS__) +#define spa_hook_list_call_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,false,##__VA_ARGS__) +#define spa_hook_list_call_once_start(l,s,t,m,v,...) spa_hook_list_do_call(l,s,t,m,v,true,##__VA_ARGS__) #ifdef __cplusplus } diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index a476868c2..8abf4bc28 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -250,13 +250,13 @@ loop_invoke(struct spa_loop *loop, if (block) { uint64_t count = 1; - spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, before); + spa_loop_control_hook_before(&impl->hooks_list); if (read(impl->ack_fd, &count, sizeof(uint64_t)) != sizeof(uint64_t)) spa_log_warn(impl->log, NAME " %p: failed to read event fd: %s", impl, strerror(errno)); - spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, after); + spa_loop_control_hook_after(&impl->hooks_list); res = item->res; } @@ -335,12 +335,12 @@ static int loop_iterate(struct spa_loop_control *ctrl, int timeout) struct epoll_event ep[32]; int i, nfds, save_errno = 0; - spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, before); + spa_loop_control_hook_before(&impl->hooks_list); if (SPA_UNLIKELY((nfds = epoll_wait(impl->epoll_fd, ep, SPA_N_ELEMENTS(ep), timeout)) < 0)) save_errno = errno; - spa_hook_list_call(&impl->hooks_list, struct spa_loop_control_hooks, after); + spa_loop_control_hook_after(&impl->hooks_list); if (SPA_UNLIKELY(nfds < 0)) return save_errno; diff --git a/src/modules/module-client-node/protocol-native.c b/src/modules/module-client-node/protocol-native.c index a645e8009..30852a8c8 100644 --- a/src/modules/module-client-node/protocol-native.c +++ b/src/modules/module-client-node/protocol-native.c @@ -177,7 +177,7 @@ static int client_node_demarshal_add_mem(void *object, void *data, size_t size) memfd = pw_protocol_native_get_proxy_fd(proxy, memfd_idx); - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, add_mem, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, add_mem, 0, mem_id, type, memfd, flags); @@ -213,7 +213,7 @@ static int client_node_demarshal_transport(void *object, void *data, size_t size transport = pw_client_node_transport_new_from_info(&info); - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, transport, node_id, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, transport, 0, node_id, readfd, writefd, transport); return 0; } @@ -234,7 +234,7 @@ static int client_node_demarshal_set_param(void *object, void *data, size_t size "O", ¶m, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, set_param, seq, id, flags, param); + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, set_param, 0, seq, id, flags, param); return 0; } @@ -248,7 +248,7 @@ static int client_node_demarshal_event_event(void *object, void *data, size_t si if (spa_pod_parser_get(&prs, "[ O", &event, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, event, event); + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, event, 0, event); return 0; } @@ -266,7 +266,7 @@ static int client_node_demarshal_command(void *object, void *data, size_t size) "O", &command, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, command, seq, command); + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, command, 0, seq, command); return 0; } @@ -284,7 +284,7 @@ static int client_node_demarshal_add_port(void *object, void *data, size_t size) "i", &port_id, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, add_port, seq, direction, port_id); + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, add_port, 0, seq, direction, port_id); return 0; } @@ -302,7 +302,7 @@ static int client_node_demarshal_remove_port(void *object, void *data, size_t si "i", &port_id, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, remove_port, seq, direction, port_id); + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, remove_port, 0, seq, direction, port_id); return 0; } @@ -324,7 +324,7 @@ static int client_node_demarshal_port_set_param(void *object, void *data, size_t "O", ¶m, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_set_param, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_set_param, 0, seq, direction, port_id, id, flags, param); return 0; } @@ -385,7 +385,7 @@ static int client_node_demarshal_port_use_buffers(void *object, void *data, size d->data = SPA_UINT32_TO_PTR(data_id); } } - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_use_buffers, seq, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_use_buffers, 0, seq, direction, port_id, n_buffers, buffers); @@ -407,7 +407,7 @@ static int client_node_demarshal_port_command(void *object, void *data, size_t s "O", &command, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_command, direction, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_command, 0, direction, port_id, command); return 0; @@ -431,7 +431,7 @@ static int client_node_demarshal_port_set_io(void *object, void *data, size_t si "i", &sz, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_set_io, + pw_proxy_notify(proxy, struct pw_client_node_proxy_events, port_set_io, 0, seq, direction, port_id, id, memid, @@ -695,7 +695,7 @@ static int client_node_demarshal_done(void *object, void *data, size_t size) "i", &res, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_node_proxy_methods, done, seq, res); + pw_resource_do(resource, struct pw_client_node_proxy_methods, done, 0, seq, res); return 0; } @@ -721,7 +721,7 @@ static int client_node_demarshal_update(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "O", ¶ms[i], NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_node_proxy_methods, update, change_mask, + pw_resource_do(resource, struct pw_client_node_proxy_methods, update, 0, change_mask, max_input_ports, max_output_ports, n_params, @@ -782,7 +782,7 @@ static int client_node_demarshal_port_update(void *object, void *data, size_t si } } - pw_resource_do(resource, struct pw_client_node_proxy_methods, port_update, direction, + pw_resource_do(resource, struct pw_client_node_proxy_methods, port_update, 0, direction, port_id, change_mask, n_params, @@ -802,7 +802,7 @@ static int client_node_demarshal_set_active(void *object, void *data, size_t siz "b", &active, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_node_proxy_methods, set_active, active); + pw_resource_do(resource, struct pw_client_node_proxy_methods, set_active, 0, active); return 0; } @@ -818,7 +818,7 @@ static int client_node_demarshal_event_method(void *object, void *data, size_t s "O", &event, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_node_proxy_methods, event, event); + pw_resource_do(resource, struct pw_client_node_proxy_methods, event, 0, event); return 0; } @@ -831,7 +831,7 @@ static int client_node_demarshal_destroy(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[", NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_client_node_proxy_methods, destroy); + pw_resource_do(resource, struct pw_client_node_proxy_methods, destroy, 0); return 0; } diff --git a/src/modules/module-protocol-native/connection.c b/src/modules/module-protocol-native/connection.c index b46de7428..7a6e63324 100644 --- a/src/modules/module-protocol-native/connection.c +++ b/src/modules/module-protocol-native/connection.c @@ -120,7 +120,7 @@ static void *connection_ensure_size(struct pw_protocol_native_connection *conn, buf->buffer_data = realloc(buf->buffer_data, buf->buffer_maxsize); if (buf->buffer_data == NULL) { buf->buffer_maxsize = 0; - spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, error, -ENOMEM); + spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, error, 0, -ENOMEM); return NULL; } pw_log_warn("connection %p: resize buffer to %zd %zd %zd", @@ -244,7 +244,7 @@ void pw_protocol_native_connection_destroy(struct pw_protocol_native_connection pw_log_debug("connection %p: destroy", conn); - spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, destroy); + spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, destroy, 0); free(impl->out.buffer_data); free(impl->in.buffer_data); @@ -437,7 +437,8 @@ pw_protocol_native_connection_end(struct pw_protocol_native_connection *conn, printf(">>>>>>>>> out: %d %d %d\n", impl->dest_id, impl->opcode, size); spa_debug_pod(0, impl->core->type.map, (struct spa_pod *)p); } - spa_hook_list_call(&conn->listener_list, struct pw_protocol_native_connection_events, need_flush); + spa_hook_list_call(&conn->listener_list, + struct pw_protocol_native_connection_events, need_flush, 0); } /** Flush the connection object diff --git a/src/modules/module-protocol-native/connection.h b/src/modules/module-protocol-native/connection.h index 0a6572881..bcd2915a8 100644 --- a/src/modules/module-protocol-native/connection.h +++ b/src/modules/module-protocol-native/connection.h @@ -29,6 +29,8 @@ extern "C" { struct pw_protocol_native_connection_events { #define PW_VERSION_PROTOCOL_NATIVE_CONNECTION_EVENTS 0 + uint32_t version; + void (*destroy) (void *data); void (*error) (void *data, int error); diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index 7567f9fe8..b81f6d52f 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -210,7 +210,7 @@ static int core_demarshal_info(void *object, void *data, size_t size) NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_core_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_core_proxy_events, info, 0, &info); return 0; } @@ -224,7 +224,7 @@ static int core_demarshal_done(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[ i", &seq, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_core_proxy_events, done, seq); + pw_proxy_notify(proxy, struct pw_core_proxy_events, done, 0, seq); return 0; } @@ -242,7 +242,7 @@ static int core_demarshal_error(void *object, void *data, size_t size) "s", &error, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_core_proxy_events, error, id, res, error); + pw_proxy_notify(proxy, struct pw_core_proxy_events, error, 0, id, res, error); return 0; } @@ -256,7 +256,7 @@ static int core_demarshal_remove_id(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[ i", &id, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_core_proxy_events, remove_id, id); + pw_proxy_notify(proxy, struct pw_core_proxy_events, remove_id, 0, id); return 0; } @@ -280,7 +280,7 @@ static int core_demarshal_update_types_client(void *object, void *data, size_t s if (spa_pod_parser_get(&prs, "s", &types[i], NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_core_proxy_events, update_types, first_id, types, n_types); + pw_proxy_notify(proxy, struct pw_core_proxy_events, update_types, 0, first_id, types, n_types); return 0; } @@ -401,7 +401,7 @@ static int core_demarshal_client_update(void *object, void *data, size_t size) NULL) < 0) return -EINVAL; } - pw_resource_do(resource, struct pw_core_proxy_methods, client_update, &props); + pw_resource_do(resource, struct pw_core_proxy_methods, client_update, 0, &props); return 0; } @@ -424,7 +424,7 @@ static int core_demarshal_permissions(void *object, void *data, size_t size) NULL) < 0) return -EINVAL; } - pw_resource_do(resource, struct pw_core_proxy_methods, permissions, &props); + pw_resource_do(resource, struct pw_core_proxy_methods, permissions, 0, &props); return 0; } @@ -438,7 +438,7 @@ static int core_demarshal_hello(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[P]", &ptr, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_core_proxy_methods, hello); + pw_resource_do(resource, struct pw_core_proxy_methods, hello, 0); return 0; } @@ -452,7 +452,7 @@ static int core_demarshal_sync(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[i]", &seq, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_core_proxy_methods, sync, seq); + pw_resource_do(resource, struct pw_core_proxy_methods, sync, 0, seq); return 0; } @@ -466,7 +466,7 @@ static int core_demarshal_get_registry(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[ii]", &version, &new_id, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_core_proxy_methods, get_registry, version, new_id); + pw_resource_do(resource, struct pw_core_proxy_methods, get_registry, 0, version, new_id); return 0; } @@ -496,7 +496,7 @@ static int core_demarshal_create_object(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "i", &new_id, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_core_proxy_methods, create_object, factory_name, + pw_resource_do(resource, struct pw_core_proxy_methods, create_object, 0, factory_name, type, version, &props, new_id); return 0; @@ -512,7 +512,7 @@ static int core_demarshal_destroy(void *object, void *data, size_t size) if (spa_pod_parser_get(&prs, "[i]", &id, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_core_proxy_methods, destroy, id); + pw_resource_do(resource, struct pw_core_proxy_methods, destroy, 0, id); return 0; } @@ -536,7 +536,7 @@ static int core_demarshal_update_types_server(void *object, void *data, size_t s if (spa_pod_parser_get(&prs, "s", &types[i], NULL) < 0) return -EINVAL; } - pw_resource_do(resource, struct pw_core_proxy_methods, update_types, first_id, types, n_types); + pw_resource_do(resource, struct pw_core_proxy_methods, update_types, 0, first_id, types, n_types); return 0; } @@ -597,7 +597,7 @@ static int registry_demarshal_bind(void *object, void *data, size_t size) "i", &new_id, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_registry_proxy_methods, bind, id, type, version, new_id); + pw_resource_do(resource, struct pw_registry_proxy_methods, bind, 0, id, type, version, new_id); return 0; } @@ -656,7 +656,7 @@ static int module_demarshal_info(void *object, void *data, size_t size) &props.items[i].key, &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_module_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_module_proxy_events, info, 0, &info); return 0; } @@ -716,7 +716,7 @@ static int factory_demarshal_info(void *object, void *data, size_t size) "s", &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_factory_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_factory_proxy_events, info, 0, &info); return 0; } @@ -784,7 +784,7 @@ static int node_demarshal_info(void *object, void *data, size_t size) "s", &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_node_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_node_proxy_events, info, 0, &info); return 0; } @@ -816,7 +816,7 @@ static int node_demarshal_param(void *object, void *data, size_t size) "P", ¶m, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_node_proxy_events, param, id, index, next, param); + pw_proxy_notify(proxy, struct pw_node_proxy_events, param, 0, id, index, next, param); return 0; } @@ -852,7 +852,7 @@ static int node_demarshal_enum_params(void *object, void *data, size_t size) "P", &filter, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_node_proxy_methods, enum_params, id, index, num, filter); + pw_resource_do(resource, struct pw_node_proxy_methods, enum_params, 0, id, index, num, filter); return 0; } @@ -908,7 +908,7 @@ static int port_demarshal_info(void *object, void *data, size_t size) "s", &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_port_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_port_proxy_events, info, 0, &info); return 0; } @@ -940,7 +940,7 @@ static int port_demarshal_param(void *object, void *data, size_t size) "P", ¶m, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_port_proxy_events, param, id, index, next, param); + pw_proxy_notify(proxy, struct pw_port_proxy_events, param, 0, id, index, next, param); return 0; } @@ -976,7 +976,7 @@ static int port_demarshal_enum_params(void *object, void *data, size_t size) "P", &filter, NULL) < 0) return -EINVAL; - pw_resource_do(resource, struct pw_port_proxy_methods, enum_params, id, index, num, filter); + pw_resource_do(resource, struct pw_port_proxy_methods, enum_params, 0, id, index, num, filter); return 0; } @@ -1030,7 +1030,7 @@ static int client_demarshal_info(void *object, void *data, size_t size) "s", &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_client_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_client_proxy_events, info, 0, &info); return 0; } @@ -1094,7 +1094,7 @@ static int link_demarshal_info(void *object, void *data, size_t size) "s", &props.items[i].value, NULL) < 0) return -EINVAL; } - pw_proxy_notify(proxy, struct pw_link_proxy_events, info, &info); + pw_proxy_notify(proxy, struct pw_link_proxy_events, info, 0, &info); return 0; } @@ -1125,7 +1125,7 @@ static int registry_demarshal_global(void *object, void *data, size_t size) } pw_proxy_notify(proxy, struct pw_registry_proxy_events, - global, id, parent_id, permissions, type, version, + global, 0, id, parent_id, permissions, type, version, props.n_items > 0 ? &props : NULL); return 0; } @@ -1140,7 +1140,7 @@ static int registry_demarshal_global_remove(void *object, void *data, size_t siz if (spa_pod_parser_get(&prs, "[ i", &id, NULL) < 0) return -EINVAL; - pw_proxy_notify(proxy, struct pw_registry_proxy_events, global_remove, id); + pw_proxy_notify(proxy, struct pw_registry_proxy_events, global_remove, 0, id); return 0; } diff --git a/src/pipewire/client.c b/src/pipewire/client.c index df92e3a05..e25eb648e 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -286,6 +286,7 @@ static int destroy_resource(void *object, void *data) return 0; } + /** Destroy a client object * * \param client the client to destroy @@ -298,7 +299,7 @@ void pw_client_destroy(struct pw_client *client) struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); pw_log_debug("client %p: destroy", client); - spa_hook_list_call(&client->listener_list, struct pw_client_events, destroy); + pw_client_events_destroy(client); spa_hook_remove(&impl->core_listener); @@ -315,7 +316,7 @@ void pw_client_destroy(struct pw_client *client) pw_map_for_each(&client->objects, destroy_resource, client); - spa_hook_list_call(&client->listener_list, struct pw_client_events, free); + pw_client_events_free(client); pw_log_debug("client %p: free", impl); pw_map_clear(&client->objects); @@ -370,8 +371,7 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict client->info.change_mask |= PW_CLIENT_CHANGE_MASK_PROPS; client->info.props = client->properties ? &client->properties->dict : NULL; - spa_hook_list_call(&client->listener_list, struct pw_client_events, - info_changed, &client->info); + pw_client_events_info_changed(client, &client->info); spa_list_for_each(resource, &client->resource_list, link) pw_client_resource_info(resource, &client->info); @@ -505,6 +505,6 @@ void pw_client_set_busy(struct pw_client *client, bool busy) if (client->busy != busy) { pw_log_debug("client %p: busy %d", client, busy); client->busy = busy; - spa_hook_list_call(&client->listener_list, struct pw_client_events, busy_changed, busy); + pw_client_events_busy_changed(client, busy); } } diff --git a/src/pipewire/control.c b/src/pipewire/control.c index f1c096cc6..747fa1ac9 100644 --- a/src/pipewire/control.c +++ b/src/pipewire/control.c @@ -71,7 +71,7 @@ pw_control_new(struct pw_core *core, spa_list_append(&core->control_list[direction], &this->link); if (port) { spa_list_append(&port->control_list[direction], &this->port_link); - spa_hook_list_call(&port->listener_list, struct pw_port_events, control_added, this); + pw_port_events_control_added(port, this); } return this; @@ -89,7 +89,7 @@ void pw_control_destroy(struct pw_control *control) pw_log_debug("control %p: destroy", control); - spa_hook_list_call(&control->listener_list, struct pw_control_events, destroy); + pw_control_events_destroy(control); if (control->direction == SPA_DIRECTION_OUTPUT) { spa_list_for_each_safe(other, tmp, &control->inputs, inputs_link) @@ -104,12 +104,11 @@ void pw_control_destroy(struct pw_control *control) if (control->port) { spa_list_remove(&control->port_link); - spa_hook_list_call(&control->port->listener_list, - struct pw_port_events, control_removed, control); + pw_port_events_control_removed(control->port, control); } pw_log_debug("control %p: free", control); - spa_hook_list_call(&control->listener_list, struct pw_control_events, free); + pw_control_events_free(control); if (control->direction == SPA_DIRECTION_OUTPUT) { if (impl->mem) @@ -192,8 +191,8 @@ int pw_control_link(struct pw_control *control, struct pw_control *other) other->output = control; spa_list_append(&control->inputs, &other->inputs_link); - spa_hook_list_call(&control->listener_list, struct pw_control_events, linked, other); - spa_hook_list_call(&other->listener_list, struct pw_control_events, linked, control); + pw_control_events_linked(control, other); + pw_control_events_linked(other, control); exit: return res; @@ -238,8 +237,8 @@ int pw_control_unlink(struct pw_control *control, struct pw_control *other) } } - spa_hook_list_call(&control->listener_list, struct pw_control_events, unlinked, other); - spa_hook_list_call(&other->listener_list, struct pw_control_events, unlinked, control); + pw_control_events_unlinked(control, other); + pw_control_events_unlinked(other, control); return res; } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 290e91819..a844eb41e 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -474,7 +474,7 @@ void pw_core_destroy(struct pw_core *core) struct pw_node *node, *tn; pw_log_debug("core %p: destroy", core); - spa_hook_list_call(&core->listener_list, struct pw_core_events, destroy); + pw_core_events_destroy(core); spa_hook_remove(&core->global_listener); @@ -490,7 +490,7 @@ void pw_core_destroy(struct pw_core *core) spa_list_for_each_safe(global, t, &core->global_list, link) pw_global_destroy(global); - spa_hook_list_call(&core->listener_list, struct pw_core_events, free); + pw_core_events_free(core); pw_data_loop_destroy(core->data_loop_impl); @@ -561,8 +561,7 @@ int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) core->info.change_mask = PW_CORE_CHANGE_MASK_PROPS; core->info.props = &core->properties->dict; - spa_hook_list_call(&core->listener_list, struct pw_core_events, - info_changed, &core->info); + pw_core_events_info_changed(core, &core->info); spa_list_for_each(resource, &core->resource_list, link) pw_core_resource_info(resource, &core->info); diff --git a/src/pipewire/data-loop.c b/src/pipewire/data-loop.c index 05eeeac51..75f59d499 100644 --- a/src/pipewire/data-loop.c +++ b/src/pipewire/data-loop.c @@ -89,7 +89,7 @@ void pw_data_loop_destroy(struct pw_data_loop *loop) { pw_log_debug("data-loop %p: destroy", loop); - spa_hook_list_call(&loop->listener_list, struct pw_data_loop_events, destroy); + pw_data_loop_events_destroy(loop); pw_data_loop_stop(loop); diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index e60e7363a..cda3267e9 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -58,7 +58,7 @@ struct pw_factory *pw_factory_new(struct pw_core *core, void pw_factory_destroy(struct pw_factory *factory) { pw_log_debug("factory %p: destroy", factory); - spa_hook_list_call(&factory->listener_list, struct pw_factory_events, destroy); + pw_factory_events_destroy(factory); if (factory->registered) spa_list_remove(&factory->link); diff --git a/src/pipewire/global.c b/src/pipewire/global.c index e349f67bf..32512bca4 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -117,7 +117,7 @@ pw_global_register(struct pw_global *global, spa_list_append(&core->global_list, &global->link); pw_log_debug("global %p: add %u owner %p parent %p", global, global->id, owner, parent); - spa_hook_list_call(&core->listener_list, struct pw_core_events, global_added, global); + pw_core_events_global_added(core, global); spa_list_for_each(registry, &core->registry_resource_list, link) { uint32_t permissions = pw_global_get_permissions(global, registry->client); @@ -205,8 +205,7 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm if (global->version < version) goto wrong_version; - spa_hook_list_call(&global->listener_list, struct pw_global_events, bind, - client, permissions, version, id); + pw_global_events_bind(global, client, permissions, version, id); return 0; @@ -231,7 +230,7 @@ void pw_global_destroy(struct pw_global *global) struct pw_resource *registry; pw_log_debug("global %p: destroy %u", global, global->id); - spa_hook_list_call(&global->listener_list, struct pw_global_events, destroy); + pw_global_events_destroy(global); if (global->id != SPA_ID_INVALID) { spa_list_for_each(registry, &core->registry_resource_list, link) { @@ -244,11 +243,11 @@ void pw_global_destroy(struct pw_global *global) pw_map_remove(&core->globals, global->id); spa_list_remove(&global->link); - spa_hook_list_call(&core->listener_list, struct pw_core_events, global_removed, global); + pw_core_events_global_removed(core, global); } pw_log_debug("global %p: free", global); - spa_hook_list_call(&global->listener_list, struct pw_global_events, free); + pw_global_events_free(global); if (global->properties) pw_properties_free(global->properties); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 24bc18623..1b6a0fa28 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -72,7 +72,7 @@ static void pw_link_update_state(struct pw_link *link, enum pw_link_state state, free(link->error); link->error = error; - spa_hook_list_call(&link->listener_list, struct pw_link_events, state_changed, old, state, error); + pw_link_events_state_changed(link, old, state, error); } } @@ -221,8 +221,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st if (changed) { this->info.change_mask |= PW_LINK_CHANGE_MASK_FORMAT; - spa_hook_list_call(&this->listener_list, struct pw_link_events, - info_changed, &this->info); + pw_link_events_info_changed(this, &this->info); spa_list_for_each(resource, &this->resource_list, link) pw_link_resource_info(resource, &this->info); @@ -877,7 +876,7 @@ static void input_remove(struct pw_link *this, struct pw_port *port) pw_map_remove(&port->mix_port_map, this->rt.in_port.port_id); spa_list_remove(&this->input_link); - spa_hook_list_call(&this->input->listener_list, struct pw_port_events, link_removed, this); + pw_port_events_link_removed(this->input, this); clear_port_buffers(this, port); this->input = NULL; @@ -906,7 +905,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port) pw_map_remove(&port->mix_port_map, this->rt.out_port.port_id); spa_list_remove(&this->output_link); - spa_hook_list_call(&this->output->listener_list, struct pw_port_events, link_removed, this); + pw_port_events_link_removed(this->output, this); clear_port_buffers(this, port); this->output = NULL; @@ -914,7 +913,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port) static void on_port_destroy(struct pw_link *this, struct pw_port *port) { - spa_hook_list_call(&this->listener_list, struct pw_link_events, port_unlinked, port); + pw_link_events_port_unlinked(this, port); pw_link_update_state(this, PW_LINK_STATE_UNLINKED, NULL); pw_link_destroy(this); @@ -1192,8 +1191,8 @@ struct pw_link *pw_link_new(struct pw_core *core, pw_loop_invoke(input_node->data_loop, do_add_link, SPA_ID_INVALID, &input, sizeof(struct pw_port *), false, this); - spa_hook_list_call(&output->listener_list, struct pw_port_events, link_added, this); - spa_hook_list_call(&input->listener_list, struct pw_port_events, link_added, this); + spa_hook_list_call(&output->listener_list, struct pw_port_events, link_added, 0, this); + spa_hook_list_call(&input->listener_list, struct pw_port_events, link_added, 0, this); return this; @@ -1280,7 +1279,7 @@ void pw_link_destroy(struct pw_link *link) struct pw_resource *resource, *tmp; pw_log_debug("link %p: destroy", impl); - spa_hook_list_call(&link->listener_list, struct pw_link_events, destroy); + pw_link_events_destroy(link); pw_link_deactivate(link); @@ -1300,7 +1299,7 @@ void pw_link_destroy(struct pw_link *link) pw_resource_destroy(resource); pw_log_debug("link %p: free", impl); - spa_hook_list_call(&link->listener_list, struct pw_link_events, free); + pw_link_events_free(link); pw_work_queue_destroy(impl->work); diff --git a/src/pipewire/main-loop.c b/src/pipewire/main-loop.c index b2497d7e0..a36b1ebbb 100644 --- a/src/pipewire/main-loop.c +++ b/src/pipewire/main-loop.c @@ -66,7 +66,7 @@ struct pw_main_loop *pw_main_loop_new(struct pw_properties *properties) void pw_main_loop_destroy(struct pw_main_loop *loop) { pw_log_debug("main-loop %p: destroy", loop); - spa_hook_list_call(&loop->listener_list, struct pw_main_loop_events, destroy); + pw_main_loop_events_destroy(loop); pw_loop_destroy(loop->loop); diff --git a/src/pipewire/module.c b/src/pipewire/module.c index 36d8ce89a..25ee90ba3 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -298,7 +298,7 @@ void pw_module_destroy(struct pw_module *module) struct pw_resource *resource, *tmp; pw_log_debug("module %p: destroy", module); - spa_hook_list_call(&module->listener_list, struct pw_module_events, destroy); + pw_module_events_destroy(module); spa_list_remove(&module->link); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 425c94d67..3523d9cfa 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -374,7 +374,7 @@ int pw_node_register(struct pw_node *this, pw_port_register(port, owner, this->global, pw_properties_copy(port->properties)); - spa_hook_list_call(&this->listener_list, struct pw_node_events, initialized); + pw_node_events_initialized(this); pw_node_update_state(this, PW_NODE_STATE_SUSPENDED, NULL); @@ -487,8 +487,7 @@ int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict) node->info.props = &node->properties->dict; node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS; - spa_hook_list_call(&node->listener_list, struct pw_node_events, - info_changed, &node->info); + pw_node_events_info_changed(node, &node->info); spa_list_for_each(resource, &node->resource_list, link) pw_node_resource_info(resource, &node->info); @@ -505,7 +504,7 @@ static void node_done(void *data, int seq, int res) pw_log_debug("node %p: async complete event %d %d %s", node, seq, res, spa_strerror(res)); pw_work_queue_complete(impl->work, node, seq, res); - spa_hook_list_call(&node->listener_list, struct pw_node_events, async_complete, seq, res); + pw_node_events_async_complete(node, seq, res); } static void node_event(void *data, struct spa_event *event) @@ -516,14 +515,14 @@ static void node_event(void *data, struct spa_event *event) if (SPA_EVENT_TYPE(event) == node->core->type.event_node.RequestClockUpdate) { send_clock_update(node); } - spa_hook_list_call(&node->listener_list, struct pw_node_events, event, event); + pw_node_events_event(node, event); } static void node_need_input(void *data) { struct pw_node *node = data; pw_log_trace("node %p: need input", node); - spa_hook_list_call(&node->listener_list, struct pw_node_events, need_input); + pw_node_events_need_input(node); spa_graph_need_input(node->rt.graph, &node->rt.node); } @@ -532,7 +531,7 @@ static void node_have_output(void *data) struct pw_node *node = data; pw_log_trace("node %p: have output", node); spa_graph_have_output(node->rt.graph, &node->rt.node); - spa_hook_list_call(&node->listener_list, struct pw_node_events, have_output); + pw_node_events_have_output(node); } static void node_reuse_buffer(void *data, uint32_t port_id, uint32_t buffer_id) @@ -613,7 +612,7 @@ void pw_node_destroy(struct pw_node *node) struct pw_port *port, *tmpp; pw_log_debug("node %p: destroy", impl); - spa_hook_list_call(&node->listener_list, struct pw_node_events, destroy); + pw_node_events_destroy(node); if (node->registered) { pw_loop_invoke(node->data_loop, do_node_remove, 1, NULL, 0, true, node); @@ -628,11 +627,11 @@ void pw_node_destroy(struct pw_node *node) pw_log_debug("node %p: destroy ports", node); spa_list_for_each_safe(port, tmpp, &node->input_ports, link) { - spa_hook_list_call(&node->listener_list, struct pw_node_events, port_removed, port); + pw_node_events_port_removed(node, port); pw_port_destroy(port); } spa_list_for_each_safe(port, tmpp, &node->output_ports, link) { - spa_hook_list_call(&node->listener_list, struct pw_node_events, port_removed, port); + pw_node_events_port_removed(node, port); pw_port_destroy(port); } @@ -644,7 +643,7 @@ void pw_node_destroy(struct pw_node *node) pw_resource_destroy(resource); pw_log_debug("node %p: free", node); - spa_hook_list_call(&node->listener_list, struct pw_node_events, free); + pw_node_events_free(node); pw_work_queue_destroy(impl->work); @@ -860,7 +859,7 @@ int pw_node_set_state(struct pw_node *node, enum pw_node_state state) int res = 0; struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); - spa_hook_list_call(&node->listener_list, struct pw_node_events, state_request, state); + pw_node_events_state_request(node, state); pw_log_debug("node %p: set state %s", node, pw_node_state_as_string(state)); @@ -930,12 +929,10 @@ void pw_node_update_state(struct pw_node *node, enum pw_node_state state, char * node_deactivate(node); } - spa_hook_list_call(&node->listener_list, struct pw_node_events, state_changed, - old, state, error); + pw_node_events_state_changed(node, old, state, error); node->info.change_mask |= PW_NODE_CHANGE_MASK_STATE; - spa_hook_list_call(&node->listener_list, struct pw_node_events, - info_changed, &node->info); + pw_node_events_info_changed(node, &node->info); spa_list_for_each(resource, &node->resource_list, link) pw_node_resource_info(resource, &node->info); @@ -951,7 +948,7 @@ int pw_node_set_active(struct pw_node *node, bool active) if (old != active) { pw_log_debug("node %p: %s", node, active ? "activate" : "deactivate"); node->active = active; - spa_hook_list_call(&node->listener_list, struct pw_node_events, active_changed, active); + pw_node_events_active_changed(node, active); if (active) { if (node->enabled) node_activate(node); @@ -974,7 +971,7 @@ int pw_node_set_enabled(struct pw_node *node, bool enabled) if (old != enabled) { pw_log_debug("node %p: %s", node, enabled ? "enable" : "disable"); node->enabled = enabled; - spa_hook_list_call(&node->listener_list, struct pw_node_events, enabled_changed, enabled); + pw_node_events_enabled_changed(node, enabled); if (enabled) { if (node->active) diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 79badaa03..f6ea9b813 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -45,7 +45,7 @@ static void port_update_state(struct pw_port *port, enum pw_port_state state) if (port->state != state) { pw_log_debug("port %p: state %d -> %d", port, port->state, state); port->state = state; - spa_hook_list_call(&port->listener_list, struct pw_port_events, state_changed, state); + pw_port_events_state_changed(port, state); } } @@ -255,8 +255,7 @@ int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict) port->info.props = &port->properties->dict; port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS; - spa_hook_list_call(&port->listener_list, struct pw_port_events, - info_changed, &port->info); + pw_port_events_info_changed(port, &port->info); spa_list_for_each(resource, &port->resource_list, link) pw_port_resource_info(resource, &port->info); @@ -470,7 +469,7 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) if (port->state <= PW_PORT_STATE_INIT) port_update_state(port, PW_PORT_STATE_CONFIGURE); - spa_hook_list_call(&node->listener_list, struct pw_node_events, port_added, port); + pw_node_events_port_added(node, port); return 0; } @@ -526,7 +525,7 @@ static void pw_port_remove(struct pw_port *port) node->info.n_output_ports--; } spa_list_remove(&port->link); - spa_hook_list_call(&node->listener_list, struct pw_node_events, port_removed, port); + pw_node_events_port_removed(node, port); } void pw_port_destroy(struct pw_port *port) @@ -537,7 +536,7 @@ void pw_port_destroy(struct pw_port *port) pw_log_debug("port %p: destroy", port); - spa_hook_list_call(&port->listener_list, struct pw_port_events, destroy); + pw_port_events_destroy(port); if (node) pw_port_remove(port); @@ -555,7 +554,7 @@ void pw_port_destroy(struct pw_port *port) pw_resource_destroy(resource); pw_log_debug("port %p: free", port); - spa_hook_list_call(&port->listener_list, struct pw_port_events, free); + pw_port_events_free(port); free_allocation(&port->allocation); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index f0e8ad22c..2b2682abb 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -51,6 +51,8 @@ struct pw_command { int n_args; }; +#define pw_protocol_events_destroy(p) spa_hook_list_call(&p->listener_list, struct pw_protocol_events, destroy, 0) + struct pw_protocol { struct spa_list link; /**< link in core protocol_list */ struct pw_core *core; /**< core for this protocol */ @@ -74,6 +76,16 @@ struct pw_protocol { typedef uint32_t (*pw_permission_func_t) (struct pw_global *global, struct pw_client *client, void *data); +#define pw_client_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_client_events, m, v, ##__VA_ARGS__) + +#define pw_client_events_destroy(o) pw_client_events_emit(o, destroy, 0) +#define pw_client_events_free(o) pw_client_events_emit(o, free, 0) +#define pw_client_events_info_changed(o,i) pw_client_events_emit(o, info_changed, 0, i) +#define pw_client_events_resource_added(o,r) pw_client_events_emit(o, resource_added, 0, r) +#define pw_client_events_resource_impl(o,r) pw_client_events_emit(o, resource_impl, 0, r) +#define pw_client_events_resource_removed(o,r) pw_client_events_emit(o, resource_removed, 0, r) +#define pw_client_events_busy_changed(o,b) pw_client_events_emit(o, busy_changed, 0, b) + struct pw_client { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core object client list */ @@ -108,6 +120,13 @@ struct pw_client { void *user_data; /**< extra user data */ }; +#define pw_global_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_global_events, m, v, ##__VA_ARGS__) + +#define pw_global_events_registering(g) pw_global_events_emit(g, registering, 0) +#define pw_global_events_destroy(g) pw_global_events_emit(g, destroy, 0) +#define pw_global_events_free(g) pw_global_events_emit(g, free, 0) +#define pw_global_events_bind(g,...) pw_global_events_emit(g, bind, 0, __VA_ARGS__) + struct pw_global { struct pw_core *core; /**< the core */ struct pw_client *owner; /**< the owner of this object, NULL when the @@ -127,6 +146,13 @@ struct pw_global { void *object; /**< object associated with the interface */ }; +#define pw_core_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_core_events, m, v, ##__VA_ARGS__) +#define pw_core_events_destroy(c) pw_core_events_emit(c, destroy, 0) +#define pw_core_events_free(c) pw_core_events_emit(c, free, 0) +#define pw_core_events_info_changed(c,i) pw_core_events_emit(c, info_changed, 0, i) +#define pw_core_events_global_added(c,g) pw_core_events_emit(c, global_added, 0, g) +#define pw_core_events_global_removed(c,g) pw_core_events_emit(c, global_removed, 0, g) + struct pw_core { struct pw_global *global; /**< the global of the core */ struct spa_hook global_listener; @@ -169,6 +195,9 @@ struct pw_core { } rt; }; +#define pw_data_loop_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_data_loop_events, m, v, ##__VA_ARGS__) +#define pw_data_loop_events_destroy(o) pw_data_loop_events_emit(o, destroy, 0) + struct pw_data_loop { struct pw_loop *loop; @@ -180,6 +209,9 @@ struct pw_data_loop { pthread_t thread; }; +#define pw_main_loop_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_main_loop_events, m, v, ##__VA_ARGS__) +#define pw_main_loop_events_destroy(o) pw_main_loop_events_emit(o, destroy, 0) + struct pw_main_loop { struct pw_loop *loop; @@ -212,6 +244,13 @@ static inline void free_allocation(struct allocation *alloc) alloc->n_buffers = 0; } +#define pw_link_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_link_events, m, v, ##__VA_ARGS__) +#define pw_link_events_destroy(l) pw_link_events_emit(l, destroy, 0) +#define pw_link_events_free(l) pw_link_events_emit(l, free, 0) +#define pw_link_events_info_changed(l,i) pw_link_events_emit(l, info_changed, 0, i) +#define pw_link_events_state_changed(l,...) pw_link_events_emit(l, state_changed, 0, __VA_ARGS__) +#define pw_link_events_port_unlinked(l,p) pw_link_events_emit(l, port_unlinked, 0, p) + struct pw_link { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core link_list */ @@ -244,6 +283,9 @@ struct pw_link { void *user_data; }; +#define pw_module_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_module_events, m, v, ##__VA_ARGS__) +#define pw_module_events_destroy(m) pw_module_events_emit(m, destroy, 0) + struct pw_module { struct pw_core *core; /**< the core object */ struct spa_list link; /**< link in the core module_list */ @@ -259,6 +301,26 @@ struct pw_module { void *user_data; /**< module user_data */ }; +#define pw_node_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_node_events, m, v, ##__VA_ARGS__) +#define pw_node_events_destroy(n) pw_node_events_emit(n, destroy, 0) +#define pw_node_events_free(n) pw_node_events_emit(n, free, 0) +#define pw_node_events_initialized(n) pw_node_events_emit(n, initialized, 0) +#define pw_node_events_port_init(n,p) pw_node_events_emit(n, port_init, 0, p) +#define pw_node_events_port_added(n,p) pw_node_events_emit(n, port_added, 0, p) +#define pw_node_events_port_removed(n,p) pw_node_events_emit(n, port_removed, 0, p) +#define pw_node_events_info_changed(n,i) pw_node_events_emit(n, info_changed, 0, i) +#define pw_node_events_active_changed(n,a) pw_node_events_emit(n, active_changed, 0, a) +#define pw_node_events_enabled_changed(n,e) pw_node_events_emit(n, enabled_changed, 0, e) +#define pw_node_events_state_request(n,s) pw_node_events_emit(n, state_request, 0, s) +#define pw_node_events_state_changed(n,o,s,e) pw_node_events_emit(n, state_changed, 0, o, s, e) +#define pw_node_events_async_complete(n,s,r) pw_node_events_emit(n, async_complete, 0, s, r) +#define pw_node_events_event(n,e) pw_node_events_emit(n, event, 0, e) +#define pw_node_events_driver_changed(n,d) pw_node_events_emit(n, driver_changed, 0, d) +#define pw_node_events_need_input(n) pw_node_events_emit(n, need_input, 0) +#define pw_node_events_have_output(n) pw_node_events_emit(n, have_output, 0) +#define pw_node_events_reuse_buffer(n,p,b) pw_node_events_emit(n, reuse_buffer, 0, p, b) +#define pw_node_events_finish(n) pw_node_events_emit(n, finish, 0) + struct pw_node { struct pw_core *core; /**< core object */ struct spa_list link; /**< link in core node_list */ @@ -300,6 +362,16 @@ struct pw_node { void *user_data; /**< extra user data */ }; +#define pw_port_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_port_events, m, v, ##__VA_ARGS__) +#define pw_port_events_destroy(p) pw_port_events_emit(p, destroy, 0) +#define pw_port_events_free(p) pw_port_events_emit(p, free, 0) +#define pw_port_events_info_changed(p,i) pw_port_events_emit(p, info_changed, 0, i) +#define pw_port_events_link_added(p,l) pw_port_events_emit(p, link_added, 0, l) +#define pw_port_events_link_removed(p,l) pw_port_events_emit(p, link_removed, 0, l) +#define pw_port_events_state_changed(p,s) pw_port_events_emit(p, state_changed, 0, s) +#define pw_port_events_control_added(p,c) pw_port_events_emit(p, control_added, 0, c) +#define pw_port_events_control_removed(p,c) pw_port_events_emit(p, control_removed, 0, c) + struct pw_port { struct spa_list link; /**< link in node port_list */ @@ -345,6 +417,10 @@ struct pw_port { }; +#define pw_resource_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_resource_events, m, v, ##__VA_ARGS__) + +#define pw_resource_events_destroy(o) pw_resource_events_emit(o, destroy, 0) + struct pw_resource { struct pw_core *core; /**< the core object */ struct spa_list link; /**< link in object resource_list */ @@ -366,6 +442,8 @@ struct pw_resource { void *user_data; /**< extra user data */ }; +#define pw_proxy_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_proxy_events, m, v, ##__VA_ARGS__) +#define pw_proxy_events_destroy(p) pw_proxy_events_emit(p, destroy, 0) struct pw_proxy { struct pw_remote *remote; /**< the owner remote of this proxy */ @@ -381,6 +459,12 @@ struct pw_proxy { void *user_data; /**< extra user data */ }; +#define pw_remote_events_emit(r,m,v,...) spa_hook_list_call(&r->listener_list, struct pw_remote_events, m, v, ##__VA_ARGS__) +#define pw_remote_events_destroy(r) pw_remote_events_emit(r, destroy, 0) +#define pw_remote_events_info_changed(r,i) pw_remote_events_emit(r, info_changed, 0, i) +#define pw_remote_events_sync_reply(r,s) pw_remote_events_emit(r, sync_reply, 0, s) +#define pw_remote_events_state_changed(r,o,s,e) pw_remote_events_emit(r, state_changed, 0, o, s, e) + struct pw_remote { struct pw_core *core; /**< core */ struct spa_list link; /**< link in core remote_list */ @@ -408,6 +492,15 @@ struct pw_remote { void *user_data; /**< extra user data */ }; +#define pw_stream_events_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_stream_events, m, v, ##__VA_ARGS__) +#define pw_stream_events_destroy(s) pw_stream_events_emit(s, destroy, 0) +#define pw_stream_events_state_changed(s,o,n,e) pw_stream_events_emit(s, state_changed,0,o,n,e) +#define pw_stream_events_format_changed(s,f) pw_stream_events_emit(s, format_changed,0,f) +#define pw_stream_events_add_buffer(s,b) pw_stream_events_emit(s, add_buffer, 0, b) +#define pw_stream_events_remove_buffer(s,b) pw_stream_events_emit(s, remove_buffer, 0, b) +#define pw_stream_events_process(s) pw_stream_events_emit(s, process, 0) +#define pw_stream_events_drained(s) pw_stream_events_emit(s, drained, 1) + struct pw_stream { struct pw_remote *remote; /**< the owner remote */ @@ -424,6 +517,10 @@ struct pw_stream { struct spa_hook_list listener_list; }; +#define pw_factory_events_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_factory_events, m, v, ##__VA_ARGS__) + +#define pw_factory_events_destroy(s) pw_factory_events_emit(s, destroy, 0) + struct pw_factory { struct pw_core *core; /**< the core */ struct spa_list link; /**< link in core node_factory_list */ @@ -444,6 +541,12 @@ struct pw_factory { void *user_data; }; +#define pw_control_events_emit(c,m,v,...) spa_hook_list_call(&c->listener_list, struct pw_control_events, m, v, ##__VA_ARGS__) +#define pw_control_events_destroy(c) pw_control_events_emit(c, destroy, 0) +#define pw_control_events_free(c) pw_control_events_emit(c, free, 0) +#define pw_control_events_linked(c,o) pw_control_events_emit(c, linked, 0, o) +#define pw_control_events_unlinked(c,o) pw_control_events_emit(c, unlinked, 0, o) + struct pw_control { struct spa_list link; /**< link in core control_list */ struct pw_core *core; /**< the core */ diff --git a/src/pipewire/protocol.c b/src/pipewire/protocol.c index 12ac5743a..39f594099 100644 --- a/src/pipewire/protocol.c +++ b/src/pipewire/protocol.c @@ -87,7 +87,7 @@ void pw_protocol_destroy(struct pw_protocol *protocol) struct pw_protocol_client *client, *t3; pw_log_debug("protocol %p: destroy", protocol); - spa_hook_list_call(&protocol->listener_list, struct pw_protocol_events, destroy); + pw_protocol_events_destroy(protocol); spa_list_remove(&protocol->link); diff --git a/src/pipewire/proxy.c b/src/pipewire/proxy.c index 4a87b07be..641522429 100644 --- a/src/pipewire/proxy.c +++ b/src/pipewire/proxy.c @@ -119,7 +119,7 @@ void pw_proxy_destroy(struct pw_proxy *proxy) struct proxy *impl = SPA_CONTAINER_OF(proxy, struct proxy, this); pw_log_debug("proxy %p: destroy %u", proxy, proxy->id); - spa_hook_list_call(&proxy->listener_list, struct pw_proxy_events, destroy); + pw_proxy_events_destroy(proxy); pw_map_insert_at(&proxy->remote->objects, proxy->id, NULL); spa_list_remove(&proxy->link); diff --git a/src/pipewire/proxy.h b/src/pipewire/proxy.h index 5bb9b7181..572851654 100644 --- a/src/pipewire/proxy.h +++ b/src/pipewire/proxy.h @@ -145,7 +145,7 @@ struct spa_hook_list *pw_proxy_get_proxy_listeners(struct pw_proxy *proxy); /** Get the marshal functions for the proxy */ const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy); -#define pw_proxy_notify(p,type,event,...) spa_hook_list_call(pw_proxy_get_proxy_listeners(p),type,event,## __VA_ARGS__) +#define pw_proxy_notify(p,type,event,ver,...) spa_hook_list_call(pw_proxy_get_proxy_listeners(p),type,event,ver,## __VA_ARGS__) #define pw_proxy_do(p,type,method,...) ((type*) pw_proxy_get_marshal(p)->method_marshal)->method(p, ## __VA_ARGS__) #ifdef __cplusplus diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 2ae8052de..cc2a29ba0 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -144,8 +144,7 @@ pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, con pw_remote_state_as_string(state), remote->error); remote->state = state; - spa_hook_list_call(&remote->listener_list, struct pw_remote_events, state_changed, - old, state, remote->error); + pw_remote_events_state_changed(remote, old, state, remote->error); } return 0; } @@ -156,8 +155,7 @@ static void core_event_info(void *data, struct pw_core_info *info) pw_log_debug("remote %p: got core info", this); this->info = pw_core_info_update(this->info, info); - spa_hook_list_call(&this->listener_list, struct pw_remote_events, - info_changed, this->info); + pw_remote_events_info_changed(this, this->info); } static void core_event_done(void *data, uint32_t seq) @@ -168,7 +166,7 @@ static void core_event_done(void *data, uint32_t seq) if (seq == 0) pw_remote_update_state(this, PW_REMOTE_STATE_CONNECTED, NULL); - spa_hook_list_call(&this->listener_list, struct pw_remote_events, sync_reply, seq); + pw_remote_events_sync_reply(this, seq); } static void core_event_error(void *data, uint32_t id, int res, const char *error, ...) @@ -296,7 +294,7 @@ void pw_remote_destroy(struct pw_remote *remote) struct pw_stream *stream, *s2; pw_log_debug("remote %p: destroy", remote); - spa_hook_list_call(&remote->listener_list, struct pw_remote_events, destroy); + pw_remote_events_destroy(remote); if (remote->state != PW_REMOTE_STATE_UNCONNECTED) pw_remote_disconnect(remote); diff --git a/src/pipewire/resource.c b/src/pipewire/resource.c index ed4c6af7d..2299b6e5e 100644 --- a/src/pipewire/resource.c +++ b/src/pipewire/resource.c @@ -68,7 +68,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client, this->marshal = pw_protocol_get_marshal(client->protocol, type); pw_log_debug("resource %p: new for client %p id %u", this, client, id); - spa_hook_list_call(&client->listener_list, struct pw_client_events, resource_added, this); + pw_client_events_resource_added(client, this); return this; @@ -125,7 +125,7 @@ void pw_resource_set_implementation(struct pw_resource *resource, resource->implementation.funcs = implementation; resource->implementation.data = data; - spa_hook_list_call(&client->listener_list, struct pw_client_events, resource_impl, resource); + pw_client_events_resource_impl(client, resource); } void pw_resource_add_override(struct pw_resource *resource, @@ -157,10 +157,10 @@ void pw_resource_destroy(struct pw_resource *resource) struct pw_client *client = resource->client; pw_log_debug("resource %p: destroy %u", resource, resource->id); - spa_hook_list_call(&resource->listener_list, struct pw_resource_events, destroy); + pw_resource_events_destroy(resource); pw_map_insert_at(&client->objects, resource->id, NULL); - spa_hook_list_call(&client->listener_list, struct pw_client_events, resource_removed, resource); + pw_client_events_resource_removed(client, resource); if (client->core_resource) pw_core_resource_remove_id(client->core_resource, resource->id); diff --git a/src/pipewire/resource.h b/src/pipewire/resource.h index bd1dd2b02..8d2ed2a2d 100644 --- a/src/pipewire/resource.h +++ b/src/pipewire/resource.h @@ -123,11 +123,11 @@ struct spa_hook_list *pw_resource_get_implementation(struct pw_resource *resourc /** Get the marshal functions for the resource */ const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource); -#define pw_resource_do(r,type,method,...) \ - spa_hook_list_call_once(pw_resource_get_implementation(r),type,method,## __VA_ARGS__) +#define pw_resource_do(r,type,method,v,...) \ + spa_hook_list_call_once(pw_resource_get_implementation(r),type,method,v,## __VA_ARGS__) #define pw_resource_do_parent(r,l,type,method,...) \ - spa_hook_list_call_once_start(pw_resource_get_implementation(r),l,type,method,## __VA_ARGS__) + spa_hook_list_call_once_start(pw_resource_get_implementation(r),l,type,method,v,## __VA_ARGS__) #define pw_resource_notify(r,type,event,...) \ ((type*) pw_resource_get_marshal(r)->event_marshal)->event(r, ## __VA_ARGS__) diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index b9ebbc9a8..a7effad65 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -236,8 +236,7 @@ static void clear_buffers(struct pw_stream *stream) for (i = 0; i < impl->n_buffers; i++) { b = &impl->buffers[i]; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - remove_buffer, &b->buffer); + pw_stream_events_remove_buffer(stream, &b->buffer); if (SPA_FLAG_CHECK(b->flags, BUFFER_FLAG_MAPPED)) { for (j = 0; j < b->buffer.buffer->n_datas; j++) { @@ -316,8 +315,7 @@ static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state stat pw_stream_state_as_string(state), stream->error); stream->state = state; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, state_changed, - old, state, error); + pw_stream_events_state_changed(stream, old, state, error); } return res; } @@ -337,7 +335,7 @@ do_call_process(struct spa_loop *loop, struct stream *impl = user_data; struct pw_stream *stream = &impl->this; impl->in_process = true; - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, process); + pw_stream_events_process(stream); impl->in_process = false; return 0; } @@ -536,7 +534,7 @@ void pw_stream_destroy(struct pw_stream *stream) pw_log_debug("stream %p: destroy", stream); - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, destroy); + pw_stream_events_destroy(stream); if (impl->node_proxy) spa_hook_remove(&impl->proxy_listener); @@ -978,9 +976,7 @@ client_node_port_set_param(void *data, impl->pending_seq = seq; - count = spa_hook_list_call(&stream->listener_list, - struct pw_stream_events, - format_changed, impl->format); + count = pw_stream_events_format_changed(stream, impl->format); if (count == 0) pw_stream_finish_format(stream, 0, NULL, 0); @@ -1136,8 +1132,7 @@ client_node_port_use_buffers(void *data, if (impl->direction == SPA_DIRECTION_OUTPUT) push_queue(impl, &impl->dequeue, bid); - spa_hook_list_call(&stream->listener_list, struct pw_stream_events, - add_buffer, &bid->buffer); + pw_stream_events_add_buffer(stream, &bid->buffer); } add_async_complete(stream, seq, 0); diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index 38511e2ae..364fe4554 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -23,6 +23,9 @@ #include "pipewire.h" #include "thread-loop.h" +#define pw_thread_loop_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_thread_loop_events, m, v, ##__VA_ARGS__) +#define pw_thread_loop_events_destroy(o) pw_thread_loop_events_emit(o, destroy, 0) + /** \cond */ struct pw_thread_loop { struct pw_loop *loop; @@ -120,7 +123,7 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, /** Destroy a threaded loop \memberof pw_thread_loop */ void pw_thread_loop_destroy(struct pw_thread_loop *loop) { - spa_hook_list_call(&loop->listener_list, struct pw_thread_loop_events, destroy); + pw_thread_loop_events_destroy(loop); pw_thread_loop_stop(loop); From cc1062933b6b968cfac7650149d5b16edee1798e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 13:15:36 +0200 Subject: [PATCH 045/155] example: improve debug --- src/examples/video-play.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 03a98819f..8ec70b823 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -138,7 +138,7 @@ static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { struct data *data = _data; - printf("stream state: \"%s\"\n", pw_stream_state_as_string(state)); + fprintf(stderr, "stream state: \"%s\"\n", pw_stream_state_as_string(state)); switch (state) { case PW_STREAM_STATE_CONFIGURE: pw_stream_set_active(data->stream, true); @@ -235,6 +235,9 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) return; } + fprintf(stderr, "got format:\n"); + spa_debug_format(2, data->t->map, format); + spa_format_video_raw_parse(format, &data->format, &data->type.format_video); sdl_format = id_to_sdl_format(data, data->format.format); @@ -281,7 +284,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", error); + fprintf(stderr, "remote error: %s\n", error); pw_main_loop_quit(data->loop); break; @@ -293,7 +296,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo SDL_RendererInfo info; uint32_t i, c; - printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); + fprintf(stderr, "remote state: \"%s\"\n", pw_remote_state_as_string(state)); data->stream = pw_stream_new(remote, "video-play", @@ -342,7 +345,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo NULL); params[0] = spa_pod_builder_pop(&b); - printf("supported formats:\n"); + fprintf(stderr, "supported formats:\n"); spa_debug_format(2, data->t->map, params[0]); pw_stream_add_listener(data->stream, @@ -360,7 +363,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo break; } default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); + fprintf(stderr, "remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } @@ -376,7 +379,7 @@ static void connect_state_changed(void *_data, enum pw_remote_state old, { struct data *data = _data; - printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); + fprintf(stderr, "remote state: \"%s\"\n", pw_remote_state_as_string(state)); switch (state) { case PW_REMOTE_STATE_ERROR: @@ -427,13 +430,13 @@ int main(int argc, char *argv[]) init_type(&data.type, data.t->map); if (SDL_Init(SDL_INIT_VIDEO) < 0) { - printf("can't initialize SDL: %s\n", SDL_GetError()); + fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError()); return -1; } if (SDL_CreateWindowAndRenderer (WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) { - printf("can't create window: %s\n", SDL_GetError()); + fprintf(stderr, "can't create window: %s\n", SDL_GetError()); return -1; } From c6f701588f56d2b67232b200c8b6d8a496c20951 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 13:15:54 +0200 Subject: [PATCH 046/155] link: improve debug --- src/pipewire/link.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 1b6a0fa28..0fc89f90d 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -24,9 +24,6 @@ #include #include #include -#include -#include -#include #include "private.h" #include "pipewire.h" @@ -34,6 +31,11 @@ #include "link.h" #include "work-queue.h" +#undef spa_debug +#include +#include +#include + #define MAX_BUFFERS 16 /** \cond */ From 98f54c4135bd84f2933b1bec0c8c9f537cbde358 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 13:16:11 +0200 Subject: [PATCH 047/155] pipewiresink: improve driver mode --- src/gst/gstpipewiresink.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c index ea4b3eb3e..d10cac5d3 100644 --- a/src/gst/gstpipewiresink.c +++ b/src/gst/gstpipewiresink.c @@ -242,7 +242,7 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) ":", t->param_buffers.size, "ir", size, PROP_RANGE(size, INT32_MAX), NULL); spa_pod_builder_add (&b, - ":", t->param_buffers.stride, "ir", 0, PROP_RANGE(0, INT32_MAX), + ":", t->param_buffers.stride, "iru", 0, PROP_RANGE(0, INT32_MAX), ":", t->param_buffers.buffers, "iru", min_buffers, PROP_RANGE(min_buffers, max_buffers ? max_buffers : INT32_MAX), @@ -530,6 +530,8 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) if (pwsink->mode != GST_PIPEWIRE_SINK_MODE_PROVIDE) flags |= PW_STREAM_FLAG_AUTOCONNECT; + else + flags |= PW_STREAM_FLAG_DRIVER; pw_stream_connect (pwsink->stream, PW_DIRECTION_OUTPUT, @@ -605,7 +607,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) GST_DEBUG ("push buffer in queue"); g_queue_push_tail (&pwsink->queue, buffer); - if (pwsink->need_ready && pwsink->mode == GST_PIPEWIRE_SINK_MODE_PROVIDE) + if (pwsink->mode == GST_PIPEWIRE_SINK_MODE_PROVIDE) do_send_buffer (pwsink); done: From fb76b65dfb3f3b69e419c5d85c74f9c0c6419ae9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 15 Aug 2018 15:51:35 +0200 Subject: [PATCH 048/155] gst: fix clock handling again Request periodic clock updates. Interpollate clock times in the gstreamer clock Make sure we don't read the clock after shutdown. --- src/gst/gstpipewireclock.c | 10 ++++++--- src/gst/gstpipewiresrc.c | 13 ++++++------ src/pipewire/stream.c | 43 +++++++++++++------------------------- 3 files changed, 29 insertions(+), 37 deletions(-) diff --git a/src/gst/gstpipewireclock.c b/src/gst/gstpipewireclock.c index b5ec5027d..a53c40167 100644 --- a/src/gst/gstpipewireclock.c +++ b/src/gst/gstpipewireclock.c @@ -48,15 +48,19 @@ gst_pipewire_clock_get_internal_time (GstClock * clock) GstPipeWireClock *pclock = (GstPipeWireClock *) clock; GstClockTime result; struct pw_time t; + struct timespec ts; if (pclock->stream == NULL || pw_stream_get_time (pclock->stream, &t) < 0 || - t.rate.num == 0) + t.rate.denom == 0) return pclock->last_time; - result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.denom, t.rate.num); + result = gst_util_uint64_scale_int (t.ticks, GST_SECOND * t.rate.num, t.rate.denom); + clock_gettime(CLOCK_MONOTONIC, &ts); + result += SPA_TIMESPEC_TO_TIME(&ts) - t.now; - GST_DEBUG ("%"PRId64", %d/%d %"PRId64, t.ticks, t.rate.num, t.rate.denom, result); + GST_DEBUG ("%"PRId64", %"PRId64" %d/%d %"PRId64, + t.ticks, GST_SECOND, t.rate.num, t.rate.denom, result); return result; } diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 145fd584c..9d505fffa 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -1065,12 +1065,6 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc) pw_thread_loop_stop (pwsrc->main_loop); - pw_stream_destroy (pwsrc->stream); - pwsrc->stream = NULL; - - pw_remote_destroy (pwsrc->remote); - pwsrc->remote = NULL; - pwsrc->last_time = gst_clock_get_time (pwsrc->clock); gst_element_post_message (GST_ELEMENT (pwsrc), @@ -1080,6 +1074,13 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc) GST_PIPEWIRE_CLOCK (pwsrc->clock)->stream = NULL; g_clear_object (&pwsrc->clock); GST_OBJECT_UNLOCK (pwsrc); + + pw_stream_destroy (pwsrc->stream); + pwsrc->stream = NULL; + + pw_remote_destroy (pwsrc->remote); + pwsrc->remote = NULL; + } static GstStateChangeReturn diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index a7effad65..c7736be8e 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -114,9 +114,7 @@ struct stream { struct buffer buffers[MAX_BUFFERS]; int n_buffers; - int64_t last_ticks; - int32_t last_rate; - int64_t last_monotonic; + struct pw_time last_time; }; /** \endcond */ @@ -468,10 +466,6 @@ do_remove_sources(struct spa_loop *loop, pw_loop_destroy_source(stream->remote->core->data_loop, impl->rtsocket_source); impl->rtsocket_source = NULL; } - if (impl->timeout_source) { - pw_loop_destroy_source(stream->remote->core->data_loop, impl->timeout_source); - impl->timeout_source = NULL; - } if (impl->rtwritefd != -1) { close(impl->rtwritefd); impl->rtwritefd = -1; @@ -483,6 +477,10 @@ static void unhandle_socket(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + if (impl->timeout_source) { + pw_loop_destroy_source(stream->remote->core->main_loop, impl->timeout_source); + impl->timeout_source = NULL; + } pw_loop_invoke(stream->remote->core->data_loop, do_remove_sources, 1, NULL, 0, true, impl); } @@ -668,7 +666,6 @@ static void do_node_init(struct pw_stream *stream) pw_client_node_proxy_set_active(impl->node_proxy, true); } -#if 0 static void add_request_clock_update(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -686,7 +683,6 @@ static void on_timeout(void *data, uint64_t expirations) struct pw_stream *stream = data; add_request_clock_update(stream); } -#endif static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) { @@ -847,6 +843,7 @@ on_rtsocket_condition(void *data, int fd, enum spa_io mask) static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct timespec interval; impl->rtwritefd = rtwritefd; impl->rtsocket_source = pw_loop_add_io(stream->remote->core->data_loop, @@ -854,13 +851,10 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, stream); -#if 0 - struct timespec interval; impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); interval.tv_sec = 0; interval.tv_nsec = 100000000; pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); -#endif return; } @@ -925,11 +919,13 @@ static void client_node_command(void *data, uint32_t seq, const struct spa_comma PW_STREAM_PROP_LATENCY_MIN, "%" PRId64, cu->body.latency.value); } - impl->last_ticks = cu->body.ticks.value; - impl->last_rate = cu->body.rate.value; - impl->last_monotonic = cu->body.monotonic_time.value; - pw_log_debug("clock update %ld %d %ld", impl->last_ticks, - impl->last_rate, impl->last_monotonic); + impl->last_time.now = cu->body.monotonic_time.value; + impl->last_time.ticks = cu->body.ticks.value; + impl->last_time.rate.num = 1; + impl->last_time.rate.denom = cu->body.rate.value; + impl->last_time.delay = 0; + pw_log_debug("clock update %ld %d %ld", impl->last_time.ticks, + impl->last_time.rate.denom, impl->last_time.now); } else { pw_log_warn("unhandled node command %d", SPA_COMMAND_TYPE(command)); add_async_complete(stream, seq, -ENOTSUP); @@ -1366,20 +1362,11 @@ static inline int64_t get_queue_size(struct queue *queue) int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - int64_t elapsed; - struct timespec ts; - if (impl->last_rate == 0) + if (impl->last_time.rate.denom == 0) return -EAGAIN; - clock_gettime(CLOCK_MONOTONIC, &ts); - time->now = SPA_TIMESPEC_TO_TIME(&ts); - elapsed = (time->now - impl->last_monotonic) / 1000; - - time->ticks = impl->last_ticks + (elapsed * impl->last_rate) / SPA_USEC_PER_SEC; - time->rate.num = impl->last_rate; - time->rate.denom = 1; - time->delay = 0; + *time = impl->last_time; if (impl->direction == SPA_DIRECTION_INPUT) time->queued = get_queue_size(&impl->dequeue); else From 5eac8f76750a9ba5cd6e0f42a42d41247ffbabc1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 16 Aug 2018 13:26:18 +0200 Subject: [PATCH 049/155] remove last debug includes Fixes #82 --- spa/tests/test-props4.c | 2 -- src/examples/export-spa.c | 2 -- src/examples/video-src.c | 1 - src/modules/module-protocol-native/local-socket.c | 2 -- src/modules/module-protocol-native/portal-screencast.c | 2 -- 5 files changed, 9 deletions(-) diff --git a/spa/tests/test-props4.c b/spa/tests/test-props4.c index c12227ec2..8c6d8dd30 100644 --- a/spa/tests/test-props4.c +++ b/spa/tests/test-props4.c @@ -26,8 +26,6 @@ #include #include -#include - #if 0 /* ( "Format", diff --git a/src/examples/export-spa.c b/src/examples/export-spa.c index 242c0180e..91121daca 100644 --- a/src/examples/export-spa.c +++ b/src/examples/export-spa.c @@ -26,8 +26,6 @@ #include #include -#include - #include #include diff --git a/src/examples/video-src.c b/src/examples/video-src.c index f61e4c895..5960bd889 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -26,7 +26,6 @@ #include #include #include -#include #include diff --git a/src/modules/module-protocol-native/local-socket.c b/src/modules/module-protocol-native/local-socket.c index 694ed75be..5ab5a2100 100644 --- a/src/modules/module-protocol-native/local-socket.c +++ b/src/modules/module-protocol-native/local-socket.c @@ -29,8 +29,6 @@ #include #include -#include - #include #include diff --git a/src/modules/module-protocol-native/portal-screencast.c b/src/modules/module-protocol-native/portal-screencast.c index 72967371a..430fc78cc 100644 --- a/src/modules/module-protocol-native/portal-screencast.c +++ b/src/modules/module-protocol-native/portal-screencast.c @@ -25,8 +25,6 @@ #include #include -#include - #include #include From d70e027a99fdb921a78d8b323c9029d5bfdf033e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 16 Aug 2018 18:25:30 +0200 Subject: [PATCH 050/155] daemon: add some options --- src/daemon/main.c | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index a7fae1a5d..96f78b482 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -18,19 +18,34 @@ */ #include +#include +#include #include #include #include +#include "config.h" #include "daemon-config.h" +static const char *daemon_name = "pipewire-0"; + static void do_quit(void *data, int signal_number) { struct pw_main_loop *loop = data; pw_main_loop_quit(loop); } +static void show_help(const char *name) +{ + fprintf(stdout, "%s [options]\n" + " -h, --help Show this help\n" + " -v, --version Show version\n" + " -n, --name Daemon name (Default %s)\n", + name, + daemon_name); +} + int main(int argc, char *argv[]) { struct pw_core *core; @@ -38,9 +53,38 @@ int main(int argc, char *argv[]) struct pw_daemon_config *config; char *err = NULL; struct pw_properties *props; + static const struct option long_options[] = { + {"help", 0, NULL, 'h'}, + {"version", 0, NULL, 'v'}, + {"name", 1, NULL, 'n'}, + {NULL, 0, NULL, 0} + }; + char c; pw_init(&argc, &argv); + while ((c = getopt_long(argc, argv, "hvn:", long_options, NULL)) != -1) { + switch (c) { + case 'h' : + show_help(argv[0]); + return 0; + case 'v' : + fprintf(stdout, "%s\n" + "Compiled with libpipewire %s\n" + "Linked with libpipewire %s\n", + argv[0], + pw_get_headers_version(), + pw_get_library_version()); + return 0; + case 'n' : + daemon_name = optarg; + fprintf(stdout, "set name %s\n", daemon_name); + break; + default: + return -1; + } + } + /* parse configuration */ config = pw_daemon_config_new(); if (pw_daemon_config_load(config, &err) < 0) { @@ -49,7 +93,7 @@ int main(int argc, char *argv[]) return -1; } - props = pw_properties_new(PW_CORE_PROP_NAME, "pipewire-0", + props = pw_properties_new(PW_CORE_PROP_NAME, daemon_name, PW_CORE_PROP_DAEMON, "1", NULL); loop = pw_main_loop_new(props); From eab60c14c25928e5f2769e370dbee826bfa81868 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 16 Aug 2018 18:28:20 +0200 Subject: [PATCH 051/155] man: update man page --- man/pipewire.1.xml.in | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/man/pipewire.1.xml.in b/man/pipewire.1.xml.in index 735e696d8..6c1802131 100644 --- a/man/pipewire.1.xml.in +++ b/man/pipewire.1.xml.in @@ -22,7 +22,7 @@ License along with PipeWire; if not, see . - pipewire + pipewire [options] @@ -39,11 +39,17 @@ License along with PipeWire; if not, see . + +
From aea505425bc5570b5e5ac9538b7f881f20094494 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 Aug 2018 10:18:41 +0200 Subject: [PATCH 052/155] man: add man page for config file --- man/meson.build | 2 ++ man/pipewire.conf.5.xml.in | 68 ++++++++++++++++++++++++++++++++++++++ meson.build | 10 +++--- 3 files changed, 76 insertions(+), 4 deletions(-) create mode 100644 man/pipewire.conf.5.xml.in diff --git a/man/meson.build b/man/meson.build index 65644442d..1d7045bf4 100644 --- a/man/meson.build +++ b/man/meson.build @@ -3,10 +3,12 @@ manpage_conf.set('PACKAGE_NAME', meson.project_name()) manpage_conf.set('PACKAGE_VERSION', meson.project_version()) manpage_conf.set('PACKAGE_URL', 'http://pipewire.org') manpage_conf.set('PACKAGE_BUGREPORT', 'https://github.com/PipeWire/pipewire/issues') +manpage_conf.set('PIPEWIRE_CONFIG_DIR', pipewire_configdir) manpage_conf.set('top_srcdir', meson.source_root()) manpage_conf.set('top_builddir', meson.build_root()) manpages = ['pipewire.1', + 'pipewire.conf.5', 'pipewire-cli.1', 'pipewire-monitor.1' ] diff --git a/man/pipewire.conf.5.xml.in b/man/pipewire.conf.5.xml.in new file mode 100644 index 000000000..03fa6467f --- /dev/null +++ b/man/pipewire.conf.5.xml.in @@ -0,0 +1,68 @@ + + + + + + + + + +

@PIPEWIRE_CONFIG_DIR@/pipewire.conf

+
+ + +

PipeWire is a service that allows access to multimedia devices + and allows media sharing between applications.

+ +

On startup, the daemon reads a configuration file to configure + itself. It executes a series of commands listed in the config + file.

+ +

The config file in the default location is used but the + environment variable PIPEWIRE_CONFIG_FILE can be used to specify + an alternative config file.

+
+ +
+ + +
+ +
+ +
+ +
+

The PipeWire Developers <@PACKAGE_BUGREPORT@>; PipeWire is available from

+
+ +
+

+ , + , +

+
+ +
diff --git a/meson.build b/meson.build index 4a8714572..b3c477fe3 100644 --- a/meson.build +++ b/meson.build @@ -29,7 +29,9 @@ pipewire_libdir = join_paths(prefix, get_option('libdir')) pipewire_localedir = join_paths(prefix, get_option('localedir')) pipewire_sysconfdir = join_paths(prefix, get_option('sysconfdir')) -modules_install_dir = join_paths(get_option('libdir'), 'pipewire-@0@'.format(apiversion)) +pipewire_configdir = join_paths(pipewire_sysconfdir, 'pipewire') +modules_install_dir = join_paths(pipewire_libdir, 'pipewire-@0@'.format(apiversion)) +spa_plugindir = join_paths(pipewire_libdir, 'spa') gnome = import('gnome') @@ -55,10 +57,10 @@ cdata.set('PACKAGE_STRING', '"PipeWire @0@"'.format(pipewire_version)) cdata.set('PACKAGE_TARNAME', '"pipewire"') cdata.set('PACKAGE_URL', '"http://pipewire.org"') cdata.set('PACKAGE_VERSION', '"@0@"'.format(pipewire_version)) -cdata.set('MODULEDIR', '"@0@/pipewire-@1@"'.format(pipewire_libdir,apiversion)) -cdata.set('PIPEWIRE_CONFIG_DIR', '"@0@/pipewire"'.format(pipewire_sysconfdir)) +cdata.set('MODULEDIR', '"@0@"'.format(modules_install_dir)) +cdata.set('PIPEWIRE_CONFIG_DIR', '"@0@"'.format(pipewire_configdir)) cdata.set('VERSION', '"@0@"'.format(pipewire_version)) -cdata.set('PLUGINDIR', '"@0@/spa"'.format(pipewire_libdir)) +cdata.set('PLUGINDIR', '"@0@"'.format(spa_plugindir)) # FIXME: --with-memory-alignment],[8,N,malloc,pagesize (default is 32)]) option cdata.set('MEMORY_ALIGNMENT_MALLOC', 1) From 90400b17d624369512007366eddb9996a3558d22 Mon Sep 17 00:00:00 2001 From: Rasmus Thomsen Date: Sun, 5 Aug 2018 22:25:30 +0200 Subject: [PATCH 053/155] build: respect 'includedir' meson param --- src/pipewire/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 7cd6f55c7..8aeb6f57c 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -63,7 +63,7 @@ pipewire_sources = [ configure_file(input : 'version.h.in', output : 'version.h', - install_dir : 'include/pipewire', + install_dir : join_paths(get_option('includedir'), 'pipewire'), configuration : cdata) install_headers(pipewire_headers, subdir : 'pipewire') From 165c441cedd38e738d8a2a68d68e1e4fc1fda13e Mon Sep 17 00:00:00 2001 From: Rasmus Thomsen Date: Sat, 19 May 2018 11:41:41 +0200 Subject: [PATCH 054/155] meson: add systemd option This is handy for source distributions, which want to avoid automagic dependencies --- meson_options.txt | 4 ++++ src/daemon/meson.build | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/meson_options.txt b/meson_options.txt index 02b931943..8e7976865 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,3 +10,7 @@ option('enable_gstreamer', description: 'Build GStreamer plugins', type: 'boolean', value: false) +option('systemd', + description: 'Enable systemd integration', + type: 'boolean', + value: true) diff --git a/src/daemon/meson.build b/src/daemon/meson.build index 27eb1f009..0761224d7 100644 --- a/src/daemon/meson.build +++ b/src/daemon/meson.build @@ -30,8 +30,11 @@ executable('pipewire', dependencies : [pipewire_dep], ) -systemd = dependency('systemd', required: false) - -if systemd.found() - subdir('systemd') +if get_option('systemd') + systemd = dependency('systemd', required: false) + if systemd.found() + subdir('systemd') + else + warning('Systemd integration was enabled, but systemd is not available') + endif endif From 3bf53f5e22f29578989e9a078e4ff9c041eb56d0 Mon Sep 17 00:00:00 2001 From: Rasmus Thomsen Date: Sat, 19 May 2018 11:44:28 +0200 Subject: [PATCH 055/155] meson: rename options as per meson's style guide see https://mesonbuild.com/Style-guide.html --- meson.build | 6 +++--- meson_options.txt | 6 +++--- src/meson.build | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/meson.build b/meson.build index b3c477fe3..52109810a 100644 --- a/meson.build +++ b/meson.build @@ -153,7 +153,7 @@ dbus_dep = dependency('dbus-1') #optional dependencies jack_dep = dependency('jack', version : '>= 1.9.10', required : false) -if get_option('enable_gstreamer') +if get_option('gstreamer') glib_dep = dependency('glib-2.0', version : '>=2.32.0') gobject_dep = dependency('gobject-2.0') gmodule_dep = dependency('gmodule-2.0') @@ -169,7 +169,7 @@ subdir('spa') subdir('src') subdir('pkgconfig') -if get_option('enable_docs') +if get_option('docs') doxygen = find_program('doxygen', required : false) if doxygen.found() subdir('doc') @@ -178,7 +178,7 @@ if get_option('enable_docs') endif endif -if get_option('enable_man') +if get_option('man') xmltoman = find_program('xmltoman', required : false) if xmltoman.found() subdir('man') diff --git a/meson_options.txt b/meson_options.txt index 8e7976865..3d21b2b4b 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,12 +1,12 @@ -option('enable_docs', +option('docs', description: 'Build documentation', type: 'boolean', value: false) -option('enable_man', +option('man', description: 'Build manpages', type: 'boolean', value: false) -option('enable_gstreamer', +option('gstreamer', description: 'Build GStreamer plugins', type: 'boolean', value: false) diff --git a/src/meson.build b/src/meson.build index b30f784d6..0ad7778d6 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,6 @@ subdir('tools') subdir('modules') subdir('examples') -if get_option('enable_gstreamer') +if get_option('gstreamer') subdir('gst') endif From c6c7c4577e6709087d677d9bc15b0112a19918f0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 Aug 2018 10:34:38 +0200 Subject: [PATCH 056/155] meson: remove jack dependency --- meson.build | 3 --- 1 file changed, 3 deletions(-) diff --git a/meson.build b/meson.build index 52109810a..4be3a83cf 100644 --- a/meson.build +++ b/meson.build @@ -150,9 +150,6 @@ dl_lib = cc.find_library('dl', required : false) pthread_lib = dependency('threads') dbus_dep = dependency('dbus-1') -#optional dependencies -jack_dep = dependency('jack', version : '>= 1.9.10', required : false) - if get_option('gstreamer') glib_dep = dependency('glib-2.0', version : '>=2.32.0') gobject_dep = dependency('gobject-2.0') From 9ea266f78989eb9649316f868375ebcca979a82a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 Aug 2018 13:18:00 +0200 Subject: [PATCH 057/155] protocol: don't log error on disconnect Just log an info message on disconnect. Fixes #33 --- src/modules/module-protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index f975947e4..7417aa4f6 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -275,7 +275,7 @@ connection_data(void *data, int fd, enum spa_io mask) struct pw_client *client = this->client; if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { - pw_log_error("protocol-native %p: got connection error", client->protocol); + pw_log_info("protocol-native %p: client %p disconnected", client->protocol, client); pw_client_destroy(client); return; } From 8ae757768904865c9b1a40a1d3bbbca109890cfe Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 Aug 2018 16:28:43 +0200 Subject: [PATCH 058/155] remove unused functions --- src/pipewire/module.c | 10 ---------- src/pipewire/module.h | 4 ---- src/pipewire/remote.c | 2 +- src/pipewire/remote.h | 3 --- 4 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/pipewire/module.c b/src/pipewire/module.c index 25ee90ba3..07282f950 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -152,16 +152,6 @@ static const struct pw_global_events global_events = { .bind = global_bind, }; -struct pw_module * pw_core_find_module(struct pw_core *core, const char *filename) -{ - struct pw_module *module; - spa_list_for_each(module, &core->module_list, link) { - if (strcmp(module->info.filename, filename) == 0) - return module; - } - return NULL; -} - /** Load a module * * \param core a \ref pw_core diff --git a/src/pipewire/module.h b/src/pipewire/module.h index 78c91a549..144105b1f 100644 --- a/src/pipewire/module.h +++ b/src/pipewire/module.h @@ -91,10 +91,6 @@ void pw_module_add_listener(struct pw_module *module, /** Destroy a module */ void pw_module_destroy(struct pw_module *module); -/** Find a module by filename */ -struct pw_module * -pw_core_find_module(struct pw_core *core, const char *filename); - #ifdef __cplusplus } #endif diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index cc2a29ba0..99a3c689c 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -118,7 +118,7 @@ const char *pw_remote_state_as_string(enum pw_remote_state state) return "invalid-state"; } -int +static int pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...) { enum pw_remote_state old = remote->state; diff --git a/src/pipewire/remote.h b/src/pipewire/remote.h index e88267be1..df0c496ce 100644 --- a/src/pipewire/remote.h +++ b/src/pipewire/remote.h @@ -197,9 +197,6 @@ struct pw_proxy *pw_remote_find_proxy(struct pw_remote *remote, uint32_t id); /** Disconnect from the remote PipeWire. \memberof pw_remote */ int pw_remote_disconnect(struct pw_remote *remote); -/** Update the state of the remote, mostly used by protocols */ -int pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...); - /** run a local node in a remote graph */ struct pw_proxy *pw_remote_export(struct pw_remote *remote, struct pw_node *node); From 8d53d3018f2d3bccd72bffb901ec36095d430382 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 Aug 2018 12:45:18 +0200 Subject: [PATCH 059/155] Release 0.2.3 --- NEWS | 24 +++++++++++------------- meson.build | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index f1671eb03..0c4d06f10 100644 --- a/NEWS +++ b/NEWS @@ -1,17 +1,15 @@ -PipeWire 0.2.2 +PipeWire 0.2.3 -- Various fixes to memory handling -- Fixes for shutdown -- v4l2 fix enumeration of frame intervals -- Make the daemon stop when the setup commands fail -- Improve safety of hooks -- Update stream API to more future proof version -- Add more options to stream API such as scheduling in the - main thread and automatic mapping of buffers -- Add version file and macros to check compile time and - runtime versions of pipewire -- Future proof some structs -- Increment API version and .so version +- Fix deviceprovider caps introspection +- Refcounting fixes in pipewiresrc +- Remove clock interpolation from stream +- Improve clock in gstreamer elements +- Remove spalib +- Fix crash with pw_map +- Add version number to hook list +- Improve driver mode in gstreamer elements +- add daemon options +- add man pages Work is ongoing in the work branch that features a completely new scheduling method that will enable audio support. Some of these diff --git a/meson.build b/meson.build index 4be3a83cf..443da44c8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.2', + version : '0.2.3', meson_version : '>= 0.36.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 021d6cf25a068e255b3a6244e2ed8b0507fbd1b5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 30 Aug 2018 14:49:08 +0200 Subject: [PATCH 060/155] man: install manpages in the right directory --- man/meson.build | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/man/meson.build b/man/meson.build index 1d7045bf4..6c6d13d6a 100644 --- a/man/meson.build +++ b/man/meson.build @@ -7,22 +7,25 @@ manpage_conf.set('PIPEWIRE_CONFIG_DIR', pipewire_configdir) manpage_conf.set('top_srcdir', meson.source_root()) manpage_conf.set('top_builddir', meson.build_root()) -manpages = ['pipewire.1', - 'pipewire.conf.5', - 'pipewire-cli.1', - 'pipewire-monitor.1' ] +manpages = [ + [ 'pipewire', '1' ], + [ 'pipewire.conf', '5' ], + [ 'pipewire-cli', '1' ], + [ 'pipewire-monitor', '1' ] +] foreach m : manpages - infile = m + '.xml.in' - outfile = m + '.xml' + file = m.get(0) + '.' + m.get(1) + infile = file + '.xml.in' + outfile = file + '.xml' xml = configure_file(input : infile, output : outfile, configuration : manpage_conf) - custom_target(m + '.target', - output : m, + custom_target(file + '.target', + output : file, input : xml, command : [xmltoman, '@INPUT@'], capture : true, install : true, - install_dir : join_paths(get_option('mandir'), 'man1')) + install_dir : join_paths(get_option('mandir'), 'man', m.get(1))) endforeach From 692d96b9a48a34f8c1888eeb2e7ca13054814565 Mon Sep 17 00:00:00 2001 From: Jesse Pullinen Date: Thu, 30 Aug 2018 19:40:40 +0300 Subject: [PATCH 061/155] Fix memory leak in pw_properties_set removing a property leaked the key --- src/pipewire/properties.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 269b77fb6..627168535 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -247,13 +247,13 @@ void pw_properties_free(struct pw_properties *properties) free(impl); } -static int do_replace(struct pw_properties *properties, char *key, char *value) +static int do_replace(struct pw_properties *properties, const char *key, char *value) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); int index = find_index(properties, key); if (index == -1) { - add_func(properties, key, value); + add_func(properties, strdup(key), value); } else { struct spa_dict_item *item = pw_array_get_unchecked(&impl->items, index, struct spa_dict_item); @@ -267,7 +267,7 @@ static int do_replace(struct pw_properties *properties, char *key, char *value) item->value = other->value; impl->items.size -= sizeof(struct spa_dict_item); } else { - item->key = key; + item->key = strdup(key); item->value = value; } } @@ -288,7 +288,7 @@ static int do_replace(struct pw_properties *properties, char *key, char *value) */ int pw_properties_set(struct pw_properties *properties, const char *key, const char *value) { - return do_replace(properties, strdup(key), value ? strdup(value) : NULL); + return do_replace(properties, key, value ? strdup(value) : NULL); } /** Set a property value by format @@ -312,7 +312,7 @@ int pw_properties_setf(struct pw_properties *properties, const char *key, const vasprintf(&value, format, varargs); va_end(varargs); - return do_replace(properties, strdup(key), value); + return do_replace(properties, key, value); } /** Get a property From bbba49aae1e593cf5e1c00fdfcb39dc3f0d91ec5 Mon Sep 17 00:00:00 2001 From: "Jan Alexander Steffens (heftig)" Date: Sun, 2 Sep 2018 03:22:14 +0200 Subject: [PATCH 062/155] meson: Use pkgconfig.generate Also fixes the moduledir having a duplicated prefix. --- meson.build | 4 ++-- pkgconfig/libpipewire.pc.in | 11 ----------- pkgconfig/libspa.pc.in | 7 ------- pkgconfig/meson.build | 25 ------------------------- spa/meson.build | 6 ++++++ src/pipewire/meson.build | 11 ++++++++++- 6 files changed, 18 insertions(+), 46 deletions(-) delete mode 100644 pkgconfig/libpipewire.pc.in delete mode 100644 pkgconfig/libspa.pc.in delete mode 100644 pkgconfig/meson.build diff --git a/meson.build b/meson.build index 443da44c8..bcbe35e95 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('pipewire', 'c', version : '0.2.3', - meson_version : '>= 0.36.0', + meson_version : '>= 0.42.0', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -34,6 +34,7 @@ modules_install_dir = join_paths(pipewire_libdir, 'pipewire-@0@'.format(apiversi spa_plugindir = join_paths(pipewire_libdir, 'spa') gnome = import('gnome') +pkgconfig = import('pkgconfig') cc = meson.get_compiler('c') @@ -164,7 +165,6 @@ endif subdir('spa') subdir('src') -subdir('pkgconfig') if get_option('docs') doxygen = find_program('doxygen', required : false) diff --git a/pkgconfig/libpipewire.pc.in b/pkgconfig/libpipewire.pc.in deleted file mode 100644 index ca302fbea..000000000 --- a/pkgconfig/libpipewire.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@/ -moduledir=@moduledir@ - -Name: libpipewire -Description: PipeWire Interface -Version: @VERSION@ -Libs: -L${libdir} -lpipewire-@PIPEWIRE_API_VERSION@ -Cflags: -I${includedir} -D_REENTRANT diff --git a/pkgconfig/libspa.pc.in b/pkgconfig/libspa.pc.in deleted file mode 100644 index e5878d2d8..000000000 --- a/pkgconfig/libspa.pc.in +++ /dev/null @@ -1,7 +0,0 @@ -prefix=@prefix@ -includedir=@includedir@/ - -Name: libspa -Description: Simple Plugin API -Version: @VERSION@ -Cflags: -I${includedir} -D_REENTRANT diff --git a/pkgconfig/meson.build b/pkgconfig/meson.build deleted file mode 100644 index 9d5757846..000000000 --- a/pkgconfig/meson.build +++ /dev/null @@ -1,25 +0,0 @@ -pkgconf = configuration_data() - -pkgconf.set('prefix', get_option('prefix')) -pkgconf.set('exec_prefix', '${prefix}') -pkgconf.set('libdir', '${prefix}/@0@'.format(get_option('libdir'))) -pkgconf.set('includedir', '${prefix}/@0@'.format(get_option('includedir'))) -pkgconf.set('moduledir', '${prefix}/@0@'.format(modules_install_dir)) -pkgconf.set('PIPEWIRE_API_VERSION', apiversion) -pkgconf.set('VERSION', pipewire_version) - -pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) - -pkg_files = [ - [ 'libpipewire', apiversion ], - [ 'libspa', spaversion ], -] - -foreach p : pkg_files - infile = p.get(0) + '.pc.in' - outfile = p.get(0) + '-@0@.pc'.format(p.get(1)) - configure_file(input : infile, - output : outfile, - configuration : pkgconf, - install_dir : pkg_install_dir) -endforeach diff --git a/spa/meson.build b/spa/meson.build index 09e1c2f08..d190b9b2a 100644 --- a/spa/meson.build +++ b/spa/meson.build @@ -24,3 +24,9 @@ subdir('include') subdir('plugins') subdir('tools') subdir('tests') + +pkgconfig.generate(filebase : 'libspa-@0@'.format(spaversion), + name : 'libspa', + description : 'Simple Plugin API', + version : pipewire_version, + extra_cflags : '-D_REENTRANT') diff --git a/src/pipewire/meson.build b/src/pipewire/meson.build index 8aeb6f57c..d2d75b840 100644 --- a/src/pipewire/meson.build +++ b/src/pipewire/meson.build @@ -74,7 +74,8 @@ libpipewire_c_args = [ '-D_POSIX_C_SOURCE', ] -libpipewire = shared_library('pipewire-@0@'.format(apiversion), pipewire_sources, +libpipewire_name = 'pipewire-@0@'.format(apiversion) +libpipewire = shared_library(libpipewire_name, pipewire_sources, version : libversion, soversion : soversion, c_args : libpipewire_c_args, @@ -87,3 +88,11 @@ pipewire_dep = declare_dependency(link_with : libpipewire, include_directories : [pipewire_inc, configinc, spa_inc], dependencies : [pthread_lib], ) + +pkgconfig.generate(filebase : 'lib@0@'.format(libpipewire_name), + libraries : [libpipewire], + name : 'libpipewire', + description : 'PipeWire Interface', + version : pipewire_version, + extra_cflags : '-D_REENTRANT', + variables : ['moduledir=${libdir}/@0@'.format(libpipewire_name)]) From f58f63ae64b98bb5c0d6cd6d0729ce57c54fdf3e Mon Sep 17 00:00:00 2001 From: Tomas Popela Date: Thu, 6 Sep 2018 12:38:44 +0200 Subject: [PATCH 063/155] Fix build with clang By using __typeof__ instead of typeof: /usr/include/pipewire/array.h:85:11: error: use of undeclared identifier 'typeof'; did you mean 'typeid'? alloc = SPA_MAX(alloc, arr->extend); --- spa/include/spa/utils/defs.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 0486c0251..e0ad462c8 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -68,21 +68,21 @@ struct spa_fraction { #define SPA_MIN(a,b) \ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ _a < _b ? _a : _b; \ }) #define SPA_MAX(a,b) \ ({ \ - typeof(a) _a = (a); \ - typeof(b) _b = (b); \ + __typeof__(a) _a = (a); \ + __typeof__(b) _b = (b); \ _a > _b ? _a : _b; \ }) #define SPA_CLAMP(v,low,high) \ ({ \ - typeof(v) _v = (v); \ - typeof(low) _low = (low); \ - typeof(high) _high = (high); \ + __typeof__(v) _v = (v); \ + __typeof__(low) _low = (low); \ + __typeof__(high) _high = (high); \ _v > _high ? _high : ( _v < _low ? _low : _v); \ }) From 9e60fd0b57f0607237ffd972f88d421eb56e7b5f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 17 Sep 2018 12:24:15 +0200 Subject: [PATCH 064/155] stream: improve cleanup Destroy proxies before disconnect, they might still need the connection. Destroy the stream related objects when the stream node is destroyed. Don't try to remove the mainloop sources from the data loop. Don't try to create properties in _connect, we already created them in _new. In disconnect, make the server destroy the node and destroy our local proxy. --- src/pipewire/remote.c | 11 +++++----- src/pipewire/stream.c | 47 +++++++++++++++++++++---------------------- 2 files changed, 28 insertions(+), 30 deletions(-) diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 99a3c689c..26e656806 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -180,11 +180,10 @@ static void core_event_remove_id(void *data, uint32_t id) struct pw_remote *this = data; struct pw_proxy *proxy; - proxy = pw_map_lookup(&this->objects, id); - if (proxy) { - pw_log_debug("remote %p: object remove %u", this, id); + pw_log_debug("remote %p: object remove %u", this, id); + if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) pw_proxy_destroy(proxy); - } + pw_map_remove(&this->objects, id); } @@ -442,12 +441,12 @@ int pw_remote_disconnect(struct pw_remote *remote) spa_list_for_each_safe(stream, s2, &remote->stream_list, link) pw_stream_disconnect(stream); - pw_protocol_client_disconnect (remote->conn); - spa_list_for_each_safe(proxy, t2, &remote->proxy_list, link) pw_proxy_destroy(proxy); remote->core_proxy = NULL; + pw_protocol_client_disconnect (remote->conn); + pw_map_clear(&remote->objects); pw_map_clear(&remote->types); remote->n_types = 0; diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index c7736be8e..fa8922c16 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -229,7 +229,7 @@ static void clear_buffers(struct pw_stream *stream) struct buffer *b; int i, j; - pw_log_debug("stream %p: clear buffers", stream); + pw_log_debug("stream %p: clear %d buffers", stream, impl->n_buffers); for (i = 0; i < impl->n_buffers; i++) { b = &impl->buffers[i]; @@ -534,33 +534,21 @@ void pw_stream_destroy(struct pw_stream *stream) pw_stream_events_destroy(stream); - if (impl->node_proxy) - spa_hook_remove(&impl->proxy_listener); - pw_stream_disconnect(stream); spa_list_remove(&stream->link); - set_init_params(stream, 0, NULL); - set_params(stream, 0, NULL); - - if (impl->format) - free(impl->format); + pw_array_clear(&impl->mem_ids); if (stream->error) free(stream->error); - clear_buffers(stream); - - clear_mems(stream); - pw_array_clear(&impl->mem_ids); + if (stream->name) + free(stream->name); if (stream->properties) pw_properties_free(stream->properties); - if (stream->name) - free(stream->name); - free(impl); } @@ -821,7 +809,7 @@ on_rtsocket_condition(void *data, int fd, enum spa_io mask) if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { pw_log_warn("got error"); - unhandle_socket(stream); + do_remove_sources(stream->remote->core->data_loop->loop, false, 0, NULL, 0, impl); return; } @@ -1241,6 +1229,21 @@ static void on_node_proxy_destroy(void *data) impl->node_proxy = NULL; spa_hook_remove(&impl->proxy_listener); + set_init_params(this, 0, NULL); + set_params(this, 0, NULL); + + clear_buffers(this); + clear_mems(this); + + if (impl->format) { + free(impl->format); + impl->format = NULL; + } + if (impl->trans) { + pw_client_node_transport_destroy(impl->trans); + impl->trans = NULL; + } + stream_set_state(this, PW_STREAM_STATE_UNCONNECTED, NULL); } @@ -1268,8 +1271,6 @@ pw_stream_connect(struct pw_stream *stream, stream_set_state(stream, PW_STREAM_STATE_CONNECTING, NULL); - if (stream->properties == NULL) - stream->properties = pw_properties_new(NULL, NULL); if (port_path) pw_properties_set(stream->properties, PW_NODE_PROP_TARGET_NODE, port_path); if (flags & PW_STREAM_FLAG_AUTOCONNECT) @@ -1332,17 +1333,15 @@ int pw_stream_disconnect(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + pw_log_debug("stream %p: disconnect", stream); + impl->disconnecting = true; unhandle_socket(stream); if (impl->node_proxy) { pw_client_node_proxy_destroy(impl->node_proxy); - impl->node_proxy = NULL; - } - if (impl->trans) { - pw_client_node_transport_destroy(impl->trans); - impl->trans = NULL; + pw_proxy_destroy((struct pw_proxy *)impl->node_proxy); } return 0; } From 8d2a9fcf62744116c8dd6c9a0c8c19b71bdb90e3 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Sep 2018 15:58:05 +0200 Subject: [PATCH 065/155] pipewire: fix leak of dbus interface Track loaded interfaces. Add a method to release the dbus interface when the core is destroyed. Free SDL resources in video-play example --- src/examples/video-play.c | 4 +++ src/pipewire/core.c | 6 +++- src/pipewire/pipewire.c | 72 +++++++++++++++++++++++++++++++++------ src/pipewire/pipewire.h | 1 + src/pipewire/private.h | 2 ++ 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 8ec70b823..b259a86b6 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -449,5 +449,9 @@ int main(int argc, char *argv[]) pw_core_destroy(data.core); pw_main_loop_destroy(data.loop); + SDL_DestroyTexture(data.texture); + SDL_DestroyRenderer(data.renderer); + SDL_DestroyWindow(data.window); + return 0; } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index a844eb41e..6134a6ea3 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -391,12 +391,14 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro spa_graph_init(&this->rt.graph); spa_graph_set_callbacks(&this->rt.graph, &spa_graph_impl_default, NULL); + this->dbus_iface = pw_get_spa_dbus(this->main_loop); + this->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, this->type.map); this->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop); this->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop); this->support[3] = SPA_SUPPORT_INIT(SPA_TYPE__LoopUtils, this->main_loop->utils); this->support[4] = SPA_SUPPORT_INIT(SPA_TYPE__Log, pw_log_get()); - this->support[5] = SPA_SUPPORT_INIT(SPA_TYPE__DBus, pw_get_spa_dbus(this->main_loop)); + this->support[5] = SPA_SUPPORT_INIT(SPA_TYPE__DBus, this->dbus_iface); this->n_support = 6; pw_log_debug("%p", this->support[5].data); @@ -494,6 +496,8 @@ void pw_core_destroy(struct pw_core *core) pw_data_loop_destroy(core->data_loop_impl); + pw_release_spa_dbus(core->dbus_iface); + pw_properties_free(core->properties); pw_map_clear(&core->globals); diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index 925e8af24..d1c6746b8 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -44,6 +44,19 @@ static struct support_info { uint32_t n_support; } support_info; +struct interface { + struct spa_list link; + struct spa_handle *handle; + uint32_t type; + void *iface; +}; + +struct registry { + struct spa_list interfaces; +}; + +static struct registry global_registry; + static bool open_support(const char *path, const char *lib, @@ -92,7 +105,7 @@ static const struct spa_handle_factory *get_factory(struct support_info *info, c return NULL; } -static void * +static struct interface * load_interface(struct support_info *info, const char *factory_name, const char *type) @@ -101,7 +114,8 @@ load_interface(struct support_info *info, struct spa_handle *handle; uint32_t type_id; const struct spa_handle_factory *factory; - void *iface; + struct interface *iface; + void *ptr; struct spa_type_map *map = NULL; factory = get_factory(info, factory_name); @@ -118,12 +132,22 @@ load_interface(struct support_info *info, map = pw_get_support_interface(SPA_TYPE__TypeMap); type_id = map ? spa_type_map_get_id(map, type) : 0; - if ((res = spa_handle_get_interface(handle, type_id, &iface)) < 0) { + if ((res = spa_handle_get_interface(handle, type_id, &ptr)) < 0) { fprintf(stderr, "can't get %s interface %d\n", type, res); goto interface_failed; } + + if ((iface = calloc(1, sizeof(struct interface))) == NULL) + goto alloc_failed; + + iface->handle = handle; + iface->type = type_id; + iface->iface = ptr; + spa_list_append(&global_registry.interfaces, &iface->link); + return iface; + alloc_failed: interface_failed: spa_handle_clear(handle); init_failed: @@ -175,6 +199,7 @@ void *pw_get_spa_dbus(struct pw_loop *loop) { struct support_info dbus_support_info; const char *str; + struct interface *iface; dbus_support_info.n_support = support_info.n_support; memcpy(dbus_support_info.support, support_info.support, @@ -186,11 +211,36 @@ void *pw_get_spa_dbus(struct pw_loop *loop) if ((str = getenv("SPA_PLUGIN_DIR")) == NULL) str = PLUGINDIR; - if (open_support(str, "support/libspa-dbus", &dbus_support_info)) - return load_interface(&dbus_support_info, "dbus", SPA_TYPE__DBus); - + if (open_support(str, "support/libspa-dbus", &dbus_support_info)) { + iface = load_interface(&dbus_support_info, "dbus", SPA_TYPE__DBus); + if (iface != NULL) + return iface->iface; + } return NULL; } +static struct interface *find_interface(void *iface) +{ + struct interface *i; + spa_list_for_each(i, &global_registry.interfaces, link) { + if (i->iface == iface) + return i; + } + return NULL; +} + +int pw_release_spa_dbus(void *dbus) +{ + struct interface *iface; + + if ((iface = find_interface(dbus)) == NULL) + return -ENOENT; + + spa_list_remove(&iface->link); + spa_handle_clear(iface->handle); + free(iface->handle); + free(iface); + return 0; +} /** Initialize PipeWire * @@ -207,7 +257,7 @@ void *pw_get_spa_dbus(struct pw_loop *loop) void pw_init(int *argc, char **argv[]) { const char *str; - void *iface; + struct interface *iface; struct support_info *info = &support_info; if ((str = getenv("PIPEWIRE_DEBUG"))) @@ -219,15 +269,17 @@ void pw_init(int *argc, char **argv[]) if (support_info.n_support > 0) return; + spa_list_init(&global_registry.interfaces); + if (open_support(str, "support/libspa-support", info)) { iface = load_interface(info, "mapper", SPA_TYPE__TypeMap); if (iface != NULL) - info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, iface); + info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, iface->iface); iface = load_interface(info, "logger", SPA_TYPE__Log); if (iface != NULL) { - info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__Log, iface); - pw_log_set(iface); + info->support[info->n_support++] = SPA_SUPPORT_INIT(SPA_TYPE__Log, iface->iface); + pw_log_set(iface->iface); } } pw_log_info("version %s", pw_get_library_version()); diff --git a/src/pipewire/pipewire.h b/src/pipewire/pipewire.h index dcf705ea8..16bc28463 100644 --- a/src/pipewire/pipewire.h +++ b/src/pipewire/pipewire.h @@ -134,6 +134,7 @@ void * pw_get_support_interface(const char *type); void *pw_get_spa_dbus(struct pw_loop *loop); +int pw_release_spa_dbus(void *dbus); const struct spa_handle_factory * pw_get_support_factory(const char *factory_name); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 2b2682abb..a9b189af6 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -183,6 +183,8 @@ struct pw_core { struct pw_loop *data_loop; /**< data loop for data passing */ struct pw_data_loop *data_loop_impl; + void *dbus_iface; + struct spa_support support[16]; /**< support for spa plugins */ uint32_t n_support; /**< number of support items */ From 58efa8c2f439caae6b7885dd4c4018da9adfb5bc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Sep 2018 16:06:29 +0200 Subject: [PATCH 066/155] man: fix man page install path Fixes #85 --- man/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/man/meson.build b/man/meson.build index 6c6d13d6a..ffa332172 100644 --- a/man/meson.build +++ b/man/meson.build @@ -27,5 +27,5 @@ foreach m : manpages command : [xmltoman, '@INPUT@'], capture : true, install : true, - install_dir : join_paths(get_option('mandir'), 'man', m.get(1))) + install_dir : join_paths(get_option('mandir'), 'man' + m.get(1))) endforeach From 9fdb8a0e5f4da704338d5ab38df4682f8b48f5d4 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Sun, 23 Sep 2018 06:25:16 +0530 Subject: [PATCH 067/155] meson: Add an uninstalled target and script This makes it easier to run PipeWire from the build environment --- meson.build | 3 +++ pw-uninstalled.sh | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100755 pw-uninstalled.sh diff --git a/meson.build b/meson.build index bcbe35e95..8e440fe51 100644 --- a/meson.build +++ b/meson.build @@ -183,3 +183,6 @@ if get_option('man') warning('Man page generation was enabled, but xmltoman is not available') endif endif + +setenv = find_program('pw-uninstalled.sh') +run_target('uninstalled', command : [setenv, '-b@0@'.format(meson.build_root())]) diff --git a/pw-uninstalled.sh b/pw-uninstalled.sh new file mode 100755 index 000000000..4054f7040 --- /dev/null +++ b/pw-uninstalled.sh @@ -0,0 +1,37 @@ +#!/bin/sh + +set -e + +while getopts ":b:" opt; do + case ${opt} in + b) + BUILDDIR=${OPTARG} + ;; + \?) + echo "Invalid option: -${OPTARG}" + exit -1 + ;; + :) + echo "Option -${OPTARG} requires an argument" + exit -1 + ;; + esac +done + +if [ -z "${BUILDDIR}" ]; then + BUILDDIR=${PWD}/build + echo "Using default build directory: ${BUILDDIR}" +fi + +if [ ! -d ${BUILDDIR} ]; then + echo "Invalid build directory: ${BUILDDIR}" + exit -1 +fi + +export PIPEWIRE_CONFIG_FILE="${BUILDDIR}/src/daemon/pipewire.conf" +export SPA_PLUGIN_DIR="${BUILDDIR}/spa/plugins" +export PIPEWIRE_MODULE_DIR="${BUILDDIR}/src/modules" +export PATH="${BUILDDIR}/src/daemon:${PATH}" + +# FIXME: find a nice, shell-neutral way to specify a prompt +${SHELL} From e5dcacdefbdf50f23b51d3cb172a398aa5e9309f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Oct 2018 09:50:43 +0200 Subject: [PATCH 068/155] add systemd socket activation --- config.h.meson | 3 ++ meson.build | 10 +++++ src/daemon/meson.build | 9 +---- src/modules/meson.build | 2 +- src/modules/module-protocol-native.c | 59 +++++++++++++++++----------- 5 files changed, 52 insertions(+), 31 deletions(-) diff --git a/config.h.meson b/config.h.meson index 335f3de50..ad0b79d05 100644 --- a/config.h.meson +++ b/config.h.meson @@ -317,6 +317,9 @@ /* Define to 1 if you have the header file. */ #mesondefine HAVE_WINSOCK2_H +/* for the systemd header files */ +#mesondefine HAVE_SYSTEMD_DAEMON + /* the host CPU */ #mesondefine HOST_CPU diff --git a/meson.build b/meson.build index 8e440fe51..dde1f22b2 100644 --- a/meson.build +++ b/meson.build @@ -125,6 +125,16 @@ if cc.has_function('memfd_create', prefix : '#include ', args : [ '- cdata.set('HAVE_MEMFD_CREATE', 1) endif +if get_option('systemd') + systemd = dependency('systemd', required: false) + systemd_dep = dependency('libsystemd', required: false) + if systemd.found() + cdata.set('HAVE_SYSTEMD_DAEMON', 1) + else + warning('Systemd integration was enabled, but systemd is not available') + endif +endif + configure_file(input : 'config.h.meson', output : 'config.h', configuration : cdata) diff --git a/src/daemon/meson.build b/src/daemon/meson.build index 0761224d7..8b4f52059 100644 --- a/src/daemon/meson.build +++ b/src/daemon/meson.build @@ -30,11 +30,6 @@ executable('pipewire', dependencies : [pipewire_dep], ) -if get_option('systemd') - systemd = dependency('systemd', required: false) - if systemd.found() - subdir('systemd') - else - warning('Systemd integration was enabled, but systemd is not available') - endif +if systemd.found() + subdir('systemd') endif diff --git a/src/modules/meson.build b/src/modules/meson.build index 2c5092df6..4dcb6e59c 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -81,7 +81,7 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ include_directories : [configinc, spa_inc], install : true, install_dir : modules_install_dir, - dependencies : [mathlib, dl_lib, pipewire_dep], + dependencies : [mathlib, dl_lib, pipewire_dep, systemd_dep], ) pipewire_module_audio_dsp = shared_library('pipewire-module-audio-dsp', diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 7417aa4f6..84ebb5c19 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -32,6 +32,10 @@ #include "config.h" +#ifdef HAVE_SYSTEMD_DAEMON +#include +#endif + #include "pipewire/pipewire.h" #include "pipewire/private.h" #include "pipewire/log.h" @@ -88,6 +92,7 @@ struct server { int fd_lock; struct sockaddr_un addr; char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN]; + bool activated; struct pw_loop *loop; struct spa_source *source; @@ -386,8 +391,6 @@ static bool init_socket_name(struct server *s, const char *name) static bool lock_socket(struct server *s) { - struct stat socket_stat; - snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX); s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC, @@ -403,15 +406,6 @@ static bool lock_socket(struct server *s) s->lock_addr); goto err_fd; } - - if (stat(s->addr.sun_path, &socket_stat) < 0) { - if (errno != ENOENT) { - pw_log_error("did not manage to stat file %s\n", s->addr.sun_path); - goto err_fd; - } - } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) { - unlink(s->addr.sun_path); - } return true; err_fd: @@ -455,24 +449,43 @@ socket_data(void *data, int fd, enum spa_io mask) static bool add_socket(struct pw_protocol *protocol, struct server *s) { socklen_t size; - int fd; + int fd = -1; + bool activated = false; - if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) - goto error; - - size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); - if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) { - pw_log_error("bind() failed with error: %m"); - goto error_close; +#ifdef HAVE_SYSTEMD_DAEMON + { + int i, n = sd_listen_fds(0); + for (i = 0; i < n; ++i) { + if (sd_is_socket_unix(SD_LISTEN_FDS_START + i, SOCK_STREAM, + 1, s->addr.sun_path, 0) > 0) { + fd = SD_LISTEN_FDS_START + i; + activated = true; + pw_log_info("Found socket activation socket for '%s'", s->addr.sun_path); + break; + } + } } +#endif - if (listen(fd, 128) < 0) { - pw_log_error("listen() failed with error: %m"); - goto error_close; + if (fd < 0) { + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) + goto error; + + size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); + if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) { + pw_log_error("bind() failed with error: %m"); + goto error_close; + } + + if (listen(fd, 128) < 0) { + pw_log_error("listen() failed with error: %m"); + goto error_close; + } } s->loop = pw_core_get_main_loop(protocol->core); s->source = pw_loop_add_io(s->loop, fd, SPA_IO_IN, true, socket_data, s); + s->activated = activated; if (s->source == NULL) goto error_close; @@ -712,7 +725,7 @@ static void destroy_server(struct pw_protocol_server *server) if (s->source) pw_loop_destroy_source(s->loop, s->source); - if (s->addr.sun_path[0]) + if (s->addr.sun_path[0] && !s->activated) unlink(s->addr.sun_path); if (s->lock_addr[0]) unlink(s->lock_addr); From 6266cd0f485a7426abdb32c3aef7107f587c2cb5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Oct 2018 11:14:52 +0200 Subject: [PATCH 069/155] protocol-native: -1 is for invalid fd, not 1 --- src/modules/module-protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 84ebb5c19..65fdaf5c4 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -729,7 +729,7 @@ static void destroy_server(struct pw_protocol_server *server) unlink(s->addr.sun_path); if (s->lock_addr[0]) unlink(s->lock_addr); - if (s->fd_lock != 1) + if (s->fd_lock != -1) close(s->fd_lock); free(s); } From e29229b6e0009f3b704e9501b13cb3714737d6c9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 18 Oct 2018 11:15:27 +0200 Subject: [PATCH 070/155] protocol-native: return errno when server failed this gives a better error code --- src/modules/module-protocol-native.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 65fdaf5c4..4816492ab 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -928,7 +928,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie val = pw_properties_get(pw_core_get_properties(core), PW_CORE_PROP_DAEMON); if (val && pw_properties_parse_bool(val)) { if (impl_add_server(this, core, properties) == NULL) - return -ENOMEM; + return -errno; } pw_module_add_listener(module, &d->module_listener, &module_events, d); From 68c2866f7d5a6965339eaf287c54616d2270c2b2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 29 Oct 2018 13:11:38 +0000 Subject: [PATCH 071/155] Fix build when systemd is found but not libsystemd Getting the following otherwise: ``` [13/28] Compiling C object 'src/modules/src@modules@@pipewire-module-protocol-native@sha/module-protocol-native.c.o'. FAILED: src/modules/src@modules@@pipewire-module-protocol-native@sha/module-protocol-native.c.o ccache cc -Isrc/modules/src@modules@@pipewire-module-protocol-native@sha -Isrc/modules -I../src/modules -I. -I../ -Ispa/include -I../spa/include -Isrc -I../src -fdiagnostics-color=always -pipe -D_FILE_OFFSET_BITS=64 -Wall -Winvalid-pch -std=gnu99 -O2 -g -fPIC -pthread -DHAVE_CONFIG_H -D_GNU_SOURCE -MD -MQ 'src/modules/src@modules@@pipewire-module-protocol-native@sha/module-protocol-native.c.o' -MF 'src/modules/src@modules@@pipewire-module-protocol-native@sha/module-protocol-native.c.o.d' -o 'src/modules/src@modules@@pipewire-module-protocol-native@sha/module-protocol-native.c.o' -c ../src/modules/module-protocol-native.c ../src/modules/module-protocol-native.c:36:10: fatal error: systemd/sd-daemon.h: No such file or directory #include ^~~~~~~~~~~~~~~~~~~~~ ``` --- meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meson.build b/meson.build index dde1f22b2..d8c22aab1 100644 --- a/meson.build +++ b/meson.build @@ -128,7 +128,7 @@ endif if get_option('systemd') systemd = dependency('systemd', required: false) systemd_dep = dependency('libsystemd', required: false) - if systemd.found() + if systemd.found() and systemd_dep.found() cdata.set('HAVE_SYSTEMD_DAEMON', 1) else warning('Systemd integration was enabled, but systemd is not available') From 8693e416bc8208af8132391800b4ae023f0b0740 Mon Sep 17 00:00:00 2001 From: Mathieu Duponchelle Date: Mon, 29 Oct 2018 14:00:31 +0100 Subject: [PATCH 072/155] examples: document how to run --- src/examples/README | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/examples/README diff --git a/src/examples/README b/src/examples/README new file mode 100644 index 000000000..ef545b363 --- /dev/null +++ b/src/examples/README @@ -0,0 +1,19 @@ +# Running the examples + +A pipewire daemon needs to be running for the examples to connect to: + +``` shell +./pw-uninstalled.sh +./build/src/daemon/pipewire +``` + +You can then run the examples in a second terminal, for example: + +``` shell +./pw-uninstalled.sh +./build/src/examples/local-v4l2 +``` + +This assumes the development package for `SDL2` was installed, check the meson +build definition in `src/examples` to find out the dependencies for each +example. From 795b352cbaf68ce6f05ab9e9d46d4eff39ffee14 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 29 Oct 2018 13:27:24 +0000 Subject: [PATCH 073/155] meson: Use feature for GStreamer and make it auto Bumping version dependency of meson Fix minor new warning in meson --- meson.build | 31 ++++++++++++++++++++----------- meson_options.txt | 4 ++-- src/daemon/meson.build | 3 +-- src/meson.build | 2 +- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/meson.build b/meson.build index d8c22aab1..2d0bf91cb 100644 --- a/meson.build +++ b/meson.build @@ -1,6 +1,6 @@ project('pipewire', 'c', version : '0.2.3', - meson_version : '>= 0.42.0', + meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', 'c_std=gnu99', 'buildtype=debugoptimized' ]) @@ -161,16 +161,25 @@ dl_lib = cc.find_library('dl', required : false) pthread_lib = dependency('threads') dbus_dep = dependency('dbus-1') -if get_option('gstreamer') - glib_dep = dependency('glib-2.0', version : '>=2.32.0') - gobject_dep = dependency('gobject-2.0') - gmodule_dep = dependency('gmodule-2.0') - gio_dep = [dependency('gio-2.0'), dependency('gio-unix-2.0')] - gst_dep = [dependency('gstreamer-1.0'), - dependency('gstreamer-plugins-base-1.0'), - dependency('gstreamer-video-1.0'), - dependency('gstreamer-audio-1.0'), - dependency('gstreamer-allocators-1.0'),] +if not get_option('gstreamer').disabled() + build_gst = true + glib_dep = [dependency('glib-2.0', version : '>=2.32.0', required: get_option('gstreamer'))] + gobject_dep = [dependency('gobject-2.0', required: get_option('gstreamer'))] + gmodule_dep = [dependency('gmodule-2.0', required: get_option('gstreamer'))] + gio_dep = [dependency('gio-2.0', required: get_option('gstreamer')), dependency('gio-unix-2.0', required: get_option('gstreamer'))] + gst_dep = [dependency('gstreamer-1.0', required: get_option('gstreamer')), + dependency('gstreamer-plugins-base-1.0', required: get_option('gstreamer')), + dependency('gstreamer-video-1.0', required: get_option('gstreamer')), + dependency('gstreamer-audio-1.0', required: get_option('gstreamer')), + dependency('gstreamer-allocators-1.0', required: get_option('gstreamer')),] + foreach dep: glib_dep + gobject_dep + gio_dep + gst_dep + if build_gst and not dep.found() + build_gst = false + message('@0@ not found, disabling GStreamer'.format(dep)) + endif + endforeach +else + build_gst = false endif subdir('spa') diff --git a/meson_options.txt b/meson_options.txt index 3d21b2b4b..5ea74ff0e 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -8,8 +8,8 @@ option('man', value: false) option('gstreamer', description: 'Build GStreamer plugins', - type: 'boolean', - value: false) + type: 'feature', + value: 'auto') option('systemd', description: 'Enable systemd integration', type: 'boolean', diff --git a/src/daemon/meson.build b/src/daemon/meson.build index 8b4f52059..fb694e7cc 100644 --- a/src/daemon/meson.build +++ b/src/daemon/meson.build @@ -13,12 +13,11 @@ pipewire_c_args = [ '-DG_LOG_DOMAIN=g_log_domain_pipewire', ] -conf_config = configuration_data() conf_install_dir = join_paths(get_option('sysconfdir'), 'pipewire') configure_file(input : 'pipewire.conf.in', output : 'pipewire.conf', - configuration : conf_config, + copy : true, install_dir : conf_install_dir) diff --git a/src/meson.build b/src/meson.build index 0ad7778d6..723e2c69a 100644 --- a/src/meson.build +++ b/src/meson.build @@ -6,6 +6,6 @@ subdir('tools') subdir('modules') subdir('examples') -if get_option('gstreamer') +if build_gst subdir('gst') endif From 0b2eec9f166ec93001972e4d92dd86a9ad3d07a2 Mon Sep 17 00:00:00 2001 From: Thibault Saunier Date: Mon, 29 Oct 2018 13:33:17 +0000 Subject: [PATCH 074/155] Set GStreamer plugins path in uninstalled env --- pw-uninstalled.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/pw-uninstalled.sh b/pw-uninstalled.sh index 4054f7040..e5a856071 100755 --- a/pw-uninstalled.sh +++ b/pw-uninstalled.sh @@ -32,6 +32,7 @@ export PIPEWIRE_CONFIG_FILE="${BUILDDIR}/src/daemon/pipewire.conf" export SPA_PLUGIN_DIR="${BUILDDIR}/spa/plugins" export PIPEWIRE_MODULE_DIR="${BUILDDIR}/src/modules" export PATH="${BUILDDIR}/src/daemon:${PATH}" +export GST_PLUGIN_PATH="${BUILDDIR}/src/gst/:${GST_PLUGIN_PATH}" # FIXME: find a nice, shell-neutral way to specify a prompt ${SHELL} From 4af917e9539aaf6e7811e69e0bccf436b31f9311 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Thu, 25 Oct 2018 15:05:13 +0100 Subject: [PATCH 075/155] gitignore: Add build dir and cscope files --- .gitignore | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 0c2f76c23..568ae4e82 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,8 @@ ABOUT-NLS *.tar.gz *.tar.xz *.o +build/ config.h.meson - +cscope.out +cscope.in.out +cscope.po.out From 10ce1a02cf752bbe86b41c111300face95112945 Mon Sep 17 00:00:00 2001 From: Arun Raghavan Date: Tue, 30 Oct 2018 07:55:21 +0000 Subject: [PATCH 076/155] gitignore: Add vim files --- .gitignore | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.gitignore b/.gitignore index 568ae4e82..06a377378 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,27 @@ config.h.meson cscope.out cscope.in.out cscope.po.out + +# Created by https://www.gitignore.io/api/vim + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + + +# End of https://www.gitignore.io/api/vim From d5c894cfd8ec3d972cc9130123676aee99f583b0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Nov 2018 12:21:44 +0100 Subject: [PATCH 077/155] properties: don't add NULL values NULL values should remove the key. --- src/pipewire/properties.c | 53 ++++++++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 15 deletions(-) diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 627168535..5c493b01d 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -98,7 +98,8 @@ struct pw_properties *pw_properties_new(const char *key, ...) va_start(varargs, key); while (key != NULL) { value = va_arg(varargs, char *); - add_func(&impl->this, strdup(key), value ? strdup(value) : NULL); + if (value) + add_func(&impl->this, strdup(key), strdup(value)); key = va_arg(varargs, char *); } va_end(varargs); @@ -123,9 +124,9 @@ struct pw_properties *pw_properties_new_dict(const struct spa_dict *dict) return NULL; for (i = 0; i < dict->n_items; i++) { - if (dict->items[i].key != NULL) + if (dict->items[i].key != NULL && dict->items[i].value != NULL) add_func(&impl->this, strdup(dict->items[i].key), - dict->items[i].value ? strdup(dict->items[i].value) : NULL); + strdup(dict->items[i].value)); } return &impl->this; @@ -186,7 +187,7 @@ struct pw_properties *pw_properties_copy(const struct pw_properties *properties) return NULL; pw_array_for_each(item, &impl->items) - add_func(copy, strdup(item->key), item->value ? strdup(item->value) : NULL); + add_func(copy, strdup(item->key), strdup(item->value)); return copy; } @@ -241,37 +242,45 @@ void pw_properties_free(struct pw_properties *properties) struct spa_dict_item *item; pw_array_for_each(item, &impl->items) - clear_item(item); + clear_item(item); pw_array_clear(&impl->items); free(impl); } -static int do_replace(struct pw_properties *properties, const char *key, char *value) +static int do_replace(struct pw_properties *properties, const char *key, char *value, bool copy) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); int index = find_index(properties, key); if (index == -1) { - add_func(properties, strdup(key), value); + if (value == NULL) + return 0; + add_func(properties, strdup(key), copy ? strdup(value) : value); } else { struct spa_dict_item *item = pw_array_get_unchecked(&impl->items, index, struct spa_dict_item); - clear_item(item); + if (value && strcmp(item->value, value) == 0) { + if (!copy) + free(value); + return 0; + } + if (value == NULL) { struct spa_dict_item *other = pw_array_get_unchecked(&impl->items, pw_array_get_len(&impl->items, struct spa_dict_item) - 1, struct spa_dict_item); + clear_item(item); item->key = other->key; item->value = other->value; impl->items.size -= sizeof(struct spa_dict_item); } else { - item->key = strdup(key); - item->value = value; + free((char *) item->value); + item->value = copy ? strdup(value) : value; } } - return 0; + return 1; } /** Set a property value @@ -279,6 +288,9 @@ static int do_replace(struct pw_properties *properties, const char *key, char *v * \param properties the properties to change * \param key a key * \param value a value or NULL to remove the key + * \return 1 if the properties were changed. 0 if nothing was changed because + * the property already existed with the same value or because the key to remove + * did not exist. * * Set the property in \a properties with \a key to \a value. Any previous value * of \a key will be overwritten. When \a value is NULL, the key will be @@ -288,7 +300,16 @@ static int do_replace(struct pw_properties *properties, const char *key, char *v */ int pw_properties_set(struct pw_properties *properties, const char *key, const char *value) { - return do_replace(properties, key, value ? strdup(value) : NULL); + return do_replace(properties, key, (char*)value, true); +} + +int +pw_properties_setva(struct pw_properties *properties, + const char *key, const char *format, va_list args) +{ + char *value; + vasprintf(&value, format, args); + return do_replace(properties, key, value, false); } /** Set a property value by format @@ -297,6 +318,8 @@ int pw_properties_set(struct pw_properties *properties, const char *key, const c * \param key a key * \param format a value * \param ... extra arguments + * \return 1 if the properties were changed. 0 if nothing was changed because + * the property already existed with the same value. * * Set the property in \a properties with \a key to the value in printf style \a format * Any previous value of \a key will be overwritten. @@ -305,14 +328,14 @@ int pw_properties_set(struct pw_properties *properties, const char *key, const c */ int pw_properties_setf(struct pw_properties *properties, const char *key, const char *format, ...) { + int res; va_list varargs; - char *value; va_start(varargs, format); - vasprintf(&value, format, varargs); + res = pw_properties_setva(properties, key, format, varargs); va_end(varargs); - return do_replace(properties, key, value); + return res; } /** Get a property From 1f5fec59838bc85ef9d7cb53450f55e66c101fb7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Nov 2018 12:31:51 +0100 Subject: [PATCH 078/155] improve update_properties Make _update_properties return the number of changed properties and only emit info when something changed. --- src/pipewire/client.c | 27 ++++++++++++--------------- src/pipewire/core.c | 11 ++++++++--- src/pipewire/node.c | 12 ++++++++---- src/pipewire/port.c | 12 ++++++++---- 4 files changed, 36 insertions(+), 26 deletions(-) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index e25eb648e..876ac8e40 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -196,7 +196,7 @@ struct pw_client *pw_client_new(struct pw_core *core, pw_core_add_listener(core, &impl->core_listener, &core_events, impl); - this->info.props = this->properties ? &this->properties->dict : NULL; + this->info.props = &this->properties->dict; return this; } @@ -323,8 +323,7 @@ void pw_client_destroy(struct pw_client *client) pw_map_clear(&client->types); pw_array_clear(&impl->permissions); - if (client->properties) - pw_properties_free(client->properties); + pw_properties_free(client->properties); free(impl); } @@ -356,21 +355,19 @@ const struct pw_client_info *pw_client_get_info(struct pw_client *client) int pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict) { struct pw_resource *resource; + uint32_t i, changed = 0; - if (client->properties == NULL) { - if (dict) - client->properties = pw_properties_new_dict(dict); - } else { - uint32_t i; + for (i = 0; i < dict->n_items; i++) + changed += pw_properties_set(client->properties, + dict->items[i].key, dict->items[i].value); - for (i = 0; i < dict->n_items; i++) - pw_properties_set(client->properties, - dict->items[i].key, dict->items[i].value); - } + pw_log_debug("client %p: updated %d properties", client, changed); + + if (!changed) + return 0; client->info.change_mask |= PW_CLIENT_CHANGE_MASK_PROPS; - client->info.props = client->properties ? &client->properties->dict : NULL; - + client->info.props = &client->properties->dict; pw_client_events_info_changed(client, &client->info); spa_list_for_each(resource, &client->resource_list, link) @@ -378,7 +375,7 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict client->info.change_mask = 0; - return 0; + return changed; } struct permissions_update { diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 6134a6ea3..3d989e347 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -557,10 +557,15 @@ const struct pw_properties *pw_core_get_properties(struct pw_core *core) int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) { struct pw_resource *resource; - uint32_t i; + uint32_t i, changed = 0; for (i = 0; i < dict->n_items; i++) - pw_properties_set(core->properties, dict->items[i].key, dict->items[i].value); + changed += pw_properties_set(core->properties, dict->items[i].key, dict->items[i].value); + + pw_log_debug("core %p: updated %d properties", core, changed); + + if (!changed) + return 0; core->info.change_mask = PW_CORE_CHANGE_MASK_PROPS; core->info.props = &core->properties->dict; @@ -572,7 +577,7 @@ int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) core->info.change_mask = 0; - return 0; + return changed; } int pw_core_for_each_global(struct pw_core *core, diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 3523d9cfa..726e30cc3 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -477,15 +477,19 @@ const struct pw_properties *pw_node_get_properties(struct pw_node *node) int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict) { struct pw_resource *resource; - uint32_t i; + uint32_t i, changed = 0; for (i = 0; i < dict->n_items; i++) - pw_properties_set(node->properties, dict->items[i].key, dict->items[i].value); + changed += pw_properties_set(node->properties, dict->items[i].key, dict->items[i].value); + + pw_log_debug("node %p: updated %d properties", node, changed); + + if (!changed) + return 0; check_properties(node); node->info.props = &node->properties->dict; - node->info.change_mask |= PW_NODE_CHANGE_MASK_PROPS; pw_node_events_info_changed(node, &node->info); @@ -494,7 +498,7 @@ int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict) node->info.change_mask = 0; - return 0; + return changed; } static void node_done(void *data, int seq, int res) diff --git a/src/pipewire/port.c b/src/pipewire/port.c index f6ea9b813..c1702660d 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -247,13 +247,17 @@ const struct pw_properties *pw_port_get_properties(struct pw_port *port) int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict) { struct pw_resource *resource; - uint32_t i; + uint32_t i, changed = 0; for (i = 0; i < dict->n_items; i++) - pw_properties_set(port->properties, dict->items[i].key, dict->items[i].value); + changed += pw_properties_set(port->properties, dict->items[i].key, dict->items[i].value); + + pw_log_debug("port %p: updated %d properties", port, changed); + + if (!changed) + return 0; port->info.props = &port->properties->dict; - port->info.change_mask |= PW_PORT_CHANGE_MASK_PROPS; pw_port_events_info_changed(port, &port->info); @@ -262,7 +266,7 @@ int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict) port->info.change_mask = 0; - return 0; + return changed; } struct pw_node *pw_port_get_node(struct pw_port *port) From 6f918561c905baa4fd3d0afd3d271bc60b2b35ea Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 6 Nov 2018 13:28:36 +0100 Subject: [PATCH 079/155] flatpak: also check for client property changes If a client changes the "pipewire.access" property to "flatpak", start handling the client as a flatpak client and do portal checks. This is useful when the portal makes a connection for the client and needs to for portal checks. --- src/modules/module-flatpak.c | 48 +++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index 13f4342c5..189585d4d 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -56,8 +56,10 @@ struct client_info { struct spa_list link; struct impl *impl; struct pw_client *client; + struct spa_hook client_listener; struct spa_list resources; struct spa_list async_pending; + bool checked; bool camera_allowed; }; @@ -128,6 +130,7 @@ static void client_info_free(struct client_info *cinfo) spa_list_for_each_safe(p, tp, &cinfo->async_pending, link) free_pending(p); + spa_hook_remove(&cinfo->client_listener); spa_list_remove(&cinfo->link); free(cinfo); } @@ -279,6 +282,7 @@ portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data) cinfo->camera_allowed = false; pw_log_debug("camera access not allowed"); } + cinfo->checked = true; pw_core_for_each_global(cinfo->impl->core, set_global_permissions, cinfo); free_pending(p); @@ -380,6 +384,32 @@ static void do_portal_check(struct client_info *cinfo) return; } +static void client_info_changed(void *data, struct pw_client_info *info) +{ + struct client_info *cinfo = data; + const char *str; + + if (info->props == NULL) + return; + + if ((str = spa_dict_lookup(info->props, "pipewire.access")) == NULL) + return; + + if (strcmp(str, "flatpak") != 0) + return; + + if (cinfo->checked) + return; + + pw_log_debug("module %p: client %p set to flatpak access", cinfo->impl, cinfo->client); + do_portal_check(cinfo); +} + +static const struct pw_client_events client_events = { + PW_VERSION_CLIENT_EVENTS, + .info_changed = client_info_changed +}; + static void core_global_added(void *data, struct pw_global *global) { @@ -390,6 +420,15 @@ core_global_added(void *data, struct pw_global *global) if (pw_global_get_type(global) == impl->type->client) { struct pw_client *client = pw_global_get_object(global); + /* clients are placed in a list and we do a portal check when needed */ + cinfo = calloc(1, sizeof(struct client_info)); + cinfo->impl = impl; + cinfo->client = client; + spa_list_init(&cinfo->async_pending); + pw_client_add_listener(client, &cinfo->client_listener, &client_events, cinfo); + + spa_list_append(&impl->client_list, &cinfo->link); + res = check_sandboxed(client); if (res == 0) { pw_log_debug("module %p: non sandboxed client %p", impl, client); @@ -404,15 +443,6 @@ core_global_added(void *data, struct pw_global *global) pw_log_debug("module %p: sandboxed client %p added", impl, client); } - /* sandboxed clients are placed in a list and we do a portal check */ - cinfo = calloc(1, sizeof(struct client_info)); - cinfo->impl = impl; - cinfo->client = client; - - spa_list_init(&cinfo->async_pending); - - spa_list_append(&impl->client_list, &cinfo->link); - do_portal_check(cinfo); } else { From 1ea84b2869d5506851ee4f52c98e16d14333b46d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 12 Nov 2018 10:50:21 +0100 Subject: [PATCH 080/155] spa: explicitly cast the offset to signed int As reported by Marcello Blancasio, convert the offset to a signed int to avoid conversion without sign extension. Fixes unmap of stream memory. Fixes #103 --- spa/include/spa/utils/defs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index e0ad462c8..f955478b7 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -86,7 +86,7 @@ struct spa_fraction { _v > _high ? _high : ( _v < _low ? _low : _v); \ }) -#define SPA_MEMBER(b,o,t) ((t*)((uint8_t*)(b) + (o))) +#define SPA_MEMBER(b,o,t) ((t*)((uint8_t*)(b) + (int)(o))) #define SPA_CONTAINER_OF(p,t,m) (t*)((uint8_t*)p - offsetof (t,m)) From 16b6a51b789b9d714418087f0797d29fb7b86c60 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Nov 2018 10:18:50 +0100 Subject: [PATCH 081/155] examples: add video crop example Add support for video crop metadata in video-play and draw only the cropped areas. Add support for video crop in video-src and make it generate cropping regions that grow and shrink dynamically. --- src/examples/meson.build | 2 +- src/examples/video-play.c | 28 +++++++++++++++++++++++++--- src/examples/video-src.c | 33 +++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 8 deletions(-) diff --git a/src/examples/meson.build b/src/examples/meson.build index 4890f68ee..37b3d4ff8 100644 --- a/src/examples/meson.build +++ b/src/examples/meson.build @@ -1,7 +1,7 @@ executable('video-src', 'video-src.c', install: false, - dependencies : [pipewire_dep], + dependencies : [pipewire_dep, mathlib], ) executable('export-source', 'export-source.c', diff --git a/src/examples/video-play.c b/src/examples/video-play.c index b259a86b6..287c2c4d8 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -73,6 +73,7 @@ struct data { int32_t stride; int counter; + SDL_Rect rect; }; static void handle_events(struct data *data) @@ -96,6 +97,7 @@ on_stream_process(void *_data) struct spa_buffer *b; void *sdata, *ddata; int sstride, dstride, ostride; + struct spa_meta_video_crop *mc; uint32_t i; uint8_t *src, *dst; @@ -114,6 +116,17 @@ on_stream_process(void *_data) fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); goto done; } + if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) { + if (data->rect.x != mc->x || + data->rect.y != mc->y || + data->rect.w != mc->width || + data->rect.h != mc->height) { + data->rect.x = mc->x; + data->rect.y = mc->y; + data->rect.w = mc->width; + data->rect.h = mc->height; + } + } sstride = b->datas[0].chunk->stride; ostride = SPA_MIN(sstride, dstride); @@ -127,7 +140,7 @@ on_stream_process(void *_data) SDL_UnlockTexture(data->texture); SDL_RenderClear(data->renderer); - SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); + SDL_RenderCopy(data->renderer, data->texture, &data->rect, NULL); SDL_RenderPresent(data->renderer); done: @@ -226,7 +239,7 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - const struct spa_pod *params[2]; + const struct spa_pod *params[3]; Uint32 sdl_format; void *d; @@ -254,6 +267,11 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) SDL_LockTexture(data->texture, NULL, &d, &data->stride); SDL_UnlockTexture(data->texture); + data->rect.x = 0; + data->rect.y = 0; + data->rect.w = data->format.size.width; + data->rect.h = data->format.size.height; + params[0] = spa_pod_builder_object(&b, t->param.idBuffers, t->param_buffers.Buffers, ":", t->param_buffers.size, "i", data->stride * data->format.size.height, @@ -266,8 +284,12 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.Header, ":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); + params[2] = spa_pod_builder_object(&b, + t->param.idMeta, t->param_meta.Meta, + ":", t->param_meta.type, "I", t->meta.VideoCrop, + ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); - pw_stream_finish_format(stream, 0, params, 2); + pw_stream_finish_format(stream, 0, params, 3); } static const struct pw_stream_events stream_events = { diff --git a/src/examples/video-src.c b/src/examples/video-src.c index 5960bd889..db508a596 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -44,7 +45,12 @@ static inline void init_type(struct type *type, struct spa_type_map *map) spa_type_video_format_map(map, &type->video_format); } -#define BPP 3 +#define BPP 3 +#define WIDTH 320 +#define HEIGHT 200 +#define CROP 8 + +#define M_PI_M2 ( M_PI + M_PI ) struct data { struct type type; @@ -65,6 +71,8 @@ struct data { int counter; uint32_t seq; + double crop; + double accumulator; }; static void on_timeout(void *userdata, uint64_t expirations) @@ -73,6 +81,7 @@ static void on_timeout(void *userdata, uint64_t expirations) int i, j; uint8_t *p; struct spa_meta_header *h; + struct spa_meta_video_crop *mc; struct pw_buffer *buf; struct spa_buffer *b; @@ -97,6 +106,18 @@ static void on_timeout(void *userdata, uint64_t expirations) h->seq = data->seq++; h->dts_offset = 0; } + if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) { + mc->x = data->crop; + mc->y = data->crop; + mc->width = WIDTH - data->crop*2; + mc->height = HEIGHT - data->crop*2; + + data->accumulator += M_PI_M2 / 50.0; + if (data->accumulator >= M_PI_M2) + data->accumulator -= M_PI_M2; + + data->crop = (sin(data->accumulator) + 1.0) * 32.0; + } for (i = 0; i < data->format.size.height; i++) { for (j = 0; j < data->format.size.width * BPP; j++) { @@ -148,7 +169,7 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - const struct spa_pod *params[2]; + const struct spa_pod *params[3]; if (format == NULL) { pw_stream_finish_format(stream, 0, NULL, 0); @@ -170,8 +191,12 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.Header, ":", t->param_meta.size, "i", sizeof(struct spa_meta_header)); + params[2] = spa_pod_builder_object(&b, + t->param.idMeta, t->param_meta.Meta, + ":", t->param_meta.type, "I", t->meta.VideoCrop, + ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); - pw_stream_finish_format(stream, 0, params, 2); + pw_stream_finish_format(stream, 0, params, 3); } static const struct pw_stream_events stream_events = { @@ -214,7 +239,7 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo "I", data->type.media_type.video, "I", data->type.media_subtype.raw, ":", data->type.format_video.format, "I", data->type.video_format.RGB, - ":", data->type.format_video.size, "Rru", &SPA_RECTANGLE(320, 240), + ":", data->type.format_video.size, "Rru", &SPA_RECTANGLE(WIDTH, HEIGHT), SPA_POD_PROP_MIN_MAX(&SPA_RECTANGLE(1, 1), &SPA_RECTANGLE(4096, 4096)), ":", data->type.format_video.framerate, "F", &SPA_FRACTION(25, 1)); From 49afacd66fef5eb7824745d0d8a5dafeda62feec Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Nov 2018 10:54:57 +0100 Subject: [PATCH 082/155] v4l2: fix crash when unplugging Only remove the v4l2 fd once on disconnect Make sure we don't use the clock anymore when a link is destroyed. --- spa/plugins/v4l2/v4l2-utils.c | 6 ++++-- src/pipewire/link.c | 3 +++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 56e2c9bb9..34bb2bcda 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -1194,7 +1194,8 @@ static void v4l2_on_fd_events(struct spa_source *source) if (source->rmask & SPA_IO_ERR) { struct port *port = &this->out_ports[0]; spa_log_error(this->log, "v4l2 %p: error %d", this, source->rmask); - spa_loop_remove_source(port->data_loop, &port->source); + if (port->source.loop) + spa_loop_remove_source(port->data_loop, &port->source); return; } @@ -1470,7 +1471,8 @@ static int do_remove_source(struct spa_loop *loop, void *user_data) { struct port *port = user_data; - spa_loop_remove_source(port->data_loop, &port->source); + if (port->source.loop) + spa_loop_remove_source(port->data_loop, &port->source); return 0; } diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 0fc89f90d..8a4dbeaf8 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1288,6 +1288,9 @@ void pw_link_destroy(struct pw_link *link) if (link->registered) spa_list_remove(&link->link); + if (link->output->node->clock == link->input->node->clock) + link->input->node->clock = NULL; + input_remove(link, link->input); output_remove(link, link->output); From 14ebb85e7482c5b7963d2e647608464f5cd148bb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 22 Nov 2018 11:21:50 +0100 Subject: [PATCH 083/155] Release 0.2.4 --- NEWS | 22 ++++++++-------------- meson.build | 2 +- 2 files changed, 9 insertions(+), 15 deletions(-) diff --git a/NEWS b/NEWS index 0c4d06f10..e426bd420 100644 --- a/NEWS +++ b/NEWS @@ -1,16 +1,10 @@ -PipeWire 0.2.3 +PipeWire 0.2.4 -- Fix deviceprovider caps introspection -- Refcounting fixes in pipewiresrc -- Remove clock interpolation from stream -- Improve clock in gstreamer elements -- Remove spalib -- Fix crash with pw_map -- Add version number to hook list -- Improve driver mode in gstreamer elements -- add daemon options -- add man pages +- Install man pages in right directory +- Add systemd socket activation +- Various memory leak and corruption fixes in properties, dbus and + buffer mmaped memory. +- Fix v4l2 crash on unplug +- improve stream cleanup -Work is ongoing in the work branch that features a completely new -scheduling method that will enable audio support. Some of these -API changes are backported in this branch. +This is mostly a bugfix release. diff --git a/meson.build b/meson.build index 2d0bf91cb..06c435f0d 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.3', + version : '0.2.4', meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 57ba8108f12a1acd894ab5664c7230b85015356b Mon Sep 17 00:00:00 2001 From: maxice8 Date: Thu, 22 Nov 2018 17:36:59 -0200 Subject: [PATCH 084/155] meson: Fix configure when systemd option is set to false Otherwise it fails with systemd variable not found. --- src/daemon/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/meson.build b/src/daemon/meson.build index fb694e7cc..f2a327fb8 100644 --- a/src/daemon/meson.build +++ b/src/daemon/meson.build @@ -29,6 +29,6 @@ executable('pipewire', dependencies : [pipewire_dep], ) -if systemd.found() +if get_option('systemd') and systemd.found() subdir('systemd') endif From 5dcaa450fff24c36102ed20b791403da012a25fb Mon Sep 17 00:00:00 2001 From: maxice8 Date: Thu, 22 Nov 2018 18:07:53 -0200 Subject: [PATCH 085/155] meson: don't add systemd_dep to dependencies if systemd option is false. --- src/modules/meson.build | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/modules/meson.build b/src/modules/meson.build index 4dcb6e59c..619ca2ec0 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -71,6 +71,12 @@ pipewire_module_link_factory = shared_library('pipewire-module-link-factory', # dependencies : [glib_dep, gio_dep, mathlib, dl_lib, pipewire_dep], #) +pipewire_module_protocol_native_deps = [mathlib, dl_lib, pipewire_dep] + +if get_option('systemd') + pipewire_module_protocol_native_deps += systemd_dep +endif + pipewire_module_protocol_native = shared_library('pipewire-module-protocol-native', [ 'module-protocol-native.c', 'module-protocol-native/local-socket.c', @@ -81,7 +87,7 @@ pipewire_module_protocol_native = shared_library('pipewire-module-protocol-nativ include_directories : [configinc, spa_inc], install : true, install_dir : modules_install_dir, - dependencies : [mathlib, dl_lib, pipewire_dep, systemd_dep], + dependencies : pipewire_module_protocol_native_deps, ) pipewire_module_audio_dsp = shared_library('pipewire-module-audio-dsp', From 67a0b33dc89075da9834abcb73bd57c59330a965 Mon Sep 17 00:00:00 2001 From: maxice8 Date: Thu, 22 Nov 2018 19:16:24 -0200 Subject: [PATCH 086/155] module-rtkit: define RLIMIT_RTTIME in case it isn't defined. musl libc doesn't define RLIMIT_RTTIME --- src/modules/module-rtkit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/modules/module-rtkit.c b/src/modules/module-rtkit.c index b83db9c42..3670cdeb1 100644 --- a/src/modules/module-rtkit.c +++ b/src/modules/module-rtkit.c @@ -95,6 +95,10 @@ struct impl { #define RTKIT_SERVICE_NAME "org.freedesktop.RealtimeKit1" #define RTKIT_OBJECT_PATH "/org/freedesktop/RealtimeKit1" +#ifndef RLIMIT_RTTIME +#define RLIMIT_RTTIME 15 +#endif + /** \cond */ struct pw_rtkit_bus { DBusConnection *bus; From cd53eca92ba4ba0a763ad3ee555faf0345ff59b0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2018 11:07:45 +0100 Subject: [PATCH 087/155] meta: add cursor metadata and examples Add a moving and flashing circle cursor to video-src Render the cursor in video-play --- spa/include/spa/buffer/meta.h | 23 ++++++++++++++ src/examples/video-play.c | 57 +++++++++++++++++++++++++++++++++-- src/examples/video-src.c | 50 ++++++++++++++++++++++++++---- 3 files changed, 122 insertions(+), 8 deletions(-) diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index fcd879551..e45d176b3 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -36,6 +36,7 @@ extern "C" { #define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header" #define SPA_TYPE_META__VideoCrop SPA_TYPE_META_BASE "VideoCrop" +#define SPA_TYPE_META__Cursor SPA_TYPE_META_BASE "Cursor" /** * A metadata element. @@ -84,6 +85,28 @@ struct spa_meta_control { uint32_t offset; /**< offset in buffer memory */ }; +/** + * Bitmap information + */ +struct spa_meta_bitmap { + uint32_t format; /**< bitmap video format */ + uint32_t width, height; /**< width and height of bitmap */ + uint32_t stride; /**< stride of bitmap data */ + uint32_t size; /**< size of bitmap data */ + uint32_t offset; /**< offset of bitmap data in this structure */ +}; + +/** + * Cursor information + */ +struct spa_meta_cursor { + uint32_t id; /**< cursor id */ + int32_t x, y; /**< offsets on screen */ + int32_t hotspot_x, hotspot_y; /**< offsets for hotspot in bitmap */ + uint32_t bitmap_offset; /**< offset of bitmap meta in this structure */ +}; + + struct spa_type_meta { uint32_t Header; uint32_t VideoCrop; diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 287c2c4d8..6c9496cef 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -36,6 +36,7 @@ struct type { struct spa_type_media_subtype media_subtype; struct spa_type_format_video format_video; struct spa_type_video_format video_format; + uint32_t meta_cursor; }; static inline void init_type(struct type *type, struct spa_type_map *map) @@ -44,6 +45,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map) spa_type_media_subtype_map(map, &type->media_subtype); spa_type_format_video_map(map, &type->format_video); spa_type_video_format_map(map, &type->video_format); + type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); } #define WIDTH 640 @@ -58,6 +60,7 @@ struct data { SDL_Renderer *renderer; SDL_Window *window; SDL_Texture *texture; + SDL_Texture *cursor; struct pw_main_loop *loop; @@ -74,6 +77,7 @@ struct data { int counter; SDL_Rect rect; + SDL_Rect cursor_rect; }; static void handle_events(struct data *data) @@ -98,8 +102,10 @@ on_stream_process(void *_data) void *sdata, *ddata; int sstride, dstride, ostride; struct spa_meta_video_crop *mc; + struct spa_meta_cursor *mcs; uint32_t i; uint8_t *src, *dst; + bool render_cursor = false; handle_events(data); @@ -127,6 +133,37 @@ on_stream_process(void *_data) data->rect.h = mc->height; } } + if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor))) { + struct spa_meta_bitmap *mb; + void *cdata; + int cstride; + + data->cursor_rect.x = mcs->x; + data->cursor_rect.y = mcs->y; + + mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap); + data->cursor_rect.w = mb->width; + data->cursor_rect.h = mb->height; + + if (SDL_LockTexture(data->cursor, NULL, &cdata, &cstride) < 0) { + fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError()); + goto done; + } + + src = SPA_MEMBER(mb, mb->offset, uint8_t); + dst = cdata; + ostride = SPA_MIN(cstride, mb->stride); + + for (i = 0; i < mb->height; i++) { + memcpy(dst, src, ostride); + dst += cstride; + src += mb->stride; + } + SDL_UnlockTexture(data->cursor); + + render_cursor = true; + } + sstride = b->datas[0].chunk->stride; ostride = SPA_MIN(sstride, dstride); @@ -141,6 +178,9 @@ on_stream_process(void *_data) SDL_RenderClear(data->renderer); SDL_RenderCopy(data->renderer, data->texture, &data->rect, NULL); + if (render_cursor) { + SDL_RenderCopy(data->renderer, data->cursor, NULL, &data->cursor_rect); + } SDL_RenderPresent(data->renderer); done: @@ -239,7 +279,7 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - const struct spa_pod *params[3]; + const struct spa_pod *params[4]; Uint32 sdl_format; void *d; @@ -267,6 +307,12 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) SDL_LockTexture(data->texture, NULL, &d, &data->stride); SDL_UnlockTexture(data->texture); + data->cursor = SDL_CreateTexture(data->renderer, + SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, + 64, 64); + SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); + data->rect.x = 0; data->rect.y = 0; data->rect.w = data->format.size.width; @@ -288,8 +334,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.VideoCrop, ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); + params[3] = spa_pod_builder_object(&b, + t->param.idMeta, t->param_meta.Meta, + ":", t->param_meta.type, "I", data->type.meta_cursor, + ":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) + + sizeof(struct spa_meta_bitmap) + + 64 * 64 * 4); - pw_stream_finish_format(stream, 0, params, 3); + pw_stream_finish_format(stream, 0, params, 4); } static const struct pw_stream_events stream_events = { @@ -472,6 +524,7 @@ int main(int argc, char *argv[]) pw_main_loop_destroy(data.loop); SDL_DestroyTexture(data.texture); + SDL_DestroyTexture(data.cursor); SDL_DestroyRenderer(data.renderer); SDL_DestroyWindow(data.window); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index db508a596..dda359cdb 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -35,6 +35,7 @@ struct type { struct spa_type_media_subtype media_subtype; struct spa_type_format_video format_video; struct spa_type_video_format video_format; + uint32_t meta_cursor; }; static inline void init_type(struct type *type, struct spa_type_map *map) @@ -43,6 +44,7 @@ static inline void init_type(struct type *type, struct spa_type_map *map) spa_type_media_subtype_map(map, &type->media_subtype); spa_type_format_video_map(map, &type->format_video); spa_type_video_format_map(map, &type->video_format); + type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); } #define BPP 3 @@ -82,6 +84,7 @@ static void on_timeout(void *userdata, uint64_t expirations) uint8_t *p; struct spa_meta_header *h; struct spa_meta_video_crop *mc; + struct spa_meta_cursor *mcs; struct pw_buffer *buf; struct spa_buffer *b; @@ -107,16 +110,41 @@ static void on_timeout(void *userdata, uint64_t expirations) h->dts_offset = 0; } if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) { + data->crop = (sin(data->accumulator) + 1.0) * 32.0; mc->x = data->crop; mc->y = data->crop; mc->width = WIDTH - data->crop*2; mc->height = HEIGHT - data->crop*2; + } + if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor))) { + struct spa_meta_bitmap *mb; + uint32_t *bitmap, color; - data->accumulator += M_PI_M2 / 50.0; - if (data->accumulator >= M_PI_M2) - data->accumulator -= M_PI_M2; + mcs->id = 0; + mcs->x = (sin(data->accumulator) + 1.0) * 160.0 + 80; + mcs->y = (cos(data->accumulator) + 1.0) * 100.0 + 50; + mcs->hotspot_x = 0; + mcs->hotspot_y = 0; + mcs->bitmap_offset = sizeof(struct spa_meta_cursor); - data->crop = (sin(data->accumulator) + 1.0) * 32.0; + mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap); + mb->format = data->type.video_format.ARGB; + mb->width = 64; + mb->height = 64; + mb->stride = 64 * 4; + mb->size = mb->stride * mb->height; + mb->offset = sizeof(struct spa_meta_bitmap); + + bitmap = SPA_MEMBER(mb, mb->offset, uint32_t); + color = (cos(data->accumulator) + 1.0) * (1 << 23); + color |= 0xff000000; + + for (i = 0; i < mb->height; i++) { + for (j = 0; j < mb->width; j++) { + int v = (i - 32) * (i - 32) + (j - 32) * (j - 32); + bitmap[i*64+j] = (v <= 32*32) ? color : 0x00000000; + } + } } for (i = 0; i < data->format.size.height; i++) { @@ -127,6 +155,10 @@ static void on_timeout(void *userdata, uint64_t expirations) data->counter += 13; } + data->accumulator += M_PI_M2 / 50.0; + if (data->accumulator >= M_PI_M2) + data->accumulator -= M_PI_M2; + b->datas[0].chunk->size = b->datas[0].maxsize; done: @@ -169,7 +201,7 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) struct pw_type *t = data->t; uint8_t params_buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); - const struct spa_pod *params[3]; + const struct spa_pod *params[4]; if (format == NULL) { pw_stream_finish_format(stream, 0, NULL, 0); @@ -195,8 +227,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.VideoCrop, ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); + params[3] = spa_pod_builder_object(&b, + t->param.idMeta, t->param_meta.Meta, + ":", t->param_meta.type, "I", data->type.meta_cursor, + ":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) + + sizeof(struct spa_meta_bitmap) + + 64 * 64 * 4); - pw_stream_finish_format(stream, 0, params, 3); + pw_stream_finish_format(stream, 0, params, 4); } static const struct pw_stream_events stream_events = { From 218fd081dfee14f2d168cc62ccf46b925141aff4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2018 12:08:53 +0100 Subject: [PATCH 088/155] meta: define invalid cursor metadata --- spa/include/spa/buffer/meta.h | 2 +- src/examples/video-play.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index e45d176b3..b58fc11dd 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -100,7 +100,7 @@ struct spa_meta_bitmap { * Cursor information */ struct spa_meta_cursor { - uint32_t id; /**< cursor id */ + uint32_t id; /**< cursor id, SPA_ID_INVALID for no cursor */ int32_t x, y; /**< offsets on screen */ int32_t hotspot_x, hotspot_y; /**< offsets for hotspot in bitmap */ uint32_t bitmap_offset; /**< offset of bitmap meta in this structure */ diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 6c9496cef..32784fc75 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -133,7 +133,8 @@ on_stream_process(void *_data) data->rect.h = mc->height; } } - if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor))) { + if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor)) && + mcs->id != SPA_ID_INVALID) { struct spa_meta_bitmap *mb; void *cdata; int cstride; From 8205486554f949c509519eccc90126ed921ea991 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2018 12:09:31 +0100 Subject: [PATCH 089/155] video-play: handle arbitrary cursor sizes video-play: only allocate the texture when we know the size and format of the cursor bitmap. video-src: make cursor size defined with constants. --- src/examples/video-play.c | 28 +++++++++++++++++---------- src/examples/video-src.c | 40 +++++++++++++++++++++++++++------------ 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 32784fc75..a18c13485 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -80,6 +80,8 @@ struct data { SDL_Rect cursor_rect; }; +static Uint32 id_to_sdl_format(struct data *data, uint32_t id); + static void handle_events(struct data *data) { SDL_Event event; @@ -146,6 +148,15 @@ on_stream_process(void *_data) data->cursor_rect.w = mb->width; data->cursor_rect.h = mb->height; + if (data->cursor == NULL) { + data->cursor = SDL_CreateTexture(data->renderer, + id_to_sdl_format(data, mb->format), + SDL_TEXTUREACCESS_STREAMING, + mb->width, mb->height); + SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); + } + + if (SDL_LockTexture(data->cursor, NULL, &cdata, &cstride) < 0) { fprintf(stderr, "Couldn't lock cursor texture: %s\n", SDL_GetError()); goto done; @@ -308,12 +319,6 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) SDL_LockTexture(data->texture, NULL, &d, &data->stride); SDL_UnlockTexture(data->texture); - data->cursor = SDL_CreateTexture(data->renderer, - SDL_PIXELFORMAT_ARGB8888, - SDL_TEXTUREACCESS_STREAMING, - 64, 64); - SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); - data->rect.x = 0; data->rect.y = 0; data->rect.w = data->format.size.width; @@ -335,12 +340,14 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.VideoCrop, ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); +#define CURSOR_META_SIZE(w,h) (sizeof(struct spa_meta_cursor) + \ + sizeof(struct spa_meta_bitmap) + w * h * 4) params[3] = spa_pod_builder_object(&b, t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", data->type.meta_cursor, - ":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) + - sizeof(struct spa_meta_bitmap) + - 64 * 64 * 4); + ":", t->param_meta.size, "iru", CURSOR_META_SIZE(64,64), + SPA_POD_PROP_MIN_MAX(CURSOR_META_SIZE(1,1), + CURSOR_META_SIZE(256,256))); pw_stream_finish_format(stream, 0, params, 4); } @@ -525,7 +532,8 @@ int main(int argc, char *argv[]) pw_main_loop_destroy(data.loop); SDL_DestroyTexture(data.texture); - SDL_DestroyTexture(data.cursor); + if (data.cursor) + SDL_DestroyTexture(data.cursor); SDL_DestroyRenderer(data.renderer); SDL_DestroyWindow(data.window); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index dda359cdb..239631987 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -51,6 +51,9 @@ static inline void init_type(struct type *type, struct spa_type_map *map) #define WIDTH 320 #define HEIGHT 200 #define CROP 8 +#define CURSOR_WIDTH 64 +#define CURSOR_HEIGHT 64 +#define CURSOR_BPP 4 #define M_PI_M2 ( M_PI + M_PI ) @@ -77,6 +80,24 @@ struct data { double accumulator; }; +static void draw_elipse(uint32_t *dst, int width, int height, uint32_t color) +{ + int i, j, r1, r2, r12, r22, r122; + + r1 = width/2; + r12 = r1 * r1; + r2 = height/2; + r22 = r2 * r2; + r122 = r12 * r22; + + for (i = -r2; i < r2; i++) { + for (j = -r1; j < r1; j++) { + dst[(i + r2)*width+(j+r1)] = + (i * i * r12 + j * j * r22 <= r122) ? color : 0x00000000; + } + } +} + static void on_timeout(void *userdata, uint64_t expirations) { struct data *data = userdata; @@ -129,9 +150,9 @@ static void on_timeout(void *userdata, uint64_t expirations) mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap); mb->format = data->type.video_format.ARGB; - mb->width = 64; - mb->height = 64; - mb->stride = 64 * 4; + mb->width = CURSOR_WIDTH; + mb->height = CURSOR_HEIGHT; + mb->stride = CURSOR_WIDTH * CURSOR_BPP; mb->size = mb->stride * mb->height; mb->offset = sizeof(struct spa_meta_bitmap); @@ -139,12 +160,7 @@ static void on_timeout(void *userdata, uint64_t expirations) color = (cos(data->accumulator) + 1.0) * (1 << 23); color |= 0xff000000; - for (i = 0; i < mb->height; i++) { - for (j = 0; j < mb->width; j++) { - int v = (i - 32) * (i - 32) + (j - 32) * (j - 32); - bitmap[i*64+j] = (v <= 32*32) ? color : 0x00000000; - } - } + draw_elipse(bitmap, mb->width, mb->height, color); } for (i = 0; i < data->format.size.height; i++) { @@ -227,12 +243,12 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", t->meta.VideoCrop, ":", t->param_meta.size, "i", sizeof(struct spa_meta_video_crop)); +#define CURSOR_META_SIZE(w,h) (sizeof(struct spa_meta_cursor) + \ + sizeof(struct spa_meta_bitmap) + w * h * CURSOR_BPP) params[3] = spa_pod_builder_object(&b, t->param.idMeta, t->param_meta.Meta, ":", t->param_meta.type, "I", data->type.meta_cursor, - ":", t->param_meta.size, "i", sizeof(struct spa_meta_cursor) + - sizeof(struct spa_meta_bitmap) + - 64 * 64 * 4); + ":", t->param_meta.size, "i", CURSOR_META_SIZE(CURSOR_WIDTH,CURSOR_HEIGHT)); pw_stream_finish_format(stream, 0, params, 4); } From 39078f2abcec18a8906e31b1caa969b15d2ddb74 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Nov 2018 15:49:58 +0100 Subject: [PATCH 090/155] meta: use spa_point and spa_rectangle Change Cursor and Bitmap to what the work branch uses --- spa/include/spa/buffer/meta.h | 19 ++++++++++++------- spa/include/spa/utils/defs.h | 13 ++++++++++++- src/examples/video-play.c | 27 +++++++++++---------------- src/examples/video-src.c | 15 +++++++-------- 4 files changed, 42 insertions(+), 32 deletions(-) diff --git a/spa/include/spa/buffer/meta.h b/spa/include/spa/buffer/meta.h index b58fc11dd..553448dfe 100644 --- a/spa/include/spa/buffer/meta.h +++ b/spa/include/spa/buffer/meta.h @@ -36,6 +36,7 @@ extern "C" { #define SPA_TYPE_META__Header SPA_TYPE_META_BASE "Header" #define SPA_TYPE_META__VideoCrop SPA_TYPE_META_BASE "VideoCrop" +#define SPA_TYPE_META__Bitmap SPA_TYPE_META_BASE "Bitmap" #define SPA_TYPE_META__Cursor SPA_TYPE_META_BASE "Cursor" /** @@ -85,24 +86,28 @@ struct spa_meta_control { uint32_t offset; /**< offset in buffer memory */ }; +#define spa_meta_bitmap_is_valid(m) ((m)->format != 0) + /** * Bitmap information */ struct spa_meta_bitmap { - uint32_t format; /**< bitmap video format */ - uint32_t width, height; /**< width and height of bitmap */ - uint32_t stride; /**< stride of bitmap data */ - uint32_t size; /**< size of bitmap data */ + uint32_t format; /**< bitmap video format, 0 invalid */ + struct spa_rectangle size; /**< width and height of bitmap */ + int32_t stride; /**< stride of bitmap data */ uint32_t offset; /**< offset of bitmap data in this structure */ }; +#define spa_meta_cursor_is_valid(m) ((m)->id != 0) + /** * Cursor information */ struct spa_meta_cursor { - uint32_t id; /**< cursor id, SPA_ID_INVALID for no cursor */ - int32_t x, y; /**< offsets on screen */ - int32_t hotspot_x, hotspot_y; /**< offsets for hotspot in bitmap */ + uint32_t id; /**< cursor id, 0 for no cursor */ + uint32_t flags; /**< extra flags */ + struct spa_point position; /**< position on screen */ + struct spa_point hotspot; /**< offsets for hotspot in bitmap */ uint32_t bitmap_offset; /**< offset of bitmap meta in this structure */ }; diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index f955478b7..69454cf4b 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -52,12 +52,23 @@ enum spa_direction { }; #define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height } - struct spa_rectangle { uint32_t width; uint32_t height; }; +#define SPA_POINT(x,y) (struct spa_point){ x, y } +struct spa_point { + int32_t x; + int32_t y; +}; + +#define SPA_REGION(x,y,width,height) (struct spa_region){ SPA_POINT(x,y), SPA_RECTANGLE(width,height) } +struct spa_region { + struct spa_point position; + struct spa_rectangle size; +}; + #define SPA_FRACTION(num,denom) (struct spa_fraction){ num, denom } struct spa_fraction { uint32_t num; diff --git a/src/examples/video-play.c b/src/examples/video-play.c index a18c13485..7ba9034ee 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -125,34 +125,29 @@ on_stream_process(void *_data) goto done; } if ((mc = spa_buffer_find_meta(b, data->t->meta.VideoCrop))) { - if (data->rect.x != mc->x || - data->rect.y != mc->y || - data->rect.w != mc->width || - data->rect.h != mc->height) { - data->rect.x = mc->x; - data->rect.y = mc->y; - data->rect.w = mc->width; - data->rect.h = mc->height; - } + data->rect.x = mc->x; + data->rect.y = mc->y; + data->rect.w = mc->width; + data->rect.h = mc->height; } if ((mcs = spa_buffer_find_meta(b, data->type.meta_cursor)) && - mcs->id != SPA_ID_INVALID) { + spa_meta_cursor_is_valid(mcs)) { struct spa_meta_bitmap *mb; void *cdata; int cstride; - data->cursor_rect.x = mcs->x; - data->cursor_rect.y = mcs->y; + data->cursor_rect.x = mcs->position.x; + data->cursor_rect.y = mcs->position.y; mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap); - data->cursor_rect.w = mb->width; - data->cursor_rect.h = mb->height; + data->cursor_rect.w = mb->size.width; + data->cursor_rect.h = mb->size.height; if (data->cursor == NULL) { data->cursor = SDL_CreateTexture(data->renderer, id_to_sdl_format(data, mb->format), SDL_TEXTUREACCESS_STREAMING, - mb->width, mb->height); + mb->size.width, mb->size.height); SDL_SetTextureBlendMode(data->cursor, SDL_BLENDMODE_BLEND); } @@ -166,7 +161,7 @@ on_stream_process(void *_data) dst = cdata; ostride = SPA_MIN(cstride, mb->stride); - for (i = 0; i < mb->height; i++) { + for (i = 0; i < mb->size.height; i++) { memcpy(dst, src, ostride); dst += cstride; src += mb->stride; diff --git a/src/examples/video-src.c b/src/examples/video-src.c index 239631987..d756ba0e0 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -142,25 +142,24 @@ static void on_timeout(void *userdata, uint64_t expirations) uint32_t *bitmap, color; mcs->id = 0; - mcs->x = (sin(data->accumulator) + 1.0) * 160.0 + 80; - mcs->y = (cos(data->accumulator) + 1.0) * 100.0 + 50; - mcs->hotspot_x = 0; - mcs->hotspot_y = 0; + mcs->position.x = (sin(data->accumulator) + 1.0) * 160.0 + 80; + mcs->position.y = (cos(data->accumulator) + 1.0) * 100.0 + 50; + mcs->hotspot.x = 0; + mcs->hotspot.y = 0; mcs->bitmap_offset = sizeof(struct spa_meta_cursor); mb = SPA_MEMBER(mcs, mcs->bitmap_offset, struct spa_meta_bitmap); mb->format = data->type.video_format.ARGB; - mb->width = CURSOR_WIDTH; - mb->height = CURSOR_HEIGHT; + mb->size.width = CURSOR_WIDTH; + mb->size.height = CURSOR_HEIGHT; mb->stride = CURSOR_WIDTH * CURSOR_BPP; - mb->size = mb->stride * mb->height; mb->offset = sizeof(struct spa_meta_bitmap); bitmap = SPA_MEMBER(mb, mb->offset, uint32_t); color = (cos(data->accumulator) + 1.0) * (1 << 23); color |= 0xff000000; - draw_elipse(bitmap, mb->width, mb->height, color); + draw_elipse(bitmap, mb->size.width, mb->size.height, color); } for (i = 0; i < data->format.size.height; i++) { From 73aac68908c2c9f1dda2aab20bc4044fb0367782 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 12 Dec 2018 15:47:01 +0100 Subject: [PATCH 091/155] flatpak: only update permissions on sandboxed clients --- src/modules/module-flatpak.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index 189585d4d..ab32a2277 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -61,6 +61,7 @@ struct client_info { struct spa_list async_pending; bool checked; bool camera_allowed; + bool sandboxed; }; struct async_pending { @@ -434,6 +435,7 @@ core_global_added(void *data, struct pw_global *global) pw_log_debug("module %p: non sandboxed client %p", impl, client); return; } + cinfo->sandboxed = true; if (res < 0) { pw_log_warn("module %p: client %p sandbox check failed: %s", @@ -446,8 +448,10 @@ core_global_added(void *data, struct pw_global *global) do_portal_check(cinfo); } else { - spa_list_for_each(cinfo, &impl->client_list, link) - set_global_permissions(cinfo, global); + spa_list_for_each(cinfo, &impl->client_list, link) { + if (cinfo->sandboxed) + set_global_permissions(cinfo, global); + } } } From 053e01177d4d728f5c346839a6dd1c566d790712 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 24 Sep 2018 11:35:46 +0200 Subject: [PATCH 092/155] loop: use simple hook emission Add new simple hook emision without a cursor. The one with the cursor is not thread safe and is not needed for the loop. Fixes #110 --- spa/include/spa/support/loop.h | 4 ++-- spa/include/spa/utils/hook.h | 12 ++++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/spa/include/spa/support/loop.h b/spa/include/spa/support/loop.h index d6fa85b26..b08c9d2e7 100644 --- a/spa/include/spa/support/loop.h +++ b/spa/include/spa/support/loop.h @@ -111,8 +111,8 @@ struct spa_loop_control_hooks { void (*after) (void *data); }; -#define spa_loop_control_hook_before(l) spa_hook_list_call(l, struct spa_loop_control_hooks, before, 0) -#define spa_loop_control_hook_after(l) spa_hook_list_call(l, struct spa_loop_control_hooks, after, 0) +#define spa_loop_control_hook_before(l) spa_hook_list_call_simple(l, struct spa_loop_control_hooks, before, 0) +#define spa_loop_control_hook_after(l) spa_hook_list_call_simple(l, struct spa_loop_control_hooks, after, 0) /** * Control an event loop diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index bde20dc27..dd04af9af 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -82,6 +82,18 @@ static inline void spa_hook_remove(struct spa_hook *hook) hook->removed(hook); } +#define spa_hook_list_call_simple(l,type,method,vers,...) \ +({ \ + struct spa_hook_list *list = l; \ + struct spa_hook *ci; \ + spa_list_for_each(ci, &list->list, link) { \ + const type *cb = ci->funcs; \ + if (cb && cb->version >= vers && cb->method) { \ + cb->method(ci->data, ## __VA_ARGS__); \ + } \ + } \ +}) + /** Call all hooks in a list, starting from the given one and optionally stopping * after calling the first non-NULL function, returns the number of methods * called */ From 7f52246cafffe278307a3a056d5c1407177cab3c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 18 Dec 2018 15:26:08 +0100 Subject: [PATCH 093/155] Add some more error checking Fixes #116 --- src/pipewire/thread-loop.c | 35 ++++++++++++++++++++++++++--------- src/pipewire/utils.h | 14 +++++++++++--- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index 364fe4554..d0d358e07 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -18,6 +18,7 @@ */ #include +#include #include #include "pipewire.h" @@ -96,28 +97,45 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, this = calloc(1, sizeof(struct pw_thread_loop)); if (this == NULL) - return NULL; + goto error1; pw_log_debug("thread-loop %p: new", this); this->loop = loop; this->name = name ? strdup(name) : NULL; - pw_loop_add_hook(loop, &this->hook, &impl_hooks, this); - spa_hook_list_init(&this->listener_list); pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&this->lock, &attr); + if ((errno = pthread_mutex_init(&this->lock, &attr)) != 0) + goto error2; + pthread_condattr_init(&cattr); pthread_condattr_setclock(&cattr, CLOCK_REALTIME); - pthread_cond_init(&this->cond, &cattr); - pthread_cond_init(&this->accept_cond, &cattr); + if ((errno = pthread_cond_init(&this->cond, &cattr)) != 0) + goto error3; + if ((errno = pthread_cond_init(&this->accept_cond, &cattr)) != 0) + goto error4; - this->event = pw_loop_add_event(this->loop, do_stop, this); + if ((this->event = pw_loop_add_event(this->loop, do_stop, this)) == NULL) + goto error5; + + pw_loop_add_hook(loop, &this->hook, &impl_hooks, this); return this; + + error5: + pthread_cond_destroy(&this->accept_cond); + error4: + pthread_cond_destroy(&this->cond); + error3: + pthread_mutex_destroy(&this->lock); + error2: + free(this->name); + free(this); + error1: + return NULL; } /** Destroy a threaded loop \memberof pw_thread_loop */ @@ -127,8 +145,7 @@ void pw_thread_loop_destroy(struct pw_thread_loop *loop) pw_thread_loop_stop(loop); - if (loop->name) - free(loop->name); + free(loop->name); pthread_mutex_destroy(&loop->lock); pthread_cond_destroy(&loop->cond); pthread_cond_destroy(&loop->accept_cond); diff --git a/src/pipewire/utils.h b/src/pipewire/utils.h index 22871b9a2..2ce9fdde0 100644 --- a/src/pipewire/utils.h +++ b/src/pipewire/utils.h @@ -51,9 +51,17 @@ pw_strip(char *str, const char *whitespace); static inline struct spa_pod * pw_spa_pod_copy(const struct spa_pod *pod) { - return pod ? - (struct spa_pod *) memcpy(malloc(SPA_POD_SIZE(pod)), pod, SPA_POD_SIZE(pod)) - : NULL; + size_t size; + struct spa_pod *c; + + if (pod == NULL) + return NULL; + + size = SPA_POD_SIZE(pod); + if ((c = malloc(size)) == NULL) + return NULL; + + return (struct spa_pod *) memcpy(c, pod, size); } #ifdef __cplusplus From 5390079b4a2bfb5cbf565e654424ee372ad630fd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 18 Dec 2018 16:01:12 +0100 Subject: [PATCH 094/155] video-src: set valid cursor id --- src/examples/video-src.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/examples/video-src.c b/src/examples/video-src.c index d756ba0e0..dbc639fde 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -141,7 +141,7 @@ static void on_timeout(void *userdata, uint64_t expirations) struct spa_meta_bitmap *mb; uint32_t *bitmap, color; - mcs->id = 0; + mcs->id = 1; /* 0 is invalid cursor, anything else is valid */ mcs->position.x = (sin(data->accumulator) + 1.0) * 160.0 + 80; mcs->position.y = (cos(data->accumulator) + 1.0) * 100.0 + 50; mcs->hotspot.x = 0; From 5c6bd8e5c7ebe39e6068456465877753f532cc38 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Dec 2018 17:47:25 +0100 Subject: [PATCH 095/155] free() can handle NULL just fine so skip the check Fixes #117 --- src/daemon/daemon-config.c | 2 +- src/modules/module-protocol-dbus.c | 1 + src/pipewire/factory.c | 3 +- src/pipewire/introspect.c | 72 ++++++++++-------------------- src/pipewire/link.c | 11 ++--- src/pipewire/module.c | 9 ++-- src/pipewire/node.c | 6 +-- src/pipewire/port.c | 3 +- src/pipewire/remote.c | 10 ++--- src/pipewire/stream.c | 16 +++---- 10 files changed, 46 insertions(+), 87 deletions(-) diff --git a/src/daemon/daemon-config.c b/src/daemon/daemon-config.c index a2bccf988..bcc09ac3d 100644 --- a/src/daemon/daemon-config.c +++ b/src/daemon/daemon-config.c @@ -90,7 +90,7 @@ void pw_daemon_config_free(struct pw_daemon_config *config) struct pw_command *cmd, *tmp; spa_list_for_each_safe(cmd, tmp, &config->commands, link) - pw_command_free(cmd); + pw_command_free(cmd); free(config); } diff --git a/src/modules/module-protocol-dbus.c b/src/modules/module-protocol-dbus.c index 4e0e64d9d..3e030c009 100644 --- a/src/modules/module-protocol-dbus.c +++ b/src/modules/module-protocol-dbus.c @@ -211,6 +211,7 @@ static void client_destroy(struct client *this) if (this->sender) { spa_list_remove(&this->link); free(this->sender); + this->sender = NULL; } } diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index cda3267e9..35b4cdcb1 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -67,8 +67,7 @@ void pw_factory_destroy(struct pw_factory *factory) spa_hook_remove(&factory->global_listener); pw_global_destroy(factory->global); } - if (factory->info.name) - free((char *)factory->info.name); + free((char *)factory->info.name); if (factory->properties) pw_properties_free(factory->properties); diff --git a/src/pipewire/introspect.c b/src/pipewire/introspect.c index d9aed7fa8..bf75f98bc 100644 --- a/src/pipewire/introspect.c +++ b/src/pipewire/introspect.c @@ -130,23 +130,19 @@ struct pw_core_info *pw_core_info_update(struct pw_core_info *info, info->change_mask = update->change_mask; if (update->change_mask & PW_CORE_CHANGE_MASK_USER_NAME) { - if (info->user_name) - free((void *) info->user_name); + free((void *) info->user_name); info->user_name = update->user_name ? strdup(update->user_name) : NULL; } if (update->change_mask & PW_CORE_CHANGE_MASK_HOST_NAME) { - if (info->host_name) - free((void *) info->host_name); + free((void *) info->host_name); info->host_name = update->host_name ? strdup(update->host_name) : NULL; } if (update->change_mask & PW_CORE_CHANGE_MASK_VERSION) { - if (info->version) - free((void *) info->version); + free((void *) info->version); info->version = update->version ? strdup(update->version) : NULL; } if (update->change_mask & PW_CORE_CHANGE_MASK_NAME) { - if (info->name) - free((void *) info->name); + free((void *) info->name); info->name = update->name ? strdup(update->name) : NULL; } if (update->change_mask & PW_CORE_CHANGE_MASK_COOKIE) @@ -161,14 +157,10 @@ struct pw_core_info *pw_core_info_update(struct pw_core_info *info, void pw_core_info_free(struct pw_core_info *info) { - if (info->user_name) - free((void *) info->user_name); - if (info->host_name) - free((void *) info->host_name); - if (info->version) - free((void *) info->version); - if (info->name) - free((void *) info->name); + free((void *) info->user_name); + free((void *) info->host_name); + free((void *) info->version); + free((void *) info->name); if (info->props) pw_spa_dict_destroy(info->props); free(info); @@ -190,8 +182,7 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info, info->change_mask = update->change_mask; if (update->change_mask & PW_NODE_CHANGE_MASK_NAME) { - if (info->name) - free((void *) info->name); + free((void *) info->name); info->name = update->name ? strdup(update->name) : NULL; } if (update->change_mask & PW_NODE_CHANGE_MASK_INPUT_PORTS) { @@ -205,8 +196,7 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info, if (update->change_mask & PW_NODE_CHANGE_MASK_STATE) { info->state = update->state; - if (info->error) - free((void *) info->error); + free((void *) info->error); info->error = update->error ? strdup(update->error) : NULL; } if (update->change_mask & PW_NODE_CHANGE_MASK_PROPS) { @@ -220,10 +210,8 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info, void pw_node_info_free(struct pw_node_info *info) { - if (info->name) - free((void *) info->name); - if (info->error) - free((void *) info->error); + free((void *) info->name); + free((void *) info->error); if (info->props) pw_spa_dict_destroy(info->props); free(info); @@ -245,8 +233,7 @@ struct pw_port_info *pw_port_info_update(struct pw_port_info *info, info->change_mask = update->change_mask; if (update->change_mask & PW_PORT_CHANGE_MASK_NAME) { - if (info->name) - free((void *) info->name); + free((void *) info->name); info->name = update->name ? strdup(update->name) : NULL; } if (update->change_mask & PW_PORT_CHANGE_MASK_PROPS) { @@ -260,8 +247,7 @@ struct pw_port_info *pw_port_info_update(struct pw_port_info *info, void pw_port_info_free(struct pw_port_info *info) { - if (info->name) - free((void *) info->name); + free((void *) info->name); if (info->props) pw_spa_dict_destroy(info->props); free(info); @@ -279,8 +265,7 @@ struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, return NULL; } info->id = update->id; - if (info->name) - free((void *) info->name); + free((void *) info->name); info->name = update->name ? strdup(update->name) : NULL; info->type = update->type; info->version = update->version; @@ -296,8 +281,7 @@ struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, void pw_factory_info_free(struct pw_factory_info *info) { - if (info->name) - free((void *) info->name); + free((void *) info->name); if (info->props) pw_spa_dict_destroy(info->props); free(info); @@ -318,18 +302,15 @@ struct pw_module_info *pw_module_info_update(struct pw_module_info *info, info->change_mask = update->change_mask; if (update->change_mask & PW_MODULE_CHANGE_MASK_NAME) { - if (info->name) - free((void *) info->name); + free((void *) info->name); info->name = update->name ? strdup(update->name) : NULL; } if (update->change_mask & PW_MODULE_CHANGE_MASK_FILENAME) { - if (info->filename) - free((void *) info->filename); + free((void *) info->filename); info->filename = update->filename ? strdup(update->filename) : NULL; } if (update->change_mask & PW_MODULE_CHANGE_MASK_ARGS) { - if (info->args) - free((void *) info->args); + free((void *) info->args); info->args = update->args ? strdup(update->args) : NULL; } if (update->change_mask & PW_MODULE_CHANGE_MASK_PROPS) { @@ -342,12 +323,9 @@ struct pw_module_info *pw_module_info_update(struct pw_module_info *info, void pw_module_info_free(struct pw_module_info *info) { - if (info->name) - free((void *) info->name); - if (info->filename) - free((void *) info->filename); - if (info->args) - free((void *) info->args); + free((void *) info->name); + free((void *) info->filename); + free((void *) info->args); if (info->props) pw_spa_dict_destroy(info->props); free(info); @@ -406,8 +384,7 @@ struct pw_link_info *pw_link_info_update(struct pw_link_info *info, info->input_port_id = update->input_port_id; } if (update->change_mask & PW_LINK_CHANGE_MASK_FORMAT) { - if (info->format) - free(info->format); + free(info->format); info->format = pw_spa_pod_copy(update->format); } return info; @@ -415,7 +392,6 @@ struct pw_link_info *pw_link_info_update(struct pw_link_info *info, void pw_link_info_free(struct pw_link_info *info) { - if (info->format) - free(info->format); + free(info->format); free(info); } diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 8a4dbeaf8..ab35f05b5 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -215,9 +215,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st pw_work_queue_add(impl->work, input->node, res2, complete_ready, input); } - - if (this->info.format) - free(this->info.format); + free(this->info.format); this->info.format = format; if (changed) { @@ -235,8 +233,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st error: pw_link_update_state(this, PW_LINK_STATE_ERROR, error); - if (format) - free(format); + free(format); return res; } @@ -1311,9 +1308,7 @@ void pw_link_destroy(struct pw_link *link) if (link->properties) pw_properties_free(link->properties); - if (link->info.format) - free(link->info.format); - + free(link->info.format); free(impl); } diff --git a/src/pipewire/module.c b/src/pipewire/module.c index 07282f950..d89235240 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -299,12 +299,9 @@ void pw_module_destroy(struct pw_module *module) spa_list_for_each_safe(resource, tmp, &module->resource_list, link) pw_resource_destroy(resource); - if (module->info.name) - free((char *) module->info.name); - if (module->info.filename) - free((char *) module->info.filename); - if (module->info.args) - free((char *) module->info.args); + free((char *) module->info.name); + free((char *) module->info.filename); + free((char *) module->info.args); dlclose(impl->hnd); free(impl); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 726e30cc3..38f4c8a9d 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -654,8 +654,7 @@ void pw_node_destroy(struct pw_node *node) pw_map_clear(&node->input_port_map); pw_map_clear(&node->output_port_map); - if (node->properties) - pw_properties_free(node->properties); + pw_properties_free(node->properties); clear_info(node); @@ -922,8 +921,7 @@ void pw_node_update_state(struct pw_node *node, enum pw_node_state state, char * pw_log_debug("node %p: update state from %s -> %s", node, pw_node_state_as_string(old), pw_node_state_as_string(state)); - if (node->info.error) - free((char*)node->info.error); + free((char*)node->info.error); node->info.error = error; node->info.state = state; diff --git a/src/pipewire/port.c b/src/pipewire/port.c index c1702660d..e3db4e0eb 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -564,8 +564,7 @@ void pw_port_destroy(struct pw_port *port) pw_map_clear(&port->mix_port_map); - if (port->properties) - pw_properties_free(port->properties); + pw_properties_free(port->properties); free(port); } diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 26e656806..c19f3512d 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -124,8 +124,7 @@ pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, con enum pw_remote_state old = remote->state; if (old != state) { - if (remote->error) - free(remote->error); + free(remote->error); if (fmt) { va_list varargs; @@ -305,8 +304,9 @@ void pw_remote_destroy(struct pw_remote *remote) spa_list_remove(&remote->link); - if (remote->properties) - pw_properties_free(remote->properties); + pw_log_debug("remote %p: free", remote); + pw_properties_free(remote->properties); + free(remote->error); free(impl); } @@ -452,7 +452,7 @@ int pw_remote_disconnect(struct pw_remote *remote) remote->n_types = 0; if (remote->info) { - pw_core_info_free (remote->info); + pw_core_info_free(remote->info); remote->info = NULL; } pw_remote_update_state(remote, PW_REMOTE_STATE_UNCONNECTED, NULL); diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index fa8922c16..0f3a5bdee 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -304,8 +304,7 @@ static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state stat enum pw_stream_state old = stream->state; bool res = old != state; if (res) { - if (stream->error) - free(stream->error); + free(stream->error); stream->error = error; pw_log_debug("stream %p: update state from %s -> %s (%s)", stream, @@ -540,14 +539,10 @@ void pw_stream_destroy(struct pw_stream *stream) pw_array_clear(&impl->mem_ids); - if (stream->error) - free(stream->error); + free(stream->error); + free(stream->name); - if (stream->name) - free(stream->name); - - if (stream->properties) - pw_properties_free(stream->properties); + pw_properties_free(stream->properties); free(impl); } @@ -948,8 +943,7 @@ client_node_port_set_param(void *data, pw_log_debug("stream %p: format changed %d", stream, seq); - if (impl->format) - free(impl->format); + free(impl->format); if (spa_pod_is_object_type(param, t->spa_format)) { impl->format = pw_spa_pod_copy(param); From bcec14decbdd61eb200abfc396f779cc89c0dade Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Dec 2018 10:06:16 +0100 Subject: [PATCH 096/155] Release 0.2.5 --- NEWS | 15 ++++++++------- meson.build | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index e426bd420..8768c6eca 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,11 @@ -PipeWire 0.2.4 +PipeWire 0.2.5 -- Install man pages in right directory -- Add systemd socket activation -- Various memory leak and corruption fixes in properties, dbus and - buffer mmaped memory. -- Fix v4l2 crash on unplug -- improve stream cleanup +- build fixes for systemd +- Add cursor and bitmap metadata. This can be used to send a cursor + sprite with the video stream. +- permissions were set too strict for non-flatpak clients +- Fix crash in loop caused by thread unsafe hook emission +- Add more error checking for thread-loop +- Small cleanups and bugfixes This is mostly a bugfix release. diff --git a/meson.build b/meson.build index 06c435f0d..3c3b6dfb0 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.4', + version : '0.2.5', meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From c511b530ed0184e5a90c8e5947975b1e621d9889 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Dec 2018 10:33:59 +0100 Subject: [PATCH 097/155] thread-loop: improve error checking --- src/pipewire/thread-loop.c | 40 ++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index d0d358e07..201e3b7a9 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -74,6 +74,14 @@ static void do_stop(void *data, uint64_t count) this->running = false; } +#define CHECK(expression,label) \ +do { \ + if ((errno = expression) != 0) { \ + pw_log_error(#expression ": %s", strerror(errno)); \ + goto label; \ + } \ +} while(false); + /** Create a new \ref pw_thread_loop * * \param loop the loop to wrap @@ -97,7 +105,7 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, this = calloc(1, sizeof(struct pw_thread_loop)); if (this == NULL) - goto error1; + goto no_mem; pw_log_debug("thread-loop %p: new", this); @@ -106,35 +114,33 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, spa_hook_list_init(&this->listener_list); - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - if ((errno = pthread_mutex_init(&this->lock, &attr)) != 0) - goto error2; + CHECK(pthread_mutexattr_init(&attr), clean_this); + CHECK(pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE), clean_this); + CHECK(pthread_mutex_init(&this->lock, &attr), clean_this); - pthread_condattr_init(&cattr); - pthread_condattr_setclock(&cattr, CLOCK_REALTIME); - if ((errno = pthread_cond_init(&this->cond, &cattr)) != 0) - goto error3; - if ((errno = pthread_cond_init(&this->accept_cond, &cattr)) != 0) - goto error4; + CHECK(pthread_condattr_init(&cattr), clean_lock); + CHECK(pthread_condattr_setclock(&cattr, CLOCK_REALTIME), clean_lock); + + CHECK(pthread_cond_init(&this->cond, &cattr), clean_lock); + CHECK(pthread_cond_init(&this->accept_cond, &cattr), clean_cond); if ((this->event = pw_loop_add_event(this->loop, do_stop, this)) == NULL) - goto error5; + goto clean_acceptcond; pw_loop_add_hook(loop, &this->hook, &impl_hooks, this); return this; - error5: + clean_acceptcond: pthread_cond_destroy(&this->accept_cond); - error4: + clean_cond: pthread_cond_destroy(&this->cond); - error3: + clean_lock: pthread_mutex_destroy(&this->lock); - error2: + clean_this: free(this->name); free(this); - error1: + no_mem: return NULL; } From f8b156ac14be086f15608029e3c22ca99a82b3b1 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 20 Dec 2018 10:34:12 +0100 Subject: [PATCH 098/155] thread-loop: fix leak of event Destroy the event when the loop is destroyed --- src/pipewire/thread-loop.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index 201e3b7a9..77b860356 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -151,13 +151,15 @@ void pw_thread_loop_destroy(struct pw_thread_loop *loop) pw_thread_loop_stop(loop); - free(loop->name); - pthread_mutex_destroy(&loop->lock); - pthread_cond_destroy(&loop->cond); - pthread_cond_destroy(&loop->accept_cond); - spa_hook_remove(&loop->hook); + pw_loop_destroy_source(loop->loop, loop->event); + + pthread_cond_destroy(&loop->accept_cond); + pthread_cond_destroy(&loop->cond); + pthread_mutex_destroy(&loop->lock); + + free(loop->name); free(loop); } From 371da358d1580dc06218d18a12a99611cac39e4e Mon Sep 17 00:00:00 2001 From: Jan Grulich Date: Wed, 2 Jan 2019 10:05:40 +0100 Subject: [PATCH 099/155] Avoid invalid conversion error with C++ compilators --- src/pipewire/utils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pipewire/utils.h b/src/pipewire/utils.h index 2ce9fdde0..7262ff42a 100644 --- a/src/pipewire/utils.h +++ b/src/pipewire/utils.h @@ -58,7 +58,7 @@ pw_spa_pod_copy(const struct spa_pod *pod) return NULL; size = SPA_POD_SIZE(pod); - if ((c = malloc(size)) == NULL) + if ((c = (struct spa_pod *) malloc(size)) == NULL) return NULL; return (struct spa_pod *) memcpy(c, pod, size); From dd3eb55aee38d1a27e2eabd611a378220577c854 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 09:21:16 +0100 Subject: [PATCH 100/155] utils: add SPA_EXPORT --- spa/include/spa/utils/defs.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 69454cf4b..86ad04e7e 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -127,10 +127,12 @@ struct spa_fraction { #define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #define SPA_ALIGNED(align) __attribute__((aligned(align))) #define SPA_DEPRECATED __attribute__ ((deprecated)) +#define SPA_EXPORT __attribute__ ((visibility("default"))) #else #define SPA_PRINTF_FUNC(fmt, arg1) #define SPA_ALIGNED(align) #define SPA_DEPRECATED +#define SPA_EXPORT #endif #define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1)) From 317f3b6be734a54544a3ccdd64d3054075896f44 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 11:09:32 +0100 Subject: [PATCH 101/155] type: add function to map types Add a helper function to map the types. This should be used instead of calling directly into the type mapper when CFI is used. --- spa/include/spa/param/format.h | 6 ++++ src/pipewire/type.c | 59 +++++++++++++++++++++++++++++++++- src/pipewire/type.h | 2 ++ 3 files changed, 66 insertions(+), 1 deletion(-) diff --git a/spa/include/spa/param/format.h b/spa/include/spa/param/format.h index 70de0f69b..4c0cf6925 100644 --- a/spa/include/spa/param/format.h +++ b/spa/include/spa/param/format.h @@ -45,6 +45,9 @@ extern "C" { #define SPA_TYPE_MEDIA_SUBTYPE__raw SPA_TYPE_MEDIA_SUBTYPE_BASE "raw" /* video subtypes */ +#define SPA_TYPE_MEDIA_SUBTYPE__Video SPA_TYPE_MEDIA_SUBTYPE_BASE "Video" +#define SPA_TYPE_MEDIA_SUBTYPE_VIDEO_BASE SPA_TYPE_MEDIA_SUBTYPE__Video ":" + #define SPA_TYPE_MEDIA_SUBTYPE__h264 SPA_TYPE_MEDIA_SUBTYPE_BASE "h264" #define SPA_TYPE_MEDIA_SUBTYPE__mjpg SPA_TYPE_MEDIA_SUBTYPE_BASE "mjpg" #define SPA_TYPE_MEDIA_SUBTYPE__dv SPA_TYPE_MEDIA_SUBTYPE_BASE "dv" @@ -61,6 +64,9 @@ extern "C" { #define SPA_TYPE_MEDIA_SUBTYPE__bayer SPA_TYPE_MEDIA_SUBTYPE_BASE "bayer" /* audio subtypes */ +#define SPA_TYPE_MEDIA_SUBTYPE__Audio SPA_TYPE_MEDIA_SUBTYPE_BASE "Audio" +#define SPA_TYPE_MEDIA_SUBTYPE_AUDIO_BASE SPA_TYPE_MEDIA_SUBTYPE__Audio ":" + #define SPA_TYPE_MEDIA_SUBTYPE__mp3 SPA_TYPE_MEDIA_SUBTYPE_BASE "mp3" #define SPA_TYPE_MEDIA_SUBTYPE__aac SPA_TYPE_MEDIA_SUBTYPE_BASE "aac" #define SPA_TYPE_MEDIA_SUBTYPE__vorbis SPA_TYPE_MEDIA_SUBTYPE_BASE "vorbis" diff --git a/src/pipewire/type.c b/src/pipewire/type.c index 89c9b3c25..9d458ceae 100644 --- a/src/pipewire/type.c +++ b/src/pipewire/type.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -25,12 +26,17 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include "pipewire/pipewire.h" #include "pipewire/type.h" #include "pipewire/module.h" - /** Initializes the type system * \param type a type structure * \memberof pw_type @@ -38,6 +44,8 @@ int pw_type_init(struct pw_type *type) { type->map = pw_get_support_interface(SPA_TYPE__TypeMap); + if (type->map == NULL) + return -EFAULT; type->core = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Core); type->registry = spa_type_map_get_id(type->map, PW_TYPE_INTERFACE__Registry); @@ -67,3 +75,52 @@ int pw_type_init(struct pw_type *type) spa_type_param_io_map(type->map, &type->param_io); return 0; } + +int pw_type_get(struct pw_type *type, const char *id, void *data) +{ + if (!strcmp(id, SPA_TYPE__MediaType)) { + struct spa_type_media_type *t = data; + spa_type_media_type_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE__MediaSubtype)) { + struct spa_type_media_subtype *t = data; + spa_type_media_subtype_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE_MEDIA_SUBTYPE__Video)) { + struct spa_type_media_subtype_video *t = data; + spa_type_media_subtype_video_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE_MEDIA_SUBTYPE__Audio)) { + struct spa_type_media_subtype_audio *t = data; + spa_type_media_subtype_audio_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE_FORMAT__Video)) { + struct spa_type_format_video *t = data; + spa_type_format_video_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE_FORMAT__Audio)) { + struct spa_type_format_audio *t = data; + spa_type_format_audio_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE__AudioFormat)) { + struct spa_type_audio_format *t = data; + spa_type_audio_format_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE__VideoFormat)) { + struct spa_type_video_format *t = data; + spa_type_video_format_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE__AudioFormat)) { + struct spa_type_audio_format *t = data; + spa_type_audio_format_map(type->map, t); + } + else if (!strcmp(id, SPA_TYPE_PARAM__VideoPadding)) { + struct spa_type_param_video_padding *t = data; + spa_type_param_video_padding_map(type->map, t); + } + else { + uint32_t *t = data; + *t = spa_type_map_get_id(type->map, id); + } + return 0; +} diff --git a/src/pipewire/type.h b/src/pipewire/type.h index 6c4b75298..9c77da3c6 100644 --- a/src/pipewire/type.h +++ b/src/pipewire/type.h @@ -81,6 +81,8 @@ struct pw_type { int pw_type_init(struct pw_type *type); +int pw_type_get(struct pw_type *type, const char *id, void *data); + #ifdef __cplusplus } #endif From e4cac644d20e75e8c1b706e42172613d112d8b73 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 11:35:36 +0100 Subject: [PATCH 102/155] fix some compiler warnings with clang --- spa/include/spa/utils/defs.h | 2 ++ spa/include/spa/utils/hook.h | 2 +- spa/plugins/bluez5/bluez5-monitor.c | 2 +- spa/plugins/support/dbus.c | 2 +- spa/tests/test-v4l2.c | 4 +++- spa/tools/spa-inspect.c | 4 +++- spa/tools/spa-monitor.c | 4 +++- src/examples/export-sink.c | 4 +++- src/examples/export-source.c | 4 +++- src/examples/local-v4l2.c | 4 +++- src/examples/video-play.c | 4 +++- src/examples/video-src.c | 4 +++- src/modules/module-link-factory.c | 4 ++-- src/pipewire/control.c | 8 ++++---- src/pipewire/core.c | 12 +++++------- src/pipewire/link.c | 16 ++++++++-------- src/pipewire/node.c | 5 ++++- src/pipewire/port.c | 19 ++++++++++--------- src/pipewire/private.h | 1 + src/pipewire/remote.c | 8 ++++---- 20 files changed, 67 insertions(+), 46 deletions(-) diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 86ad04e7e..8d2bbc6d9 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -51,6 +51,8 @@ enum spa_direction { SPA_DIRECTION_OUTPUT = 1, }; +#define SPA_DIRECTION_REVERSE(d) ((d) ^ 1) + #define SPA_RECTANGLE(width,height) (struct spa_rectangle){ width, height } struct spa_rectangle { uint32_t width; diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index dd04af9af..7685631af 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -101,7 +101,7 @@ static inline void spa_hook_remove(struct spa_hook *hook) ({ \ struct spa_hook_list *list = l; \ struct spa_list *s = start ? (struct spa_list *)start : &list->list; \ - struct spa_hook cursor = { 0 }, *ci; \ + struct spa_hook cursor = { { 0} }, *ci; \ int count = 0; \ spa_list_cursor_start(cursor, s, link); \ spa_list_for_each_cursor(ci, cursor, &list->list, link) { \ diff --git a/spa/plugins/bluez5/bluez5-monitor.c b/spa/plugins/bluez5/bluez5-monitor.c index 939aa70ed..140efa4d7 100644 --- a/spa/plugins/bluez5/bluez5-monitor.c +++ b/spa/plugins/bluez5/bluez5-monitor.c @@ -1215,7 +1215,7 @@ impl_init(const struct spa_handle_factory *factory, } init_type(&this->type, this->map); - this->dbus_connection = spa_dbus_get_connection(this->dbus, DBUS_BUS_SYSTEM); + this->dbus_connection = spa_dbus_get_connection(this->dbus, SPA_DBUS_TYPE_SYSTEM); if (this->dbus_connection == NULL) { spa_log_error(this->log, "no dbus connection"); return -EIO; diff --git a/spa/plugins/support/dbus.c b/spa/plugins/support/dbus.c index 8f9787352..ee4ed67bd 100644 --- a/spa/plugins/support/dbus.c +++ b/spa/plugins/support/dbus.c @@ -299,7 +299,7 @@ impl_get_connection(struct spa_dbus *dbus, conn = calloc(1, sizeof(struct connection)); conn->this = impl_connection; conn->impl = impl; - conn->conn = dbus_bus_get_private(type, &error); + conn->conn = dbus_bus_get_private((DBusBusType)type, &error); if (conn->conn == NULL) goto error; diff --git a/spa/tests/test-v4l2.c b/spa/tests/test-v4l2.c index 98ba7f5ac..ef3b06119 100644 --- a/spa/tests/test-v4l2.c +++ b/spa/tests/test-v4l2.c @@ -566,10 +566,12 @@ static void run_async_source(struct data *data) int main(int argc, char *argv[]) { - struct data data = { 0 }; + struct data data; int res; const char *str; + spa_zero(data); + data.use_buffer = true; data.map = &default_map.map; diff --git a/spa/tools/spa-inspect.c b/spa/tools/spa-inspect.c index 12b5cbb92..da41a82f0 100644 --- a/spa/tools/spa-inspect.c +++ b/spa/tools/spa-inspect.c @@ -261,13 +261,15 @@ static void do_remove_source(struct spa_source *source) int main(int argc, char *argv[]) { - struct data data = { 0 }; + struct data data; int res; void *handle; spa_handle_factory_enum_func_t enum_func; uint32_t index; const char *str; + spa_zero(data); + if (argc < 2) { printf("usage: %s \n", argv[0]); return -1; diff --git a/spa/tools/spa-monitor.c b/spa/tools/spa-monitor.c index 39e5c3831..9fb0049a0 100644 --- a/spa/tools/spa-monitor.c +++ b/spa/tools/spa-monitor.c @@ -163,12 +163,14 @@ static void handle_monitor(struct data *data, struct spa_monitor *monitor) int main(int argc, char *argv[]) { - struct data data = { 0 }; + struct data data; int res; void *handle; spa_handle_factory_enum_func_t enum_func; uint32_t fidx; + spa_zero(data); + data.map = &default_map.map; data.log = &default_log.log; data.main_loop.version = SPA_VERSION_LOOP; diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index 0aa916324..d34d3055f 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -643,7 +643,9 @@ static const struct pw_remote_events remote_events = { int main(int argc, char *argv[]) { - struct data data = { 0, }; + struct data data; + + spa_zero(data); pw_init(&argc, &argv); diff --git a/src/examples/export-source.c b/src/examples/export-source.c index d137d7c3d..e26722779 100644 --- a/src/examples/export-source.c +++ b/src/examples/export-source.c @@ -579,7 +579,9 @@ static const struct pw_remote_events remote_events = { int main(int argc, char *argv[]) { - struct data data = { 0, }; + struct data data; + + spa_zero(data); pw_init(&argc, &argv); diff --git a/src/examples/local-v4l2.c b/src/examples/local-v4l2.c index f5915a71d..d22d4dd8a 100644 --- a/src/examples/local-v4l2.c +++ b/src/examples/local-v4l2.c @@ -499,7 +499,9 @@ static void make_nodes(struct data *data) int main(int argc, char *argv[]) { - struct data data = { 0, }; + struct data data; + + spa_zero(data); pw_init(&argc, &argv); diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 7ba9034ee..22312fad7 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -494,7 +494,9 @@ static int get_fd(struct data *data) int main(int argc, char *argv[]) { - struct data data = { 0, }; + struct data data; + + spa_zero(data); pw_init(&argc, &argv); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index dbc639fde..acefe1d41 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -323,7 +323,9 @@ static const struct pw_remote_events remote_events = { int main(int argc, char *argv[]) { - struct data data = { 0, }; + struct data data; + + spa_zero(data); pw_init(&argc, &argv); diff --git a/src/modules/module-link-factory.c b/src/modules/module-link-factory.c index d9eeed6cf..15069084b 100644 --- a/src/modules/module-link-factory.c +++ b/src/modules/module-link-factory.c @@ -96,7 +96,7 @@ static void *create_object(void *_data, input_node = pw_global_get_object(global); if (output_port_id == -1) - outport = pw_node_get_free_port(output_node, SPA_DIRECTION_OUTPUT); + outport = pw_node_get_free_port(output_node, PW_DIRECTION_OUTPUT); else { global = pw_core_find_global(core, output_port_id); if (global == NULL || pw_global_get_type(global) != t->port) @@ -108,7 +108,7 @@ static void *create_object(void *_data, goto no_output_port; if (input_port_id == -1) - inport = pw_node_get_free_port(input_node, SPA_DIRECTION_INPUT); + inport = pw_node_get_free_port(input_node, PW_DIRECTION_INPUT); else { global = pw_core_find_global(core, input_port_id); if (global == NULL || pw_global_get_type(global) != t->port) diff --git a/src/pipewire/control.c b/src/pipewire/control.c index 747fa1ac9..e09cf233f 100644 --- a/src/pipewire/control.c +++ b/src/pipewire/control.c @@ -169,7 +169,7 @@ int pw_control_link(struct pw_control *control, struct pw_control *other) if (other->port) { struct pw_port *port = other->port; if ((res = spa_node_port_set_io(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, other->id, impl->mem->ptr, control->size)) < 0) { goto exit; @@ -180,7 +180,7 @@ int pw_control_link(struct pw_control *control, struct pw_control *other) if (control->port) { struct pw_port *port = control->port; if ((res = spa_node_port_set_io(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, control->id, impl->mem->ptr, control->size)) < 0) { goto exit; @@ -222,7 +222,7 @@ int pw_control_unlink(struct pw_control *control, struct pw_control *other) if (spa_list_is_empty(&control->inputs)) { struct pw_port *port = control->port; if ((res = spa_node_port_set_io(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, control->id, NULL, 0)) < 0) { pw_log_warn("control %p: can't unset port control io", control); } @@ -231,7 +231,7 @@ int pw_control_unlink(struct pw_control *control, struct pw_control *other) if (other->port) { struct pw_port *port = other->port; if ((res = spa_node_port_set_io(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, other->id, NULL, 0)) < 0) { pw_log_warn("control %p: can't unset port control io", control); } diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 3d989e347..07c6581a7 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -662,9 +662,7 @@ struct pw_port *pw_core_find_port(struct pw_core *core, pw_log_debug("id \"%u\" matches node %p", id, n); best = - pw_node_get_free_port(n, - pw_direction_reverse(other_port-> - direction)); + pw_node_get_free_port(n, pw_direction_reverse(other_port->direction)); if (best) break; } @@ -752,7 +750,7 @@ int pw_core_find_format(struct pw_core *core, if (in_state == PW_PORT_STATE_CONFIGURE && out_state > PW_PORT_STATE_CONFIGURE) { /* only input needs format */ if ((res = spa_node_port_enum_params(output->node->node, - output->direction, output->port_id, + output->spa_direction, output->port_id, t->param.idFormat, &oidx, NULL, format, builder)) <= 0) { if (res == 0) @@ -763,7 +761,7 @@ int pw_core_find_format(struct pw_core *core, } else if (out_state == PW_PORT_STATE_CONFIGURE && in_state > PW_PORT_STATE_CONFIGURE) { /* only output needs format */ if ((res = spa_node_port_enum_params(input->node->node, - input->direction, input->port_id, + input->spa_direction, input->port_id, t->param.idFormat, &iidx, NULL, format, builder)) <= 0) { if (res == 0) @@ -780,7 +778,7 @@ int pw_core_find_format(struct pw_core *core, pw_log_debug("core %p: do enum input %d", core, iidx); spa_pod_builder_init(&fb, fbuf, sizeof(fbuf)); if ((res = spa_node_port_enum_params(input->node->node, - input->direction, input->port_id, + input->spa_direction, input->port_id, t->param.idEnumFormat, &iidx, NULL, &filter, &fb)) <= 0) { if (res == 0 && iidx == 0) { @@ -795,7 +793,7 @@ int pw_core_find_format(struct pw_core *core, spa_debug_format(2, core->type.map, filter); if ((res = spa_node_port_enum_params(output->node->node, - output->direction, output->port_id, + output->spa_direction, output->port_id, t->param.idEnumFormat, &oidx, filter, format, builder)) <= 0) { if (res == 0) { diff --git a/src/pipewire/link.c b/src/pipewire/link.c index ab35f05b5..b0b78bfd5 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -146,7 +146,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st if (out_state > PW_PORT_STATE_CONFIGURE && output->node->info.state == PW_NODE_STATE_IDLE) { if ((res = spa_node_port_enum_params(output->node->node, - output->direction, output->port_id, + output->spa_direction, output->port_id, t->param.idFormat, &index, NULL, ¤t, &b)) <= 0) { if (res == 0) @@ -167,7 +167,7 @@ static int do_negotiate(struct pw_link *this, uint32_t in_state, uint32_t out_st } if (in_state > PW_PORT_STATE_CONFIGURE && input->node->info.state == PW_NODE_STATE_IDLE) { if ((res = spa_node_port_enum_params(input->node->node, - input->direction, input->port_id, + input->spa_direction, input->port_id, t->param.idFormat, &index, NULL, ¤t, &b)) <= 0) { if (res == 0) @@ -447,7 +447,7 @@ param_filter(struct pw_link *this, spa_pod_builder_init(&ib, ibuf, sizeof(ibuf)); pw_log_debug("iparam %d", iidx); if ((res = spa_node_port_enum_params(in_port->node->node, - in_port->direction, in_port->port_id, + in_port->spa_direction, in_port->port_id, id, &iidx, NULL, &iparam, &ib)) < 0) break; @@ -462,7 +462,7 @@ param_filter(struct pw_link *this, for (oidx = 0;;) { pw_log_debug("oparam %d", oidx); - if (spa_node_port_enum_params(out_port->node->node, out_port->direction, + if (spa_node_port_enum_params(out_port->node->node, out_port->spa_direction, out_port->port_id, id, &oidx, iparam, &oparam, result) <= 0) { break; @@ -500,12 +500,12 @@ static int do_allocation(struct pw_link *this, uint32_t in_state, uint32_t out_s pw_log_debug("link %p: doing alloc buffers %p %p", this, output->node, input->node); /* find out what's possible */ - if ((res = spa_node_port_get_info(output->node->node, output->direction, output->port_id, + if ((res = spa_node_port_get_info(output->node->node, output->spa_direction, output->port_id, &oinfo)) < 0) { asprintf(&error, "error get output port info: %d", res); goto error; } - if ((res = spa_node_port_get_info(input->node->node, input->direction, input->port_id, + if ((res = spa_node_port_get_info(input->node->node, input->spa_direction, input->port_id, &iinfo)) < 0) { asprintf(&error, "error get input port info: %d", res); goto error; @@ -1170,12 +1170,12 @@ struct pw_link *pw_link_new(struct pw_core *core, input_node, input->port_id, this->rt.in_port.port_id); spa_graph_port_init(&this->rt.out_port, - PW_DIRECTION_OUTPUT, + SPA_DIRECTION_OUTPUT, this->rt.out_port.port_id, SPA_GRAPH_PORT_FLAG_DISABLED, &this->io); spa_graph_port_init(&this->rt.in_port, - PW_DIRECTION_INPUT, + SPA_DIRECTION_INPUT, this->rt.in_port.port_id, SPA_GRAPH_PORT_FLAG_DISABLED, &this->io); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 38f4c8a9d..e5a1fc110 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -783,7 +783,10 @@ struct pw_port *pw_node_get_free_port(struct pw_node *node, enum pw_direction di pw_log_debug("node %p: creating port direction %d %u", node, direction, port_id); - if ((res = spa_node_add_port(node->node, direction, port_id)) < 0) { + if ((res = spa_node_add_port(node->node, + direction == PW_DIRECTION_INPUT ? + SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT, + port_id)) < 0) { pw_log_error("node %p: could not add port %d %s", node, port_id, spa_strerror(res)); goto no_mem; } diff --git a/src/pipewire/port.c b/src/pipewire/port.c index e3db4e0eb..da5065b86 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -182,6 +182,7 @@ struct pw_port *pw_port_new(enum pw_direction direction, goto no_mem; this->direction = direction; + this->spa_direction = direction == PW_DIRECTION_INPUT ? SPA_DIRECTION_INPUT : SPA_DIRECTION_OUTPUT; this->port_id = port_id; this->properties = properties; this->state = PW_PORT_STATE_INIT; @@ -201,7 +202,7 @@ struct pw_port *pw_port_new(enum pw_direction direction, spa_hook_list_init(&this->listener_list); spa_graph_port_init(&this->rt.port, - this->direction, + this->spa_direction, this->port_id, 0, &this->io); @@ -214,7 +215,7 @@ struct pw_port *pw_port_new(enum pw_direction direction, pw_map_init(&this->mix_port_map, 64, 64); spa_graph_port_init(&this->rt.mix_port, - pw_direction_reverse(this->direction), + SPA_DIRECTION_REVERSE(this->spa_direction), 0, 0, &this->io); @@ -422,7 +423,7 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) port->node = node; spa_node_port_get_info(node->node, - port->direction, port_id, + port->spa_direction, port_id, &port->spa_info); if (port->spa_info->props) @@ -459,7 +460,7 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) pw_log_debug("port %p: setting node io", port); spa_node_port_set_io(node->node, - port->direction, port_id, + port->spa_direction, port_id, t->io.Buffers, port->rt.port.io, sizeof(*port->rt.port.io)); @@ -575,7 +576,7 @@ do_port_command(struct spa_loop *loop, { struct pw_port *port = user_data; struct pw_node *node = port->node; - return spa_node_port_send_command(node->node, port->direction, port->port_id, data); + return spa_node_port_send_command(node->node, port->spa_direction, port->port_id, data); } int pw_port_send_command(struct pw_port *port, bool block, const struct spa_command *command) @@ -607,7 +608,7 @@ int pw_port_for_each_param(struct pw_port *port, spa_pod_builder_init(&b, buf, sizeof(buf)); idx = index; if ((res = spa_node_port_enum_params(node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, param_id, &index, filter, ¶m, &b)) <= 0) break; @@ -664,7 +665,7 @@ int pw_port_set_param(struct pw_port *port, uint32_t id, uint32_t flags, struct pw_core *core = node->core; struct pw_type *t = &core->type; - res = spa_node_port_set_param(node->node, port->direction, port->port_id, id, flags, param); + res = spa_node_port_set_param(node->node, port->spa_direction, port->port_id, id, flags, param); pw_log_debug("port %p: set param %s: %d (%s)", port, spa_type_map_get_type(t->map, id), res, spa_strerror(res)); @@ -692,7 +693,7 @@ int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint3 if (n_buffers > 0 && port->state < PW_PORT_STATE_READY) return -EIO; - res = spa_node_port_use_buffers(node->node, port->direction, port->port_id, buffers, n_buffers); + res = spa_node_port_use_buffers(node->node, port->spa_direction, port->port_id, buffers, n_buffers); pw_log_debug("port %p: use %d buffers: %d (%s)", port, n_buffers, res, spa_strerror(res)); port->allocated = false; @@ -722,7 +723,7 @@ int pw_port_alloc_buffers(struct pw_port *port, if (port->state < PW_PORT_STATE_READY) return -EIO; - res = spa_node_port_alloc_buffers(node->node, port->direction, port->port_id, + res = spa_node_port_alloc_buffers(node->node, port->spa_direction, port->port_id, params, n_params, buffers, n_buffers); pw_log_debug("port %p: alloc %d buffers: %d (%s)", port, *n_buffers, res, spa_strerror(res)); diff --git a/src/pipewire/private.h b/src/pipewire/private.h index a9b189af6..17e8884bf 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -383,6 +383,7 @@ struct pw_port { bool registered; enum pw_direction direction; /**< port direction */ + enum spa_direction spa_direction;/**< port direction */ uint32_t port_id; /**< port id */ const struct spa_port_info *spa_info; diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index c19f3512d..6b93d841e 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -784,7 +784,7 @@ static void add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32 spa_pod_builder_init(&b, buf, sizeof(buf)); if (spa_node_port_enum_params(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, data->t->param.idList, &idx1, NULL, ¶m, &b) <= 0) break; @@ -795,7 +795,7 @@ static void add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32 for (idx2 = 0;; n_params++) { spa_pod_builder_init(&b, buf, sizeof(buf)); if (spa_node_port_enum_params(port->node->node, - port->direction, port->port_id, + port->spa_direction, port->port_id, id, &idx2, NULL, ¶m, &b) <= 0) break; @@ -806,13 +806,13 @@ static void add_port_update(struct pw_proxy *proxy, struct pw_port *port, uint32 } } if (change_mask & PW_CLIENT_NODE_PORT_UPDATE_INFO) { - spa_node_port_get_info(port->node->node, port->direction, port->port_id, &port_info); + spa_node_port_get_info(port->node->node, port->spa_direction, port->port_id, &port_info); pi = * port_info; pi.flags &= ~SPA_PORT_INFO_FLAG_CAN_ALLOC_BUFFERS; } pw_client_node_proxy_port_update(data->node_proxy, - port->direction, + port->spa_direction, port->port_id, change_mask, n_params, From 703309f6cd0787494c9b8acf038a0b3746122c1e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 11:38:12 +0100 Subject: [PATCH 103/155] spa: don't use constructor attribute to register factories --- spa/plugins/bluez5/bluez5-monitor.c | 10 +------- spa/plugins/bluez5/plugin.c | 27 +++++++--------------- spa/plugins/support/logger.c | 10 +------- spa/plugins/support/loop.c | 10 +------- spa/plugins/support/mapper.c | 10 +------- spa/plugins/support/meson.build | 20 ++++++++-------- spa/plugins/support/plugin.c | 36 ++++++++++++++--------------- 7 files changed, 39 insertions(+), 84 deletions(-) diff --git a/spa/plugins/bluez5/bluez5-monitor.c b/spa/plugins/bluez5/bluez5-monitor.c index 140efa4d7..e82ac5a86 100644 --- a/spa/plugins/bluez5/bluez5-monitor.c +++ b/spa/plugins/bluez5/bluez5-monitor.c @@ -1252,7 +1252,7 @@ impl_enum_interface_info(const struct spa_handle_factory *factory, return 1; } -static const struct spa_handle_factory spa_bluez5_monitor_factory = { +const struct spa_handle_factory spa_bluez5_monitor_factory = { SPA_VERSION_MONITOR, NAME, NULL, @@ -1260,11 +1260,3 @@ static const struct spa_handle_factory spa_bluez5_monitor_factory = { impl_init, impl_enum_interface_info, }; - -int spa_handle_factory_register(const struct spa_handle_factory *factory); - -static void reg(void) __attribute__ ((constructor)); -static void reg(void) -{ - spa_handle_factory_register(&spa_bluez5_monitor_factory); -} diff --git a/spa/plugins/bluez5/plugin.c b/spa/plugins/bluez5/plugin.c index 031385cf1..fa77907b4 100644 --- a/spa/plugins/bluez5/plugin.c +++ b/spa/plugins/bluez5/plugin.c @@ -22,21 +22,7 @@ #include -#define MAX_FACTORIES 16 - -static const struct spa_handle_factory *factories[MAX_FACTORIES]; -static int n_factories; - -int spa_handle_factory_register(const struct spa_handle_factory *factory) -{ - if (n_factories >= MAX_FACTORIES) { - fprintf(stderr, "too many factories\n"); - return -ENOMEM; - } - - factories[n_factories++] = factory; - return 0; -} +extern const struct spa_handle_factory spa_bluez5_monitor_factory; int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) @@ -44,10 +30,13 @@ spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *ind spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(index != NULL, -EINVAL); - if (*index >= n_factories) + switch (*index) { + case 0: + *factory = &spa_bluez5_monitor_factory; + break; + default: return 0; - - *factory = factories[(*index)++]; - + } + (*index)++; return 1; } diff --git a/spa/plugins/support/logger.c b/spa/plugins/support/logger.c index ce5deafd0..7e3103c7d 100644 --- a/spa/plugins/support/logger.c +++ b/spa/plugins/support/logger.c @@ -255,7 +255,7 @@ impl_enum_interface_info(const struct spa_handle_factory *factory, return 1; } -static const struct spa_handle_factory logger_factory = { +const struct spa_handle_factory spa_support_logger_factory = { SPA_VERSION_HANDLE_FACTORY, NAME, NULL, @@ -263,11 +263,3 @@ static const struct spa_handle_factory logger_factory = { impl_init, impl_enum_interface_info, }; - -int spa_handle_factory_register(const struct spa_handle_factory *factory); - -static void reg(void) __attribute__ ((constructor)); -static void reg(void) -{ - spa_handle_factory_register(&logger_factory); -} diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 8abf4bc28..1c770a16b 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -776,7 +776,7 @@ impl_enum_interface_info(const struct spa_handle_factory *factory, return 1; } -static const struct spa_handle_factory loop_factory = { +const struct spa_handle_factory spa_support_loop_factory = { SPA_VERSION_HANDLE_FACTORY, NAME, NULL, @@ -784,11 +784,3 @@ static const struct spa_handle_factory loop_factory = { impl_init, impl_enum_interface_info }; - -int spa_handle_factory_register(const struct spa_handle_factory *factory); - -static void reg(void) __attribute__ ((constructor)); -static void reg(void) -{ - spa_handle_factory_register(&loop_factory); -} diff --git a/spa/plugins/support/mapper.c b/spa/plugins/support/mapper.c index b1f5ba0ed..0498e00a0 100644 --- a/spa/plugins/support/mapper.c +++ b/spa/plugins/support/mapper.c @@ -202,7 +202,7 @@ impl_enum_interface_info(const struct spa_handle_factory *factory, return 1; } -static const struct spa_handle_factory type_map_factory = { +const struct spa_handle_factory spa_support_type_map_factory = { SPA_VERSION_HANDLE_FACTORY, NAME, NULL, @@ -210,11 +210,3 @@ static const struct spa_handle_factory type_map_factory = { impl_init, impl_enum_interface_info, }; - -int spa_handle_factory_register(const struct spa_handle_factory *factory); - -static void reg(void) __attribute__ ((constructor)); -static void reg(void) -{ - spa_handle_factory_register(&type_map_factory); -} diff --git a/spa/plugins/support/meson.build b/spa/plugins/support/meson.build index 475e295f2..e1e751803 100644 --- a/spa/plugins/support/meson.build +++ b/spa/plugins/support/meson.build @@ -4,17 +4,17 @@ spa_support_sources = ['mapper.c', 'plugin.c'] spa_support_lib = shared_library('spa-support', - spa_support_sources, - include_directories : [ spa_inc], - dependencies : threads_dep, - install : true, - install_dir : '@0@/spa/support'.format(get_option('libdir'))) + spa_support_sources, + include_directories : [ spa_inc], + dependencies : threads_dep, + install : true, + install_dir : '@0@/spa/support'.format(get_option('libdir'))) spa_dbus_sources = ['dbus.c'] spa_dbus_lib = shared_library('spa-dbus', - spa_dbus_sources, - include_directories : [ spa_inc], - dependencies : dbus_dep, - install : true, - install_dir : '@0@/spa/support'.format(get_option('libdir'))) + spa_dbus_sources, + include_directories : [ spa_inc], + dependencies : dbus_dep, + install : true, + install_dir : '@0@/spa/support'.format(get_option('libdir'))) diff --git a/spa/plugins/support/plugin.c b/spa/plugins/support/plugin.c index 3cbd3da79..6abd64d75 100644 --- a/spa/plugins/support/plugin.c +++ b/spa/plugins/support/plugin.c @@ -22,31 +22,29 @@ #include -#define MAX_FACTORIES 16 +extern const struct spa_handle_factory spa_support_logger_factory; +extern const struct spa_handle_factory spa_support_loop_factory; +extern const struct spa_handle_factory spa_support_type_map_factory; -static const struct spa_handle_factory *factories[MAX_FACTORIES]; -static int n_factories; - -int spa_handle_factory_register(const struct spa_handle_factory *factory) -{ - if (n_factories < MAX_FACTORIES) - factories[n_factories++] = factory; - else { - fprintf(stderr, "too many factories\n"); - return -ENOMEM; - } - return 0; -} - -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); spa_return_val_if_fail(index != NULL, -EINVAL); - if (*index >= n_factories) + switch (*index) { + case 0: + *factory = &spa_support_logger_factory; + break; + case 1: + *factory = &spa_support_loop_factory; + break; + case 2: + *factory = &spa_support_type_map_factory; + break; + default: return 0; - - *factory = factories[(*index)++]; + } + (*index)++; return 1; } From 3424c05298579c06c6bf5a0c7f74143c84c90fcb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 11:43:47 +0100 Subject: [PATCH 104/155] example: use core methods to register types --- src/examples/video-play.c | 26 +++++++++++++++----------- src/examples/video-src.c | 14 +++++++------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 22312fad7..735a91370 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -39,13 +39,13 @@ struct type { uint32_t meta_cursor; }; -static inline void init_type(struct type *type, struct spa_type_map *map) +static inline void init_type(struct type *type, struct pw_type *map) { - spa_type_media_type_map(map, &type->media_type); - spa_type_media_subtype_map(map, &type->media_subtype); - spa_type_format_video_map(map, &type->format_video); - spa_type_video_format_map(map, &type->video_format); - type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); + pw_type_get(map, SPA_TYPE__MediaType, &type->media_type); + pw_type_get(map, SPA_TYPE__MediaSubtype, &type->media_subtype); + pw_type_get(map, SPA_TYPE_FORMAT__Video, &type->format_video); + pw_type_get(map, SPA_TYPE__VideoFormat, &type->video_format); + pw_type_get(map, SPA_TYPE_META__Cursor, &type->meta_cursor); } #define WIDTH 640 @@ -295,8 +295,10 @@ on_stream_format_changed(void *_data, const struct spa_pod *format) return; } - fprintf(stderr, "got format:\n"); - spa_debug_format(2, data->t->map, format); + if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) { + fprintf(stderr, "got format:\n"); + spa_debug_format(2, data->t->map, format); + } spa_format_video_raw_parse(format, &data->format, &data->type.format_video); @@ -422,8 +424,10 @@ static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remo NULL); params[0] = spa_pod_builder_pop(&b); - fprintf(stderr, "supported formats:\n"); - spa_debug_format(2, data->t->map, params[0]); + if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) { + fprintf(stderr, "supported formats:\n"); + spa_debug_format(2, data->t->map, params[0]); + } pw_stream_add_listener(data->stream, &data->stream_listener, @@ -506,7 +510,7 @@ int main(int argc, char *argv[]) data.remote = pw_remote_new(data.core, NULL, 0); data.path = argc > 1 ? argv[1] : NULL; - init_type(&data.type, data.t->map); + init_type(&data.type, data.t); if (SDL_Init(SDL_INIT_VIDEO) < 0) { fprintf(stderr, "can't initialize SDL: %s\n", SDL_GetError()); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index acefe1d41..647b595ab 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -38,13 +38,13 @@ struct type { uint32_t meta_cursor; }; -static inline void init_type(struct type *type, struct spa_type_map *map) +static inline void init_type(struct type *type, struct pw_type *map) { - spa_type_media_type_map(map, &type->media_type); - spa_type_media_subtype_map(map, &type->media_subtype); - spa_type_format_video_map(map, &type->format_video); - spa_type_video_format_map(map, &type->video_format); - type->meta_cursor = spa_type_map_get_id(map, SPA_TYPE_META__Cursor); + pw_type_get(map, SPA_TYPE__MediaType, &type->media_type); + pw_type_get(map, SPA_TYPE__MediaSubtype, &type->media_subtype); + pw_type_get(map, SPA_TYPE_FORMAT__Video, &type->format_video); + pw_type_get(map, SPA_TYPE__VideoFormat, &type->video_format); + pw_type_get(map, SPA_TYPE_META__Cursor, &type->meta_cursor); } #define BPP 3 @@ -334,7 +334,7 @@ int main(int argc, char *argv[]) data.t = pw_core_get_type(data.core); data.remote = pw_remote_new(data.core, NULL, 0); - init_type(&data.type, data.t->map); + init_type(&data.type, data.t); data.timer = pw_loop_add_timer(pw_main_loop_get_loop(data.loop), on_timeout, &data); From f6391be2144d8c7cb5b92c46842abfca6577b5a8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 6 Feb 2019 11:59:05 +0100 Subject: [PATCH 105/155] add SPA_EXPORT where needed --- spa/plugins/alsa/alsa.c | 1 + spa/plugins/audiomixer/plugin.c | 2 +- spa/plugins/audiotestsrc/plugin.c | 1 + spa/plugins/bluez5/plugin.c | 2 +- spa/plugins/ffmpeg/ffmpeg.c | 2 +- spa/plugins/support/dbus.c | 1 + spa/plugins/test/plugin.c | 2 +- spa/plugins/v4l2/v4l2.c | 2 +- spa/plugins/videotestsrc/plugin.c | 2 +- spa/plugins/volume/plugin.c | 1 + src/modules/module-audio-dsp.c | 1 + src/modules/module-autolink.c | 1 + src/modules/module-client-node.c | 1 + src/modules/module-flatpak.c | 1 + src/modules/module-link-factory.c | 1 + src/modules/module-mixer.c | 1 + src/modules/module-protocol-dbus.c | 1 + src/modules/module-protocol-native.c | 1 + src/modules/module-rtkit.c | 1 + src/modules/module-suspend-on-idle.c | 1 + src/modules/spa/module-monitor.c | 1 + src/modules/spa/module-node-factory.c | 1 + src/modules/spa/module-node.c | 1 + src/pipewire/client.c | 15 +++++++++++++++ src/pipewire/command.c | 3 +++ src/pipewire/control.c | 4 ++++ src/pipewire/core.c | 13 +++++++++++++ src/pipewire/data-loop.c | 7 +++++++ src/pipewire/factory.c | 8 ++++++++ src/pipewire/global.c | 14 ++++++++++++++ src/pipewire/introspect.c | 17 +++++++++++++++++ src/pipewire/link.c | 11 +++++++++++ src/pipewire/log.c | 7 ++++++- src/pipewire/loop.c | 2 ++ src/pipewire/main-loop.c | 6 ++++++ src/pipewire/mem.c | 5 +++++ src/pipewire/module.c | 6 ++++++ src/pipewire/node.c | 18 ++++++++++++++++++ src/pipewire/pipewire.c | 17 ++++++++++++++++- src/pipewire/port.c | 6 ++++++ src/pipewire/properties.c | 11 +++++++++++ src/pipewire/protocol.c | 9 +++++++++ src/pipewire/proxy.c | 9 +++++++++ src/pipewire/remote.c | 16 ++++++++++++++++ src/pipewire/resource.c | 14 ++++++++++++++ src/pipewire/stream.c | 19 +++++++++++++++++++ src/pipewire/thread-loop.c | 13 +++++++++++++ src/pipewire/utils.c | 4 ++++ 48 files changed, 275 insertions(+), 8 deletions(-) diff --git a/spa/plugins/alsa/alsa.c b/spa/plugins/alsa/alsa.c index 41f7a2014..1e95ce527 100644 --- a/spa/plugins/alsa/alsa.c +++ b/spa/plugins/alsa/alsa.c @@ -25,6 +25,7 @@ extern const struct spa_handle_factory spa_alsa_source_factory; extern const struct spa_handle_factory spa_alsa_sink_factory; extern const struct spa_handle_factory spa_alsa_monitor_factory; +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/spa/plugins/audiomixer/plugin.c b/spa/plugins/audiomixer/plugin.c index 8735390e7..d500c096a 100644 --- a/spa/plugins/audiomixer/plugin.c +++ b/spa/plugins/audiomixer/plugin.c @@ -23,7 +23,7 @@ extern const struct spa_handle_factory spa_audiomixer_factory; -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/spa/plugins/audiotestsrc/plugin.c b/spa/plugins/audiotestsrc/plugin.c index b2029a19b..210829410 100644 --- a/spa/plugins/audiotestsrc/plugin.c +++ b/spa/plugins/audiotestsrc/plugin.c @@ -23,6 +23,7 @@ extern const struct spa_handle_factory spa_audiotestsrc_factory; +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { diff --git a/spa/plugins/bluez5/plugin.c b/spa/plugins/bluez5/plugin.c index fa77907b4..d6ff85406 100644 --- a/spa/plugins/bluez5/plugin.c +++ b/spa/plugins/bluez5/plugin.c @@ -24,7 +24,7 @@ extern const struct spa_handle_factory spa_bluez5_monitor_factory; -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/spa/plugins/ffmpeg/ffmpeg.c b/spa/plugins/ffmpeg/ffmpeg.c index e9ff12197..8e3f5beba 100644 --- a/spa/plugins/ffmpeg/ffmpeg.c +++ b/spa/plugins/ffmpeg/ffmpeg.c @@ -76,7 +76,7 @@ ffmpeg_enum_interface_info(const struct spa_handle_factory *factory, return 1; } - +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { static const AVCodec *c = NULL; diff --git a/spa/plugins/support/dbus.c b/spa/plugins/support/dbus.c index ee4ed67bd..b3f797296 100644 --- a/spa/plugins/support/dbus.c +++ b/spa/plugins/support/dbus.c @@ -431,6 +431,7 @@ static const struct spa_handle_factory dbus_factory = { impl_enum_interface_info, }; +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { diff --git a/spa/plugins/test/plugin.c b/spa/plugins/test/plugin.c index 1bddeeb0e..94d1992d6 100644 --- a/spa/plugins/test/plugin.c +++ b/spa/plugins/test/plugin.c @@ -24,7 +24,7 @@ extern const struct spa_handle_factory spa_fakesrc_factory; extern const struct spa_handle_factory spa_fakesink_factory; -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/spa/plugins/v4l2/v4l2.c b/spa/plugins/v4l2/v4l2.c index 8079965b3..8d6bb75ff 100644 --- a/spa/plugins/v4l2/v4l2.c +++ b/spa/plugins/v4l2/v4l2.c @@ -24,7 +24,7 @@ extern const struct spa_handle_factory spa_v4l2_source_factory; extern const struct spa_handle_factory spa_v4l2_monitor_factory; -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { diff --git a/spa/plugins/videotestsrc/plugin.c b/spa/plugins/videotestsrc/plugin.c index c565bb727..77b996253 100644 --- a/spa/plugins/videotestsrc/plugin.c +++ b/spa/plugins/videotestsrc/plugin.c @@ -23,7 +23,7 @@ extern const struct spa_handle_factory spa_videotestsrc_factory; -int +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/spa/plugins/volume/plugin.c b/spa/plugins/volume/plugin.c index 488896a79..8abc7e741 100644 --- a/spa/plugins/volume/plugin.c +++ b/spa/plugins/volume/plugin.c @@ -23,6 +23,7 @@ extern const struct spa_handle_factory spa_volume_factory; +SPA_EXPORT int spa_handle_factory_enum(const struct spa_handle_factory **factory, uint32_t *index) { spa_return_val_if_fail(factory != NULL, -EINVAL); diff --git a/src/modules/module-audio-dsp.c b/src/modules/module-audio-dsp.c index 1b28c2d3b..8c1c174c3 100644 --- a/src/modules/module-audio-dsp.c +++ b/src/modules/module-audio-dsp.c @@ -925,6 +925,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-autolink.c b/src/modules/module-autolink.c index 241afbd22..4aeace5fc 100644 --- a/src/modules/module-autolink.c +++ b/src/modules/module-autolink.c @@ -390,6 +390,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-client-node.c b/src/modules/module-client-node.c index 616a6c950..ebd37ee12 100644 --- a/src/modules/module-client-node.c +++ b/src/modules/module-client-node.c @@ -140,6 +140,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index ab32a2277..59c6f67a2 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -544,6 +544,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return -ENOMEM; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-link-factory.c b/src/modules/module-link-factory.c index 15069084b..903d80c81 100644 --- a/src/modules/module-link-factory.c +++ b/src/modules/module-link-factory.c @@ -225,6 +225,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-mixer.c b/src/modules/module-mixer.c index f3c1a2f34..ce5ce0268 100644 --- a/src/modules/module-mixer.c +++ b/src/modules/module-mixer.c @@ -241,6 +241,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-protocol-dbus.c b/src/modules/module-protocol-dbus.c index 3e030c009..1d54a4c3d 100644 --- a/src/modules/module-protocol-dbus.c +++ b/src/modules/module-protocol-dbus.c @@ -626,6 +626,7 @@ static void pw_protocol_dbus_destroy(struct impl *impl) } #endif +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { pw_protocol_dbus_new(module->core, NULL); diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 4816492ab..c00fb1637 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -936,6 +936,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-rtkit.c b/src/modules/module-rtkit.c index 3670cdeb1..0db327554 100644 --- a/src/modules/module-rtkit.c +++ b/src/modules/module-rtkit.c @@ -482,6 +482,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 47e1a26e1..56775376f 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -212,6 +212,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/spa/module-monitor.c b/src/modules/spa/module-monitor.c index 24f25c06e..1c6ae44ea 100644 --- a/src/modules/spa/module-monitor.c +++ b/src/modules/spa/module-monitor.c @@ -52,6 +52,7 @@ const struct pw_module_events module_events = { .destroy = module_destroy, }; +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { const char *dir; diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index 9e2129d9d..560089a7c 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -196,6 +196,7 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie return 0; } +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { return module_init(module, NULL); diff --git a/src/modules/spa/module-node.c b/src/modules/spa/module-node.c index 8265f01ab..ec45bda08 100644 --- a/src/modules/spa/module-node.c +++ b/src/modules/spa/module-node.c @@ -53,6 +53,7 @@ static const struct pw_module_events module_events = { .destroy = module_destroy, }; +SPA_EXPORT int pipewire__module_init(struct pw_module *module, const char *args) { struct pw_properties *props = NULL; diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 876ac8e40..c5257c227 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -148,6 +148,7 @@ static const struct pw_core_events core_events = { * * \memberof pw_client */ +SPA_EXPORT struct pw_client *pw_client_new(struct pw_core *core, struct ucred *ucred, struct pw_properties *properties, @@ -215,6 +216,7 @@ static const struct pw_global_events global_events = { .bind = global_bind, }; +SPA_EXPORT int pw_client_register(struct pw_client *client, struct pw_client *owner, struct pw_global *parent, @@ -241,31 +243,37 @@ int pw_client_register(struct pw_client *client, return 0; } +SPA_EXPORT struct pw_core *pw_client_get_core(struct pw_client *client) { return client->core; } +SPA_EXPORT struct pw_resource *pw_client_get_core_resource(struct pw_client *client) { return client->core_resource; } +SPA_EXPORT struct pw_resource *pw_client_find_resource(struct pw_client *client, uint32_t id) { return pw_map_lookup(&client->objects, id); } +SPA_EXPORT struct pw_global *pw_client_get_global(struct pw_client *client) { return client->global; } +SPA_EXPORT const struct pw_properties *pw_client_get_properties(struct pw_client *client) { return client->properties; } +SPA_EXPORT const struct ucred *pw_client_get_ucred(struct pw_client *client) { if (!client->ucred_valid) @@ -274,6 +282,7 @@ const struct ucred *pw_client_get_ucred(struct pw_client *client) return &client->ucred; } +SPA_EXPORT void *pw_client_get_user_data(struct pw_client *client) { return client->user_data; @@ -293,6 +302,7 @@ static int destroy_resource(void *object, void *data) * * \memberof pw_client */ +SPA_EXPORT void pw_client_destroy(struct pw_client *client) { struct pw_resource *resource, *tmp; @@ -328,6 +338,7 @@ void pw_client_destroy(struct pw_client *client) free(impl); } +SPA_EXPORT void pw_client_add_listener(struct pw_client *client, struct spa_hook *listener, const struct pw_client_events *events, @@ -336,6 +347,7 @@ void pw_client_add_listener(struct pw_client *client, spa_hook_list_append(&client->listener_list, listener, events, data); } +SPA_EXPORT const struct pw_client_info *pw_client_get_info(struct pw_client *client) { return &client->info; @@ -352,6 +364,7 @@ const struct pw_client_info *pw_client_get_info(struct pw_client *client) * * \memberof pw_client */ +SPA_EXPORT int pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict) { struct pw_resource *resource; @@ -436,6 +449,7 @@ static uint32_t parse_mask(const char *str) return mask; } +SPA_EXPORT int pw_client_update_permissions(struct pw_client *client, const struct spa_dict *dict) { struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); @@ -497,6 +511,7 @@ int pw_client_update_permissions(struct pw_client *client, const struct spa_dict return 0; } +SPA_EXPORT void pw_client_set_busy(struct pw_client *client, bool busy) { if (client->busy != busy) { diff --git a/src/pipewire/command.c b/src/pipewire/command.c index 1578829bb..24fc40460 100644 --- a/src/pipewire/command.c +++ b/src/pipewire/command.c @@ -135,6 +135,7 @@ static struct pw_command *parse_command_module_load(const char *line, char **err * * \memberof pw_command */ +SPA_EXPORT void pw_command_free(struct pw_command *command) { struct impl *impl = SPA_CONTAINER_OF(command, struct impl, this); @@ -154,6 +155,7 @@ void pw_command_free(struct pw_command *command) * * \memberof pw_command */ +SPA_EXPORT struct pw_command *pw_command_parse(const char *line, char **err) { struct pw_command *command = NULL; @@ -187,6 +189,7 @@ struct pw_command *pw_command_parse(const char *line, char **err) * * \memberof pw_command */ +SPA_EXPORT int pw_command_run(struct pw_command *command, struct pw_core *core, char **err) { return command->func(command, core, err); diff --git a/src/pipewire/control.c b/src/pipewire/control.c index e09cf233f..1c8873db0 100644 --- a/src/pipewire/control.c +++ b/src/pipewire/control.c @@ -120,11 +120,13 @@ void pw_control_destroy(struct pw_control *control) free(control); } +SPA_EXPORT struct pw_port *pw_control_get_port(struct pw_control *control) { return control->port; } +SPA_EXPORT void pw_control_add_listener(struct pw_control *control, struct spa_hook *listener, const struct pw_control_events *events, @@ -133,6 +135,7 @@ void pw_control_add_listener(struct pw_control *control, spa_hook_list_append(&control->listener_list, listener, events, data); } +SPA_EXPORT int pw_control_link(struct pw_control *control, struct pw_control *other) { int res = 0; @@ -198,6 +201,7 @@ int pw_control_link(struct pw_control *control, struct pw_control *other) return res; } +SPA_EXPORT int pw_control_unlink(struct pw_control *control, struct pw_control *other) { int res = 0; diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 07c6581a7..fc49d445e 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -360,6 +360,7 @@ static const struct pw_global_events global_events = { * * \memberof pw_core */ +SPA_EXPORT struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *properties) { struct pw_core *this; @@ -468,6 +469,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro * * \memberof pw_core */ +SPA_EXPORT void pw_core_destroy(struct pw_core *core) { struct pw_global *global, *t; @@ -506,16 +508,19 @@ void pw_core_destroy(struct pw_core *core) free(core); } +SPA_EXPORT const struct pw_core_info *pw_core_get_info(struct pw_core *core) { return &core->info; } +SPA_EXPORT struct pw_global *pw_core_get_global(struct pw_core *core) { return core->global; } +SPA_EXPORT void pw_core_add_listener(struct pw_core *core, struct spa_hook *listener, const struct pw_core_events *events, @@ -524,22 +529,26 @@ void pw_core_add_listener(struct pw_core *core, spa_hook_list_append(&core->listener_list, listener, events, data); } +SPA_EXPORT struct pw_type *pw_core_get_type(struct pw_core *core) { return &core->type; } +SPA_EXPORT const struct spa_support *pw_core_get_support(struct pw_core *core, uint32_t *n_support) { *n_support = core->n_support; return core->support; } +SPA_EXPORT struct pw_loop *pw_core_get_main_loop(struct pw_core *core) { return core->main_loop; } +SPA_EXPORT const struct pw_properties *pw_core_get_properties(struct pw_core *core) { return core->properties; @@ -554,6 +563,7 @@ const struct pw_properties *pw_core_get_properties(struct pw_core *core) * * \memberof pw_core */ +SPA_EXPORT int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) { struct pw_resource *resource; @@ -580,6 +590,7 @@ int pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict) return changed; } +SPA_EXPORT int pw_core_for_each_global(struct pw_core *core, int (*callback) (void *data, struct pw_global *global), void *data) @@ -597,6 +608,7 @@ int pw_core_for_each_global(struct pw_core *core, return 0; } +SPA_EXPORT struct pw_global *pw_core_find_global(struct pw_core *core, uint32_t id) { struct pw_global *global; @@ -830,6 +842,7 @@ int pw_core_find_format(struct pw_core *core, * * \memberof pw_core */ +SPA_EXPORT struct pw_factory *pw_core_find_factory(struct pw_core *core, const char *name) { diff --git a/src/pipewire/data-loop.c b/src/pipewire/data-loop.c index 75f59d499..41f60d52b 100644 --- a/src/pipewire/data-loop.c +++ b/src/pipewire/data-loop.c @@ -56,6 +56,7 @@ static void do_stop(void *data, uint64_t count) * * \memberof pw_data_loop */ +SPA_EXPORT struct pw_data_loop *pw_data_loop_new(struct pw_properties *properties) { struct pw_data_loop *this; @@ -85,6 +86,7 @@ struct pw_data_loop *pw_data_loop_new(struct pw_properties *properties) * \param loop the data loop to destroy * \memberof pw_data_loop */ +SPA_EXPORT void pw_data_loop_destroy(struct pw_data_loop *loop) { pw_log_debug("data-loop %p: destroy", loop); @@ -98,6 +100,7 @@ void pw_data_loop_destroy(struct pw_data_loop *loop) free(loop); } +SPA_EXPORT void pw_data_loop_add_listener(struct pw_data_loop *loop, struct spa_hook *listener, const struct pw_data_loop_events *events, @@ -106,6 +109,7 @@ void pw_data_loop_add_listener(struct pw_data_loop *loop, spa_hook_list_append(&loop->listener_list, listener, events, data); } +SPA_EXPORT struct pw_loop * pw_data_loop_get_loop(struct pw_data_loop *loop) { @@ -120,6 +124,7 @@ pw_data_loop_get_loop(struct pw_data_loop *loop) * * \memberof pw_data_loop */ +SPA_EXPORT int pw_data_loop_start(struct pw_data_loop *loop) { if (!loop->running) { @@ -143,6 +148,7 @@ int pw_data_loop_start(struct pw_data_loop *loop) * * \memberof pw_data_loop */ +SPA_EXPORT int pw_data_loop_stop(struct pw_data_loop *loop) { if (loop->running) { @@ -159,6 +165,7 @@ int pw_data_loop_stop(struct pw_data_loop *loop) * * \memberof pw_data_loop */ +SPA_EXPORT bool pw_data_loop_in_thread(struct pw_data_loop * loop) { return pthread_equal(loop->thread, pthread_self()); diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index 35b4cdcb1..fb611eef1 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -27,6 +27,7 @@ struct resource_data { struct spa_hook resource_listener; }; +SPA_EXPORT struct pw_factory *pw_factory_new(struct pw_core *core, const char *name, uint32_t type, @@ -55,6 +56,7 @@ struct pw_factory *pw_factory_new(struct pw_core *core, return this; } +SPA_EXPORT void pw_factory_destroy(struct pw_factory *factory) { pw_log_debug("factory %p: destroy", factory); @@ -132,6 +134,7 @@ static const struct pw_global_events global_events = { .bind = global_bind, }; +SPA_EXPORT int pw_factory_register(struct pw_factory *factory, struct pw_client *owner, struct pw_global *parent, @@ -167,16 +170,19 @@ int pw_factory_register(struct pw_factory *factory, return 0; } +SPA_EXPORT void *pw_factory_get_user_data(struct pw_factory *factory) { return factory->user_data; } +SPA_EXPORT struct pw_global *pw_factory_get_global(struct pw_factory *factory) { return factory->global; } +SPA_EXPORT void pw_factory_add_listener(struct pw_factory *factory, struct spa_hook *listener, const struct pw_factory_events *events, @@ -185,6 +191,7 @@ void pw_factory_add_listener(struct pw_factory *factory, spa_hook_list_append(&factory->listener_list, listener, events, data); } +SPA_EXPORT void pw_factory_set_implementation(struct pw_factory *factory, const struct pw_factory_implementation *implementation, void *data) @@ -193,6 +200,7 @@ void pw_factory_set_implementation(struct pw_factory *factory, factory->implementation_data = data; } +SPA_EXPORT void *pw_factory_create_object(struct pw_factory *factory, struct pw_resource *resource, uint32_t type, diff --git a/src/pipewire/global.c b/src/pipewire/global.c index 32512bca4..00258ff88 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -33,6 +33,7 @@ struct global_impl { /** \endcond */ +SPA_EXPORT uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_client *client) { uint32_t perms = PW_PERM_RWX; @@ -55,6 +56,7 @@ uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_client *c * * \memberof pw_global */ +SPA_EXPORT struct pw_global * pw_global_new(struct pw_core *core, uint32_t type, @@ -95,6 +97,7 @@ pw_global_new(struct pw_core *core, * * \memberof pw_global */ +SPA_EXPORT int pw_global_register(struct pw_global *global, struct pw_client *owner, @@ -135,46 +138,55 @@ pw_global_register(struct pw_global *global, return 0; } +SPA_EXPORT struct pw_core *pw_global_get_core(struct pw_global *global) { return global->core; } +SPA_EXPORT struct pw_client *pw_global_get_owner(struct pw_global *global) { return global->owner; } +SPA_EXPORT struct pw_global *pw_global_get_parent(struct pw_global *global) { return global->parent; } +SPA_EXPORT uint32_t pw_global_get_type(struct pw_global *global) { return global->type; } +SPA_EXPORT uint32_t pw_global_get_version(struct pw_global *global) { return global->version; } +SPA_EXPORT const struct pw_properties *pw_global_get_properties(struct pw_global *global) { return global->properties; } +SPA_EXPORT void * pw_global_get_object(struct pw_global *global) { return global->object; } +SPA_EXPORT uint32_t pw_global_get_id(struct pw_global *global) { return global->id; } +SPA_EXPORT void pw_global_add_listener(struct pw_global *global, struct spa_hook *listener, const struct pw_global_events *events, @@ -196,6 +208,7 @@ void pw_global_add_listener(struct pw_global *global, * * \memberof pw_global */ +SPA_EXPORT int pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t permissions, uint32_t version, uint32_t id) @@ -224,6 +237,7 @@ pw_global_bind(struct pw_global *global, struct pw_client *client, uint32_t perm * * \memberof pw_global */ +SPA_EXPORT void pw_global_destroy(struct pw_global *global) { struct pw_core *core = global->core; diff --git a/src/pipewire/introspect.c b/src/pipewire/introspect.c index bf75f98bc..1e728924b 100644 --- a/src/pipewire/introspect.c +++ b/src/pipewire/introspect.c @@ -23,6 +23,7 @@ #include "pipewire/remote.h" +SPA_EXPORT const char *pw_node_state_as_string(enum pw_node_state state) { switch (state) { @@ -40,6 +41,7 @@ const char *pw_node_state_as_string(enum pw_node_state state) return "invalid-state"; } +SPA_EXPORT const char *pw_direction_as_string(enum pw_direction direction) { switch (direction) { @@ -53,6 +55,7 @@ const char *pw_direction_as_string(enum pw_direction direction) return "invalid-direction"; } +SPA_EXPORT const char *pw_link_state_as_string(enum pw_link_state state) { switch (state) { @@ -115,6 +118,7 @@ static struct spa_dict *pw_spa_dict_copy(struct spa_dict *dict) return NULL; } +SPA_EXPORT struct pw_core_info *pw_core_info_update(struct pw_core_info *info, const struct pw_core_info *update) { @@ -155,6 +159,7 @@ struct pw_core_info *pw_core_info_update(struct pw_core_info *info, return info; } +SPA_EXPORT void pw_core_info_free(struct pw_core_info *info) { free((void *) info->user_name); @@ -166,6 +171,7 @@ void pw_core_info_free(struct pw_core_info *info) free(info); } +SPA_EXPORT struct pw_node_info *pw_node_info_update(struct pw_node_info *info, const struct pw_node_info *update) { @@ -207,6 +213,7 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info, return info; } +SPA_EXPORT void pw_node_info_free(struct pw_node_info *info) { @@ -217,6 +224,7 @@ void pw_node_info_free(struct pw_node_info *info) free(info); } +SPA_EXPORT struct pw_port_info *pw_port_info_update(struct pw_port_info *info, const struct pw_port_info *update) { @@ -244,6 +252,7 @@ struct pw_port_info *pw_port_info_update(struct pw_port_info *info, return info; } +SPA_EXPORT void pw_port_info_free(struct pw_port_info *info) { @@ -253,6 +262,7 @@ void pw_port_info_free(struct pw_port_info *info) free(info); } +SPA_EXPORT struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, const struct pw_factory_info *update) { @@ -279,6 +289,7 @@ struct pw_factory_info *pw_factory_info_update(struct pw_factory_info *info, return info; } +SPA_EXPORT void pw_factory_info_free(struct pw_factory_info *info) { free((void *) info->name); @@ -287,6 +298,7 @@ void pw_factory_info_free(struct pw_factory_info *info) free(info); } +SPA_EXPORT struct pw_module_info *pw_module_info_update(struct pw_module_info *info, const struct pw_module_info *update) { @@ -321,6 +333,7 @@ struct pw_module_info *pw_module_info_update(struct pw_module_info *info, return info; } +SPA_EXPORT void pw_module_info_free(struct pw_module_info *info) { free((void *) info->name); @@ -332,6 +345,7 @@ void pw_module_info_free(struct pw_module_info *info) } +SPA_EXPORT struct pw_client_info *pw_client_info_update(struct pw_client_info *info, const struct pw_client_info *update) { @@ -354,6 +368,7 @@ struct pw_client_info *pw_client_info_update(struct pw_client_info *info, return info; } +SPA_EXPORT void pw_client_info_free(struct pw_client_info *info) { if (info->props) @@ -361,6 +376,7 @@ void pw_client_info_free(struct pw_client_info *info) free(info); } +SPA_EXPORT struct pw_link_info *pw_link_info_update(struct pw_link_info *info, const struct pw_link_info *update) { @@ -390,6 +406,7 @@ struct pw_link_info *pw_link_info_update(struct pw_link_info *info, return info; } +SPA_EXPORT void pw_link_info_free(struct pw_link_info *info) { free(info->format); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index b0b78bfd5..fcea75350 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1086,6 +1086,7 @@ static const struct pw_node_events output_node_events = { .async_complete = output_node_async_complete, }; +SPA_EXPORT struct pw_link *pw_link_new(struct pw_core *core, struct pw_port *output, struct pw_port *input, @@ -1220,6 +1221,7 @@ static const struct pw_global_events global_events = { .bind = global_bind, }; +SPA_EXPORT int pw_link_register(struct pw_link *link, struct pw_client *owner, struct pw_global *parent, @@ -1272,6 +1274,7 @@ int pw_link_register(struct pw_link *link, return 0; } +SPA_EXPORT void pw_link_destroy(struct pw_link *link) { struct impl *impl = SPA_CONTAINER_OF(link, struct impl, this); @@ -1312,6 +1315,7 @@ void pw_link_destroy(struct pw_link *link) free(impl); } +SPA_EXPORT void pw_link_add_listener(struct pw_link *link, struct spa_hook *listener, const struct pw_link_events *events, @@ -1321,6 +1325,7 @@ void pw_link_add_listener(struct pw_link *link, spa_hook_list_append(&link->listener_list, listener, events, data); } +SPA_EXPORT struct pw_link *pw_link_find(struct pw_port *output_port, struct pw_port *input_port) { struct pw_link *pl; @@ -1332,31 +1337,37 @@ struct pw_link *pw_link_find(struct pw_port *output_port, struct pw_port *input_ return NULL; } +SPA_EXPORT struct pw_core *pw_link_get_core(struct pw_link *link) { return link->core; } +SPA_EXPORT void *pw_link_get_user_data(struct pw_link *link) { return link->user_data; } +SPA_EXPORT const struct pw_link_info *pw_link_get_info(struct pw_link *link) { return &link->info; } +SPA_EXPORT struct pw_global *pw_link_get_global(struct pw_link *link) { return link->global; } +SPA_EXPORT struct pw_port *pw_link_get_output(struct pw_link *link) { return link->output; } +SPA_EXPORT struct pw_port *pw_link_get_input(struct pw_link *link) { return link->input; diff --git a/src/pipewire/log.c b/src/pipewire/log.c index 80835281f..ab6ebba97 100644 --- a/src/pipewire/log.c +++ b/src/pipewire/log.c @@ -21,7 +21,7 @@ #define DEFAULT_LOG_LEVEL SPA_LOG_LEVEL_ERROR -enum spa_log_level pw_log_level = DEFAULT_LOG_LEVEL; +SPA_EXPORT enum spa_log_level pw_log_level = DEFAULT_LOG_LEVEL; static struct spa_log *global_log = NULL; @@ -29,6 +29,7 @@ static struct spa_log *global_log = NULL; * \param log the global log to set * \memberof pw_log */ +SPA_EXPORT void pw_log_set(struct spa_log *log) { global_log = log; @@ -40,6 +41,7 @@ void pw_log_set(struct spa_log *log) * \return the global log * \memberof pw_log */ +SPA_EXPORT struct spa_log *pw_log_get(void) { return global_log; @@ -49,6 +51,7 @@ struct spa_log *pw_log_get(void) * \param level the new log level * \memberof pw_log */ +SPA_EXPORT void pw_log_set_level(enum spa_log_level level) { pw_log_level = level; @@ -66,6 +69,7 @@ void pw_log_set_level(enum spa_log_level level) * * \memberof pw_log */ +SPA_EXPORT void pw_log_log(enum spa_log_level level, const char *file, @@ -91,6 +95,7 @@ pw_log_log(enum spa_log_level level, * * \memberof pw_log */ +SPA_EXPORT void pw_log_logv(enum spa_log_level level, const char *file, diff --git a/src/pipewire/loop.c b/src/pipewire/loop.c index 6944125fb..a34dfdd1f 100644 --- a/src/pipewire/loop.c +++ b/src/pipewire/loop.c @@ -41,6 +41,7 @@ struct impl { * \returns a newly allocated loop * \memberof pw_loop */ +SPA_EXPORT struct pw_loop *pw_loop_new(struct pw_properties *properties) { int res; @@ -116,6 +117,7 @@ struct pw_loop *pw_loop_new(struct pw_properties *properties) * \param loop a loop to destroy * \memberof pw_loop */ +SPA_EXPORT void pw_loop_destroy(struct pw_loop *loop) { struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); diff --git a/src/pipewire/main-loop.c b/src/pipewire/main-loop.c index a36b1ebbb..6a0a5942a 100644 --- a/src/pipewire/main-loop.c +++ b/src/pipewire/main-loop.c @@ -33,6 +33,7 @@ static void do_stop(void *data, uint64_t count) * * \memberof pw_main_loop */ +SPA_EXPORT struct pw_main_loop *pw_main_loop_new(struct pw_properties *properties) { struct pw_main_loop *this; @@ -63,6 +64,7 @@ struct pw_main_loop *pw_main_loop_new(struct pw_properties *properties) * * \memberof pw_main_loop */ +SPA_EXPORT void pw_main_loop_destroy(struct pw_main_loop *loop) { pw_log_debug("main-loop %p: destroy", loop); @@ -73,6 +75,7 @@ void pw_main_loop_destroy(struct pw_main_loop *loop) free(loop); } +SPA_EXPORT void pw_main_loop_add_listener(struct pw_main_loop *loop, struct spa_hook *listener, const struct pw_main_loop_events *events, @@ -81,6 +84,7 @@ void pw_main_loop_add_listener(struct pw_main_loop *loop, spa_hook_list_append(&loop->listener_list, listener, events, data); } +SPA_EXPORT struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop) { return loop->loop; @@ -93,6 +97,7 @@ struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop) * * \memberof pw_main_loop */ +SPA_EXPORT void pw_main_loop_quit(struct pw_main_loop *loop) { pw_log_debug("main-loop %p: quit", loop); @@ -107,6 +112,7 @@ void pw_main_loop_quit(struct pw_main_loop *loop) * * \memberof pw_main_loop */ +SPA_EXPORT void pw_main_loop_run(struct pw_main_loop *loop) { pw_log_debug("main-loop %p: run", loop); diff --git a/src/pipewire/mem.c b/src/pipewire/mem.c index a5767e07a..355ffa67c 100644 --- a/src/pipewire/mem.c +++ b/src/pipewire/mem.c @@ -93,6 +93,7 @@ static struct spa_list _memblocks = SPA_LIST_INIT(&_memblocks); * \return 0 on success, < 0 on error * \memberof pw_memblock */ +SPA_EXPORT int pw_memblock_map(struct pw_memblock *mem) { if (mem->ptr != NULL) @@ -149,6 +150,7 @@ int pw_memblock_map(struct pw_memblock *mem) * \return 0 on success, < 0 on error * \memberof pw_memblock */ +SPA_EXPORT int pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_memblock **mem) { struct memblock tmp, *p; @@ -224,6 +226,7 @@ int pw_memblock_alloc(enum pw_memblock_flags flags, size_t size, struct pw_membl return -ENOMEM; } +SPA_EXPORT int pw_memblock_import(enum pw_memblock_flags flags, int fd, off_t offset, size_t size, @@ -248,6 +251,7 @@ pw_memblock_import(enum pw_memblock_flags flags, * \param mem a memblock * \memberof pw_memblock */ +SPA_EXPORT void pw_memblock_free(struct pw_memblock *mem) { struct memblock *m = (struct memblock *)mem; @@ -268,6 +272,7 @@ void pw_memblock_free(struct pw_memblock *mem) free(mem); } +SPA_EXPORT struct pw_memblock * pw_memblock_find(const void *ptr) { struct memblock *m; diff --git a/src/pipewire/module.c b/src/pipewire/module.c index d89235240..de069a0c8 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -162,6 +162,7 @@ static const struct pw_global_events global_events = { * * \memberof pw_module */ +SPA_EXPORT struct pw_module * pw_module_load(struct pw_core *core, const char *name, const char *args, @@ -282,6 +283,7 @@ pw_module_load(struct pw_core *core, * \param module the module to destroy * \memberof pw_module */ +SPA_EXPORT void pw_module_destroy(struct pw_module *module) { struct impl *impl = SPA_CONTAINER_OF(module, struct impl, this); @@ -307,23 +309,27 @@ void pw_module_destroy(struct pw_module *module) free(impl); } +SPA_EXPORT struct pw_core * pw_module_get_core(struct pw_module *module) { return module->core; } +SPA_EXPORT struct pw_global * pw_module_get_global(struct pw_module *module) { return module->global; } +SPA_EXPORT const struct pw_module_info * pw_module_get_info(struct pw_module *module) { return &module->info; } +SPA_EXPORT void pw_module_add_listener(struct pw_module *module, struct spa_hook *listener, const struct pw_module_events *events, diff --git a/src/pipewire/node.c b/src/pipewire/node.c index e5a1fc110..24f5cbb71 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -325,6 +325,7 @@ static const struct pw_global_events global_events = { .bind = global_bind, }; +SPA_EXPORT int pw_node_register(struct pw_node *this, struct pw_client *owner, struct pw_global *parent, @@ -392,6 +393,7 @@ static void check_properties(struct pw_node *node) impl->pause_on_idle = true; } +SPA_EXPORT struct pw_node *pw_node_new(struct pw_core *core, const char *name, struct pw_properties *properties, @@ -449,31 +451,37 @@ struct pw_node *pw_node_new(struct pw_core *core, return NULL; } +SPA_EXPORT const struct pw_node_info *pw_node_get_info(struct pw_node *node) { return &node->info; } +SPA_EXPORT void * pw_node_get_user_data(struct pw_node *node) { return node->user_data; } +SPA_EXPORT struct pw_core * pw_node_get_core(struct pw_node *node) { return node->core; } +SPA_EXPORT struct pw_global *pw_node_get_global(struct pw_node *node) { return node->global; } +SPA_EXPORT const struct pw_properties *pw_node_get_properties(struct pw_node *node) { return node->properties; } +SPA_EXPORT int pw_node_update_properties(struct pw_node *node, const struct spa_dict *dict) { struct pw_resource *resource; @@ -564,6 +572,7 @@ static const struct spa_node_callbacks node_callbacks = { }; +SPA_EXPORT void pw_node_set_implementation(struct pw_node *node, struct spa_node *spa_node) { @@ -575,11 +584,13 @@ void pw_node_set_implementation(struct pw_node *node, pw_node_update_properties(node, spa_node->info); } +SPA_EXPORT struct spa_node *pw_node_get_implementation(struct pw_node *node) { return node->node; } +SPA_EXPORT void pw_node_add_listener(struct pw_node *node, struct spa_hook *listener, const struct pw_node_events *events, @@ -609,6 +620,7 @@ do_node_remove(struct spa_loop *loop, * * \memberof pw_node */ +SPA_EXPORT void pw_node_destroy(struct pw_node *node) { struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); @@ -681,6 +693,7 @@ int pw_node_for_each_port(struct pw_node *node, return 0; } +SPA_EXPORT int pw_node_for_each_param(struct pw_node *node, uint32_t param_id, uint32_t index, uint32_t max, @@ -860,6 +873,7 @@ static void node_activate(struct pw_node *this) * * \memberof pw_node */ +SPA_EXPORT int pw_node_set_state(struct pw_node *node, enum pw_node_state state) { int res = 0; @@ -946,6 +960,7 @@ void pw_node_update_state(struct pw_node *node, enum pw_node_state state, char * } } +SPA_EXPORT int pw_node_set_active(struct pw_node *node, bool active) { bool old = node->active; @@ -964,11 +979,13 @@ int pw_node_set_active(struct pw_node *node, bool active) return 0; } +SPA_EXPORT bool pw_node_is_active(struct pw_node *node) { return node->active; } +SPA_EXPORT int pw_node_set_enabled(struct pw_node *node, bool enabled) { bool old = node->enabled; @@ -989,6 +1006,7 @@ int pw_node_set_enabled(struct pw_node *node, bool enabled) return 0; } +SPA_EXPORT bool pw_node_is_enabled(struct pw_node *node) { return node->enabled; diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index d1c6746b8..2160c29e2 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -72,7 +72,7 @@ open_support(const char *path, goto open_failed; } if ((info->enum_func = dlsym(info->hnd, SPA_HANDLE_FACTORY_ENUM_FUNC_NAME)) == NULL) { - fprintf(stderr, "can't find enum function\n"); + fprintf(stderr, "can't find enum function in %s\n", filename); goto no_symbol; } free(filename); @@ -173,6 +173,7 @@ static void configure_debug(const char *str) * \param type the interface type * \return the interface or NULL when not configured */ +SPA_EXPORT void *pw_get_support_interface(const char *type) { int i; @@ -184,17 +185,20 @@ void *pw_get_support_interface(const char *type) return NULL; } +SPA_EXPORT const struct spa_handle_factory *pw_get_support_factory(const char *factory_name) { return get_factory(&support_info, factory_name); } +SPA_EXPORT const struct spa_support *pw_get_support(uint32_t *n_support) { *n_support = support_info.n_support; return support_info.support; } +SPA_EXPORT void *pw_get_spa_dbus(struct pw_loop *loop) { struct support_info dbus_support_info; @@ -228,6 +232,7 @@ static struct interface *find_interface(void *iface) return NULL; } +SPA_EXPORT int pw_release_spa_dbus(void *dbus) { struct interface *iface; @@ -254,6 +259,7 @@ int pw_release_spa_dbus(void *dbus) * * \memberof pw_pipewire */ +SPA_EXPORT void pw_init(int *argc, char **argv[]) { const char *str; @@ -295,6 +301,7 @@ void pw_init(int *argc, char **argv[]) * * \memberof pw_pipewire */ +SPA_EXPORT bool pw_debug_is_category_enabled(const char *name) { int i; @@ -310,12 +317,14 @@ bool pw_debug_is_category_enabled(const char *name) } /** Get the application name \memberof pw_pipewire */ +SPA_EXPORT const char *pw_get_application_name(void) { return NULL; } /** Get the program name \memberof pw_pipewire */ +SPA_EXPORT const char *pw_get_prgname(void) { static char tcomm[16 + 1]; @@ -328,6 +337,7 @@ const char *pw_get_prgname(void) } /** Get the user name \memberof pw_pipewire */ +SPA_EXPORT const char *pw_get_user_name(void) { struct passwd *pw; @@ -339,6 +349,7 @@ const char *pw_get_user_name(void) } /** Get the host name \memberof pw_pipewire */ +SPA_EXPORT const char *pw_get_host_name(void) { static char hname[256]; @@ -356,6 +367,7 @@ const char *pw_get_host_name(void) * * \memberof pw_pipewire */ +SPA_EXPORT char *pw_get_client_name(void) { char *c; @@ -379,6 +391,7 @@ char *pw_get_client_name(void) * * \memberof pw_pipewire */ +SPA_EXPORT void pw_fill_remote_properties(struct pw_core *core, struct pw_properties *properties) { const char *val; @@ -419,6 +432,7 @@ void pw_fill_remote_properties(struct pw_core *core, struct pw_properties *prope * * \memberof pw_pipewire */ +SPA_EXPORT void pw_fill_stream_properties(struct pw_core *core, struct pw_properties *properties) { } @@ -434,6 +448,7 @@ enum pw_direction pw_direction_reverse(enum pw_direction direction) } /** Get the currently running version */ +SPA_EXPORT const char* pw_get_library_version(void) { return pw_get_headers_version(); diff --git a/src/pipewire/port.c b/src/pipewire/port.c index da5065b86..3a9b268d9 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -230,21 +230,25 @@ struct pw_port *pw_port_new(enum pw_direction direction, return NULL; } +SPA_EXPORT enum pw_direction pw_port_get_direction(struct pw_port *port) { return port->direction; } +SPA_EXPORT uint32_t pw_port_get_id(struct pw_port *port) { return port->port_id; } +SPA_EXPORT const struct pw_properties *pw_port_get_properties(struct pw_port *port) { return port->properties; } +SPA_EXPORT int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict) { struct pw_resource *resource; @@ -270,11 +274,13 @@ int pw_port_update_properties(struct pw_port *port, const struct spa_dict *dict) return changed; } +SPA_EXPORT struct pw_node *pw_port_get_node(struct pw_port *port) { return port->node; } +SPA_EXPORT void pw_port_add_listener(struct pw_port *port, struct spa_hook *listener, const struct pw_port_events *events, diff --git a/src/pipewire/properties.c b/src/pipewire/properties.c index 5c493b01d..d3e462bf7 100644 --- a/src/pipewire/properties.c +++ b/src/pipewire/properties.c @@ -85,6 +85,7 @@ static struct properties *properties_new(int prealloc) * * \memberof pw_properties */ +SPA_EXPORT struct pw_properties *pw_properties_new(const char *key, ...) { struct properties *impl; @@ -114,6 +115,7 @@ struct pw_properties *pw_properties_new(const char *key, ...) * * \memberof pw_properties */ +SPA_EXPORT struct pw_properties *pw_properties_new_dict(const struct spa_dict *dict) { uint32_t i; @@ -142,6 +144,7 @@ struct pw_properties *pw_properties_new_dict(const struct spa_dict *dict) * * \memberof pw_properties */ +SPA_EXPORT struct pw_properties * pw_properties_new_string(const char *str) { @@ -176,6 +179,7 @@ pw_properties_new_string(const char *str) * * \memberof pw_properties */ +SPA_EXPORT struct pw_properties *pw_properties_copy(const struct pw_properties *properties) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); @@ -203,6 +207,7 @@ struct pw_properties *pw_properties_copy(const struct pw_properties *properties) * * \memberof pw_properties */ +SPA_EXPORT struct pw_properties *pw_properties_merge(const struct pw_properties *oldprops, struct pw_properties *newprops) { @@ -236,6 +241,7 @@ struct pw_properties *pw_properties_merge(const struct pw_properties *oldprops, * * \memberof pw_properties */ +SPA_EXPORT void pw_properties_free(struct pw_properties *properties) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); @@ -298,11 +304,13 @@ static int do_replace(struct pw_properties *properties, const char *key, char *v * * \memberof pw_properties */ +SPA_EXPORT int pw_properties_set(struct pw_properties *properties, const char *key, const char *value) { return do_replace(properties, key, (char*)value, true); } +SPA_EXPORT int pw_properties_setva(struct pw_properties *properties, const char *key, const char *format, va_list args) @@ -326,6 +334,7 @@ pw_properties_setva(struct pw_properties *properties, * * \memberof pw_properties */ +SPA_EXPORT int pw_properties_setf(struct pw_properties *properties, const char *key, const char *format, ...) { int res; @@ -348,6 +357,7 @@ int pw_properties_setf(struct pw_properties *properties, const char *key, const * * \memberof pw_properties */ +SPA_EXPORT const char *pw_properties_get(const struct pw_properties *properties, const char *key) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); @@ -372,6 +382,7 @@ const char *pw_properties_get(const struct pw_properties *properties, const char * * \memberof pw_properties */ +SPA_EXPORT const char *pw_properties_iterate(const struct pw_properties *properties, void **state) { struct properties *impl = SPA_CONTAINER_OF(properties, struct properties, this); diff --git a/src/pipewire/protocol.c b/src/pipewire/protocol.c index 39f594099..da1004c78 100644 --- a/src/pipewire/protocol.c +++ b/src/pipewire/protocol.c @@ -34,6 +34,7 @@ struct marshal { }; /** \endcond */ +SPA_EXPORT struct pw_protocol *pw_protocol_new(struct pw_core *core, const char *name, size_t user_data_size) @@ -62,23 +63,27 @@ struct pw_protocol *pw_protocol_new(struct pw_core *core, return protocol; } +SPA_EXPORT void *pw_protocol_get_user_data(struct pw_protocol *protocol) { return protocol->user_data; } +SPA_EXPORT const struct pw_protocol_implementaton * pw_protocol_get_implementation(struct pw_protocol *protocol) { return protocol->implementation; } +SPA_EXPORT const void * pw_protocol_get_extension(struct pw_protocol *protocol) { return protocol->extension; } +SPA_EXPORT void pw_protocol_destroy(struct pw_protocol *protocol) { struct impl *impl = SPA_CONTAINER_OF(protocol, struct impl, this); @@ -105,6 +110,7 @@ void pw_protocol_destroy(struct pw_protocol *protocol) free(impl); } +SPA_EXPORT void pw_protocol_add_listener(struct pw_protocol *protocol, struct spa_hook *listener, const struct pw_protocol_events *events, @@ -113,6 +119,7 @@ void pw_protocol_add_listener(struct pw_protocol *protocol, spa_hook_list_append(&protocol->listener_list, listener, events, data); } +SPA_EXPORT int pw_protocol_add_marshal(struct pw_protocol *protocol, const struct pw_protocol_marshal *marshal) @@ -134,6 +141,7 @@ pw_protocol_add_marshal(struct pw_protocol *protocol, return 0; } +SPA_EXPORT const struct pw_protocol_marshal * pw_protocol_get_marshal(struct pw_protocol *protocol, uint32_t type) { @@ -149,6 +157,7 @@ pw_protocol_get_marshal(struct pw_protocol *protocol, uint32_t type) return NULL; } +SPA_EXPORT struct pw_protocol *pw_core_find_protocol(struct pw_core *core, const char *name) { struct pw_protocol *protocol; diff --git a/src/pipewire/proxy.c b/src/pipewire/proxy.c index 641522429..df4cd435a 100644 --- a/src/pipewire/proxy.c +++ b/src/pipewire/proxy.c @@ -43,6 +43,7 @@ struct proxy { * * \memberof pw_proxy */ +SPA_EXPORT struct pw_proxy *pw_proxy_new(struct pw_proxy *factory, uint32_t type, size_t user_data_size) @@ -75,21 +76,25 @@ struct pw_proxy *pw_proxy_new(struct pw_proxy *factory, return this; } +SPA_EXPORT void *pw_proxy_get_user_data(struct pw_proxy *proxy) { return proxy->user_data; } +SPA_EXPORT uint32_t pw_proxy_get_id(struct pw_proxy *proxy) { return proxy->id; } +SPA_EXPORT struct pw_protocol *pw_proxy_get_protocol(struct pw_proxy *proxy) { return proxy->remote->conn->protocol; } +SPA_EXPORT void pw_proxy_add_listener(struct pw_proxy *proxy, struct spa_hook *listener, const struct pw_proxy_events *events, @@ -98,6 +103,7 @@ void pw_proxy_add_listener(struct pw_proxy *proxy, spa_hook_list_append(&proxy->listener_list, listener, events, data); } +SPA_EXPORT void pw_proxy_add_proxy_listener(struct pw_proxy *proxy, struct spa_hook *listener, const void *events, @@ -114,6 +120,7 @@ void pw_proxy_add_proxy_listener(struct pw_proxy *proxy, * decides to destroy the server side object * \memberof pw_proxy */ +SPA_EXPORT void pw_proxy_destroy(struct pw_proxy *proxy) { struct proxy *impl = SPA_CONTAINER_OF(proxy, struct proxy, this); @@ -127,11 +134,13 @@ void pw_proxy_destroy(struct pw_proxy *proxy) free(impl); } +SPA_EXPORT struct spa_hook_list *pw_proxy_get_proxy_listeners(struct pw_proxy *proxy) { return &proxy->proxy_listener_list; } +SPA_EXPORT const struct pw_protocol_marshal *pw_proxy_get_marshal(struct pw_proxy *proxy) { return proxy->marshal; diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 6b93d841e..9887fcba8 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -103,6 +103,7 @@ struct node_data { /** \endcond */ +SPA_EXPORT const char *pw_remote_state_as_string(enum pw_remote_state state) { switch (state) { @@ -208,6 +209,7 @@ static const struct pw_core_proxy_events core_proxy_events = { .info = core_event_info, }; +SPA_EXPORT struct pw_remote *pw_remote_new(struct pw_core *core, struct pw_properties *properties, size_t user_data_size) @@ -286,6 +288,7 @@ struct pw_remote *pw_remote_new(struct pw_core *core, return NULL; } +SPA_EXPORT void pw_remote_destroy(struct pw_remote *remote) { struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this); @@ -311,21 +314,25 @@ void pw_remote_destroy(struct pw_remote *remote) free(impl); } +SPA_EXPORT struct pw_core *pw_remote_get_core(struct pw_remote *remote) { return remote->core; } +SPA_EXPORT const struct pw_properties *pw_remote_get_properties(struct pw_remote *remote) { return remote->properties; } +SPA_EXPORT void *pw_remote_get_user_data(struct pw_remote *remote) { return remote->user_data; } +SPA_EXPORT enum pw_remote_state pw_remote_get_state(struct pw_remote *remote, const char **error) { if (error) @@ -333,6 +340,7 @@ enum pw_remote_state pw_remote_get_state(struct pw_remote *remote, const char ** return remote->state; } +SPA_EXPORT void pw_remote_add_listener(struct pw_remote *remote, struct spa_hook *listener, const struct pw_remote_events *events, @@ -366,16 +374,19 @@ static int do_connect(struct pw_remote *remote) return -ENOMEM; } +SPA_EXPORT struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote) { return remote->core_proxy; } +SPA_EXPORT const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote) { return remote->info; } +SPA_EXPORT struct pw_proxy *pw_remote_find_proxy(struct pw_remote *remote, uint32_t id) { return pw_map_lookup(&remote->objects, id); @@ -393,6 +404,7 @@ static void done_connect(void *data, int result) do_connect(remote); } +SPA_EXPORT int pw_remote_connect(struct pw_remote *remote) { int res; @@ -407,6 +419,7 @@ int pw_remote_connect(struct pw_remote *remote) return remote->state == PW_REMOTE_STATE_ERROR ? -EIO : 0; } +SPA_EXPORT int pw_remote_connect_fd(struct pw_remote *remote, int fd) { int res; @@ -422,6 +435,7 @@ int pw_remote_connect_fd(struct pw_remote *remote, int fd) return do_connect(remote); } +SPA_EXPORT int pw_remote_steal_fd(struct pw_remote *remote) { int fd; @@ -432,6 +446,7 @@ int pw_remote_steal_fd(struct pw_remote *remote) return fd; } +SPA_EXPORT int pw_remote_disconnect(struct pw_remote *remote) { struct pw_proxy *proxy, *t2; @@ -1318,6 +1333,7 @@ static const struct spa_node node_impl = { .port_reuse_buffer = impl_port_reuse_buffer, }; +SPA_EXPORT struct pw_proxy *pw_remote_export(struct pw_remote *remote, struct pw_node *node) { diff --git a/src/pipewire/resource.c b/src/pipewire/resource.c index 2299b6e5e..21959ca31 100644 --- a/src/pipewire/resource.c +++ b/src/pipewire/resource.c @@ -30,6 +30,7 @@ struct impl { }; /** \endcond */ +SPA_EXPORT struct pw_resource *pw_resource_new(struct pw_client *client, uint32_t id, uint32_t permissions, @@ -78,36 +79,43 @@ struct pw_resource *pw_resource_new(struct pw_client *client, return NULL; } +SPA_EXPORT struct pw_client *pw_resource_get_client(struct pw_resource *resource) { return resource->client; } +SPA_EXPORT uint32_t pw_resource_get_id(struct pw_resource *resource) { return resource->id; } +SPA_EXPORT uint32_t pw_resource_get_permissions(struct pw_resource *resource) { return resource->permissions; } +SPA_EXPORT uint32_t pw_resource_get_type(struct pw_resource *resource) { return resource->type; } +SPA_EXPORT struct pw_protocol *pw_resource_get_protocol(struct pw_resource *resource) { return resource->client->protocol; } +SPA_EXPORT void *pw_resource_get_user_data(struct pw_resource *resource) { return resource->user_data; } +SPA_EXPORT void pw_resource_add_listener(struct pw_resource *resource, struct spa_hook *listener, const struct pw_resource_events *events, @@ -116,6 +124,7 @@ void pw_resource_add_listener(struct pw_resource *resource, spa_hook_list_append(&resource->listener_list, listener, events, data); } +SPA_EXPORT void pw_resource_set_implementation(struct pw_resource *resource, const void *implementation, void *data) @@ -128,6 +137,7 @@ void pw_resource_set_implementation(struct pw_resource *resource, pw_client_events_resource_impl(client, resource); } +SPA_EXPORT void pw_resource_add_override(struct pw_resource *resource, struct spa_hook *listener, const void *implementation, @@ -136,22 +146,26 @@ void pw_resource_add_override(struct pw_resource *resource, spa_hook_list_prepend(&resource->implementation_list, listener, implementation, data); } +SPA_EXPORT struct spa_hook_list *pw_resource_get_implementation(struct pw_resource *resource) { return &resource->implementation_list; } +SPA_EXPORT const struct pw_protocol_marshal *pw_resource_get_marshal(struct pw_resource *resource) { return resource->marshal; } +SPA_EXPORT void pw_resource_error(struct pw_resource *resource, int result, const char *error) { if (resource->client->core_resource) pw_core_resource_error(resource->client->core_resource, resource->id, result, error); } +SPA_EXPORT void pw_resource_destroy(struct pw_resource *resource) { struct pw_client *client = resource->client; diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index 0f3a5bdee..be02aa8b4 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -348,6 +348,7 @@ static void call_process(struct stream *impl) } } +SPA_EXPORT const char *pw_stream_state_as_string(enum pw_stream_state state) { switch (state) { @@ -369,6 +370,7 @@ const char *pw_stream_state_as_string(enum pw_stream_state state) return "invalid-state"; } +SPA_EXPORT struct pw_stream *pw_stream_new(struct pw_remote *remote, const char *name, struct pw_properties *props) { @@ -422,6 +424,7 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, return NULL; } +SPA_EXPORT struct pw_stream * pw_stream_new_simple(struct pw_loop *loop, const char *name, struct pw_properties *props, const struct pw_stream_events *events, void *data) @@ -429,6 +432,7 @@ pw_stream_new_simple(struct pw_loop *loop, const char *name, struct pw_propertie return NULL; } +SPA_EXPORT enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error) { if (error) @@ -436,16 +440,19 @@ enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char ** return stream->state; } +SPA_EXPORT const char *pw_stream_get_name(struct pw_stream *stream) { return stream->name; } +SPA_EXPORT const struct pw_properties *pw_stream_get_properties(struct pw_stream *stream) { return stream->properties; } +SPA_EXPORT void pw_stream_add_listener(struct pw_stream *stream, struct spa_hook *listener, const struct pw_stream_events *events, @@ -525,6 +532,7 @@ static void set_params(struct pw_stream *stream, int n_params, const struct spa_ } } +SPA_EXPORT void pw_stream_destroy(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1246,6 +1254,7 @@ static const struct pw_proxy_events proxy_events = { .destroy = on_node_proxy_destroy, }; +SPA_EXPORT int pw_stream_connect(struct pw_stream *stream, enum pw_direction direction, @@ -1286,18 +1295,21 @@ pw_stream_connect(struct pw_stream *stream, return 0; } +SPA_EXPORT struct pw_remote * pw_stream_get_remote(struct pw_stream *stream) { return stream->remote; } +SPA_EXPORT uint32_t pw_stream_get_node_id(struct pw_stream *stream) { return stream->node_id; } +SPA_EXPORT void pw_stream_finish_format(struct pw_stream *stream, int res, @@ -1323,6 +1335,7 @@ pw_stream_finish_format(struct pw_stream *stream, impl->pending_seq = SPA_ID_INVALID; } +SPA_EXPORT int pw_stream_disconnect(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1340,6 +1353,7 @@ int pw_stream_disconnect(struct pw_stream *stream) return 0; } +SPA_EXPORT int pw_stream_set_active(struct pw_stream *stream, bool active) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1352,6 +1366,7 @@ static inline int64_t get_queue_size(struct queue *queue) return (int64_t)(queue->incount - queue->outcount); } +SPA_EXPORT int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1371,16 +1386,19 @@ int pw_stream_get_time(struct pw_stream *stream, struct pw_time *time) return 0; } +SPA_EXPORT int pw_stream_set_control(struct pw_stream *stream, const char *name, float value) { return -ENOTSUP; } +SPA_EXPORT int pw_stream_get_control(struct pw_stream *stream, const char *name, float *value) { return -ENOTSUP; } +SPA_EXPORT struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -1395,6 +1413,7 @@ struct pw_buffer *pw_stream_dequeue_buffer(struct pw_stream *stream) return &b->buffer; } +SPA_EXPORT int pw_stream_queue_buffer(struct pw_stream *stream, struct pw_buffer *buffer) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index 77b860356..c7c7fc07f 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -96,6 +96,7 @@ do { \ * * \memberof pw_thread_loop */ +SPA_EXPORT struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, const char *name) { @@ -145,6 +146,7 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, } /** Destroy a threaded loop \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_destroy(struct pw_thread_loop *loop) { pw_thread_loop_events_destroy(loop); @@ -163,6 +165,7 @@ void pw_thread_loop_destroy(struct pw_thread_loop *loop) free(loop); } +SPA_EXPORT void pw_thread_loop_add_listener(struct pw_thread_loop *loop, struct spa_hook *listener, const struct pw_thread_loop_events *events, @@ -171,6 +174,7 @@ void pw_thread_loop_add_listener(struct pw_thread_loop *loop, spa_hook_list_append(&loop->listener_list, listener, events, data); } +SPA_EXPORT struct pw_loop * pw_thread_loop_get_loop(struct pw_thread_loop *loop) { @@ -204,6 +208,7 @@ static void *do_loop(void *user_data) * * \memberof pw_thread_loop */ +SPA_EXPORT int pw_thread_loop_start(struct pw_thread_loop *loop) { if (!loop->running) { @@ -226,6 +231,7 @@ int pw_thread_loop_start(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_stop(struct pw_thread_loop *loop) { pw_log_debug("thread-loop: %p stopping", loop); @@ -246,6 +252,7 @@ void pw_thread_loop_stop(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_lock(struct pw_thread_loop *loop) { pthread_mutex_lock(&loop->lock); @@ -257,6 +264,7 @@ void pw_thread_loop_lock(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_unlock(struct pw_thread_loop *loop) { pthread_mutex_unlock(&loop->lock); @@ -272,6 +280,7 @@ void pw_thread_loop_unlock(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept) { if (loop->n_waiting > 0) @@ -291,6 +300,7 @@ void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_wait(struct pw_thread_loop *loop) { loop->n_waiting++; @@ -307,6 +317,7 @@ void pw_thread_loop_wait(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT int pw_thread_loop_timed_wait(struct pw_thread_loop *loop, int wait_max_sec) { struct timespec timeout; @@ -328,6 +339,7 @@ int pw_thread_loop_timed_wait(struct pw_thread_loop *loop, int wait_max_sec) * * \memberof pw_thread_loop */ +SPA_EXPORT void pw_thread_loop_accept(struct pw_thread_loop *loop) { loop->n_waiting_for_accept--; @@ -341,6 +353,7 @@ void pw_thread_loop_accept(struct pw_thread_loop *loop) * * \memberof pw_thread_loop */ +SPA_EXPORT bool pw_thread_loop_in_thread(struct pw_thread_loop *loop) { return pthread_self() == loop->thread; diff --git a/src/pipewire/utils.c b/src/pipewire/utils.c index 744997d27..dfcf248f5 100644 --- a/src/pipewire/utils.c +++ b/src/pipewire/utils.c @@ -36,6 +36,7 @@ * * \memberof pw_utils */ +SPA_EXPORT const char *pw_split_walk(const char *str, const char *delimiter, size_t * len, const char **state) { const char *s = *state ? *state : str; @@ -61,6 +62,7 @@ const char *pw_split_walk(const char *str, const char *delimiter, size_t * len, * * \memberof pw_utils */ +SPA_EXPORT char **pw_split_strv(const char *str, const char *delimiter, int max_tokens, int *n_tokens) { const char *state = NULL, *s = NULL; @@ -94,6 +96,7 @@ char **pw_split_strv(const char *str, const char *delimiter, int max_tokens, int * * \memberof pw_utils */ +SPA_EXPORT void pw_free_strv(char **str) { int i; @@ -112,6 +115,7 @@ void pw_free_strv(char **str) * * \memberof pw_utils */ +SPA_EXPORT char *pw_strip(char *str, const char *whitespace) { char *e, *l = NULL; From 737851df6c09c7b583a298876cfcf867745abb8d Mon Sep 17 00:00:00 2001 From: ncraun-vivint <43623033+ncraun-vivint@users.noreply.github.com> Date: Mon, 28 Jan 2019 11:01:19 -0500 Subject: [PATCH 106/155] Quote "$@" in autogen.sh An unquoted $@ will break for arguments with spaces in their names. Unquoted $@ will work until it doesn't, and then it can be tricky to track down exactly what went wrong. Using "$@" will save someone some headache in the future. --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 97970dfa0..eacc495c9 100755 --- a/autogen.sh +++ b/autogen.sh @@ -19,5 +19,5 @@ rm -rf ./build mkdir build -meson build $@ +meson build "$@" ln -s build/Makefile Makefile From 181a6a2cead2d260cddb309bcdb02b14f913a745 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 13 Feb 2019 21:01:06 +0100 Subject: [PATCH 107/155] v4l2: do not keep non-capture devices open If VIDIOC_QUERYCAP fails, or V4L2_CAP_VIDEO_CAPTURE is not set, spa_v4l2_open should close the port file descriptor again. --- spa/plugins/v4l2/v4l2-utils.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 34bb2bcda..024f44aa7 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -80,6 +80,8 @@ static int spa_v4l2_open(struct impl *this) if (xioctl(port->fd, VIDIOC_QUERYCAP, &port->cap) < 0) { err = errno; spa_log_error(port->log, "QUERYCAP: %m"); + close(port->fd); + port->fd = -1; return -err; } @@ -87,6 +89,8 @@ static int spa_v4l2_open(struct impl *this) ((port->cap.capabilities & V4L2_CAP_DEVICE_CAPS) && (port->cap.device_caps & V4L2_CAP_VIDEO_CAPTURE) == 0)) { spa_log_error(port->log, "v4l2: %s is no video capture device", props->device); + close(port->fd); + port->fd = -1; return -ENODEV; } From bdc81f6dc03c583c64fc6fa81f49fef8cc1e59fb Mon Sep 17 00:00:00 2001 From: Matthias Fend Date: Mon, 25 Mar 2019 13:04:12 +0100 Subject: [PATCH 108/155] daemon: use correct type for getopt_long() return value Depending on the compiler configuration 'char' may be an unsigned type which will not work as expected. Signed-off-by: Matthias Fend --- src/daemon/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/daemon/main.c b/src/daemon/main.c index 96f78b482..1c50951bd 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -59,7 +59,7 @@ int main(int argc, char *argv[]) {"name", 1, NULL, 'n'}, {NULL, 0, NULL, 0} }; - char c; + int c; pw_init(&argc, &argv); From 6e7db20bf5d0fbbee54232cdfa925a345f471966 Mon Sep 17 00:00:00 2001 From: Nicolas Dufresne Date: Tue, 30 Oct 2018 16:20:39 +0000 Subject: [PATCH 109/155] rtkit: Allow disabling with DISABLE_RTKIT Allow disabling real time thread, this is useful to run inside valgrind without being killed. Signed-off-by: Nicolas Dufresne --- src/modules/module-rtkit.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/module-rtkit.c b/src/modules/module-rtkit.c index 0db327554..444e326c6 100644 --- a/src/modules/module-rtkit.c +++ b/src/modules/module-rtkit.c @@ -273,6 +273,9 @@ int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int pr DBusError error; int ret; + if (getenv("DISABLE_RTKIT")) + return -EPERM; + dbus_error_init(&error); if (thread == 0) From 9f2cfe1cd6fe9d986fe548306ea7a25a86602675 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 9 Jan 2019 11:17:46 +0100 Subject: [PATCH 110/155] rtkit: improve DISABLE_RTKIT DISABLE_RTKIT should not even try to get the dbus connection or anything. --- src/modules/module-rtkit.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/modules/module-rtkit.c b/src/modules/module-rtkit.c index 444e326c6..7c9effd10 100644 --- a/src/modules/module-rtkit.c +++ b/src/modules/module-rtkit.c @@ -110,6 +110,9 @@ struct pw_rtkit_bus *pw_rtkit_bus_get_system(void) struct pw_rtkit_bus *bus; DBusError error; + if (getenv("DISABLE_RTKIT")) + return NULL; + dbus_error_init(&error); bus = calloc(1, sizeof(struct pw_rtkit_bus)); @@ -273,9 +276,6 @@ int pw_rtkit_make_realtime(struct pw_rtkit_bus *connection, pid_t thread, int pr DBusError error; int ret; - if (getenv("DISABLE_RTKIT")) - return -EPERM; - dbus_error_init(&error); if (thread == 0) @@ -411,6 +411,8 @@ static void idle_func(struct spa_source *source) long long rttime; uint64_t count; + read(impl->source.fd, &count, sizeof(uint64_t)); + rtprio = 20; rttime = 20000; @@ -421,7 +423,10 @@ static void idle_func(struct spa_source *source) pw_log_debug("SCHED_OTHER|SCHED_RESET_ON_FORK worked."); return; } + system_bus = pw_rtkit_bus_get_system(); + if (system_bus == NULL) + return; rl.rlim_cur = rl.rlim_max = rttime; if ((r = setrlimit(RLIMIT_RTTIME, &rl)) < 0) @@ -444,8 +449,6 @@ static void idle_func(struct spa_source *source) pw_log_debug("thread made realtime"); } pw_rtkit_bus_free(system_bus); - - read(impl->source.fd, &count, sizeof(uint64_t)); } static int module_init(struct pw_module *module, struct pw_properties *properties) From 9f7c9022cf3a43707b44025e2d11456883787dbf Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 10 Apr 2019 17:03:14 +0200 Subject: [PATCH 111/155] format: map all mjpeg formats to video/mjpeg Fixes #139 --- spa/plugins/v4l2/v4l2-utils.c | 4 ++-- src/gst/gstpipewireformat.c | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 024f44aa7..4adf0c619 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -330,8 +330,8 @@ static const struct format_info format_info[] = { /* compressed formats */ {V4L2_PIX_FMT_MJPEG, FORMAT_ENCODED, VIDEO, MJPG}, - {V4L2_PIX_FMT_JPEG, FORMAT_ENCODED, IMAGE, JPEG}, - {V4L2_PIX_FMT_PJPG, FORMAT_UNKNOWN, VIDEO, RAW}, + {V4L2_PIX_FMT_JPEG, FORMAT_ENCODED, VIDEO, MJPG}, + {V4L2_PIX_FMT_PJPG, FORMAT_ENCODED, VIDEO, MJPG}, {V4L2_PIX_FMT_DV, FORMAT_ENCODED, VIDEO, DV}, {V4L2_PIX_FMT_MPEG, FORMAT_ENCODED, VIDEO, MPEGTS}, {V4L2_PIX_FMT_H264, FORMAT_ENCODED, VIDEO, H264}, diff --git a/src/gst/gstpipewireformat.c b/src/gst/gstpipewireformat.c index 5a5d42018..9fa9f3424 100644 --- a/src/gst/gstpipewireformat.c +++ b/src/gst/gstpipewireformat.c @@ -69,6 +69,7 @@ static const struct media_type media_type_map[] = { { "video/x-raw", &type.media_type.video, &type.media_subtype.raw }, { "audio/x-raw", &type.media_type.audio, &type.media_subtype.raw }, { "image/jpeg", &type.media_type.video, &type.media_subtype_video.mjpg }, + { "video/x-jpeg", &type.media_type.video, &type.media_subtype_video.mjpg }, { "video/x-h264", &type.media_type.video, &type.media_subtype_video.h264 }, { NULL, } }; From e4be9837c4ff2de0e4a2818fc672c61e9cdae9f0 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 30 Apr 2019 15:54:29 +0200 Subject: [PATCH 112/155] v4l2: add Camera media.role --- spa/plugins/v4l2/v4l2-source.c | 1 + 1 file changed, 1 insertion(+) diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index f8a2b2732..a875a5d62 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -859,6 +859,7 @@ static int impl_node_process_output(struct spa_node *node) static const struct spa_dict_item info_items[] = { { "media.class", "Video/Source" }, + { "media.role", "Camera" }, { "node.pause-on-idle", "false" }, }; From 3f5b3b7cb1d84e6ded4b02dafb79ea0e245440e8 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 May 2019 12:07:25 +0200 Subject: [PATCH 113/155] pipewiresrc: actually use the fd when set --- src/gst/gstpipewiresrc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 9d505fffa..9458a23c5 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -996,7 +996,10 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) &pwsrc->remote_listener, &remote_events, pwsrc); - pw_remote_connect (pwsrc->remote); + if (pwsrc->fd == -1) + pw_remote_connect (pwsrc->remote); + else + pw_remote_connect_fd (pwsrc->remote, pwsrc->fd); while (TRUE) { enum pw_remote_state state = pw_remote_get_state(pwsrc->remote, &error); From fa0b4f9321a3952af96ae8b63a882e9a9133cd35 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 May 2019 15:41:26 +0200 Subject: [PATCH 114/155] client: properties with "pipewire." prefix are read-only Properties that start with "pipewire." can only be set once. This prevents a client from overwriting the ucred or any of the other protected properties once they are set by the core or a module. --- src/pipewire/client.c | 15 ++++++++++++--- src/pipewire/core.c | 3 ++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index c5257c227..2730c3d0c 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -370,9 +370,18 @@ int pw_client_update_properties(struct pw_client *client, const struct spa_dict struct pw_resource *resource; uint32_t i, changed = 0; - for (i = 0; i < dict->n_items; i++) - changed += pw_properties_set(client->properties, - dict->items[i].key, dict->items[i].value); + for (i = 0; i < dict->n_items; i++) { + const char *key = dict->items[i].key, *old, *val = dict->items[i].value; + + if (strstr(key, "pipewire.") == key && + (old = pw_properties_get(client->properties, key)) != NULL && + (val == NULL || strcmp(old, val))) { + pw_log_warn("client %p: refused update of key %s from %s to %s", + client, key, old, val); + continue; + } + changed += pw_properties_set(client->properties, key, val); + } pw_log_debug("client %p: updated %d properties", client, changed); diff --git a/src/pipewire/core.c b/src/pipewire/core.c index fc49d445e..7c74b2a41 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -117,7 +117,8 @@ static void core_hello(void *object) static void core_client_update(void *object, const struct spa_dict *props) { struct pw_resource *resource = object; - pw_client_update_properties(resource->client, props); + struct pw_client *client = resource->client; + pw_client_update_properties(client, props); } static void core_permissions(void *object, const struct spa_dict *props) From 2b5c6fd6769edc70253bc40ce1a627afe1dce500 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 May 2019 17:04:16 +0200 Subject: [PATCH 115/155] list: add _consume method Add safer way to destroy a list of objects. --- spa/include/spa/utils/list.h | 5 +++++ spa/plugins/support/loop.c | 4 ++-- src/modules/module-protocol-native.c | 4 ++-- src/pipewire/client.c | 6 +++--- src/pipewire/core.c | 16 ++++++++-------- src/pipewire/link.c | 6 +++--- src/pipewire/module.c | 4 ++-- src/pipewire/node.c | 10 +++++----- src/pipewire/port.c | 10 +++++----- src/pipewire/protocol.c | 8 ++++---- src/pipewire/remote.c | 8 ++++---- 11 files changed, 43 insertions(+), 38 deletions(-) diff --git a/spa/include/spa/utils/list.h b/spa/include/spa/utils/list.h index 18a06a523..523fbae94 100644 --- a/spa/include/spa/utils/list.h +++ b/spa/include/spa/utils/list.h @@ -78,6 +78,11 @@ static inline void spa_list_remove(struct spa_list *elem) #define spa_list_next(pos, member) \ SPA_CONTAINER_OF((pos)->member.next, __typeof__(*pos), member) +#define spa_list_consume(pos, head, member) \ + for (pos = spa_list_first(head, __typeof__(*pos), member); \ + !spa_list_is_empty(head); \ + pos = spa_list_first(head, __typeof__(*pos), member)) + #define spa_list_for_each_next(pos, head, curr, member) \ for (pos = spa_list_first(curr, __typeof__(*pos), member); \ !spa_list_is_end(pos, head, member); \ diff --git a/spa/plugins/support/loop.c b/spa/plugins/support/loop.c index 1c770a16b..941a75050 100644 --- a/spa/plugins/support/loop.c +++ b/spa/plugins/support/loop.c @@ -686,13 +686,13 @@ static int impl_get_interface(struct spa_handle *handle, uint32_t interface_id, static int impl_clear(struct spa_handle *handle) { struct impl *impl; - struct source_impl *source, *tmp; + struct source_impl *source; spa_return_val_if_fail(handle != NULL, -EINVAL); impl = (struct impl *) handle; - spa_list_for_each_safe(source, tmp, &impl->source_list, link) + spa_list_consume(source, &impl->source_list, link) loop_destroy_source(&source->source); process_destroy(impl); diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index c00fb1637..4929fc6d7 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -716,11 +716,11 @@ impl_new_client(struct pw_protocol *protocol, static void destroy_server(struct pw_protocol_server *server) { struct server *s = SPA_CONTAINER_OF(server, struct server, this); - struct pw_client *client, *tmp; + struct pw_client *client; spa_list_remove(&server->link); - spa_list_for_each_safe(client, tmp, &server->client_list, protocol_link) + spa_list_consume(client, &server->client_list, protocol_link) pw_client_destroy(client); if (s->source) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 2730c3d0c..8259db2a7 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -105,7 +105,7 @@ global_bind(void *_data, struct pw_client *client, uint32_t permissions, data = pw_resource_get_user_data(resource); pw_resource_add_listener(resource, &data->resource_listener, &resource_events, resource); - pw_log_debug("client %p: bound to %d", this, resource->id); + pw_log_debug("client %p: bound to %p %d", this, resource, resource->id); spa_list_append(&this->resource_list, &resource->link); @@ -305,7 +305,7 @@ static int destroy_resource(void *object, void *data) SPA_EXPORT void pw_client_destroy(struct pw_client *client) { - struct pw_resource *resource, *tmp; + struct pw_resource *resource; struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); pw_log_debug("client %p: destroy", client); @@ -321,7 +321,7 @@ void pw_client_destroy(struct pw_client *client) pw_global_destroy(client->global); } - spa_list_for_each_safe(resource, tmp, &client->resource_list, link) + spa_list_consume(resource, &client->resource_list, link) pw_resource_destroy(resource); pw_map_for_each(&client->objects, destroy_resource, client); diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 7c74b2a41..c0bf02786 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -473,26 +473,26 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro SPA_EXPORT void pw_core_destroy(struct pw_core *core) { - struct pw_global *global, *t; - struct pw_module *module, *tm; - struct pw_remote *remote, *tr; - struct pw_node *node, *tn; + struct pw_global *global; + struct pw_module *module; + struct pw_remote *remote; + struct pw_node *node; pw_log_debug("core %p: destroy", core); pw_core_events_destroy(core); spa_hook_remove(&core->global_listener); - spa_list_for_each_safe(remote, tr, &core->remote_list, link) + spa_list_consume(remote, &core->remote_list, link) pw_remote_destroy(remote); - spa_list_for_each_safe(module, tm, &core->module_list, link) + spa_list_consume(module, &core->module_list, link) pw_module_destroy(module); - spa_list_for_each_safe(node, tn, &core->node_list, link) + spa_list_consume(node, &core->node_list, link) pw_node_destroy(node); - spa_list_for_each_safe(global, t, &core->global_list, link) + spa_list_consume(global, &core->global_list, link) pw_global_destroy(global); pw_core_events_free(core); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index fcea75350..b352f2899 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1278,7 +1278,7 @@ SPA_EXPORT void pw_link_destroy(struct pw_link *link) { struct impl *impl = SPA_CONTAINER_OF(link, struct impl, this); - struct pw_resource *resource, *tmp; + struct pw_resource *resource; pw_log_debug("link %p: destroy", impl); pw_link_events_destroy(link); @@ -1300,8 +1300,8 @@ void pw_link_destroy(struct pw_link *link) pw_global_destroy(link->global); } - spa_list_for_each_safe(resource, tmp, &link->resource_list, link) - pw_resource_destroy(resource); + spa_list_consume(resource, &link->resource_list, link) + pw_resource_destroy(resource); pw_log_debug("link %p: free", impl); pw_link_events_free(link); diff --git a/src/pipewire/module.c b/src/pipewire/module.c index de069a0c8..da4173ea8 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -287,7 +287,7 @@ SPA_EXPORT void pw_module_destroy(struct pw_module *module) { struct impl *impl = SPA_CONTAINER_OF(module, struct impl, this); - struct pw_resource *resource, *tmp; + struct pw_resource *resource; pw_log_debug("module %p: destroy", module); pw_module_events_destroy(module); @@ -298,7 +298,7 @@ void pw_module_destroy(struct pw_module *module) spa_hook_remove(&module->global_listener); pw_global_destroy(module->global); } - spa_list_for_each_safe(resource, tmp, &module->resource_list, link) + spa_list_consume(resource, &module->resource_list, link) pw_resource_destroy(resource); free((char *) module->info.name); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 24f5cbb71..81725e2d7 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -624,8 +624,8 @@ SPA_EXPORT void pw_node_destroy(struct pw_node *node) { struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); - struct pw_resource *resource, *tmp; - struct pw_port *port, *tmpp; + struct pw_resource *resource; + struct pw_port *port; pw_log_debug("node %p: destroy", impl); pw_node_events_destroy(node); @@ -642,11 +642,11 @@ void pw_node_destroy(struct pw_node *node) pw_port_unlink(port); pw_log_debug("node %p: destroy ports", node); - spa_list_for_each_safe(port, tmpp, &node->input_ports, link) { + spa_list_consume(port, &node->input_ports, link) { pw_node_events_port_removed(node, port); pw_port_destroy(port); } - spa_list_for_each_safe(port, tmpp, &node->output_ports, link) { + spa_list_consume(port, &node->output_ports, link) { pw_node_events_port_removed(node, port); pw_port_destroy(port); } @@ -655,7 +655,7 @@ void pw_node_destroy(struct pw_node *node) spa_hook_remove(&node->global_listener); pw_global_destroy(node->global); } - spa_list_for_each_safe(resource, tmp, &node->resource_list, link) + spa_list_consume(resource, &node->resource_list, link) pw_resource_destroy(resource); pw_log_debug("node %p: free", node); diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 3a9b268d9..ab4642c38 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -542,8 +542,8 @@ static void pw_port_remove(struct pw_port *port) void pw_port_destroy(struct pw_port *port) { struct pw_node *node = port->node; - struct pw_control *control, *ctemp; - struct pw_resource *resource, *tmp; + struct pw_control *control; + struct pw_resource *resource; pw_log_debug("port %p: destroy", port); @@ -552,16 +552,16 @@ void pw_port_destroy(struct pw_port *port) if (node) pw_port_remove(port); - spa_list_for_each_safe(control, ctemp, &port->control_list[0], port_link) + spa_list_consume(control, &port->control_list[0], port_link) pw_control_destroy(control); - spa_list_for_each_safe(control, ctemp, &port->control_list[1], port_link) + spa_list_consume(control, &port->control_list[1], port_link) pw_control_destroy(control); if (port->global) { spa_hook_remove(&port->global_listener); pw_global_destroy(port->global); } - spa_list_for_each_safe(resource, tmp, &port->resource_list, link) + spa_list_consume(resource, &port->resource_list, link) pw_resource_destroy(resource); pw_log_debug("port %p: free", port); diff --git a/src/pipewire/protocol.c b/src/pipewire/protocol.c index da1004c78..93adc6a59 100644 --- a/src/pipewire/protocol.c +++ b/src/pipewire/protocol.c @@ -88,18 +88,18 @@ void pw_protocol_destroy(struct pw_protocol *protocol) { struct impl *impl = SPA_CONTAINER_OF(protocol, struct impl, this); struct marshal *marshal, *t1; - struct pw_protocol_server *server, *t2; - struct pw_protocol_client *client, *t3; + struct pw_protocol_server *server; + struct pw_protocol_client *client; pw_log_debug("protocol %p: destroy", protocol); pw_protocol_events_destroy(protocol); spa_list_remove(&protocol->link); - spa_list_for_each_safe(server, t2, &protocol->server_list, link) + spa_list_consume(server, &protocol->server_list, link) pw_protocol_server_destroy(server); - spa_list_for_each_safe(client, t3, &protocol->client_list, link) + spa_list_consume(client, &protocol->client_list, link) pw_protocol_client_destroy(client); spa_list_for_each_safe(marshal, t1, &protocol->marshal_list, link) diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 9887fcba8..544c77b68 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -292,7 +292,7 @@ SPA_EXPORT void pw_remote_destroy(struct pw_remote *remote) { struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this); - struct pw_stream *stream, *s2; + struct pw_stream *stream; pw_log_debug("remote %p: destroy", remote); pw_remote_events_destroy(remote); @@ -300,7 +300,7 @@ void pw_remote_destroy(struct pw_remote *remote) if (remote->state != PW_REMOTE_STATE_UNCONNECTED) pw_remote_disconnect(remote); - spa_list_for_each_safe(stream, s2, &remote->stream_list, link) + spa_list_consume(stream, &remote->stream_list, link) pw_stream_destroy(stream); pw_protocol_client_destroy (remote->conn); @@ -449,14 +449,14 @@ int pw_remote_steal_fd(struct pw_remote *remote) SPA_EXPORT int pw_remote_disconnect(struct pw_remote *remote) { - struct pw_proxy *proxy, *t2; + struct pw_proxy *proxy; struct pw_stream *stream, *s2; pw_log_debug("remote %p: disconnect", remote); spa_list_for_each_safe(stream, s2, &remote->stream_list, link) pw_stream_disconnect(stream); - spa_list_for_each_safe(proxy, t2, &remote->proxy_list, link) + spa_list_consume(proxy, &remote->proxy_list, link) pw_proxy_destroy(proxy); remote->core_proxy = NULL; From 7670ee7eec2305b697c41b921628eb9c6463596e Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 May 2019 17:05:05 +0200 Subject: [PATCH 116/155] core: destroy all resources on hello Destroy all resources (except the core) for a client when it does a hello. This typically needs to be done after passing the connection fd from one client to another. --- src/pipewire/core.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index c0bf02786..48ffaa14a 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -102,13 +102,23 @@ static const struct pw_resource_events resource_events = { .destroy = destroy_registry_resource }; +static int destroy_resource(void *object, void *data) +{ + struct pw_resource *resource = object; + if (resource && resource != resource->client->core_resource) + pw_resource_destroy(resource); + return 0; +} + static void core_hello(void *object) { struct pw_resource *resource = object; + struct pw_client *client = resource->client; struct pw_core *this = resource->core; - pw_log_debug("core %p: hello from source %p", this, resource); - resource->client->n_types = 0; + pw_log_debug("core %p: hello from resource %p", this, resource); + client->n_types = 0; + pw_map_for_each(&client->objects, destroy_resource, client); this->info.change_mask = PW_CORE_CHANGE_MASK_ALL; pw_core_resource_info(resource, &this->info); From 5d2f0f5182cd59e83629e9727f915d7aebb61bb9 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 6 May 2019 17:48:23 +0200 Subject: [PATCH 117/155] remote: only remove the proxy id when it existed --- src/pipewire/remote.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 544c77b68..173eb4fe9 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -181,10 +181,10 @@ static void core_event_remove_id(void *data, uint32_t id) struct pw_proxy *proxy; pw_log_debug("remote %p: object remove %u", this, id); - if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) + if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) { pw_proxy_destroy(proxy); - - pw_map_remove(&this->objects, id); + pw_map_remove(&this->objects, id); + } } static void From e0eeedc369d03c3531d052a8cc95e361ff7d16ab Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 10 May 2019 12:09:26 +0200 Subject: [PATCH 118/155] core: don't send remove_id in hello The hello method should also destroy the resources for a client but not send a remove_id for them. --- src/pipewire/core.c | 4 +++- src/pipewire/interfaces.h | 3 +++ src/pipewire/private.h | 2 ++ src/pipewire/remote.c | 8 +++++--- src/pipewire/resource.c | 2 +- 5 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 48ffaa14a..dcf0def6d 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -105,8 +105,10 @@ static const struct pw_resource_events resource_events = { static int destroy_resource(void *object, void *data) { struct pw_resource *resource = object; - if (resource && resource != resource->client->core_resource) + if (resource && resource != resource->client->core_resource) { + resource->removed = true; pw_resource_destroy(resource); + } return 0; } diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index 3794f702d..9217ce9c3 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -117,6 +117,9 @@ struct pw_core_proxy_methods { /** * Start a conversation with the server. This will send * the core info and server types. + * + * All the existing resources for the client (except the core + * resource) will be destroyed. */ void (*hello) (void *object); /** diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 17e8884bf..42612f1da 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -435,6 +435,8 @@ struct pw_resource { uint32_t type; /**< type of the client interface */ uint32_t version; /**< version of the client interface */ + bool removed; /**< if the resource was removed */ + struct spa_hook implementation; struct spa_hook_list implementation_list; struct spa_hook_list listener_list; diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 173eb4fe9..f63a973a4 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -181,10 +181,12 @@ static void core_event_remove_id(void *data, uint32_t id) struct pw_proxy *proxy; pw_log_debug("remote %p: object remove %u", this, id); - if ((proxy = pw_map_lookup(&this->objects, id)) != NULL) { - pw_proxy_destroy(proxy); - pw_map_remove(&this->objects, id); + if ((proxy = pw_map_lookup(&this->objects, id)) == NULL) { + pw_log_warn("remote %p: asked to remove unknown object id %u", this, id); + return; } + pw_proxy_destroy(proxy); + pw_map_remove(&this->objects, id); } static void diff --git a/src/pipewire/resource.c b/src/pipewire/resource.c index 21959ca31..a3fc53944 100644 --- a/src/pipewire/resource.c +++ b/src/pipewire/resource.c @@ -176,7 +176,7 @@ void pw_resource_destroy(struct pw_resource *resource) pw_map_insert_at(&client->objects, resource->id, NULL); pw_client_events_resource_removed(client, resource); - if (client->core_resource) + if (client->core_resource && !resource->removed) pw_core_resource_remove_id(client->core_resource, resource->id); pw_log_debug("resource %p: free", resource); From 3854f8557a8d47ebaa5173e44669a9e58e148128 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 10 May 2019 13:12:22 +0200 Subject: [PATCH 119/155] protocol: add security label to a client Don't pass the ucred to the client construct, just set the properties in the protocol. Use the client properties to get ucred. Add the security label to the client properties (from SO_PEERSEC) --- src/modules/module-flatpak.c | 42 ++++++++++++++++++++-------- src/modules/module-protocol-native.c | 28 ++++++++++++------- src/pipewire/client.c | 18 ------------ src/pipewire/client.h | 11 +------- src/pipewire/private.h | 2 -- 5 files changed, 49 insertions(+), 52 deletions(-) diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index 59c6f67a2..3c981201d 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -139,20 +139,25 @@ static void client_info_free(struct client_info *cinfo) static int check_sandboxed(struct pw_client *client) { char root_path[2048]; - int root_fd, info_fd, res; - const struct ucred *ucred; + int root_fd, info_fd, res, pid; + const char *str; + const struct pw_properties *props; struct stat stat_buf; - ucred = pw_client_get_ucred(client); + if ((props = pw_client_get_properties(client))) + str = pw_properties_get(props, PW_CLIENT_PROP_UCRED_PID); + else + str = NULL; - if (ucred) { - pw_log_info("client has trusted pid %d", ucred->pid); + if (str) { + pid = atoi(str); + pw_log_info("client has trusted pid %d", pid); } else { pw_log_info("no trusted pid found, assuming not sandboxed\n"); return 0; } - sprintf(root_path, "/proc/%u/root", ucred->pid); + sprintf(root_path, "/proc/%u/root", pid); root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); if (root_fd == -1) { /* Not able to open the root dir shouldn't happen. Probably the app died and @@ -182,11 +187,22 @@ static int check_sandboxed(struct pw_client *client) return 1; } +static int get_client_prop(struct pw_client *client, const char *prop) +{ + const struct pw_properties *props; + const char *str; + if ((props = pw_client_get_properties(client)) == NULL) + return -EINVAL; + if ((str = pw_properties_get(props, prop)) == NULL) + return -EINVAL; + return atoi(str); +} + static bool check_global_owner(struct pw_client *client, struct pw_global *global) { struct pw_client *owner; - const struct ucred *owner_ucred, *client_ucred; + int owner_uid, client_uid; if (global == NULL) return false; @@ -195,14 +211,14 @@ check_global_owner(struct pw_client *client, struct pw_global *global) if (owner == NULL) return false; - owner_ucred = pw_client_get_ucred(owner); - client_ucred = pw_client_get_ucred(client); + owner_uid = get_client_prop(owner, PW_CLIENT_PROP_UCRED_UID); + client_uid = get_client_prop(client, PW_CLIENT_PROP_UCRED_UID); - if (owner_ucred == NULL || client_ucred == NULL) + if (owner_uid < 0 || client_uid < 0) return false; /* same user can see eachothers objects */ - return owner_ucred->uid == client_ucred->uid; + return owner_uid == client_uid; } static int @@ -320,7 +336,9 @@ static void do_portal_check(struct client_info *cinfo) device = "camera"; - pid = pw_client_get_ucred(client)->pid; + pid = get_client_prop(client, PW_CLIENT_PROP_UCRED_PID); + if (pid < 0) + goto not_allowed; if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) goto message_failed; diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 4929fc6d7..131657f61 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -313,24 +313,32 @@ static struct pw_client *client_new(struct server *s, int fd) struct pw_protocol *protocol = s->this.protocol; struct protocol_data *pd = protocol->user_data; socklen_t len; - struct ucred ucred, *ucredp; + struct ucred ucred; struct pw_core *core = protocol->core; struct pw_properties *props; - - len = sizeof(ucred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { - pw_log_error("no peercred: %m"); - ucredp = NULL; - } else { - ucredp = &ucred; - } + char buffer[1024]; props = pw_properties_new(PW_CLIENT_PROP_PROTOCOL, "protocol-native", NULL); if (props == NULL) goto no_props; + len = sizeof(ucred); + if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0) { + pw_log_error("no peercred: %m"); + } else { + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_PID, "%d", ucred.pid); + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_UID, "%d", ucred.uid); + pw_properties_setf(props, PW_CLIENT_PROP_UCRED_GID, "%d", ucred.gid); + } + + len = sizeof(buffer); + if (getsockopt(fd, SOL_SOCKET, SO_PEERSEC, buffer, &len) < 0) { + pw_log_error("no peersec: %m"); + } else { + pw_properties_setf(props, PW_CLIENT_PROP_SEC_LABEL, "%s", buffer); + } + client = pw_client_new(protocol->core, - ucredp, props, sizeof(struct client_data)); if (client == NULL) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 8259db2a7..a09e3da84 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -150,7 +150,6 @@ static const struct pw_core_events core_events = { */ SPA_EXPORT struct pw_client *pw_client_new(struct pw_core *core, - struct ucred *ucred, struct pw_properties *properties, size_t user_data_size) { @@ -165,20 +164,12 @@ struct pw_client *pw_client_new(struct pw_core *core, pw_log_debug("client %p: new", this); this->core = core; - if ((this->ucred_valid = (ucred != NULL))) - this->ucred = *ucred; if (properties == NULL) properties = pw_properties_new(NULL, NULL); if (properties == NULL) return NULL; - if (ucred) { - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_PID, "%d", ucred->pid); - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_UID, "%d", ucred->uid); - pw_properties_setf(properties, PW_CLIENT_PROP_UCRED_GID, "%d", ucred->gid); - } - pw_array_init(&impl->permissions, 1024); this->properties = properties; @@ -273,15 +264,6 @@ const struct pw_properties *pw_client_get_properties(struct pw_client *client) return client->properties; } -SPA_EXPORT -const struct ucred *pw_client_get_ucred(struct pw_client *client) -{ - if (!client->ucred_valid) - return NULL; - - return &client->ucred; -} - SPA_EXPORT void *pw_client_get_user_data(struct pw_client *client) { diff --git a/src/pipewire/client.h b/src/pipewire/client.h index f653f93eb..a454d4a2f 100644 --- a/src/pipewire/client.h +++ b/src/pipewire/client.h @@ -24,12 +24,6 @@ extern "C" { #endif -#ifndef __USE_GNU -#define __USE_GNU -#endif - -#include - #include /** \class pw_client @@ -119,11 +113,11 @@ struct pw_client_events { #define PW_CLIENT_PROP_UCRED_PID "pipewire.ucred.pid" /**< Client pid, set by protocol */ #define PW_CLIENT_PROP_UCRED_UID "pipewire.ucred.uid" /**< Client uid, set by protocol*/ #define PW_CLIENT_PROP_UCRED_GID "pipewire.ucred.gid" /**< client gid, set by protocol*/ +#define PW_CLIENT_PROP_SEC_LABEL "pipewire.sec.label" /**< client security label, set by protocol*/ /** Create a new client. This is mainly used by protocols. */ struct pw_client * pw_client_new(struct pw_core *core, /**< the core object */ - struct ucred *ucred, /**< optional ucred */ struct pw_properties *properties, /**< client properties */ size_t user_data_size /**< extra user data size */); @@ -163,9 +157,6 @@ struct pw_resource *pw_client_find_resource(struct pw_client *client, uint32_t i /** Get the global associated with this client */ struct pw_global *pw_client_get_global(struct pw_client *client); -/** Get the ucred from a client or NULL when not specified/valid */ -const struct ucred *pw_client_get_ucred(struct pw_client *client); - /** listen to events from this client */ void pw_client_add_listener(struct pw_client *client, struct spa_hook *listener, diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 42612f1da..9e51d21a9 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -99,8 +99,6 @@ struct pw_client { struct pw_properties *properties; /**< Client properties */ struct pw_client_info info; /**< client info */ - bool ucred_valid; /**< if the ucred member is valid */ - struct ucred ucred; /**< ucred information */ struct pw_resource *core_resource; /**< core resource object */ From d7acbb222e6e163a3e461c083fd2d346ca380a2f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 May 2019 12:51:20 +0200 Subject: [PATCH 120/155] link: check permissions When creating a link between two nodes, check if the owner of a node (when it is a client) can see the other node. --- src/pipewire/link.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/pipewire/link.c b/src/pipewire/link.c index b352f2899..f4529be96 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1086,6 +1086,28 @@ static const struct pw_node_events output_node_events = { .async_complete = output_node_async_complete, }; +static int +check_permission(struct pw_core *core, + struct pw_port *output, + struct pw_port *input, + struct pw_properties *properties) +{ + struct pw_node *input_node, *output_node; + struct pw_client *client; + + input_node = input->node; + output_node = output->node; + + if ((client = output_node->global->owner) != NULL && + !PW_PERM_IS_R(pw_global_get_permissions(input_node->global, client))) + return -EPERM; + + if ((client = input_node->global->owner) != NULL && + !PW_PERM_IS_R(pw_global_get_permissions(output_node->global, client))) + return -EPERM; + return 0; +} + SPA_EXPORT struct pw_link *pw_link_new(struct pw_core *core, struct pw_port *output, @@ -1105,6 +1127,9 @@ struct pw_link *pw_link_new(struct pw_core *core, if (pw_link_find(output, input)) goto link_exists; + if (check_permission(core, output, input, properties) < 0) + goto link_not_allowed; + impl = calloc(1, sizeof(struct impl) + user_data_size); if (impl == NULL) goto no_mem; @@ -1202,6 +1227,9 @@ struct pw_link *pw_link_new(struct pw_core *core, link_exists: asprintf(error, "link already exists"); return NULL; + link_not_allowed: + asprintf(error, "link not allowed"); + return NULL; no_mem: asprintf(error, "no memory"); return NULL; From 83bc033837f7525d898f1de91119f669f9bf97f5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 May 2019 15:46:32 +0200 Subject: [PATCH 121/155] global: combine all permissions of the object tree To get the permissions of an object, combine the permissions of the object and all the parent nodes up to the root. This is necessary to enforce that a client can never see and object id (in this case the parent id) it is not allowed to see. --- src/pipewire/global.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/pipewire/global.c b/src/pipewire/global.c index 00258ff88..c963965e7 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -38,9 +38,15 @@ uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_client *c { uint32_t perms = PW_PERM_RWX; - if (client->permission_func != NULL) - perms &= client->permission_func(global, client, client->permission_data); + if (client->permission_func == NULL) + return perms; + perms = client->permission_func(global, client, client->permission_data); + + while (global != global->parent) { + global = global->parent; + perms &= client->permission_func(global, client, client->permission_data); + } return perms; } From 98da5a2e9e5524751aaa96e2043d475135a2bb9b Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 13 May 2019 17:04:43 +0200 Subject: [PATCH 122/155] global: emit permissions_changed event Add a permissions_changed event when the permissions change for a global for a client. Recheck if a link is still allowed when node permissions changed and destroy the link if not. --- src/pipewire/client.c | 9 +++++++-- src/pipewire/global.h | 8 +++++++- src/pipewire/link.c | 22 ++++++++++++++++++++++ src/pipewire/private.h | 2 ++ 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index a09e3da84..4c647fe2a 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -395,6 +395,7 @@ static int do_permissions(void *data, struct pw_global *global) struct impl *impl = SPA_CONTAINER_OF(client, struct impl, this); struct permission *p; size_t len, i; + uint32_t old; len = pw_array_get_len(&impl->permissions, struct permission); if (len <= global->id) { @@ -410,12 +411,16 @@ static int do_permissions(void *data, struct pw_global *global) p = pw_array_get_unchecked(&impl->permissions, global->id, struct permission); if (p->permissions == -1) - p->permissions = impl->permissions_default; + old = p->permissions = impl->permissions_default; else if (update->only_new) return 0; + old = p->permissions; p->permissions &= update->permissions; - pw_log_debug("client %p: set global %d permissions to %08x", client, global->id, p->permissions); + pw_log_debug("client %p: change global %d permissions %08x -> %08x", + client, global->id, old, p->permissions); + + pw_global_events_permissions_changed(global, client, old, p->permissions); return 0; } diff --git a/src/pipewire/global.h b/src/pipewire/global.h index 813409f92..2c5f07ff9 100644 --- a/src/pipewire/global.h +++ b/src/pipewire/global.h @@ -57,7 +57,7 @@ struct pw_global; /** Global events, use \ref pw_global_add_listener */ struct pw_global_events { -#define PW_VERSION_GLOBAL_EVENTS 0 +#define PW_VERSION_GLOBAL_EVENTS 1 uint32_t version; /** The global is destroyed */ @@ -72,6 +72,12 @@ struct pw_global_events { uint32_t permissions, /**< permissions for the bind */ uint32_t version, /**< client interface version */ uint32_t id /**< client proxy id */); + + /* permissions for the global changed, Since version 1 */ + void (*permissions_changed) (void *data, + struct pw_client *client, + uint32_t old_permissions, + uint32_t new_permissions); }; /** Create a new global object */ diff --git a/src/pipewire/link.c b/src/pipewire/link.c index f4529be96..9b33c1606 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -51,8 +51,10 @@ struct impl { struct spa_hook input_port_listener; struct spa_hook input_node_listener; + struct spa_hook input_global_listener; struct spa_hook output_port_listener; struct spa_hook output_node_listener; + struct spa_hook output_global_listener; }; struct resource_data { @@ -868,6 +870,7 @@ static void input_remove(struct pw_link *this, struct pw_port *port) pw_log_debug("link %p: remove input port %p", this, port); spa_hook_remove(&impl->input_port_listener); spa_hook_remove(&impl->input_node_listener); + spa_hook_remove(&impl->input_global_listener); pw_loop_invoke(port->node->data_loop, do_remove_input, 1, NULL, 0, true, this); @@ -897,6 +900,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port) pw_log_debug("link %p: remove output port %p", this, port); spa_hook_remove(&impl->output_port_listener); spa_hook_remove(&impl->output_node_listener); + spa_hook_remove(&impl->output_global_listener); pw_loop_invoke(port->node->data_loop, do_remove_output, 1, NULL, 0, true, this); @@ -1105,9 +1109,25 @@ check_permission(struct pw_core *core, if ((client = input_node->global->owner) != NULL && !PW_PERM_IS_R(pw_global_get_permissions(output_node->global, client))) return -EPERM; + return 0; } +static void global_permissions_changed(void *data, + struct pw_client *client, uint32_t old, uint32_t new) +{ + struct pw_link *this = data; + + if (check_permission(this->core, this->output, this->input, this->properties) < 0) + pw_link_destroy(this); +} + + +static const struct pw_global_events global_node_events = { + PW_VERSION_GLOBAL_EVENTS, + .permissions_changed = global_permissions_changed, +}; + SPA_EXPORT struct pw_link *pw_link_new(struct pw_core *core, struct pw_port *output, @@ -1166,8 +1186,10 @@ struct pw_link *pw_link_new(struct pw_core *core, pw_port_add_listener(input, &impl->input_port_listener, &input_port_events, impl); pw_node_add_listener(input_node, &impl->input_node_listener, &input_node_events, impl); + pw_global_add_listener(input_node->global, &impl->input_global_listener, &global_node_events, impl); pw_port_add_listener(output, &impl->output_port_listener, &output_port_events, impl); pw_node_add_listener(output_node, &impl->output_node_listener, &output_node_events, impl); + pw_global_add_listener(output_node->global, &impl->output_global_listener, &global_node_events, impl); input_node->live = output_node->live; if (output_node->clock) diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 9e51d21a9..1bb314e7c 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -124,6 +124,8 @@ struct pw_client { #define pw_global_events_destroy(g) pw_global_events_emit(g, destroy, 0) #define pw_global_events_free(g) pw_global_events_emit(g, free, 0) #define pw_global_events_bind(g,...) pw_global_events_emit(g, bind, 0, __VA_ARGS__) +#define pw_global_events_permissions_changed(g,...) \ + pw_global_events_emit(g, permissions_changed, 1, __VA_ARGS__) struct pw_global { struct pw_core *core; /**< the core */ From 5f507c804f37aef129c857266904ec551e1eee4f Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Mon, 25 Mar 2019 08:47:00 +0100 Subject: [PATCH 123/155] remove libv4l2 dependency It's not used anywhere right now. --- spa/meson.build | 1 - spa/plugins/v4l2/meson.build | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/spa/meson.build b/spa/meson.build index d190b9b2a..b5294bf36 100644 --- a/spa/meson.build +++ b/spa/meson.build @@ -2,7 +2,6 @@ alsa_dep = dependency('alsa') -v4l2_dep = dependency('libv4l2') x11_dep = dependency('x11', required : false) sdl_dep = dependency('sdl2', required : false) avcodec_dep = dependency('libavcodec', required : false) diff --git a/spa/plugins/v4l2/meson.build b/spa/plugins/v4l2/meson.build index 847adbcdc..e4552b02a 100644 --- a/spa/plugins/v4l2/meson.build +++ b/spa/plugins/v4l2/meson.build @@ -5,6 +5,6 @@ v4l2_sources = ['v4l2.c', v4l2lib = shared_library('spa-v4l2', v4l2_sources, include_directories : [ spa_inc ], - dependencies : [ v4l2_dep, libudev_dep ], + dependencies : [ libudev_dep ], install : true, install_dir : '@0@/spa/v4l2'.format(get_option('libdir'))) From 3ce0c4b81a77fe392eb808a7ea9c2b3eb5e74dc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 10 May 2019 18:42:19 +0200 Subject: [PATCH 124/155] pipewire/node: Pass along 'media.role' node property too --- src/pipewire/node.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 81725e2d7..0a752a0e0 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -351,6 +351,8 @@ int pw_node_register(struct pw_node *this, if ((str = pw_properties_get(this->properties, "media.class")) != NULL) pw_properties_set(properties, "media.class", str); + if ((str = pw_properties_get(this->properties, "media.role")) != NULL) + pw_properties_set(properties, "media.role", str); pw_properties_set(properties, "node.name", this->info.name); spa_list_append(&core->node_list, &this->link); From 31145b58dc2c6487820775ffea80bb52e1b482cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 10 May 2019 18:01:25 +0200 Subject: [PATCH 125/155] Rename module-flatpak module-portal It'll use the portal and permission store explicitly, and nothing particularly flatpak specific. --- src/daemon/pipewire.conf.in | 2 +- src/modules/meson.build | 2 +- src/modules/{module-flatpak.c => module-portal.c} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/modules/{module-flatpak.c => module-portal.c} (100%) diff --git a/src/daemon/pipewire.conf.in b/src/daemon/pipewire.conf.in index fb6cfdb4b..11a62bb46 100644 --- a/src/daemon/pipewire.conf.in +++ b/src/daemon/pipewire.conf.in @@ -9,7 +9,7 @@ load-module libpipewire-module-spa-monitor v4l2/libspa-v4l2 v4l2-monitor v4l2 load-module libpipewire-module-autolink #load-module libpipewire-module-mixer load-module libpipewire-module-client-node -load-module libpipewire-module-flatpak +load-module libpipewire-module-portal #load-module libpipewire-module-audio-dsp #load-module libpipewire-module-link-factory #load-module libpipewire-module-jack diff --git a/src/modules/meson.build b/src/modules/meson.build index 619ca2ec0..4530245b7 100644 --- a/src/modules/meson.build +++ b/src/modules/meson.build @@ -6,7 +6,7 @@ pipewire_module_c_args = [ ] if dbus_dep.found() -pipewire_module_flatpak = shared_library('pipewire-module-flatpak', [ 'module-flatpak.c' ], +pipewire_module_portal = shared_library('pipewire-module-portal', [ 'module-portal.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], install : true, diff --git a/src/modules/module-flatpak.c b/src/modules/module-portal.c similarity index 100% rename from src/modules/module-flatpak.c rename to src/modules/module-portal.c From 777b97b7d858532fdada858e5eca32c931155565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Fri, 10 May 2019 18:07:12 +0200 Subject: [PATCH 126/155] module-portal: Use permission store for portal initiated clients Detect what clients were started by the portal, and use the permission store to determine permissions of existing and future nodes. Clients are detected whether they are from the portal or not by comparing the PID of the client with the PID of the owner of the portal D-Bus name. It is assumed that the portal will set an appropriate app_id, and a comma seperated list of media roles (e.g. "Camera"), that should be queried. If app_id is an empty string, it's assumed to be a non-sandboxed client, and permissions are assumed to be allowing. --- src/modules/module-portal.c | 766 +++++++++++++++++++++++------------- 1 file changed, 487 insertions(+), 279 deletions(-) diff --git a/src/modules/module-portal.c b/src/modules/module-portal.c index 3c981201d..0861832fe 100644 --- a/src/modules/module-portal.c +++ b/src/modules/module-portal.c @@ -1,5 +1,6 @@ /* PipeWire * Copyright (C) 2016 Wim Taymans + * Copyright (C) 2019 Red Hat Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -38,6 +39,12 @@ #include "pipewire/module.h" #include "pipewire/utils.h" +enum media_role { + MEDIA_ROLE_NONE = 0, + MEDIA_ROLE_CAMERA = 1 << 0, +}; +#define MEDIA_ROLE_ALL (MEDIA_ROLE_CAMERA) + struct impl { struct pw_core *core; struct pw_type *type; @@ -50,6 +57,9 @@ struct impl { struct spa_hook module_listener; struct spa_list client_list; + + DBusPendingCall *portal_pid_pending; + pid_t portal_pid; }; struct client_info { @@ -58,17 +68,12 @@ struct client_info { struct pw_client *client; struct spa_hook client_listener; struct spa_list resources; - struct spa_list async_pending; - bool checked; - bool camera_allowed; - bool sandboxed; -}; -struct async_pending { - struct spa_list link; - struct client_info *cinfo; - bool handled; - char *handle; + bool portal_managed; + bool setup_complete; + char *app_id; + enum media_role media_roles; + enum media_role allowed_media_roles; }; static struct client_info *find_client_info(struct impl *impl, struct pw_client *client) @@ -82,143 +87,95 @@ static struct client_info *find_client_info(struct impl *impl, struct pw_client return NULL; } -static void close_request(struct async_pending *p) -{ - DBusMessage *m = NULL; - struct impl *impl = p->cinfo->impl; - - pw_log_debug("pending %p: handle %s", p, p->handle); - - if (!(m = dbus_message_new_method_call("org.freedesktop.portal.Request", - p->handle, - "org.freedesktop.portal.Request", "Close"))) { - pw_log_error("Failed to create message"); - return; - } - - if (!dbus_connection_send(impl->bus, m, NULL)) - pw_log_error("Failed to send message"); - - dbus_message_unref(m); -} - -static struct async_pending *find_pending(struct client_info *cinfo, const char *handle) -{ - struct async_pending *p; - - spa_list_for_each(p, &cinfo->async_pending, link) { - if (strcmp(p->handle, handle) == 0) - return p; - } - return NULL; -} - -static void free_pending(struct async_pending *p) -{ - if (!p->handled) - close_request(p); - - pw_log_debug("pending %p: handle %s", p, p->handle); - spa_list_remove(&p->link); - free(p->handle); - free(p); -} - static void client_info_free(struct client_info *cinfo) { - struct async_pending *p, *tp; - - spa_list_for_each_safe(p, tp, &cinfo->async_pending, link) - free_pending(p); - spa_hook_remove(&cinfo->client_listener); spa_list_remove(&cinfo->link); + free(cinfo->app_id); free(cinfo); } -static int check_sandboxed(struct pw_client *client) +static enum media_role media_role_from_string(const char *media_role_str) { - char root_path[2048]; - int root_fd, info_fd, res, pid; - const char *str; - const struct pw_properties *props; - struct stat stat_buf; - - if ((props = pw_client_get_properties(client))) - str = pw_properties_get(props, PW_CLIENT_PROP_UCRED_PID); + if (strcmp(media_role_str, "Camera") == 0) + return MEDIA_ROLE_CAMERA; else - str = NULL; + return -1; +} - if (str) { - pid = atoi(str); - pw_log_info("client has trusted pid %d", pid); - } else { - pw_log_info("no trusted pid found, assuming not sandboxed\n"); - return 0; - } +static enum media_role parse_media_roles(const char *media_types_str) +{ + enum media_role media_roles = 0; + char *buf_orig; + char *buf; - sprintf(root_path, "/proc/%u/root", pid); - root_fd = openat (AT_FDCWD, root_path, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOCTTY); - if (root_fd == -1) { - /* Not able to open the root dir shouldn't happen. Probably the app died and - * we're failing due to /proc/$pid not existing. In that case fail instead - * of treating this as privileged. */ - res = -errno; - pw_log_error("failed to open \"%s\": %m", root_path); - return res; - } - info_fd = openat (root_fd, ".flatpak-info", O_RDONLY | O_CLOEXEC | O_NOCTTY); - close (root_fd); - if (info_fd == -1) { - if (errno == ENOENT) { - pw_log_debug("no .flatpak-info, client on the host"); - /* No file => on the host */ - return 0; + buf_orig = strdup(media_types_str); + buf = buf_orig; + while (buf) { + char *media_role_str; + enum media_role media_role; + + media_role_str = buf; + strsep(&buf, ","); + + media_role = media_role_from_string(media_role_str); + if (media_role != -1) { + media_roles |= MEDIA_ROLE_CAMERA; + } + else { + pw_log_debug("Client specified unknown media role '%s'", + media_role_str); } - res = -errno; - pw_log_error("error opening .flatpak-info: %m"); - return res; - } - if (fstat (info_fd, &stat_buf) != 0 || !S_ISREG (stat_buf.st_mode)) { - /* Some weird fd => failure, assume sandboxed */ - close(info_fd); - pw_log_error("error fstat .flatpak-info: %m"); } - return 1; + free(buf); + + return media_roles; } -static int get_client_prop(struct pw_client *client, const char *prop) +static enum media_role media_role_from_properties(const struct pw_properties *props) { + const char *media_class_str; + const char *media_role_str; + + media_class_str = pw_properties_get(props, "media.class"); + media_role_str = pw_properties_get(props, "media.role"); + + if (media_class_str == NULL) + return -1; + + if (media_role_str == NULL) + return -1; + + if (strcmp(media_class_str, "Video/Source") != 0) + return -1; + + return media_role_from_string(media_role_str); +} + +static void check_portal_managed(struct client_info *cinfo) +{ + struct impl *impl = cinfo->impl; const struct pw_properties *props; - const char *str; - if ((props = pw_client_get_properties(client)) == NULL) - return -EINVAL; - if ((str = pw_properties_get(props, prop)) == NULL) - return -EINVAL; - return atoi(str); -} -static bool -check_global_owner(struct pw_client *client, struct pw_global *global) -{ - struct pw_client *owner; - int owner_uid, client_uid; + if (impl->portal_pid == 0) + return; - if (global == NULL) - return false; + props = pw_client_get_properties(cinfo->client); + if (props) { + const char *pid_str; + pid_t pid; - owner = pw_global_get_owner(global); - if (owner == NULL) - return false; + pid_str = pw_properties_get(props, PW_CLIENT_PROP_UCRED_PID); - owner_uid = get_client_prop(owner, PW_CLIENT_PROP_UCRED_UID); - client_uid = get_client_prop(client, PW_CLIENT_PROP_UCRED_UID); + pid = atoi(pid_str); - if (owner_uid < 0 || client_uid < 0) - return false; + if (pid == impl->portal_pid) { + cinfo->portal_managed = true; - /* same user can see eachothers objects */ - return owner_uid == client_uid; + pw_log_debug("module %p: portal managed client %p added", + impl, cinfo->client); + } + } } static int @@ -228,177 +185,194 @@ set_global_permissions(void *data, struct pw_global *global) struct impl *impl = cinfo->impl; struct pw_client *client = cinfo->client; const struct pw_properties *props; - const char *str; struct spa_dict_item items[1]; int n_items = 0; char perms[16]; + bool set_permission; bool allowed = false; props = pw_global_get_properties(global); if (pw_global_get_type(global) == impl->type->core) { + set_permission = true; allowed = true; } - else if (pw_global_get_type(global) == impl->type->factory) { - if (props && (str = pw_properties_get(props, "factory.name"))) { - if (strcmp(str, "client-node") == 0) - allowed = true; - } - } - else if (pw_global_get_type(global) == impl->type->node) { - if (props && (str = pw_properties_get(props, "media.class"))) { - if (strcmp(str, "Video/Source") == 0 && cinfo->camera_allowed) - allowed = true; - } - allowed |= check_global_owner(client, global); - } - else - allowed = check_global_owner(client, global); + else if (props) { + if (pw_global_get_type(global) == impl->type->factory) { + const char *factory_name; - snprintf(perms, sizeof(perms), "%d:%c--", pw_global_get_id(global), allowed ? 'r' : '-'); - items[n_items++] = SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, perms); - pw_client_update_permissions(client, &SPA_DICT_INIT(items, n_items)); + factory_name = pw_properties_get(props, "factory.name"); + if (factory_name && + strcmp(factory_name, "client-node") == 0) { + set_permission = true; + allowed = true; + } + else { + set_permission = false; + } + } + else if (pw_global_get_type(global) == impl->type->module) { + set_permission = true; + allowed = true; + } + else if (pw_global_get_type(global) == impl->type->node) { + enum media_role media_role; + + media_role = media_role_from_properties(props); + + if (media_role == -1) { + set_permission = false; + } + else if (cinfo->allowed_media_roles & media_role) { + set_permission = true; + allowed = true; + } + else if (cinfo->media_roles & media_role) { + set_permission = true; + allowed = false; + } + else { + set_permission = false; + } + } + else { + set_permission = false; + } + } + else { + set_permission = false; + } + + if (set_permission) { + snprintf(perms, sizeof(perms), + "%d:%c--", pw_global_get_id(global), allowed ? 'r' : '-'); + items[n_items++] = + SPA_DICT_ITEM_INIT(PW_CORE_PROXY_PERMISSIONS_GLOBAL, + perms); + pw_client_update_permissions(client, + &SPA_DICT_INIT(items, n_items)); + } return 0; } -static DBusHandlerResult -portal_response(DBusConnection *connection, DBusMessage *msg, void *user_data) +static bool +check_permission_allowed(DBusMessageIter *iter) { - struct client_info *cinfo = user_data; - struct pw_client *client = cinfo->client; + bool allowed = false; - if (dbus_message_is_signal(msg, "org.freedesktop.portal.Request", "Response")) { - uint32_t response = 2; - DBusError error; - struct async_pending *p; + while (dbus_message_iter_get_arg_type (iter) != DBUS_TYPE_INVALID) { + const char *permission_value; - dbus_error_init(&error); + dbus_message_iter_get_basic(iter, &permission_value); - dbus_connection_remove_filter(connection, portal_response, cinfo); - - if (!dbus_message_get_args - (msg, &error, DBUS_TYPE_UINT32, &response, DBUS_TYPE_INVALID)) { - pw_log_error("failed to parse Response: %s", error.message); - dbus_error_free(&error); + if (strcmp(permission_value, "yes") == 0) { + allowed = true; + break; } - - p = find_pending(cinfo, dbus_message_get_path(msg)); - if (p == NULL) - return DBUS_HANDLER_RESULT_HANDLED; - - p->handled = true; - - pw_log_debug("portal check result: %d", response); - - if (response == 0) { - /* allowed */ - cinfo->camera_allowed = true; - pw_log_debug("camera access allowed"); - } else { - cinfo->camera_allowed = false; - pw_log_debug("camera access not allowed"); - } - cinfo->checked = true; - pw_core_for_each_global(cinfo->impl->core, set_global_permissions, cinfo); - - free_pending(p); - pw_client_set_busy(client, false); - - return DBUS_HANDLER_RESULT_HANDLED; + dbus_message_iter_next(iter); } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + return allowed; } - -static void do_portal_check(struct client_info *cinfo) +static void do_permission_store_check(struct client_info *cinfo) { struct impl *impl = cinfo->impl; struct pw_client *client = cinfo->client; DBusMessage *m = NULL, *r = NULL; DBusError error; - pid_t pid; DBusMessageIter msg_iter; - DBusMessageIter dict_iter; - const char *handle; - const char *device; - struct async_pending *p; + const char *table; + const char *id; + DBusMessageIter r_iter; + DBusMessageIter permissions_iter; - pw_log_info("ask portal for client %p", client); - pw_client_set_busy(client, true); + if (cinfo->app_id == NULL) { + pw_log_debug("Ignoring portal check for broken portal managed client %p", + client); + goto err_not_allowed; + } + + if (cinfo->media_roles == 0) { + pw_log_debug("Ignoring portal check for portal client %p with static permissions", + client); + pw_core_for_each_global(cinfo->impl->core, + set_global_permissions, + cinfo); + return; + } + + if (strcmp(cinfo->app_id, "") == 0) { + pw_log_debug("Ignoring portal check for non-sandboxed portal client %p", + client); + cinfo->allowed_media_roles = MEDIA_ROLE_ALL; + pw_core_for_each_global(cinfo->impl->core, + set_global_permissions, + cinfo); + return; + } + + cinfo->allowed_media_roles = MEDIA_ROLE_NONE; dbus_error_init(&error); - if (!(m = dbus_message_new_method_call("org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.Device", "AccessDevice"))) - goto no_method_call; - - device = "camera"; - - pid = get_client_prop(client, PW_CLIENT_PROP_UCRED_PID); - if (pid < 0) - goto not_allowed; - if (!dbus_message_append_args(m, DBUS_TYPE_UINT32, &pid, DBUS_TYPE_INVALID)) - goto message_failed; + m = dbus_message_new_method_call("org.freedesktop.impl.portal.PermissionStore", + "/org/freedesktop/impl/portal/PermissionStore", + "org.freedesktop.impl.portal.PermissionStore", + "Lookup"); dbus_message_iter_init_append(m, &msg_iter); - dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "s", &dict_iter); - dbus_message_iter_append_basic(&dict_iter, DBUS_TYPE_STRING, &device); - dbus_message_iter_close_container(&msg_iter, &dict_iter); + table = "devices"; + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &table); + id = "camera"; + dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &id); - dbus_message_iter_open_container(&msg_iter, DBUS_TYPE_ARRAY, "{sv}", &dict_iter); - dbus_message_iter_close_container(&msg_iter, &dict_iter); - - if (!(r = dbus_connection_send_with_reply_and_block(impl->bus, m, -1, &error))) - goto send_failed; + if (!(r = dbus_connection_send_with_reply_and_block(impl->bus, m, -1, &error))) { + pw_log_error("Failed to call permission store: %s", error.message); + dbus_error_free(&error); + goto err_not_allowed; + } dbus_message_unref(m); - if (!dbus_message_get_args(r, &error, DBUS_TYPE_OBJECT_PATH, &handle, DBUS_TYPE_INVALID)) - goto parse_failed; + dbus_message_iter_init(r, &r_iter); + dbus_message_iter_recurse(&r_iter, &permissions_iter); + while (dbus_message_iter_get_arg_type(&permissions_iter) != + DBUS_TYPE_INVALID) { + DBusMessageIter permissions_entry_iter; + const char *app_id; + DBusMessageIter permission_values_iter; + bool camera_allowed; + + dbus_message_iter_recurse(&permissions_iter, + &permissions_entry_iter); + dbus_message_iter_get_basic(&permissions_entry_iter, &app_id); + + if (strcmp(app_id, cinfo->app_id) != 0) { + dbus_message_iter_next(&permissions_iter); + continue; + } + + dbus_message_iter_next(&permissions_entry_iter); + dbus_message_iter_recurse(&permissions_entry_iter, + &permission_values_iter); + + camera_allowed = check_permission_allowed(&permission_values_iter); + cinfo->allowed_media_roles |= + camera_allowed ? MEDIA_ROLE_CAMERA : MEDIA_ROLE_NONE; + pw_core_for_each_global(cinfo->impl->core, + set_global_permissions, + cinfo); + + break; + } dbus_message_unref(r); - dbus_bus_add_match(impl->bus, - "type='signal',interface='org.freedesktop.portal.Request'", &error); - dbus_connection_flush(impl->bus); - if (dbus_error_is_set(&error)) - goto subscribe_failed; - - dbus_connection_add_filter(impl->bus, portal_response, cinfo, NULL); - - p = calloc(1, sizeof(struct async_pending)); - p->cinfo = cinfo; - p->handle = strdup(handle); - p->handled = false; - - pw_log_debug("pending %p: handle %s", p, handle); - spa_list_append(&cinfo->async_pending, &p->link); - return; - no_method_call: - pw_log_error("Failed to create message"); - goto not_allowed; - message_failed: - dbus_message_unref(m); - goto not_allowed; - send_failed: - pw_log_error("Failed to call portal: %s", error.message); - dbus_error_free(&error); - dbus_message_unref(m); - goto not_allowed; - parse_failed: - pw_log_error("Failed to parse AccessDevice result: %s", error.message); - dbus_error_free(&error); - dbus_message_unref(r); - goto not_allowed; - subscribe_failed: - pw_log_error("Failed to subscribe to Request signal: %s", error.message); - dbus_error_free(&error); - goto not_allowed; - not_allowed: + err_not_allowed: pw_resource_error(pw_client_get_core_resource(client), -EPERM, "not allowed"); return; } @@ -406,22 +380,45 @@ static void do_portal_check(struct client_info *cinfo) static void client_info_changed(void *data, struct pw_client_info *info) { struct client_info *cinfo = data; - const char *str; + const struct pw_properties *properties; + const char *app_id; + const char *media_roles; + + if (!cinfo->portal_managed) + return; if (info->props == NULL) return; - if ((str = spa_dict_lookup(info->props, "pipewire.access")) == NULL) + if (cinfo->setup_complete) return; + cinfo->setup_complete = true; - if (strcmp(str, "flatpak") != 0) + properties = pw_client_get_properties(cinfo->client); + if (properties == NULL) { + pw_log_error("Portal managed client didn't have any properties"); return; - - if (cinfo->checked) + } + app_id = pw_properties_get(properties, + "pipewire.access.portal.app_id"); + if (app_id == NULL) { + pw_log_error("Portal managed client didn't set app_id"); return; + } + media_roles = pw_properties_get(properties, + "pipewire.access.portal.media_roles"); - pw_log_debug("module %p: client %p set to flatpak access", cinfo->impl, cinfo->client); - do_portal_check(cinfo); + if (media_roles == NULL) { + pw_log_error("Portal managed client didn't set media_roles"); + return; + } + + cinfo->app_id = strdup(app_id); + cinfo->media_roles = parse_media_roles(media_roles); + + pw_log_debug("module %p: client %p with app_id '%s' set to portal access", + cinfo->impl, cinfo->client, cinfo->app_id); + do_permission_store_check(cinfo); } static const struct pw_client_events client_events = { @@ -434,40 +431,22 @@ core_global_added(void *data, struct pw_global *global) { struct impl *impl = data; struct client_info *cinfo; - int res; if (pw_global_get_type(global) == impl->type->client) { struct pw_client *client = pw_global_get_object(global); - /* clients are placed in a list and we do a portal check when needed */ cinfo = calloc(1, sizeof(struct client_info)); cinfo->impl = impl; cinfo->client = client; - spa_list_init(&cinfo->async_pending); pw_client_add_listener(client, &cinfo->client_listener, &client_events, cinfo); spa_list_append(&impl->client_list, &cinfo->link); - res = check_sandboxed(client); - if (res == 0) { - pw_log_debug("module %p: non sandboxed client %p", impl, client); - return; - } - cinfo->sandboxed = true; - - if (res < 0) { - pw_log_warn("module %p: client %p sandbox check failed: %s", - impl, client, spa_strerror(res)); - } - else { - pw_log_debug("module %p: sandboxed client %p added", impl, client); - } - - do_portal_check(cinfo); + check_portal_managed(cinfo); } else { spa_list_for_each(cinfo, &impl->client_list, link) { - if (cinfo->sandboxed) + if (cinfo->portal_managed) set_global_permissions(cinfo, global); } } @@ -519,6 +498,234 @@ static const struct pw_module_events module_events = { .destroy = module_destroy, }; +static void on_portal_pid_received(DBusPendingCall *pending, + void *user_data) +{ + struct impl *impl = user_data; + DBusMessage *m; + DBusError error; + uint32_t portal_pid = 0; + + m = dbus_pending_call_steal_reply(pending); + dbus_pending_call_unref(pending); + impl->portal_pid_pending = NULL; + + if (!m) { + pw_log_error("Failed to receive portal pid"); + return; + } + + dbus_error_init(&error); + dbus_message_get_args(m, &error, DBUS_TYPE_UINT32, &portal_pid, + DBUS_TYPE_INVALID); + dbus_message_unref(m); + + if (dbus_error_is_set(&error)) { + impl->portal_pid = 0; + } + else { + struct client_info *cinfo; + + impl->portal_pid = portal_pid; + + spa_list_for_each(cinfo, &impl->client_list, link) { + if (cinfo->portal_managed) + continue; + + check_portal_managed(cinfo); + } + } +} + +static void update_portal_pid(struct impl *impl) +{ + DBusMessage *m; + const char *name; + DBusPendingCall *pending; + + impl->portal_pid = 0; + + m = dbus_message_new_method_call("org.freedesktop.DBus", + "/", + "org.freedesktop.DBus", + "GetConnectionUnixProcessID"); + + name = "org.freedesktop.portal.Desktop"; + dbus_message_append_args(m, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + + dbus_connection_send_with_reply(impl->bus, m, &pending, -1); + dbus_pending_call_set_notify(pending, on_portal_pid_received, impl, NULL); + if (impl->portal_pid_pending != NULL) { + dbus_pending_call_cancel(impl->portal_pid_pending); + dbus_pending_call_unref(impl->portal_pid_pending); + } + impl->portal_pid_pending = pending; +} + +static DBusHandlerResult name_owner_changed_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + struct impl *impl = user_data; + const char *name; + const char *old_owner; + const char *new_owner; + + if (!dbus_message_is_signal(message, "org.freedesktop.DBus", + "NameOwnerChanged")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (!dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &old_owner, + DBUS_TYPE_STRING, &new_owner, + DBUS_TYPE_INVALID)) { + pw_log_error("Failed to get OwnerChanged args"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + if (strcmp(name, "org.freedesktop.portal.Desktop") != 0) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + if (strcmp(new_owner, "") == 0) { + impl->portal_pid = 0; + if (impl->portal_pid_pending != NULL) { + dbus_pending_call_cancel(impl->portal_pid_pending); + dbus_pending_call_unref(impl->portal_pid_pending); + } + } + else { + update_portal_pid(impl); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static DBusHandlerResult permission_store_changed_handler(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + struct impl *impl = user_data; + struct client_info *cinfo; + DBusMessageIter iter; + const char *table; + const char *id; + dbus_bool_t deleted; + DBusMessageIter permissions_iter; + + if (!dbus_message_is_signal(message, "org.freedesktop.impl.portal.PermissionStore", + "Changed")) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + + spa_list_for_each(cinfo, &impl->client_list, link) { + if (!cinfo->portal_managed) + continue; + + cinfo->allowed_media_roles = MEDIA_ROLE_NONE; + } + + dbus_message_iter_init(message, &iter); + dbus_message_iter_get_basic(&iter, &table); + + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &id); + + if (strcmp(table, "devices") != 0 || strcmp(id, "camera") != 0) + return DBUS_HANDLER_RESULT_HANDLED; + + dbus_message_iter_next(&iter); + dbus_message_iter_get_basic(&iter, &deleted); + + dbus_message_iter_next(&iter); + /* data variant (ignored) */ + + dbus_message_iter_next(&iter); + dbus_message_iter_recurse(&iter, &permissions_iter); + while (dbus_message_iter_get_arg_type(&permissions_iter) != + DBUS_TYPE_INVALID) { + DBusMessageIter permissions_entry_iter; + const char *app_id; + DBusMessageIter permission_values_iter; + bool camera_allowed; + + dbus_message_iter_recurse(&permissions_iter, + &permissions_entry_iter); + dbus_message_iter_get_basic(&permissions_entry_iter, &app_id); + + dbus_message_iter_next(&permissions_entry_iter); + dbus_message_iter_recurse(&permissions_entry_iter, + &permission_values_iter); + + camera_allowed = check_permission_allowed(&permission_values_iter); + + spa_list_for_each(cinfo, &impl->client_list, link) { + if (!cinfo->portal_managed) + continue; + + if (strcmp(cinfo->app_id, app_id) != 0) + continue; + + if (!(cinfo->media_roles & MEDIA_ROLE_CAMERA)) + continue; + + if (camera_allowed) + cinfo->allowed_media_roles |= MEDIA_ROLE_CAMERA; + pw_core_for_each_global(cinfo->impl->core, + set_global_permissions, + cinfo); + } + + dbus_message_iter_next(&permissions_iter); + } + + return DBUS_HANDLER_RESULT_HANDLED; +} + +static int init_dbus_connection(struct impl *impl) +{ + DBusError error; + + impl->bus = spa_dbus_connection_get(impl->conn); + + dbus_error_init(&error); + + dbus_bus_add_match(impl->bus, + "type='signal',\ + sender='org.freedesktop.DBus',\ + interface='org.freedesktop.DBus',\ + member='NameOwnerChanged'", + &error); + if (dbus_error_is_set(&error)) { + pw_log_error("Failed to add name owner changed listener: %s", + error.message); + dbus_error_free(&error); + return -1; + } + + dbus_bus_add_match(impl->bus, + "type='signal',\ + sender='org.freedesktop.impl.portal.PermissionStore',\ + interface='org.freedesktop.impl.portal.PermissionStore',\ + member='Changed'", + &error); + if (dbus_error_is_set(&error)) { + pw_log_error("Failed to add permission store changed listener: %s", + error.message); + dbus_error_free(&error); + return -1; + } + + dbus_connection_add_filter(impl->bus, name_owner_changed_handler, + impl, NULL); + dbus_connection_add_filter(impl->bus, permission_store_changed_handler, + impl, NULL); + update_portal_pid(impl); + + return 0; +} + static int module_init(struct pw_module *module, struct pw_properties *properties) { struct pw_core *core = pw_module_get_core(module); @@ -547,7 +754,8 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie if (impl->conn == NULL) goto error; - impl->bus = spa_dbus_connection_get(impl->conn); + if (init_dbus_connection(impl) != 0) + goto error; spa_list_init(&impl->client_list); From 1c8daa4a507e1580dd0a931febd64895e7aa4376 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Thu, 9 May 2019 09:24:21 +0200 Subject: [PATCH 127/155] core: fix pw_core_find_format() for active ports pw_core_find_format() is currently broken when one of the ports is already active: The format of the active port is used and the other port is completely ignored. As a result, the autolink module may try to link a new port to the first already active port even if the formats do not match. To fix this, use the format of the active port as a filter and enumerate the formats of the other port. --- src/pipewire/core.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index dcf0def6d..c0ae3f936 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -773,27 +773,51 @@ int pw_core_find_format(struct pw_core *core, in_state = PW_PORT_STATE_CONFIGURE; if (in_state == PW_PORT_STATE_CONFIGURE && out_state > PW_PORT_STATE_CONFIGURE) { - /* only input needs format */ + struct spa_pod_builder fb = { 0 }; + uint8_t fbuf[4096]; + struct spa_pod *dummy; + spa_pod_builder_init(&fb, fbuf, sizeof(fbuf)); if ((res = spa_node_port_enum_params(output->node->node, output->spa_direction, output->port_id, t->param.idFormat, &oidx, - NULL, format, builder)) <= 0) { - if (res == 0) - res = -EBADF; + NULL, format, &fb)) <= 0) { asprintf(error, "error get output format: %s", spa_strerror(res)); goto error; } + pw_log_debug("Got output %d format:", oidx); + if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) + spa_debug_format(2, core->type.map, *format); + + if ((res = spa_node_port_enum_params(input->node->node, + input->spa_direction, input->port_id, + t->param.idEnumFormat, &iidx, + *format, &dummy, builder)) <= 0) { + asprintf(error, "error input enum formats: %d", res); + goto error; + } } else if (out_state == PW_PORT_STATE_CONFIGURE && in_state > PW_PORT_STATE_CONFIGURE) { - /* only output needs format */ + struct spa_pod_builder fb = { 0 }; + uint8_t fbuf[4096]; + struct spa_pod *dummy; + spa_pod_builder_init(&fb, fbuf, sizeof(fbuf)); if ((res = spa_node_port_enum_params(input->node->node, input->spa_direction, input->port_id, t->param.idFormat, &iidx, - NULL, format, builder)) <= 0) { - if (res == 0) - res = -EBADF; + NULL, format, &fb)) <= 0) { asprintf(error, "error get input format: %s", spa_strerror(res)); goto error; } + pw_log_debug("Got input %d format:", oidx); + if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) + spa_debug_format(2, core->type.map, *format); + + if ((res = spa_node_port_enum_params(output->node->node, + output->spa_direction, output->port_id, + t->param.idEnumFormat, &oidx, + *format, &dummy, builder)) <= 0) { + asprintf(error, "error output enum formats: %d", res); + goto error; + } } else if (in_state == PW_PORT_STATE_CONFIGURE && out_state == PW_PORT_STATE_CONFIGURE) { struct spa_pod_builder fb = { 0 }; uint8_t fbuf[4096]; From abaf40ba8b064a475a92ffac35b18fd18d4cc6d7 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 17 May 2019 12:37:25 +0200 Subject: [PATCH 128/155] core: small cleanup in _find_format() --- src/pipewire/core.c | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/pipewire/core.c b/src/pipewire/core.c index c0ae3f936..1172d6d08 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -760,6 +760,9 @@ int pw_core_find_format(struct pw_core *core, int res; uint32_t iidx = 0, oidx = 0; struct pw_type *t = &core->type; + struct spa_pod_builder fb = { 0 }; + uint8_t fbuf[4096]; + struct spa_pod *filter; out_state = output->state; in_state = input->state; @@ -773,55 +776,46 @@ int pw_core_find_format(struct pw_core *core, in_state = PW_PORT_STATE_CONFIGURE; if (in_state == PW_PORT_STATE_CONFIGURE && out_state > PW_PORT_STATE_CONFIGURE) { - struct spa_pod_builder fb = { 0 }; - uint8_t fbuf[4096]; - struct spa_pod *dummy; spa_pod_builder_init(&fb, fbuf, sizeof(fbuf)); if ((res = spa_node_port_enum_params(output->node->node, output->spa_direction, output->port_id, t->param.idFormat, &oidx, - NULL, format, &fb)) <= 0) { + NULL, &filter, &fb)) <= 0) { asprintf(error, "error get output format: %s", spa_strerror(res)); goto error; } pw_log_debug("Got output %d format:", oidx); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_format(2, core->type.map, *format); + spa_debug_format(2, core->type.map, filter); if ((res = spa_node_port_enum_params(input->node->node, input->spa_direction, input->port_id, t->param.idEnumFormat, &iidx, - *format, &dummy, builder)) <= 0) { + filter, format, builder)) <= 0) { asprintf(error, "error input enum formats: %d", res); goto error; } } else if (out_state == PW_PORT_STATE_CONFIGURE && in_state > PW_PORT_STATE_CONFIGURE) { - struct spa_pod_builder fb = { 0 }; - uint8_t fbuf[4096]; - struct spa_pod *dummy; spa_pod_builder_init(&fb, fbuf, sizeof(fbuf)); if ((res = spa_node_port_enum_params(input->node->node, input->spa_direction, input->port_id, t->param.idFormat, &iidx, - NULL, format, &fb)) <= 0) { + NULL, &filter, &fb)) <= 0) { asprintf(error, "error get input format: %s", spa_strerror(res)); goto error; } - pw_log_debug("Got input %d format:", oidx); + pw_log_debug("Got input %d format:", iidx); if (pw_log_level_enabled(SPA_LOG_LEVEL_DEBUG)) - spa_debug_format(2, core->type.map, *format); + spa_debug_format(2, core->type.map, filter); if ((res = spa_node_port_enum_params(output->node->node, output->spa_direction, output->port_id, t->param.idEnumFormat, &oidx, - *format, &dummy, builder)) <= 0) { + filter, format, builder)) <= 0) { asprintf(error, "error output enum formats: %d", res); goto error; } } else if (in_state == PW_PORT_STATE_CONFIGURE && out_state == PW_PORT_STATE_CONFIGURE) { - struct spa_pod_builder fb = { 0 }; - uint8_t fbuf[4096]; - struct spa_pod *filter; again: /* both ports need a format */ pw_log_debug("core %p: do enum input %d", core, iidx); From 55eadd6c4c7d1d1973d0e0253b5e69cb3f706f92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 20 May 2019 12:29:14 +0200 Subject: [PATCH 129/155] module-portal: Ignore if pipewire.access.portal.is_portal is "yes" This is for the remotes that the portal itself owns, such as ones that track the number of cameras. --- src/modules/module-portal.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/modules/module-portal.c b/src/modules/module-portal.c index 0861832fe..4567fe1f6 100644 --- a/src/modules/module-portal.c +++ b/src/modules/module-portal.c @@ -71,6 +71,7 @@ struct client_info { bool portal_managed; bool setup_complete; + bool is_portal; char *app_id; enum media_role media_roles; enum media_role allowed_media_roles; @@ -381,6 +382,7 @@ static void client_info_changed(void *data, struct pw_client_info *info) { struct client_info *cinfo = data; const struct pw_properties *properties; + const char *is_portal; const char *app_id; const char *media_roles; @@ -399,6 +401,16 @@ static void client_info_changed(void *data, struct pw_client_info *info) pw_log_error("Portal managed client didn't have any properties"); return; } + + is_portal = pw_properties_get(properties, + "pipewire.access.portal.is_portal"); + if (is_portal != NULL && strcmp(is_portal, "yes") == 0) { + pw_log_debug("module %p: client %p is the portal itself", + cinfo->impl, cinfo->client); + cinfo->is_portal = true; + return; + }; + app_id = pw_properties_get(properties, "pipewire.access.portal.app_id"); if (app_id == NULL) { @@ -446,7 +458,8 @@ core_global_added(void *data, struct pw_global *global) } else { spa_list_for_each(cinfo, &impl->client_list, link) { - if (cinfo->portal_managed) + if (cinfo->portal_managed && + !cinfo->is_portal) set_global_permissions(cinfo, global); } } @@ -664,6 +677,9 @@ static DBusHandlerResult permission_store_changed_handler(DBusConnection *connec if (!cinfo->portal_managed) continue; + if (cinfo->is_portal) + continue; + if (strcmp(cinfo->app_id, app_id) != 0) continue; From 323917ab4ba80c6e91185ac214aba6aa51cc1c48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Mon, 20 May 2019 12:30:22 +0200 Subject: [PATCH 130/155] module-portal: Handle no app_id being set Avoid crashing if the portal would for whatever reason fail to set this. --- src/modules/module-portal.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/modules/module-portal.c b/src/modules/module-portal.c index 4567fe1f6..c52416bf6 100644 --- a/src/modules/module-portal.c +++ b/src/modules/module-portal.c @@ -680,7 +680,8 @@ static DBusHandlerResult permission_store_changed_handler(DBusConnection *connec if (cinfo->is_portal) continue; - if (strcmp(cinfo->app_id, app_id) != 0) + if (cinfo->app_id == NULL || + strcmp(cinfo->app_id, app_id) != 0) continue; if (!(cinfo->media_roles & MEDIA_ROLE_CAMERA)) From 6b269cce35beea7b8ac04be5a84aafcab2af0903 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Thu, 2 May 2019 15:02:59 +0200 Subject: [PATCH 131/155] node: use spa_list_for_each_safe() for pw_node_events_* Introduce spa_hook_list_call_simple_safe() as a new helper that uses spa_list_for_each_safe() and use it for pw_node_events_* This way multiple threads can iterate at the same time and, if only one thread is active, the current list entry can be safely removed (e.g. in pw_node_events_destroy()). Without this the node listener_list may be corrupted when the main and data loop iterate over the list at the same time (See #143). --- spa/include/spa/utils/hook.h | 13 +++++++++++++ src/pipewire/private.h | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/spa/include/spa/utils/hook.h b/spa/include/spa/utils/hook.h index 7685631af..32421248f 100644 --- a/spa/include/spa/utils/hook.h +++ b/spa/include/spa/utils/hook.h @@ -94,6 +94,19 @@ static inline void spa_hook_remove(struct spa_hook *hook) } \ }) +#define spa_hook_list_call_simple_safe(l,type,method,vers,...) \ +({ \ + struct spa_hook_list *list = l; \ + struct spa_hook *ci; \ + struct spa_hook *tmp; \ + spa_list_for_each_safe(ci, tmp, &list->list, link) { \ + const type *cb = ci->funcs; \ + if (cb && cb->version >= vers && cb->method) { \ + cb->method(ci->data, ## __VA_ARGS__); \ + } \ + } \ +}) + /** Call all hooks in a list, starting from the given one and optionally stopping * after calling the first non-NULL function, returns the number of methods * called */ diff --git a/src/pipewire/private.h b/src/pipewire/private.h index 1bb314e7c..a4f062f70 100644 --- a/src/pipewire/private.h +++ b/src/pipewire/private.h @@ -303,7 +303,7 @@ struct pw_module { void *user_data; /**< module user_data */ }; -#define pw_node_events_emit(o,m,v,...) spa_hook_list_call(&o->listener_list, struct pw_node_events, m, v, ##__VA_ARGS__) +#define pw_node_events_emit(o,m,v,...) spa_hook_list_call_simple_safe(&o->listener_list, struct pw_node_events, m, v, ##__VA_ARGS__) #define pw_node_events_destroy(n) pw_node_events_emit(n, destroy, 0) #define pw_node_events_free(n) pw_node_events_emit(n, free, 0) #define pw_node_events_initialized(n) pw_node_events_emit(n, initialized, 0) From b700d76ff45225a3a2058ad96cd8479a5f71b015 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 21 May 2019 17:11:27 +0200 Subject: [PATCH 132/155] list: use spa_list_consume some more If we know the item is removed in each iteration, _consume can handle deletion of any item while being iterated. --- src/daemon/daemon-config.c | 8 ++++---- src/modules/module-suspend-on-idle.c | 4 ++-- src/modules/spa/module-node-factory.c | 4 ++-- src/pipewire/control.c | 4 ++-- src/pipewire/node.c | 8 ++------ src/pipewire/port.c | 6 +++--- 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/daemon/daemon-config.c b/src/daemon/daemon-config.c index bcc09ac3d..877fe5d95 100644 --- a/src/daemon/daemon-config.c +++ b/src/daemon/daemon-config.c @@ -87,9 +87,9 @@ struct pw_daemon_config *pw_daemon_config_new(void) */ void pw_daemon_config_free(struct pw_daemon_config *config) { - struct pw_command *cmd, *tmp; + struct pw_command *cmd; - spa_list_for_each_safe(cmd, tmp, &config->commands, link) + spa_list_consume(cmd, &config->commands, link) pw_command_free(cmd); free(config); @@ -184,7 +184,7 @@ int pw_daemon_config_run_commands(struct pw_daemon_config *config, struct pw_cor { char *err = NULL; int ret = 0; - struct pw_command *command, *tmp; + struct pw_command *command; spa_list_for_each(command, &config->commands, link) { if ((ret = pw_command_run(command, core, &err)) < 0) { @@ -194,7 +194,7 @@ int pw_daemon_config_run_commands(struct pw_daemon_config *config, struct pw_cor } } - spa_list_for_each_safe(command, tmp, &config->commands, link) + spa_list_consume(command, &config->commands, link) pw_command_free(command); return ret; diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 56775376f..e5c1fcb30 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -156,9 +156,9 @@ core_global_removed(void *data, struct pw_global *global) static void module_destroy(void *data) { struct impl *impl = data; - struct node_info *info, *t; + struct node_info *info; - spa_list_for_each_safe(info, t, &impl->node_list, link) + spa_list_consume(info, &impl->node_list, link) node_info_free(info); spa_hook_remove(&impl->core_listener); diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index 560089a7c..318116050 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -136,11 +136,11 @@ static const struct pw_factory_implementation factory_impl = { static void factory_destroy(void *_data) { struct factory_data *data = _data; - struct node_data *nd, *t; + struct node_data *nd; spa_hook_remove(&data->module_listener); - spa_list_for_each_safe(nd, t, &data->node_list, link) + spa_list_consume(nd, &data->node_list, link) pw_node_destroy(nd->node); if (data->properties) diff --git a/src/pipewire/control.c b/src/pipewire/control.c index 1c8873db0..97d43e8a8 100644 --- a/src/pipewire/control.c +++ b/src/pipewire/control.c @@ -85,14 +85,14 @@ pw_control_new(struct pw_core *core, void pw_control_destroy(struct pw_control *control) { struct impl *impl = SPA_CONTAINER_OF(control, struct impl, this); - struct pw_control *other, *tmp; + struct pw_control *other; pw_log_debug("control %p: destroy", control); pw_control_events_destroy(control); if (control->direction == SPA_DIRECTION_OUTPUT) { - spa_list_for_each_safe(other, tmp, &control->inputs, inputs_link) + spa_list_consume(other, &control->inputs, inputs_link) pw_control_unlink(control, other); } else { diff --git a/src/pipewire/node.c b/src/pipewire/node.c index 0a752a0e0..ad6acccc9 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -644,14 +644,10 @@ void pw_node_destroy(struct pw_node *node) pw_port_unlink(port); pw_log_debug("node %p: destroy ports", node); - spa_list_consume(port, &node->input_ports, link) { - pw_node_events_port_removed(node, port); + spa_list_consume(port, &node->input_ports, link) pw_port_destroy(port); - } - spa_list_consume(port, &node->output_ports, link) { - pw_node_events_port_removed(node, port); + spa_list_consume(port, &node->output_ports, link) pw_port_destroy(port); - } if (node->global) { spa_hook_remove(&node->global_listener); diff --git a/src/pipewire/port.c b/src/pipewire/port.c index ab4642c38..7d480a82a 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -487,14 +487,14 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) void pw_port_unlink(struct pw_port *port) { - struct pw_link *l, *t; + struct pw_link *l; if (port->direction == PW_DIRECTION_OUTPUT) { - spa_list_for_each_safe(l, t, &port->links, output_link) + spa_list_consume(l, &port->links, output_link) pw_link_destroy(l); } else { - spa_list_for_each_safe(l, t, &port->links, input_link) + spa_list_consume(l, &port->links, input_link) pw_link_destroy(l); } } From 92808809ec4369b03e619ff791be13dcb81dedf2 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 May 2019 10:05:24 +0200 Subject: [PATCH 133/155] client-node: don't destroy the resource from its event Do no destroy the resource from within the event handler --- src/modules/module-client-node/client-node.c | 7 ------- src/modules/module-client-node/protocol-native.c | 1 + 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index 27e703292..ccb043d4f 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -1047,12 +1047,6 @@ static void client_node_event(void *data, struct spa_event *event) this->callbacks->event(this->callbacks_data, event); } -static void client_node_destroy(void *data) -{ - struct impl *impl = data; - pw_client_node_destroy(&impl->this); -} - static struct pw_client_node_proxy_methods client_node_methods = { PW_VERSION_CLIENT_NODE_PROXY_METHODS, .done = client_node_done, @@ -1060,7 +1054,6 @@ static struct pw_client_node_proxy_methods client_node_methods = { .port_update = client_node_port_update, .set_active = client_node_set_active, .event = client_node_event, - .destroy = client_node_destroy, }; static void node_on_data_fd_events(struct spa_source *source) diff --git a/src/modules/module-client-node/protocol-native.c b/src/modules/module-client-node/protocol-native.c index 30852a8c8..30d9e99cd 100644 --- a/src/modules/module-client-node/protocol-native.c +++ b/src/modules/module-client-node/protocol-native.c @@ -832,6 +832,7 @@ static int client_node_demarshal_destroy(void *object, void *data, size_t size) return -EINVAL; pw_resource_do(resource, struct pw_client_node_proxy_methods, destroy, 0); + pw_resource_destroy(resource); return 0; } From c67f903c612acb12a1dd92ae52a2ff831665cb5a Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 May 2019 10:09:12 +0200 Subject: [PATCH 134/155] Return -EEXIST when registering an object twice --- src/pipewire/client.c | 3 +++ src/pipewire/factory.c | 3 +++ src/pipewire/link.c | 3 +++ src/pipewire/port.c | 4 ++++ 4 files changed, 13 insertions(+) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 4c647fe2a..ef2197c92 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -215,6 +215,9 @@ int pw_client_register(struct pw_client *client, { struct pw_core *core = client->core; + if (client->registered) + return -EEXIST; + pw_log_debug("client %p: register parent %d", client, parent ? parent->id : SPA_ID_INVALID); spa_list_append(&core->client_list, &client->link); diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index fb611eef1..489b7659a 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -142,6 +142,9 @@ int pw_factory_register(struct pw_factory *factory, { struct pw_core *core = factory->core; + if (factory->registered) + return -EEXIST; + if (properties == NULL) properties = pw_properties_new(NULL, NULL); if (properties == NULL) diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 9b33c1606..1a37d5cee 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1280,6 +1280,9 @@ int pw_link_register(struct pw_link *link, struct pw_core *core = link->core; struct pw_node *input_node, *output_node; + if (link->registered) + return -EEXIST; + if (properties == NULL) properties = pw_properties_new(NULL, NULL); if (properties == NULL) diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 7d480a82a..49e55a6d5 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -426,6 +426,9 @@ int pw_port_add(struct pw_port *port, struct pw_node *node) struct pw_type *t = &core->type; const char *str, *dir; + if (port->node != NULL) + return -EEXIST; + port->node = node; spa_node_port_get_info(node->node, @@ -537,6 +540,7 @@ static void pw_port_remove(struct pw_port *port) } spa_list_remove(&port->link); pw_node_events_port_removed(node, port); + port->node = NULL; } void pw_port_destroy(struct pw_port *port) From 0951a97a364e32edbb1197b8e2b915383b2e4459 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 May 2019 10:09:48 +0200 Subject: [PATCH 135/155] destroy resources first, then the global --- src/pipewire/client.c | 12 ++++++------ src/pipewire/core.c | 12 +++++++++--- src/pipewire/factory.c | 6 ++++++ src/pipewire/link.c | 6 +++--- src/pipewire/module.c | 5 +++-- src/pipewire/node.c | 5 +++-- src/pipewire/port.c | 5 +++-- 7 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/pipewire/client.c b/src/pipewire/client.c index ef2197c92..6d237e21d 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -301,18 +301,18 @@ void pw_client_destroy(struct pw_client *client) if (client->registered) spa_list_remove(&client->link); + pw_map_for_each(&client->objects, destroy_resource, client); + + spa_list_consume(resource, &client->resource_list, link) + pw_resource_destroy(resource); + if (client->global) { spa_hook_remove(&client->global_listener); pw_global_destroy(client->global); } - spa_list_consume(resource, &client->resource_list, link) - pw_resource_destroy(resource); - - pw_map_for_each(&client->objects, destroy_resource, client); - - pw_client_events_free(client); pw_log_debug("client %p: free", impl); + pw_client_events_free(client); pw_map_clear(&client->objects); pw_map_clear(&client->types); diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 1172d6d08..99cac19e0 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -488,6 +488,7 @@ void pw_core_destroy(struct pw_core *core) struct pw_global *global; struct pw_module *module; struct pw_remote *remote; + struct pw_resource *resource; struct pw_node *node; pw_log_debug("core %p: destroy", core); @@ -504,9 +505,17 @@ void pw_core_destroy(struct pw_core *core) spa_list_consume(node, &core->node_list, link) pw_node_destroy(node); + spa_list_consume(resource, &core->registry_resource_list, link) + pw_resource_destroy(resource); + + spa_list_consume(resource, &core->resource_list, link) + pw_resource_destroy(resource); + spa_list_consume(global, &core->global_list, link) pw_global_destroy(global); + pw_map_clear(&core->globals); + pw_log_debug("core %p: free", core); pw_core_events_free(core); pw_data_loop_destroy(core->data_loop_impl); @@ -515,9 +524,6 @@ void pw_core_destroy(struct pw_core *core) pw_properties_free(core->properties); - pw_map_clear(&core->globals); - - pw_log_debug("core %p: free", core); free(core); } diff --git a/src/pipewire/factory.c b/src/pipewire/factory.c index 489b7659a..0872255f3 100644 --- a/src/pipewire/factory.c +++ b/src/pipewire/factory.c @@ -59,16 +59,22 @@ struct pw_factory *pw_factory_new(struct pw_core *core, SPA_EXPORT void pw_factory_destroy(struct pw_factory *factory) { + struct pw_resource *resource; + pw_log_debug("factory %p: destroy", factory); pw_factory_events_destroy(factory); if (factory->registered) spa_list_remove(&factory->link); + spa_list_consume(resource, &factory->resource_list, link) + pw_resource_destroy(resource); + if (factory->global) { spa_hook_remove(&factory->global_listener); pw_global_destroy(factory->global); } + free((char *)factory->info.name); if (factory->properties) pw_properties_free(factory->properties); diff --git a/src/pipewire/link.c b/src/pipewire/link.c index 1a37d5cee..3a4f5a3ef 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -1348,14 +1348,14 @@ void pw_link_destroy(struct pw_link *link) output_remove(link, link->output); + spa_list_consume(resource, &link->resource_list, link) + pw_resource_destroy(resource); + if (link->global) { spa_hook_remove(&link->global_listener); pw_global_destroy(link->global); } - spa_list_consume(resource, &link->resource_list, link) - pw_resource_destroy(resource); - pw_log_debug("link %p: free", impl); pw_link_events_free(link); diff --git a/src/pipewire/module.c b/src/pipewire/module.c index da4173ea8..02f446a41 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -294,12 +294,13 @@ void pw_module_destroy(struct pw_module *module) spa_list_remove(&module->link); + spa_list_consume(resource, &module->resource_list, link) + pw_resource_destroy(resource); + if (module->global) { spa_hook_remove(&module->global_listener); pw_global_destroy(module->global); } - spa_list_consume(resource, &module->resource_list, link) - pw_resource_destroy(resource); free((char *) module->info.name); free((char *) module->info.filename); diff --git a/src/pipewire/node.c b/src/pipewire/node.c index ad6acccc9..c7e1061ff 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -649,12 +649,13 @@ void pw_node_destroy(struct pw_node *node) spa_list_consume(port, &node->output_ports, link) pw_port_destroy(port); + spa_list_consume(resource, &node->resource_list, link) + pw_resource_destroy(resource); + if (node->global) { spa_hook_remove(&node->global_listener); pw_global_destroy(node->global); } - spa_list_consume(resource, &node->resource_list, link) - pw_resource_destroy(resource); pw_log_debug("node %p: free", node); pw_node_events_free(node); diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 49e55a6d5..c35e039ed 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -561,12 +561,13 @@ void pw_port_destroy(struct pw_port *port) spa_list_consume(control, &port->control_list[1], port_link) pw_control_destroy(control); + spa_list_consume(resource, &port->resource_list, link) + pw_resource_destroy(resource); + if (port->global) { spa_hook_remove(&port->global_listener); pw_global_destroy(port->global); } - spa_list_consume(resource, &port->resource_list, link) - pw_resource_destroy(resource); pw_log_debug("port %p: free", port); pw_port_events_free(port); From 473fb330cf1237d5e7cc586b9b39c1be6b764b06 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 10:08:16 +0200 Subject: [PATCH 136/155] autogen.sh: Reuse existing build directory Removing the build directory might delete important development files as well. Signed-off-by: Thomas Zimmermann --- autogen.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/autogen.sh b/autogen.sh index eacc495c9..72ec3dbf4 100755 --- a/autogen.sh +++ b/autogen.sh @@ -17,7 +17,6 @@ # Only there to make jhbuild happy -rm -rf ./build -mkdir build -meson build "$@" +mkdir -p build +meson setup build "$@" # use 'autogen.sh --reconfigure' to update ln -s build/Makefile Makefile From 352b04ba2161e55dec6581a7208843eef2b125ed Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 10:12:30 +0200 Subject: [PATCH 137/155] autogen.sh: Replace symbolic link to Makefile The autogen.sh script creates a symbolic link to the build/Makfile. If the link already exists, a warning is printed and the old link persists. Now replace it with the correct target. Signed-off-by: Thomas Zimmermann --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 72ec3dbf4..9f9f268d9 100755 --- a/autogen.sh +++ b/autogen.sh @@ -19,4 +19,4 @@ mkdir -p build meson setup build "$@" # use 'autogen.sh --reconfigure' to update -ln -s build/Makefile Makefile +ln -sf build/Makefile Makefile From 62afada593fec9c37ef10d09c2ebbfeb6b38bcee Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 10:18:47 +0200 Subject: [PATCH 138/155] autogen.sh: Put meson arguments right after command name According to the meson man page, arguments go directly after the command's name. Rearrange the call accordingly. Signed-off-by: Thomas Zimmermann --- autogen.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index 9f9f268d9..d66b83680 100755 --- a/autogen.sh +++ b/autogen.sh @@ -18,5 +18,5 @@ # Only there to make jhbuild happy mkdir -p build -meson setup build "$@" # use 'autogen.sh --reconfigure' to update +meson setup "$@" build # use 'autogen.sh --reconfigure' to update ln -sf build/Makefile Makefile From 768b082834c2954683e271e905293d10c3e748e1 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 10:22:57 +0200 Subject: [PATCH 139/155] autogen.sh: Check for meson If meson is not installed, at least an error message should be printed. Signed-off-by: Thomas Zimmermann --- autogen.sh | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/autogen.sh b/autogen.sh index d66b83680..415b2d931 100755 --- a/autogen.sh +++ b/autogen.sh @@ -17,6 +17,17 @@ # Only there to make jhbuild happy +if [ -z $MESON ]; then + MESON=`which meson` +fi +if [ -z $MESON ]; then + echo "error: Meson not found." + echo "Install meson to configure and build Pipewire. If meson" \ + "is already installed, set the environment variable MESON" \ + "to the binary's path." + exit 1; +fi + mkdir -p build -meson setup "$@" build # use 'autogen.sh --reconfigure' to update +$MESON setup "$@" build # use 'autogen.sh --reconfigure' to update ln -sf build/Makefile Makefile From 59fa57f2a3909d9f88561c54cbc7eef60d932721 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 11:31:21 +0200 Subject: [PATCH 140/155] autogen.sh: Immediately fail on command errors If a command fails, there's no point in continuing with configuring the project. Exit immediately. Signed-off-by: Thomas Zimmermann --- autogen.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/autogen.sh b/autogen.sh index 415b2d931..3231c93d1 100755 --- a/autogen.sh +++ b/autogen.sh @@ -17,6 +17,8 @@ # Only there to make jhbuild happy +set -e + if [ -z $MESON ]; then MESON=`which meson` fi From cc5a155c9bfcad3532720e959559ad6200cd4279 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 17 May 2019 11:48:46 +0200 Subject: [PATCH 141/155] meson.build: Test for ptrdiff_t in The build scripts assumed ptrdiff_t to just be around by default. But POSIX specifies ptrdiff_t to be defined in , which is now included from the test. Signed-off-by: Thomas Zimmermann --- meson.build | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/meson.build b/meson.build index 3c3b6dfb0..8efefdd1c 100644 --- a/meson.build +++ b/meson.build @@ -70,6 +70,7 @@ check_headers = [['dlfcn.h','HAVE_DLFCN_H'], ['inttypes.h', 'HAVE_INTTYPES_H'], ['memory.h', 'HAVE_MEMORY_H'], ['poll.h', 'HAVE_POLL_H'], + ['stddef.h', 'HAVE_STDDEF_H'], ['stdint.h', 'HAVE_STDINT_H'], ['stdio_ext.h', 'HAVE_STDIO_EXT_H'], ['strings.h', 'HAVE_STRINGS_H'], @@ -113,8 +114,8 @@ if cc.has_function('clock_gettime', prefix : '#include ') cdata.set('HAVE_CLOCK_GETTIME', 1) endif -if cc.has_type('ptrdiff_t') - cdata.set('HAVE_PTRDIFF_T') +if cc.has_type('ptrdiff_t', prefix : '#include ') + cdata.set('HAVE_PTRDIFF_T', 1) endif if cc.has_function('mkstemp', prefix : '#include ') From 85e2eba941d20d84eba24e95916c081ada733ec7 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Thu, 2 May 2019 15:08:34 +0200 Subject: [PATCH 142/155] gstpipewiresrc: clear timestamps when processing a buffer This is necessary for 'do-timestamp' to work if the source provides no timestamps. Without this, the timestamp from the first use will remain, because the basesrc only overwrites timestamps that are GST_CLOCK_TIME_NONE. --- src/gst/gstpipewiresrc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 9458a23c5..77d43c9d9 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -409,6 +409,9 @@ on_process (void *_data) GST_LOG_OBJECT (pwsrc, "got new buffer %p", buf); + GST_BUFFER_PTS (buf) = GST_CLOCK_TIME_NONE; + GST_BUFFER_DTS (buf) = GST_CLOCK_TIME_NONE; + h = data->header; if (h) { GST_INFO ("pts %" G_GUINT64_FORMAT ", dts_offset %"G_GUINT64_FORMAT, h->pts, h->dts_offset); From 4aff470a8fa1e06448b2316781b4e7a91fbda341 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 22 May 2019 11:44:12 +0200 Subject: [PATCH 143/155] Release 0.2.6 --- NEWS | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++- meson.build | 2 +- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 8768c6eca..075398104 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,33 @@ +PipeWire 0.2.6 + +This is mostly a bugfix release and is API/ABI compatible with +previous 0.2 versions. + +Work is ongoing in the work branch that features a completely new +scheduling method that will enable audio support. Some of these +API changes are backported in this branch. + +- Improve error checking for threads +- Fix some memory and fd leaks +- Fix compilation with C++ compilers and clang +- DISABLE_RTKIT should now not try to use dbus at all +- Camera Portal fixes: + - add Camera media.role + - Rename module-flatpak to module-portal + - Use the portal permissions store for camera checks +- Actually use the passed fd in pipewiresrc +- Make properties with "pipewire." prefix read-only +- Add security label to client object +- Enforce link permissions +- Permissions of objects are now combined with parent permissions +- Remove libv4l2 dependency, it is not used +- Improve format negotiation in autolink #146 +- Try to avoid list corruption with event emmission #143 +- Fix destroy of client-node memory corruption +- Various small improvements + +Older versions: + PipeWire 0.2.5 - build fixes for systemd @@ -8,4 +38,57 @@ PipeWire 0.2.5 - Add more error checking for thread-loop - Small cleanups and bugfixes -This is mostly a bugfix release. +PipeWire 0.2.4 + +- Install man pages in right directory +- Add systemd socket activation +- Various memory leak and corruption fixes in properties, dbus and + buffer mmaped memory. +- Fix v4l2 crash on unplug +- improve stream cleanup + +PipeWire 0.2.3 + +- Fix deviceprovider caps introspection +- Refcounting fixes in pipewiresrc +- Remove clock interpolation from stream +- Improve clock in gstreamer elements +- Remove spalib +- Fix crash with pw_map +- Add version number to hook list +- Improve driver mode in gstreamer elements +- add daemon options +- add man pages + +PipeWire 0.2.2 + +- Increment API version and .so version + +PipeWire 0.2.1 + +- Various fixes to memory handling +- Fixes for shutdown +- v4l2 fix enumeration of frame intervals +- Make the daemon stop when the setup commands fail +- Improve safety of hooks +- Update stream API to more future proof version +- Add more options to stream API such as scheduling in the + main thread and automatic mapping of buffers +- Add version file and macros to check compile time and + runtime versions of pipewire +- Future proof some structs + +PipeWire 0.1.9 + +- Various build fixes +- Do more permission checks +- Add support for doing async connections. This can be used to + make connections through the portal later. +- Fix device creation from the GStreamer device monitor +- v4l2 experiment with controls +- move rtkit to a module to avoid dbus dependency +- use dmabuf allocator in gstreamer elements +- Add DSP module for pro audio cases, remove jack module. The + idea is to make a replacement jack client library that talks + pipewire directly instead of trying to emulate a jack server. +- Various memory handling improvements diff --git a/meson.build b/meson.build index 8efefdd1c..a90cb1937 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.5', + version : '0.2.6', meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', 'c_std=gnu99', From 37613b67ba52b5ad4e81d7ea38adc04027d9f9e5 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 23 May 2019 09:25:51 +0200 Subject: [PATCH 144/155] alsa: handle alsa-lib 1.1.9 alsa-lib 1.1.9 removed /usr/include/alsa from the include path, we must include --- spa/plugins/alsa/alsa-monitor.c | 2 +- spa/plugins/alsa/alsa-sink.c | 2 +- spa/plugins/alsa/alsa-source.c | 2 +- spa/plugins/alsa/alsa-utils.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spa/plugins/alsa/alsa-monitor.c b/spa/plugins/alsa/alsa-monitor.c index d8935cd75..16a01302c 100644 --- a/spa/plugins/alsa/alsa-monitor.c +++ b/spa/plugins/alsa/alsa-monitor.c @@ -25,7 +25,7 @@ #include #include -#include +#include #include #include diff --git a/spa/plugins/alsa/alsa-sink.c b/spa/plugins/alsa/alsa-sink.c index c31fe3e29..3c252fabf 100644 --- a/spa/plugins/alsa/alsa-sink.c +++ b/spa/plugins/alsa/alsa-sink.c @@ -19,7 +19,7 @@ #include -#include +#include #include #include diff --git a/spa/plugins/alsa/alsa-source.c b/spa/plugins/alsa/alsa-source.c index 74bbb3c07..8efc8fdea 100644 --- a/spa/plugins/alsa/alsa-source.c +++ b/spa/plugins/alsa/alsa-source.c @@ -19,7 +19,7 @@ #include -#include +#include #include #include diff --git a/spa/plugins/alsa/alsa-utils.h b/spa/plugins/alsa/alsa-utils.h index 5ba57bc57..3b5900078 100644 --- a/spa/plugins/alsa/alsa-utils.h +++ b/spa/plugins/alsa/alsa-utils.h @@ -26,7 +26,7 @@ extern "C" { #include -#include +#include #include #include From 151b2b266e1dae3679584f38b954e4357cf1e5cc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Jun 2019 10:49:28 +0200 Subject: [PATCH 145/155] connection: add do_close flag to connect_fd Make pw_remote_connect_fd() not automatically close the provided fd but let the caller take care of that. This allows us to reuse the fd in pipewiresrc. Fixes #155 --- src/modules/module-protocol-native.c | 7 ++++--- src/modules/module-protocol-native/local-socket.c | 2 +- src/pipewire/protocol.h | 4 ++-- src/pipewire/remote.c | 8 ++++---- src/pipewire/remote.h | 3 ++- 5 files changed, 13 insertions(+), 11 deletions(-) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 131657f61..0e7b7e273 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -619,7 +619,7 @@ static const struct pw_protocol_native_connection_events conn_events = { .need_flush = on_need_flush, }; -static int impl_connect_fd(struct pw_protocol_client *client, int fd) +static int impl_connect_fd(struct pw_protocol_client *client, int fd, bool do_close) { struct client *impl = SPA_CONTAINER_OF(client, struct client, this); struct pw_remote *remote = client->remote; @@ -638,14 +638,15 @@ static int impl_connect_fd(struct pw_protocol_client *client, int fd) impl->source = pw_loop_add_io(remote->core->main_loop, fd, SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, - true, on_remote_data, impl); + do_close, on_remote_data, impl); if (impl->source == NULL) goto error_close; return 0; error_close: - close(fd); + if (do_close) + close(fd); return -ENOMEM; } diff --git a/src/modules/module-protocol-native/local-socket.c b/src/modules/module-protocol-native/local-socket.c index 5ab5a2100..0e68eea98 100644 --- a/src/modules/module-protocol-native/local-socket.c +++ b/src/modules/module-protocol-native/local-socket.c @@ -84,7 +84,7 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client, goto error_close; } - res = pw_protocol_client_connect_fd(client, fd); + res = pw_protocol_client_connect_fd(client, fd, true); done_callback(data, res); diff --git a/src/pipewire/protocol.h b/src/pipewire/protocol.h index 2b6592d1a..4a0845fbd 100644 --- a/src/pipewire/protocol.h +++ b/src/pipewire/protocol.h @@ -44,14 +44,14 @@ struct pw_protocol_client { int (*connect) (struct pw_protocol_client *client, void (*done_callback) (void *data, int result), void *data); - int (*connect_fd) (struct pw_protocol_client *client, int fd); + int (*connect_fd) (struct pw_protocol_client *client, int fd, bool close); int (*steal_fd) (struct pw_protocol_client *client); void (*disconnect) (struct pw_protocol_client *client); void (*destroy) (struct pw_protocol_client *client); }; #define pw_protocol_client_connect(c,cb,d) ((c)->connect(c,cb,d)) -#define pw_protocol_client_connect_fd(c,fd) ((c)->connect_fd(c,fd)) +#define pw_protocol_client_connect_fd(c,fd,cl) ((c)->connect_fd(c,fd,cl)) #define pw_protocol_client_steal_fd(c) ((c)->steal_fd(c)) #define pw_protocol_client_disconnect(c) ((c)->disconnect(c)) #define pw_protocol_client_destroy(c) ((c)->destroy(c)) diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index f63a973a4..472b26845 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -305,7 +305,7 @@ void pw_remote_destroy(struct pw_remote *remote) spa_list_consume(stream, &remote->stream_list, link) pw_stream_destroy(stream); - pw_protocol_client_destroy (remote->conn); + pw_protocol_client_destroy(remote->conn); spa_list_remove(&remote->link); @@ -413,7 +413,7 @@ int pw_remote_connect(struct pw_remote *remote) pw_remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL); - if ((res = pw_protocol_client_connect (remote->conn, done_connect, remote)) < 0) { + if ((res = pw_protocol_client_connect(remote->conn, done_connect, remote)) < 0) { pw_remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect failed %s", spa_strerror(res)); return res; @@ -428,7 +428,7 @@ int pw_remote_connect_fd(struct pw_remote *remote, int fd) pw_remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL); - if ((res = pw_protocol_client_connect_fd (remote->conn, fd)) < 0) { + if ((res = pw_protocol_client_connect_fd(remote->conn, fd, false)) < 0) { pw_remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect_fd failed %s", spa_strerror(res)); return res; @@ -462,7 +462,7 @@ int pw_remote_disconnect(struct pw_remote *remote) pw_proxy_destroy(proxy); remote->core_proxy = NULL; - pw_protocol_client_disconnect (remote->conn); + pw_protocol_client_disconnect(remote->conn); pw_map_clear(&remote->objects); pw_map_clear(&remote->types); diff --git a/src/pipewire/remote.h b/src/pipewire/remote.h index df0c496ce..2974a04ae 100644 --- a/src/pipewire/remote.h +++ b/src/pipewire/remote.h @@ -177,7 +177,8 @@ void pw_remote_add_listener(struct pw_remote *remote, int pw_remote_connect(struct pw_remote *remote); /** Connect to a remote PipeWire on the given socket \memberof pw_remote - * \param fd the connected socket to use + * \param fd the connected socket to use, the socket will not be closed + * automatically on disconnect or error. * \return 0 on success, < 0 on error */ int pw_remote_connect_fd(struct pw_remote *remote, int fd); From 0a6fe99a63bce08cf0a1cb8736194fbce807bd4c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Wed, 19 Jun 2019 10:59:00 +0200 Subject: [PATCH 146/155] protocol: improve error handling --- src/modules/module-protocol-native.c | 138 ++++++++++++------ .../module-protocol-native/local-socket.c | 14 +- 2 files changed, 100 insertions(+), 52 deletions(-) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index 0e7b7e273..ecfcf5f45 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -374,14 +374,14 @@ static struct pw_client *client_new(struct server *s, int fd) return NULL; } -static bool init_socket_name(struct server *s, const char *name) +static int init_socket_name(struct server *s, const char *name) { int name_size; const char *runtime_dir; if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { pw_log_error("XDG_RUNTIME_DIR not set in the environment"); - return false; + return -EIO; } s->addr.sun_family = AF_LOCAL; @@ -392,29 +392,33 @@ static bool init_socket_name(struct server *s, const char *name) pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", runtime_dir, name); *s->addr.sun_path = 0; - return false; + return -ENAMETOOLONG; } - return true; + return 0; } -static bool lock_socket(struct server *s) +static int lock_socket(struct server *s) { + int res; + snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX); s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); if (s->fd_lock < 0) { - pw_log_error("unable to open lockfile %s check permissions", s->lock_addr); + res = -errno; + pw_log_error("unable to open lockfile '%s': %m", s->lock_addr); goto err; } if (flock(s->fd_lock, LOCK_EX | LOCK_NB) < 0) { - pw_log_error("unable to lock lockfile %s, maybe another daemon is running", + res = -errno; + pw_log_error("unable to lock lockfile '%s': %m (maybe another daemon is running)", s->lock_addr); goto err_fd; } - return true; + return 0; err_fd: close(s->fd_lock); @@ -422,7 +426,7 @@ static bool lock_socket(struct server *s) err: *s->lock_addr = 0; *s->addr.sun_path = 0; - return false; + return res; } static void @@ -454,10 +458,10 @@ socket_data(void *data, int fd, enum spa_io mask) c->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP); } -static bool add_socket(struct pw_protocol *protocol, struct server *s) +static int add_socket(struct pw_protocol *protocol, struct server *s) { socklen_t size; - int fd = -1; + int fd = -1, res; bool activated = false; #ifdef HAVE_SYSTEMD_DAEMON @@ -476,33 +480,42 @@ static bool add_socket(struct pw_protocol *protocol, struct server *s) #endif if (fd < 0) { - if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) { + res = -errno; goto error; + } size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) { + res = -errno; pw_log_error("bind() failed with error: %m"); goto error_close; } if (listen(fd, 128) < 0) { + res = -errno; pw_log_error("listen() failed with error: %m"); goto error_close; } } - s->loop = pw_core_get_main_loop(protocol->core); - s->source = pw_loop_add_io(s->loop, fd, SPA_IO_IN, true, socket_data, s); s->activated = activated; - if (s->source == NULL) + s->loop = pw_core_get_main_loop(protocol->core); + if (s->loop == NULL) { + res = -errno; goto error_close; - - return true; + } + s->source = pw_loop_add_io(s->loop, fd, SPA_IO_IN, true, socket_data, s); + if (s->source == NULL) { + res = -errno; + goto error_close; + } + return 0; error_close: close(fd); error: - return false; + return res; } @@ -515,9 +528,12 @@ static int impl_steal_fd(struct pw_protocol_client *client) return -EIO; fd = dup(impl->source->fd); - + if (fd == -1) { + fd = -errno; + goto out; + } pw_protocol_client_disconnect(client); - +out: return fd; } @@ -623,31 +639,37 @@ static int impl_connect_fd(struct pw_protocol_client *client, int fd, bool do_cl { struct client *impl = SPA_CONTAINER_OF(client, struct client, this); struct pw_remote *remote = client->remote; + int res; impl->disconnecting = false; impl->connection = pw_protocol_native_connection_new(remote->core, fd); - if (impl->connection == NULL) - goto error_close; + if (impl->connection == NULL) { + res = -errno; + goto error_cleanup; + } + + impl->source = pw_loop_add_io(remote->core->main_loop, + fd, + SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, + do_close, on_remote_data, impl); + if (impl->source == NULL) { + res = -errno; + goto error_cleanup; + } pw_protocol_native_connection_add_listener(impl->connection, &impl->conn_listener, &conn_events, impl); - - impl->source = pw_loop_add_io(remote->core->main_loop, - fd, - SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, - do_close, on_remote_data, impl); - if (impl->source == NULL) - goto error_close; - return 0; - error_close: - if (do_close) - close(fd); - return -ENOMEM; +error_cleanup: + if (impl->connection) { + pw_protocol_native_connection_destroy(impl->connection); + impl->connection = NULL; + } + return res; } static void impl_disconnect(struct pw_protocol_client *client) @@ -690,6 +712,7 @@ impl_new_client(struct pw_protocol *protocol, struct client *impl; struct pw_protocol_client *this; const char *str = NULL; + int res; if ((impl = calloc(1, sizeof(struct client))) == NULL) return NULL; @@ -716,10 +739,21 @@ impl_new_client(struct pw_protocol *protocol, this->destroy = impl_destroy; impl->flush_event = pw_loop_add_event(remote->core->main_loop, do_flush_event, impl); + if (impl->flush_event == NULL) { + res = -errno; + goto error_cleanup; + } spa_list_append(&protocol->client_list, &this->link); return this; + +error_cleanup: + if (impl->properties) + pw_properties_free(impl->properties); + free(impl); + errno = -res; + return NULL; } static void destroy_server(struct pw_protocol_server *server) @@ -728,6 +762,7 @@ static void destroy_server(struct pw_protocol_server *server) struct pw_client *client; spa_list_remove(&server->link); + spa_hook_remove(&s->hook); spa_list_consume(client, &server->client_list, protocol_link) pw_client_destroy(client); @@ -783,6 +818,7 @@ impl_add_server(struct pw_protocol *protocol, struct pw_protocol_server *this; struct server *s; const char *name; + int res; if ((s = calloc(1, sizeof(struct server))) == NULL) return NULL; @@ -798,23 +834,24 @@ impl_add_server(struct pw_protocol *protocol, name = get_name(pw_core_get_properties(core)); - if (!init_socket_name(s, name)) - goto error; - - if (!lock_socket(s)) - goto error; - - if (!add_socket(protocol, s)) - goto error; - pw_loop_add_hook(pw_core_get_main_loop(core), &s->hook, &impl_hooks, s); + if ((res = init_socket_name(s, name)) < 0) + goto error; + + if ((res = lock_socket(s)) < 0) + goto error; + + if ((res = add_socket(protocol, s)) < 0) + goto error; + pw_log_info("protocol-native %p: Added server %p %s", protocol, this, name); return this; - error: +error: destroy_server(this); + errno = -res; return NULL; } @@ -910,13 +947,14 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie struct pw_protocol *this; const char *val; struct protocol_data *d; + int res; if (pw_core_find_protocol(core, PW_TYPE_PROTOCOL__Native) != NULL) return 0; this = pw_protocol_new(core, PW_TYPE_PROTOCOL__Native, sizeof(struct protocol_data)); if (this == NULL) - return -ENOMEM; + return -errno; debug_messages = pw_debug_is_category_enabled("connection"); @@ -936,13 +974,19 @@ static int module_init(struct pw_module *module, struct pw_properties *propertie if (val == NULL) val = pw_properties_get(pw_core_get_properties(core), PW_CORE_PROP_DAEMON); if (val && pw_properties_parse_bool(val)) { - if (impl_add_server(this, core, properties) == NULL) - return -errno; + if (impl_add_server(this, core, properties) == NULL) { + res = -errno; + goto error_cleanup; + } } pw_module_add_listener(module, &d->module_listener, &module_events, d); return 0; + +error_cleanup: + pw_protocol_destroy(this); + return res; } SPA_EXPORT diff --git a/src/modules/module-protocol-native/local-socket.c b/src/modules/module-protocol-native/local-socket.c index 0e68eea98..2c8ddc9fa 100644 --- a/src/modules/module-protocol-native/local-socket.c +++ b/src/modules/module-protocol-native/local-socket.c @@ -58,13 +58,16 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client, if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment"); - return -EIO; + res = -EIO; + goto error; } name = get_remote(pw_remote_get_properties(remote)); - if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) - return -errno; + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) { + res = -errno; + goto error; + } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_LOCAL; @@ -90,7 +93,8 @@ int pw_protocol_native_connect_local_socket(struct pw_protocol_client *client, return res; - error_close: - close(fd); +error_close: + close(fd); +error: return res; } From 37e66c9e55f556558088d9f6b2200d4341a37f04 Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Tue, 18 Jun 2019 09:53:12 +0200 Subject: [PATCH 147/155] deviceprovider: fix probing without starting self->type is needed in registry_event_global() so it must be set in gst_pipewire_device_provider_probe() as well. self->devices is initialized as NULL when probing is started. So it should be just a simple GList* pointer. Signed-off-by: Michael Olbrich --- src/gst/gstpipewiredeviceprovider.c | 8 ++++++-- src/gst/gstpipewiredeviceprovider.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index b6472d961..02b38c2ee 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -265,7 +265,7 @@ static void do_add_node(void *data) nd->dev = new_node (self, nd); if (nd->dev) { if(self->list_only) - *self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (nd->dev)); + self->devices = g_list_prepend (self->devices, gst_object_ref_sink (nd->dev)); else gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), nd->dev); } @@ -555,6 +555,8 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) t = pw_core_get_type(c); + self->type = pw_core_get_type (c); + if (!(r = pw_remote_new (c, NULL, sizeof(*data)))) goto failed; @@ -612,7 +614,9 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) pw_core_destroy (c); pw_loop_destroy (l); - return *self->devices; + self->type = NULL; + + return self->devices; failed: pw_loop_destroy (l); diff --git a/src/gst/gstpipewiredeviceprovider.h b/src/gst/gstpipewiredeviceprovider.h index 816226052..3cf2d41bd 100644 --- a/src/gst/gstpipewiredeviceprovider.h +++ b/src/gst/gstpipewiredeviceprovider.h @@ -98,7 +98,7 @@ struct _GstPipeWireDeviceProvider { gboolean end; gboolean list_only; - GList **devices; + GList *devices; }; struct _GstPipeWireDeviceProviderClass { From 0720e375a11244e62539d2ae9de742b77090ca09 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 21 Jun 2019 16:33:49 +0200 Subject: [PATCH 148/155] avoid error(), it's not defined on musl --- spa/tests/test-bluez5.c | 34 ++++++++++++++++++++-------------- spa/tests/test-control.c | 13 +++++++++---- spa/tests/test-mixer.c | 13 +++++++++---- spa/tools/spa-inspect.c | 27 +++++++++++++-------------- 4 files changed, 51 insertions(+), 36 deletions(-) diff --git a/spa/tests/test-bluez5.c b/spa/tests/test-bluez5.c index b29d535ed..228ebf9b0 100644 --- a/spa/tests/test-bluez5.c +++ b/spa/tests/test-bluez5.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -45,6 +44,12 @@ static struct spa_log *logger; +#define spa_error(ret,res,msg) \ +({ \ + fprintf(stderr, "%s: %s", msg, spa_strerror(res)); \ + return(ret); \ +}) + #define spa_debug(f,...) spa_log_trace(logger, f, __VA_ARGS__) #include @@ -212,10 +217,11 @@ int main(int argc, char *argv[]) if ((res = get_handle(&data, &handle, "build/spa/plugins/support/libspa-support.so", "mapper")) < 0) { - error(-1, res, "can't create mapper"); + spa_error(-1, res, "can't create mapper"); + } + if ((res = spa_handle_get_interface(handle, 0, &iface)) < 0) { + spa_error(-1, res, "can't get mapper interface"); } - if ((res = spa_handle_get_interface(handle, 0, &iface)) < 0) - error(-1, res, "can't get mapper interface"); data.map = iface; data.support[0].type = SPA_TYPE__TypeMap; @@ -226,13 +232,13 @@ int main(int argc, char *argv[]) if ((res = get_handle(&data, &handle, "build/spa/plugins/support/libspa-support.so", "logger")) < 0) { - error(-1, res, "can't create logger"); + spa_error(-1, res, "can't create logger"); } if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__Log), &iface)) < 0) - error(-1, res, "can't get log interface"); + spa_error(-1, res, "can't get log interface"); data.log = iface; data.support[1].type = SPA_TYPE__Log; @@ -245,24 +251,24 @@ int main(int argc, char *argv[]) if ((res = get_handle(&data, &handle, "build/spa/plugins/support/libspa-support.so", "loop")) < 0) { - error(-1, res, "can't create loop"); + spa_error(-1, res, "can't create loop"); } if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__Loop), &iface)) < 0) - error(-1, res, "can't get loop interface"); + spa_error(-1, res, "can't get loop interface"); data.loop = iface; if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__LoopControl), &iface)) < 0) - error(-1, res, "can't get loopcontrol interface"); + spa_error(-1, res, "can't get loopcontrol interface"); data.loop_control = iface; if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__LoopUtils), &iface)) < 0) - error(-1, res, "can't get looputils interface"); + spa_error(-1, res, "can't get looputils interface"); data.loop_utils = iface; data.support[2].type = SPA_TYPE_LOOP__DataLoop; @@ -278,13 +284,13 @@ int main(int argc, char *argv[]) if ((res = get_handle(&data, &handle, "build/spa/plugins/support/libspa-dbus.so", "dbus")) < 0) { - error(-1, res, "can't create dbus"); + spa_error(-1, res, "can't create dbus"); } if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__DBus), &iface)) < 0) - error(-1, res, "can't get dbus interface"); + spa_error(-1, res, "can't get dbus interface"); data.dbus = iface; data.support[6].type = SPA_TYPE__DBus; @@ -294,13 +300,13 @@ int main(int argc, char *argv[]) if ((res = get_handle(&data, &handle, "build/spa/plugins/bluez5/libspa-bluez5.so", "bluez5-monitor")) < 0) { - error(-1, res, "can't create bluez5-monitor"); + spa_error(-1, res, "can't create bluez5-monitor"); } if ((res = spa_handle_get_interface(handle, spa_type_map_get_id(data.map, SPA_TYPE__Monitor), &iface)) < 0) - error(-1, res, "can't get monitor interface"); + spa_error(-1, res, "can't get monitor interface"); data.monitor = iface; diff --git a/spa/tests/test-control.c b/spa/tests/test-control.c index 35b143448..5d89a85cd 100644 --- a/spa/tests/test-control.c +++ b/spa/tests/test-control.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -44,6 +43,12 @@ static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); +#define spa_error(ret,res,msg) \ +({ \ + fprintf(stderr, "%s: %s", msg, spa_strerror(res)); \ + return(ret); \ +}) + #define spa_debug(f,...) spa_log_trace(&default_log.log, f, __VA_ARGS__) #include @@ -359,7 +364,7 @@ static int make_nodes(struct data *data, const char *device) if ((res = spa_node_port_enum_params(data->source, SPA_DIRECTION_OUTPUT, 0, data->type.param_io.idPropsIn, &idx, NULL, ¶m, &b)) < 1) { if (res < 0) - error(0, -res, "port_enum_params"); + spa_error(0, -res, "port_enum_params"); break; } @@ -373,7 +378,7 @@ static int make_nodes(struct data *data, const char *device) SPA_DIRECTION_OUTPUT, 0, id, &data->ctrl_source_freq, sizeof(data->ctrl_source_freq))) < 0) - error(0, -res, "set_io freq"); + spa_error(0, -res, "set_io freq"); } else if (propId == data->type.props_volume) { @@ -381,7 +386,7 @@ static int make_nodes(struct data *data, const char *device) SPA_DIRECTION_OUTPUT, 0, id, &data->ctrl_source_volume, sizeof(data->ctrl_source_volume))) < 0) - error(0, -res, "set_io volume"); + spa_error(0, -res, "set_io volume"); } } diff --git a/spa/tests/test-mixer.c b/spa/tests/test-mixer.c index ceab622c8..6500c6ca4 100644 --- a/spa/tests/test-mixer.c +++ b/spa/tests/test-mixer.c @@ -18,7 +18,6 @@ */ #include -#include #include #include #include @@ -47,6 +46,12 @@ static SPA_TYPE_MAP_IMPL(default_map, 4096); static SPA_LOG_IMPL(default_log); +#define spa_error(ret,res,msg) \ +({ \ + fprintf(stderr, "%s: %s", msg, spa_strerror(res)); \ + return(ret); \ +}) + #define spa_debug(...) spa_log_trace(&default_log.log,__VA_ARGS__) #include @@ -370,7 +375,7 @@ static int make_nodes(struct data *data, const char *device) ":", data->type.props_min_latency, "i", MIN_LATENCY); if ((res = spa_node_set_param(data->sink, data->type.param.idProps, 0, props)) < 0) - error(0, -res, "set_param props"); + spa_error(0, -res, "set_param props"); if ((res = make_node(data, &data->mix, "build/spa/plugins/audiomixer/libspa-audiomixer.so", @@ -457,13 +462,13 @@ static int make_nodes(struct data *data, const char *device) SPA_DIRECTION_INPUT, data->mix_ports[0], data->type.io_inprop_volume, &data->ctrl_volume[0], sizeof(data->ctrl_volume[0]))) < 0) - error(0, -res, "set_io volume 0"); + spa_error(0, -res, "set_io volume 0"); if ((res = spa_node_port_set_io(data->mix, SPA_DIRECTION_INPUT, data->mix_ports[1], data->type.io_inprop_volume, &data->ctrl_volume[1], sizeof(data->ctrl_volume[1]))) < 0) - error(0, -res, "set_io volume 1"); + spa_error(0, -res, "set_io volume 1"); #ifdef USE_GRAPH diff --git a/spa/tools/spa-inspect.c b/spa/tools/spa-inspect.c index da41a82f0..9dd317f68 100644 --- a/spa/tools/spa-inspect.c +++ b/spa/tools/spa-inspect.c @@ -17,7 +17,6 @@ * Boston, MA 02110-1301, USA. */ -#include #include #include #include @@ -73,7 +72,7 @@ inspect_node_params(struct data *data, struct spa_node *node) data->type.param.idList, &idx1, NULL, ¶m, &b)) <= 0) { if (res != 0) - error(0, -res, "enum_params"); + printf("error enum_params: %s", spa_strerror(res)); break; } @@ -88,7 +87,7 @@ inspect_node_params(struct data *data, struct spa_node *node) id, &idx2, NULL, ¶m, &b)) <= 0) { if (res != 0) - error(0, -res, "enum_params %d", id); + printf("error enum_params %d: %s", id, spa_strerror(res)); break; } spa_debug_pod(0, data->map, param); @@ -115,7 +114,7 @@ inspect_port_params(struct data *data, struct spa_node *node, data->type.param.idList, &idx1, NULL, ¶m, &b)) <= 0) { if (res != 0) - error(0, -res, "port_enum_params"); + printf("error port_enum_params: %s", spa_strerror(res)); break; } spa_pod_object_parse(param, @@ -130,7 +129,7 @@ inspect_port_params(struct data *data, struct spa_node *node, id, &idx2, NULL, ¶m, &b)) <= 0) { if (res != 0) - error(0, -res, "port_enum_params"); + printf("error port_enum_params %d: %s", id, spa_strerror(res)); break; } @@ -200,10 +199,10 @@ static void inspect_factory(struct data *data, const struct spa_handle_factory * printf("factory interfaces:\n"); for (index = 0;;) { if ((res = spa_handle_factory_enum_interface_info(factory, &info, &index)) <= 0) { - if (res == 0) - break; - else - error(0, -res, "spa_handle_factory_enum_interface_info"); + if (res != 0) + printf("error spa_handle_factory_enum_interface_info: %s", + spa_strerror(res)); + break; } printf(" interface: '%s'\n", info->type); } @@ -221,10 +220,10 @@ static void inspect_factory(struct data *data, const struct spa_handle_factory * uint32_t interface_id; if ((res = spa_handle_factory_enum_interface_info(factory, &info, &index)) <= 0) { - if (res == 0) - break; - else - error(0, -res, "spa_handle_factory_enum_interface_info"); + if (res != 0) + printf("error spa_handle_factory_enum_interface_info: %s", + spa_strerror(res)); + break; } printf(" interface: '%s'\n", info->type); @@ -314,7 +313,7 @@ int main(int argc, char *argv[]) if ((res = enum_func(&factory, &index)) <= 0) { if (res != 0) - error(0, -res, "enum_func"); + printf("error enum_func: %s", spa_strerror(res)); break; } inspect_factory(&data, factory); From 4350bd624f165de81de10293a8ec5a59e8b7ce64 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 28 Jun 2019 12:22:33 +0200 Subject: [PATCH 149/155] Revert "global: combine all permissions of the object tree" This reverts commit 83bc033837f7525d898f1de91119f669f9bf97f5. This needs some more work. --- src/pipewire/global.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/pipewire/global.c b/src/pipewire/global.c index c963965e7..00258ff88 100644 --- a/src/pipewire/global.c +++ b/src/pipewire/global.c @@ -38,15 +38,9 @@ uint32_t pw_global_get_permissions(struct pw_global *global, struct pw_client *c { uint32_t perms = PW_PERM_RWX; - if (client->permission_func == NULL) - return perms; - - perms = client->permission_func(global, client, client->permission_data); - - while (global != global->parent) { - global = global->parent; + if (client->permission_func != NULL) perms &= client->permission_func(global, client, client->permission_data); - } + return perms; } From 39c01ba2fedc59a62393c1d1198552bab666f701 Mon Sep 17 00:00:00 2001 From: Michael Tretter Date: Fri, 5 Jul 2019 12:57:55 +0200 Subject: [PATCH 150/155] builder: fix calls to builder_add that are not terminated by NULL spa_pod_builder_add() is a va_args function that is terminated by a NULL argument. The last argument must be a pointer type, because otherwise checking for a NULL pointer can fail. The __attribute__((__sentinel__)) prints a compiler warning, if the last argument of a call to spa_pod_builder_add() is not a pointer type. Fix all sentinel warnings by replacing all integer type 0 with pointer type NULL in calls to spa_pod_builder_add(). --- spa/include/spa/pod/builder.h | 3 ++- spa/plugins/alsa/alsa-monitor.c | 22 +++++++++++----------- spa/plugins/alsa/alsa-utils.c | 2 +- spa/plugins/v4l2/v4l2-monitor.c | 22 +++++++++++----------- spa/plugins/v4l2/v4l2-source.c | 8 ++++---- spa/plugins/v4l2/v4l2-utils.c | 6 +++--- 6 files changed, 32 insertions(+), 31 deletions(-) diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h index b9b4ddf5d..cb1f4a748 100644 --- a/spa/include/spa/pod/builder.h +++ b/spa/include/spa/pod/builder.h @@ -574,7 +574,8 @@ spa_pod_builder_addv(struct spa_pod_builder *builder, return spa_pod_builder_deref(builder, builder->frame[builder->state.depth].ref); } -static inline void *spa_pod_builder_add(struct spa_pod_builder *builder, const char *format, ...) +static inline __attribute__((__sentinel__)) void * +spa_pod_builder_add(struct spa_pod_builder *builder, const char *format, ...) { void *res; va_list args; diff --git a/spa/plugins/alsa/alsa-monitor.c b/spa/plugins/alsa/alsa-monitor.c index 16a01302c..c53381ec1 100644 --- a/spa/plugins/alsa/alsa-monitor.c +++ b/spa/plugins/alsa/alsa-monitor.c @@ -173,22 +173,22 @@ fill_item(struct impl *this, snd_ctl_card_info_t *card_info, snd_pcm_info_t *dev if (!(str && *str)) str = udev_device_get_syspath(dev); if (str && *str) { - spa_pod_builder_add(builder, "s", "device.bus_path", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.bus_path", "s", str, NULL); } if ((str = udev_device_get_syspath(dev)) && *str) { - spa_pod_builder_add(builder, "s", "sysfs.path", "s", str, 0); + spa_pod_builder_add(builder, "s", "sysfs.path", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "ID_ID")) && *str) { - spa_pod_builder_add(builder, "s", "udev.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "udev.id", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "ID_BUS")) && *str) { - spa_pod_builder_add(builder, "s", "device.bus", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.bus", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "SUBSYSTEM")) && *str) { - spa_pod_builder_add(builder, "s", "device.subsystem", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.subsystem", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "ID_VENDOR_ID")) && *str) { - spa_pod_builder_add(builder, "s", "device.vendor.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.vendor.id", "s", str, NULL); } str = udev_device_get_property_value(dev, "ID_VENDOR_FROM_DATABASE"); if (!(str && *str)) { @@ -198,18 +198,18 @@ fill_item(struct impl *this, snd_ctl_card_info_t *card_info, snd_pcm_info_t *dev } } if (str && *str) { - spa_pod_builder_add(builder, "s", "device.vendor.name", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.vendor.name", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "ID_MODEL_ID")) && *str) { - spa_pod_builder_add(builder, "s", "device.product.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.product.id", "s", str, NULL); } - spa_pod_builder_add(builder, "s", "device.product.name", "s", name, 0); + spa_pod_builder_add(builder, "s", "device.product.name", "s", name, NULL); if ((str = udev_device_get_property_value(dev, "ID_SERIAL")) && *str) { - spa_pod_builder_add(builder, "s", "device.serial", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.serial", "s", str, NULL); } if ((str = udev_device_get_property_value(dev, "SOUND_FORM_FACTOR")) && *str) { - spa_pod_builder_add(builder, "s", "device.form_factor", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.form_factor", "s", str, NULL); } *item = spa_pod_builder_add(builder, "]>", NULL); diff --git a/spa/plugins/alsa/alsa-utils.c b/spa/plugins/alsa/alsa-utils.c index 1bc5aaa97..81848f506 100644 --- a/spa/plugins/alsa/alsa-utils.c +++ b/spa/plugins/alsa/alsa-utils.c @@ -143,7 +143,7 @@ spa_alsa_enum_format(struct state *state, uint32_t *index, spa_pod_builder_push_object(&b, state->type.param.idEnumFormat, state->type.format); spa_pod_builder_add(&b, "I", state->type.media_type.audio, - "I", state->type.media_subtype.raw, 0); + "I", state->type.media_subtype.raw, NULL); snd_pcm_format_mask_alloca(&fmask); snd_pcm_hw_params_get_format_mask(params, fmask); diff --git a/spa/plugins/v4l2/v4l2-monitor.c b/spa/plugins/v4l2/v4l2-monitor.c index cd0a97a1b..3f37557f1 100644 --- a/spa/plugins/v4l2/v4l2-monitor.c +++ b/spa/plugins/v4l2/v4l2-monitor.c @@ -132,22 +132,22 @@ static void fill_item(struct impl *this, struct item *item, struct udev_device * if (!(str && *str)) str = udev_device_get_syspath(item->udevice); if (str && *str) { - spa_pod_builder_add(builder, "s", "device.bus_path", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.bus_path", "s", str, NULL); } if ((str = udev_device_get_syspath(item->udevice)) && *str) { - spa_pod_builder_add(builder, "s", "sysfs.path", "s", str, 0); + spa_pod_builder_add(builder, "s", "sysfs.path", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "ID_ID")) && *str) { - spa_pod_builder_add(builder, "s", "udev.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "udev.id", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "ID_BUS")) && *str) { - spa_pod_builder_add(builder, "s", "device.bus", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.bus", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "SUBSYSTEM")) && *str) { - spa_pod_builder_add(builder, "s", "device.subsystem", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.subsystem", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "ID_VENDOR_ID")) && *str) { - spa_pod_builder_add(builder, "s", "device.vendor.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.vendor.id", "s", str, NULL); } str = udev_device_get_property_value(item->udevice, "ID_VENDOR_FROM_DATABASE"); if (!(str && *str)) { @@ -157,17 +157,17 @@ static void fill_item(struct impl *this, struct item *item, struct udev_device * } } if (str && *str) { - spa_pod_builder_add(builder, "s", "device.vendor.name", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.vendor.name", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "ID_MODEL_ID")) && *str) { - spa_pod_builder_add(builder, "s", "device.product.id", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.product.id", "s", str, NULL); } - spa_pod_builder_add(builder, "s", "device.product.name", "s", name, 0); + spa_pod_builder_add(builder, "s", "device.product.name", "s", name, NULL); if ((str = udev_device_get_property_value(item->udevice, "ID_SERIAL")) && *str) { - spa_pod_builder_add(builder, "s", "device.serial", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.serial", "s", str, NULL); } if ((str = udev_device_get_property_value(item->udevice, "ID_V4L_CAPABILITIES")) && *str) { - spa_pod_builder_add(builder, "s", "device.capabilities", "s", str, 0); + spa_pod_builder_add(builder, "s", "device.capabilities", "s", str, NULL); } *result = spa_pod_builder_add(builder, "]>", NULL); diff --git a/spa/plugins/v4l2/v4l2-source.c b/spa/plugins/v4l2/v4l2-source.c index a875a5d62..a18aff62e 100644 --- a/spa/plugins/v4l2/v4l2-source.c +++ b/spa/plugins/v4l2/v4l2-source.c @@ -458,22 +458,22 @@ static int port_get_format(struct spa_node *node, spa_pod_builder_add(builder, "I", port->current_format.media_type, - "I", port->current_format.media_subtype, 0); + "I", port->current_format.media_subtype, NULL); if (port->current_format.media_subtype == t->media_subtype.raw) { spa_pod_builder_add(builder, ":", t->format_video.format, "I", port->current_format.info.raw.format, ":", t->format_video.size, "R", &port->current_format.info.raw.size, - ":", t->format_video.framerate, "F", &port->current_format.info.raw.framerate, 0); + ":", t->format_video.framerate, "F", &port->current_format.info.raw.framerate, NULL); } else if (port->current_format.media_subtype == t->media_subtype_video.mjpg || port->current_format.media_subtype == t->media_subtype_video.jpeg) { spa_pod_builder_add(builder, ":", t->format_video.size, "R", &port->current_format.info.mjpg.size, - ":", t->format_video.framerate, "F", &port->current_format.info.mjpg.framerate, 0); + ":", t->format_video.framerate, "F", &port->current_format.info.mjpg.framerate, NULL); } else if (port->current_format.media_subtype == t->media_subtype_video.h264) { spa_pod_builder_add(builder, ":", t->format_video.size, "R", &port->current_format.info.h264.size, - ":", t->format_video.framerate, "F", &port->current_format.info.h264.framerate, 0); + ":", t->format_video.framerate, "F", &port->current_format.info.h264.framerate, NULL); } else return -EIO; diff --git a/spa/plugins/v4l2/v4l2-utils.c b/spa/plugins/v4l2/v4l2-utils.c index 4adf0c619..c401f4962 100644 --- a/spa/plugins/v4l2/v4l2-utils.c +++ b/spa/plugins/v4l2/v4l2-utils.c @@ -692,15 +692,15 @@ spa_v4l2_enum_format(struct impl *this, spa_pod_builder_push_object(builder, t->param.idEnumFormat, t->format); spa_pod_builder_add(builder, "I", media_type, - "I", media_subtype, 0); + "I", media_subtype, NULL); if (media_subtype == t->media_subtype.raw) { spa_pod_builder_add(builder, - ":", t->format_video.format, "I", video_format, 0); + ":", t->format_video.format, "I", video_format, NULL); } spa_pod_builder_add(builder, ":", t->format_video.size, "R", &SPA_RECTANGLE(port->frmsize.discrete.width, - port->frmsize.discrete.height), 0); + port->frmsize.discrete.height), NULL); prop = spa_pod_builder_deref(builder, spa_pod_builder_push_prop(builder, t->format_video.framerate, From 9b4b915f25df7c62e801594f8ebc5a43448e1a6c Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2019 21:13:26 +0200 Subject: [PATCH 151/155] add SPA_SENTINEL --- spa/include/spa/pod/builder.h | 2 +- spa/include/spa/utils/defs.h | 4 +++- src/pipewire/properties.h | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spa/include/spa/pod/builder.h b/spa/include/spa/pod/builder.h index cb1f4a748..5e5d7f690 100644 --- a/spa/include/spa/pod/builder.h +++ b/spa/include/spa/pod/builder.h @@ -574,7 +574,7 @@ spa_pod_builder_addv(struct spa_pod_builder *builder, return spa_pod_builder_deref(builder, builder->frame[builder->state.depth].ref); } -static inline __attribute__((__sentinel__)) void * +static inline SPA_SENTINEL void * spa_pod_builder_add(struct spa_pod_builder *builder, const char *format, ...) { void *res; diff --git a/spa/include/spa/utils/defs.h b/spa/include/spa/utils/defs.h index 8d2bbc6d9..bb23485ba 100644 --- a/spa/include/spa/utils/defs.h +++ b/spa/include/spa/utils/defs.h @@ -129,12 +129,14 @@ struct spa_fraction { #define SPA_PRINTF_FUNC(fmt, arg1) __attribute__((format(printf, fmt, arg1))) #define SPA_ALIGNED(align) __attribute__((aligned(align))) #define SPA_DEPRECATED __attribute__ ((deprecated)) -#define SPA_EXPORT __attribute__ ((visibility("default"))) +#define SPA_EXPORT __attribute__((visibility("default"))) +#define SPA_SENTINEL __attribute__((__sentinel__)) #else #define SPA_PRINTF_FUNC(fmt, arg1) #define SPA_ALIGNED(align) #define SPA_DEPRECATED #define SPA_EXPORT +#define SPA_SENTINEL #endif #define SPA_ROUND_DOWN_N(num,align) ((num) & ~((align) - 1)) diff --git a/src/pipewire/properties.h b/src/pipewire/properties.h index 693542dee..78050f414 100644 --- a/src/pipewire/properties.h +++ b/src/pipewire/properties.h @@ -40,7 +40,7 @@ struct pw_properties { }; struct pw_properties * -pw_properties_new(const char *key, ...); +pw_properties_new(const char *key, ...) SPA_SENTINEL; struct pw_properties * pw_properties_new_dict(const struct spa_dict *dict); From 633c27824faf146f4330d0cb046e58c9e87c30bd Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Jul 2019 21:16:56 +0200 Subject: [PATCH 152/155] add sentinel to parser as well --- spa/include/spa/pod/parser.h | 2 +- spa/tests/test-props2.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spa/include/spa/pod/parser.h b/spa/include/spa/pod/parser.h index 8e1ada087..7c7cc64a9 100644 --- a/spa/include/spa/pod/parser.h +++ b/spa/include/spa/pod/parser.h @@ -295,7 +295,7 @@ static inline int spa_pod_parser_getv(struct spa_pod_parser *parser, return 0; } -static inline int spa_pod_parser_get(struct spa_pod_parser *parser, +static inline SPA_SENTINEL int spa_pod_parser_get(struct spa_pod_parser *parser, const char *format, ...) { int res; diff --git a/spa/tests/test-props2.c b/spa/tests/test-props2.c index 692b95c52..e2f4e02af 100644 --- a/spa/tests/test-props2.c +++ b/spa/tests/test-props2.c @@ -110,7 +110,7 @@ int main(int argc, char *argv[]) "s", &vs, "R", &vr, "F", &vfr, - "P", &va, 0); + "P", &va, NULL); printf("%u %lu %f %g %s %ux%u %u/%u\n", vi, vl, vf, vd, vs, vr.width, vr.height, vfr.num, vfr.denom); From 9a202272f2473737c6d0f941693633cf82c000bb Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 10 Sep 2019 11:05:38 +0200 Subject: [PATCH 153/155] remote: always close the fd in connect_fd Not closing the fd causes leaks in existing apps. It's probably better to always close it and let apps deal with that by using dup or similar. Make gst sink and source dup the fd before connect_fd(). Fixes #181 --- src/gst/gstpipewiresink.c | 3 ++- src/gst/gstpipewiresrc.c | 2 +- src/pipewire/remote.c | 2 +- src/pipewire/remote.h | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c index d10cac5d3..203bdf214 100644 --- a/src/gst/gstpipewiresink.c +++ b/src/gst/gstpipewiresink.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "gstpipewireformat.h" @@ -735,7 +736,7 @@ gst_pipewire_sink_open (GstPipeWireSink * pwsink) if (pwsink->fd == -1) pw_remote_connect (pwsink->remote); else - pw_remote_connect_fd (pwsink->remote, pwsink->fd); + pw_remote_connect_fd (pwsink->remote, dup(pwsink->fd)); while (TRUE) { enum pw_remote_state state = pw_remote_get_state (pwsink->remote, &error); diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 77d43c9d9..5981cc181 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -1002,7 +1002,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) if (pwsrc->fd == -1) pw_remote_connect (pwsrc->remote); else - pw_remote_connect_fd (pwsrc->remote, pwsrc->fd); + pw_remote_connect_fd (pwsrc->remote, dup(pwsrc->fd)); while (TRUE) { enum pw_remote_state state = pw_remote_get_state(pwsrc->remote, &error); diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 472b26845..f878ca487 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -428,7 +428,7 @@ int pw_remote_connect_fd(struct pw_remote *remote, int fd) pw_remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL); - if ((res = pw_protocol_client_connect_fd(remote->conn, fd, false)) < 0) { + if ((res = pw_protocol_client_connect_fd(remote->conn, fd, true)) < 0) { pw_remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect_fd failed %s", spa_strerror(res)); return res; diff --git a/src/pipewire/remote.h b/src/pipewire/remote.h index 2974a04ae..b0e929f2c 100644 --- a/src/pipewire/remote.h +++ b/src/pipewire/remote.h @@ -177,7 +177,7 @@ void pw_remote_add_listener(struct pw_remote *remote, int pw_remote_connect(struct pw_remote *remote); /** Connect to a remote PipeWire on the given socket \memberof pw_remote - * \param fd the connected socket to use, the socket will not be closed + * \param fd the connected socket to use, the socket will be closed * automatically on disconnect or error. * \return 0 on success, < 0 on error */ int pw_remote_connect_fd(struct pw_remote *remote, int fd); From 312864d9e90cc3e15eb26eed31d14bfb6fdc5200 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 30 Aug 2019 18:08:00 +0200 Subject: [PATCH 154/155] protocol-native: attempt to remove socket After we grab the lockfile we should remove the socket when it exists so that we can bind again. This should solve startup problems after a crash, which left the socket around and caused bind failures. --- src/modules/module-protocol-native.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index ecfcf5f45..3c769a534 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -480,10 +480,23 @@ static int add_socket(struct pw_protocol *protocol, struct server *s) #endif if (fd < 0) { + struct stat socket_stat; + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) { res = -errno; goto error; } + if (stat(s->addr.sun_path, &socket_stat) < 0) { + if (errno != ENOENT) { + res = -errno; + pw_log_error("server %p: stat %s failed with error: %m", + s, s->addr.sun_path); + goto error_close; + } + } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) { + pw_log_warn("removing stale socket"); + unlink(s->addr.sun_path); + } size = offsetof(struct sockaddr_un, sun_path) + strlen(s->addr.sun_path); if (bind(fd, (struct sockaddr *) &s->addr, size) < 0) { From 14c11c0fe4d366bad4cfecdee97b6652ff9ed63d Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 26 Sep 2019 15:58:39 +0200 Subject: [PATCH 155/155] Release 0.2.7 --- NEWS | 18 +++++++++++++++--- meson.build | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/NEWS b/NEWS index 075398104..e64ee0f37 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -PipeWire 0.2.6 +PipeWire 0.2.7 This is mostly a bugfix release and is API/ABI compatible with previous 0.2 versions. @@ -7,6 +7,20 @@ Work is ongoing in the work branch that features a completely new scheduling method that will enable audio support. Some of these API changes are backported in this branch. +- Add support for alsa-lib 1.1.9 which changed the include path +- Improve error checking and reporting in the protocol +- deviceprovider: fix probing without starting +- add sentinel to some functions +- compiler fixes for musl +- Revert object tree permission checks that broke things, this is + probably not a good idea (and the tree of objects is going to + be removed later) + + +Older versions: + +PipeWire 0.2.6 + - Improve error checking for threads - Fix some memory and fd leaks - Fix compilation with C++ compilers and clang @@ -26,8 +40,6 @@ API changes are backported in this branch. - Fix destroy of client-node memory corruption - Various small improvements -Older versions: - PipeWire 0.2.5 - build fixes for systemd diff --git a/meson.build b/meson.build index a90cb1937..467076ce8 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('pipewire', 'c', - version : '0.2.6', + version : '0.2.7', meson_version : '>= 0.47.0', default_options : [ 'warning_level=1', 'c_std=gnu99',