From b898eb46cd5dadd62c0f4e0be538ebf8ceb3bd9f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Fri, 4 Aug 2017 10:18:54 +0200 Subject: [PATCH] Make structure private Make structs private. Expose methods for things we need. Signals only work on exposed structures so make a new callback helper to signal events. --- src/daemon/daemon-config.c | 1 + src/daemon/main.c | 2 +- src/examples/export-sink.c | 262 ++++++------- src/examples/export-v4l2.c | 24 +- src/examples/local-v4l2.c | 230 +++++------ src/examples/video-play.c | 93 +++-- src/examples/video-src.c | 81 ++-- src/extensions/client-node.h | 6 +- src/gst/gstpipewiredeviceprovider.c | 168 +++++---- src/gst/gstpipewiredeviceprovider.h | 6 +- src/gst/gstpipewiresink.c | 151 ++++---- src/gst/gstpipewiresink.h | 10 +- src/gst/gstpipewiresrc.c | 139 ++++--- src/gst/gstpipewiresrc.h | 9 +- src/modules/module-autolink.c | 129 ++++--- src/modules/module-client-node.c | 39 +- src/modules/module-client-node/client-node.c | 90 ++--- .../module-client-node/protocol-native.c | 1 + src/modules/module-flatpak.c | 40 +- src/modules/module-jack.c | 25 +- src/modules/module-mixer.c | 1 + src/modules/module-protocol-native.c | 35 +- .../module-protocol-native/connection.c | 3 +- .../module-protocol-native/protocol-native.c | 1 + src/modules/module-suspend-on-idle.c | 80 ++-- src/modules/spa/module-monitor.c | 4 +- src/modules/spa/module-node-factory.c | 41 +- src/modules/spa/module-node.c | 2 +- src/modules/spa/spa-monitor.c | 53 ++- src/modules/spa/spa-node.c | 192 +++++----- src/pipewire/callback.h | 84 +++++ src/pipewire/client.c | 59 ++- src/pipewire/client.h | 88 ++--- src/pipewire/command.c | 1 + src/pipewire/command.h | 8 +- src/pipewire/core.c | 139 ++++--- src/pipewire/core.h | 119 +++--- src/pipewire/data-loop.c | 86 ++--- src/pipewire/data-loop.h | 23 +- src/pipewire/interfaces.h | 93 ++--- src/pipewire/introspect.h | 1 + src/pipewire/link.c | 113 +++--- src/pipewire/link.h | 58 +-- src/pipewire/loop.c | 4 - src/pipewire/loop.h | 3 - src/pipewire/main-loop.c | 55 ++- src/pipewire/main-loop.h | 24 +- src/pipewire/module.c | 60 ++- src/pipewire/module.h | 32 +- src/pipewire/node-factory.c | 48 +++ src/pipewire/node-factory.h | 37 +- src/pipewire/node.c | 169 ++++++--- src/pipewire/node.h | 152 ++++---- src/pipewire/pipewire.c | 1 + src/pipewire/port.c | 102 ++++- src/pipewire/port.h | 133 +++---- src/pipewire/private.h | 356 ++++++++++++++++++ src/pipewire/protocol.c | 9 +- src/pipewire/protocol.h | 2 + src/pipewire/proxy.c | 67 ++-- src/pipewire/proxy.h | 62 +-- src/pipewire/remote.c | 168 ++++++--- src/pipewire/remote.h | 100 ++--- src/pipewire/resource.c | 44 ++- src/pipewire/resource.h | 52 ++- src/pipewire/stream.c | 151 ++++---- src/pipewire/stream.h | 99 +++-- src/pipewire/thread-loop.c | 146 ++++--- src/pipewire/thread-loop.h | 19 +- src/pipewire/work-queue.c | 69 ++-- src/pipewire/work-queue.h | 13 +- src/tools/pipewire-monitor.c | 133 ++++--- 72 files changed, 2980 insertions(+), 2120 deletions(-) create mode 100644 src/pipewire/callback.h create mode 100644 src/pipewire/private.h diff --git a/src/daemon/daemon-config.c b/src/daemon/daemon-config.c index e6156f4f2..6590ad55e 100644 --- a/src/daemon/daemon-config.c +++ b/src/daemon/daemon-config.c @@ -28,6 +28,7 @@ #include #include +#include #include "daemon/daemon-config.h" diff --git a/src/daemon/main.c b/src/daemon/main.c index b3e11892c..1f5ec4f1e 100644 --- a/src/daemon/main.c +++ b/src/daemon/main.c @@ -46,7 +46,7 @@ int main(int argc, char *argv[]) props = pw_properties_new("pipewire.core.name", "pipewire-0", "pipewire.daemon", "1", NULL); - core = pw_core_new(loop->loop, props); + core = pw_core_new(pw_main_loop_get_loop(loop), props); pw_daemon_config_run_commands(config, core); diff --git a/src/examples/export-sink.c b/src/examples/export-sink.c index 127642564..8a56ed7d8 100644 --- a/src/examples/export-sink.c +++ b/src/examples/export-sink.c @@ -74,14 +74,17 @@ struct data { struct pw_loop *loop; struct pw_core *core; + struct pw_type *t; struct pw_remote *remote; - struct pw_listener on_state_changed; + struct pw_callback_info remote_callbacks; struct pw_node *node; struct pw_port *port; struct spa_port_info port_info; + struct spa_port_io *io; + uint8_t buffer[1024]; struct spa_video_info_raw format; @@ -180,14 +183,21 @@ static Uint32 id_to_sdl_format(struct data *data, uint32_t id) SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -static int impl_port_enum_formats(struct pw_port *port, +static int impl_port_set_io(void *data, struct spa_port_io *io) +{ + struct data *d = data; + d->io = io; + return SPA_RESULT_OK; +} + +static int impl_port_enum_formats(void *data, struct spa_format **format, const struct spa_format *filter, int32_t index) { - struct data *data = port->user_data; + struct data *d = data; const struct spa_format *formats[1]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(data->buffer, sizeof(data->buffer)); + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(d->buffer, sizeof(d->buffer)); struct spa_pod_frame f[2]; SDL_RendererInfo info; int i, c; @@ -195,17 +205,17 @@ static int impl_port_enum_formats(struct pw_port *port, if (index != 0) return SPA_RESULT_ENUM_END; - SDL_GetRendererInfo(data->renderer, &info); + SDL_GetRendererInfo(d->renderer, &info); - spa_pod_builder_push_format(&b, &f[0], data->type.format, - data->type.media_type.video, - data->type.media_subtype.raw); + spa_pod_builder_push_format(&b, &f[0], d->type.format, + d->type.media_type.video, + d->type.media_subtype.raw); - spa_pod_builder_push_prop(&b, &f[1], data->type.format_video.format, + spa_pod_builder_push_prop(&b, &f[1], d->type.format_video.format, SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_ENUM); for (i = 0, c = 0; i < info.num_texture_formats; i++) { - uint32_t id = sdl_format_to_id(data, info.texture_formats[i]); + uint32_t id = sdl_format_to_id(d, info.texture_formats[i]); if (id == 0) continue; if (c++ == 0) @@ -214,17 +224,17 @@ static int impl_port_enum_formats(struct pw_port *port, } for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) { uint32_t id = - *SPA_MEMBER(&data->type.video_format, video_formats[i].id, + *SPA_MEMBER(&d->type.video_format, video_formats[i].id, uint32_t); - if (id != data->type.video_format.UNKNOWN) + if (id != d->type.video_format.UNKNOWN) spa_pod_builder_id(&b, id); } spa_pod_builder_pop(&b, &f[1]); spa_pod_builder_add(&b, - PROP_U_MM(&f[1], data->type.format_video.size, SPA_POD_TYPE_RECTANGLE, + PROP_U_MM(&f[1], d->type.format_video.size, SPA_POD_TYPE_RECTANGLE, WIDTH, HEIGHT, 1, 1, info.max_texture_width, info.max_texture_height), - PROP_U_MM(&f[1], data->type.format_video.framerate, SPA_POD_TYPE_FRACTION, + PROP_U_MM(&f[1], d->type.format_video.framerate, SPA_POD_TYPE_FRACTION, 25, 1, 0, 1, 30, 1), 0); @@ -238,70 +248,70 @@ static int impl_port_enum_formats(struct pw_port *port, return SPA_RESULT_OK; } -static int impl_port_set_format(struct pw_port *port, uint32_t flags, const struct spa_format *format) +static int impl_port_set_format(void *data, uint32_t flags, const struct spa_format *format) { - struct data *data = port->user_data; - struct pw_core *core = data->core; + struct data *d = data; + struct pw_type *t = d->t; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; Uint32 sdl_format; - void *d; + void *dest; if (format == NULL) return SPA_RESULT_OK; spa_debug_format(format); - spa_format_video_raw_parse(format, &data->format, &data->type.format_video); + spa_format_video_raw_parse(format, &d->format, &d->type.format_video); - sdl_format = id_to_sdl_format(data, data->format.format); + sdl_format = id_to_sdl_format(d, d->format.format); if (sdl_format == SDL_PIXELFORMAT_UNKNOWN) return SPA_RESULT_ERROR; - data->texture = SDL_CreateTexture(data->renderer, + d->texture = SDL_CreateTexture(d->renderer, sdl_format, SDL_TEXTUREACCESS_STREAMING, - data->format.size.width, - data->format.size.height); - SDL_LockTexture(data->texture, NULL, &d, &data->stride); - SDL_UnlockTexture(data->texture); + d->format.size.width, + d->format.size.height); + SDL_LockTexture(d->texture, NULL, &dest, &d->stride); + SDL_UnlockTexture(d->texture); - spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer)); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers, - PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, - data->stride * data->format.size.height), - PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, - data->stride), - PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + spa_pod_builder_init(&b, d->params_buffer, sizeof(d->params_buffer)); + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_buffers.Buffers, + PROP(&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, + d->stride * d->format.size.height), + PROP(&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, + d->stride), + PROP_U_MM(&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); - data->params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); + d->params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - core->type.meta.Header), - PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP(&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, + t->meta.Header), + PROP(&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof(struct spa_meta_header))); - data->params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); + d->params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); return SPA_RESULT_OK; } -static int impl_port_get_format(struct pw_port *port, const struct spa_format **format) +static int impl_port_get_format(void *data, const struct spa_format **format) { - struct data *data = port->user_data; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(data->buffer, sizeof(data->buffer)); + struct data *d = data; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(d->buffer, sizeof(d->buffer)); struct spa_pod_frame f[2]; - spa_pod_builder_push_format(&b, &f[0], data->type.format, - data->type.media_type.video, - data->type.media_subtype.raw); + spa_pod_builder_push_format(&b, &f[0], d->type.format, + d->type.media_type.video, + d->type.media_subtype.raw); spa_pod_builder_add(&b, - PROP(&f[1], data->type.format_video.format, SPA_POD_TYPE_ID, data->format.format), - PROP(&f[1], data->type.format_video.size, SPA_POD_TYPE_RECTANGLE, &data->format.size), - PROP(&f[1], data->type.format_video.framerate, SPA_POD_TYPE_FRACTION, &data->format.framerate), + PROP(&f[1], d->type.format_video.format, SPA_POD_TYPE_ID, d->format.format), + PROP(&f[1], d->type.format_video.size, SPA_POD_TYPE_RECTANGLE, &d->format.size), + PROP(&f[1], d->type.format_video.framerate, SPA_POD_TYPE_FRACTION, &d->format.framerate), 0); spa_pod_builder_pop(&b, &f[0]); *format = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format); @@ -309,104 +319,55 @@ static int impl_port_get_format(struct pw_port *port, const struct spa_format ** return SPA_RESULT_OK; } -static int impl_port_get_info(struct pw_port *port, const struct spa_port_info **info) +static int impl_port_get_info(void *data, const struct spa_port_info **info) { - struct data *data = port->user_data; + struct data *d = data; - data->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; - data->port_info.rate = 0; - data->port_info.props = NULL; + d->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; + d->port_info.rate = 0; + d->port_info.props = NULL; - *info = &data->port_info; + *info = &d->port_info; return SPA_RESULT_OK; } -static int impl_port_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param) +static int impl_port_enum_params(void *data, uint32_t index, struct spa_param **param) { - struct data *data = port->user_data; + struct data *d = data; if (index >= 2) return SPA_RESULT_ENUM_END; - *param = data->params[index]; + *param = d->params[index]; return SPA_RESULT_OK; } -static int impl_port_set_param(struct pw_port *port, struct spa_param *param) +static int impl_port_use_buffers(void *data, struct spa_buffer **buffers, uint32_t n_buffers) { - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers) -{ - struct data *data = port->user_data; + struct data *d = data; int i; for (i = 0; i < n_buffers; i++) - data->buffers[i] = buffers[i]; - data->n_buffers = n_buffers; + d->buffers[i] = buffers[i]; + d->n_buffers = n_buffers; return SPA_RESULT_OK; } -static int impl_port_alloc_buffers(struct pw_port *port, - struct spa_param **params, uint32_t n_params, - struct spa_buffer **buffers, uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_reuse_buffer(struct pw_port *port, uint32_t buffer_id) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_send_command(struct pw_port *port, struct spa_command *command) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static const struct pw_port_implementation impl_port = { PW_VERSION_PORT_IMPLEMENTATION, - impl_port_enum_formats, - impl_port_set_format, - impl_port_get_format, - impl_port_get_info, - impl_port_enum_params, - impl_port_set_param, - impl_port_use_buffers, - impl_port_alloc_buffers, - impl_port_reuse_buffer, - impl_port_send_command, + .set_io = impl_port_set_io, + .enum_formats = impl_port_enum_formats, + .set_format = impl_port_set_format, + .get_format = impl_port_get_format, + .get_info = impl_port_get_info, + .enum_params = impl_port_enum_params, + .use_buffers = impl_port_use_buffers, }; -static int impl_node_get_props(struct pw_node *node, struct spa_props **props) +static int impl_node_process_input(void *data) { - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_node_set_props(struct pw_node *node, const struct spa_props *props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_node_send_command(struct pw_node *node, - const struct spa_command *command) -{ - return SPA_RESULT_OK; -} - -static struct pw_port* impl_node_add_port(struct pw_node *node, - enum pw_direction direction, - uint32_t port_id) -{ - return NULL; -} - -static int impl_node_process_input(struct pw_node *node) -{ - struct data *data = node->user_data; - struct pw_port *port = data->port; + struct data *d = data; struct spa_buffer *buf; uint8_t *map; void *sdata, *ddata; @@ -414,20 +375,20 @@ static int impl_node_process_input(struct pw_node *node) int i; uint8_t *src, *dst; - buf = port->buffers[port->io.buffer_id]; + buf = d->buffers[d->io->buffer_id]; - if (buf->datas[0].type == data->type.data.MemFd || - buf->datas[0].type == data->type.data.DmaBuf) { + if (buf->datas[0].type == d->type.data.MemFd || + buf->datas[0].type == d->type.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->type.data.MemPtr) { + } else if (buf->datas[0].type == d->type.data.MemPtr) { map = NULL; sdata = buf->datas[0].data; } else return SPA_RESULT_ERROR; - if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { + if (SDL_LockTexture(d->texture, NULL, &ddata, &dstride) < 0) { fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); return SPA_RESULT_ERROR; } @@ -436,40 +397,30 @@ static int impl_node_process_input(struct pw_node *node) src = sdata; dst = ddata; - for (i = 0; i < data->format.size.height; i++) { + for (i = 0; i < d->format.size.height; i++) { memcpy(dst, src, ostride); src += sstride; dst += dstride; } - SDL_UnlockTexture(data->texture); + SDL_UnlockTexture(d->texture); - SDL_RenderClear(data->renderer); - SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); - SDL_RenderPresent(data->renderer); + SDL_RenderClear(d->renderer); + SDL_RenderCopy(d->renderer, d->texture, NULL, NULL); + SDL_RenderPresent(d->renderer); if (map) munmap(map, buf->datas[0].maxsize); - handle_events(data); + handle_events(d); - port->io.status = SPA_RESULT_NEED_BUFFER; + d->io->status = SPA_RESULT_NEED_BUFFER; return SPA_RESULT_NEED_BUFFER; } -static int impl_node_process_output(struct pw_node *node) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static const struct pw_node_implementation impl_node = { PW_VERSION_NODE_IMPLEMENTATION, - impl_node_get_props, - impl_node_set_props, - impl_node_send_command, - impl_node_add_port, - impl_node_process_input, - impl_node_process_output, + .process_input = impl_node_process_input, }; static void make_node(struct data *data) @@ -482,25 +433,23 @@ static void make_node(struct data *data) NULL); data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", props, 0); - data->node->user_data = data; - data->node->implementation = &impl_node; + pw_node_set_implementation(data->node, &impl_node, data); data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0); - data->port->user_data = data; - data->port->implementation = &impl_port; + pw_port_set_implementation(data->port, &impl_port, data); pw_port_add(data->port, data->node); pw_node_register(data->node); pw_remote_export(data->remote, data->node); } -static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote) +static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed); + struct data *data = _data; - switch (remote->state) { + switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", remote->error); + printf("remote error: %s\n", error); data->running = false; break; @@ -509,11 +458,15 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem break; default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_state_changed, +}; int main(int argc, char *argv[]) { @@ -524,14 +477,15 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; data.core = pw_core_new(data.loop, NULL); + data.t = pw_core_get_type(data.core); data.remote = pw_remote_new(data.core, NULL); data.path = argc > 1 ? argv[1] : NULL; pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL); - init_type(&data.type, data.core->type.map); + init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.core->type.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()); @@ -544,7 +498,7 @@ int main(int argc, char *argv[]) return -1; } - pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); + pw_remote_add_callbacks(data.remote, &data.remote_callbacks, &remote_callbacks, &data); pw_remote_connect(data.remote); diff --git a/src/examples/export-v4l2.c b/src/examples/export-v4l2.c index 9a0d8eb34..1084a35c2 100644 --- a/src/examples/export-v4l2.c +++ b/src/examples/export-v4l2.c @@ -64,9 +64,10 @@ struct data { struct pw_loop *loop; struct pw_core *core; + struct pw_type *t; struct pw_remote *remote; - struct pw_listener on_state_changed; + struct pw_callback_info remote_callbacks; struct pw_node *node; }; @@ -86,13 +87,13 @@ static void make_node(struct data *data) pw_remote_export(data->remote, data->node); } -static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote) +static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed); + struct data *data = _data; - switch (remote->state) { + switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", remote->error); + printf("remote error: %s\n", error); data->running = false; break; @@ -101,11 +102,15 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem break; default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_state_changed, +}; int main(int argc, char *argv[]) { @@ -116,15 +121,16 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; data.core = pw_core_new(data.loop, NULL); + data.t = pw_core_get_type(data.core); data.remote = pw_remote_new(data.core, NULL); pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL); - init_type(&data.type, data.core->type.map); + init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.core->type.map); + spa_debug_set_type_map(data.t->map); - pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); + pw_remote_add_callbacks(data.remote, &data.remote_callbacks, &remote_callbacks, &data); pw_remote_connect(data.remote); diff --git a/src/examples/local-v4l2.c b/src/examples/local-v4l2.c index aaeda6b65..d0e9cff66 100644 --- a/src/examples/local-v4l2.c +++ b/src/examples/local-v4l2.c @@ -75,6 +75,7 @@ struct data { struct spa_source *timer; struct pw_core *core; + struct pw_type *t; struct pw_node *node; struct pw_port *port; struct spa_port_info port_info; @@ -83,6 +84,8 @@ struct data { struct pw_link *link; + struct spa_port_io *io; + uint8_t buffer[1024]; struct spa_video_info_raw format; @@ -181,14 +184,21 @@ static Uint32 id_to_sdl_format(struct data *data, uint32_t id) SPA_POD_PROP (f,key,SPA_POD_PROP_FLAG_UNSET | \ SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) -static int impl_port_enum_formats(struct pw_port *port, +static int impl_port_set_io(void *data, struct spa_port_io *io) +{ + struct data *d = data; + d->io = io; + return SPA_RESULT_OK; +} + +static int impl_port_enum_formats(void *data, struct spa_format **format, const struct spa_format *filter, int32_t index) { - struct data *data = port->user_data; + struct data *d = data; const struct spa_format *formats[1]; - struct spa_pod_builder b = SPA_POD_BUILDER_INIT(data->buffer, sizeof(data->buffer)); + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(d->buffer, sizeof(d->buffer)); struct spa_pod_frame f[2]; SDL_RendererInfo info; int i, c; @@ -196,17 +206,17 @@ static int impl_port_enum_formats(struct pw_port *port, if (index != 0) return SPA_RESULT_ENUM_END; - SDL_GetRendererInfo(data->renderer, &info); + SDL_GetRendererInfo(d->renderer, &info); - spa_pod_builder_push_format(&b, &f[0], data->type.format, - data->type.media_type.video, - data->type.media_subtype.raw); + spa_pod_builder_push_format(&b, &f[0], d->type.format, + d->type.media_type.video, + d->type.media_subtype.raw); - spa_pod_builder_push_prop(&b, &f[1], data->type.format_video.format, + spa_pod_builder_push_prop(&b, &f[1], d->type.format_video.format, SPA_POD_PROP_FLAG_UNSET | SPA_POD_PROP_RANGE_ENUM); for (i = 0, c = 0; i < info.num_texture_formats; i++) { - uint32_t id = sdl_format_to_id(data, info.texture_formats[i]); + uint32_t id = sdl_format_to_id(d, info.texture_formats[i]); if (id == 0) continue; if (c++ == 0) @@ -215,17 +225,17 @@ static int impl_port_enum_formats(struct pw_port *port, } for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) { uint32_t id = - *SPA_MEMBER(&data->type.video_format, video_formats[i].id, + *SPA_MEMBER(&d->type.video_format, video_formats[i].id, uint32_t); - if (id != data->type.video_format.UNKNOWN) + if (id != d->type.video_format.UNKNOWN) spa_pod_builder_id(&b, id); } spa_pod_builder_pop(&b, &f[1]); spa_pod_builder_add(&b, - PROP_U_MM(&f[1], data->type.format_video.size, SPA_POD_TYPE_RECTANGLE, + PROP_U_MM(&f[1], d->type.format_video.size, SPA_POD_TYPE_RECTANGLE, WIDTH, HEIGHT, 1, 1, info.max_texture_width, info.max_texture_height), - PROP_U_MM(&f[1], data->type.format_video.framerate, SPA_POD_TYPE_FRACTION, + PROP_U_MM(&f[1], d->type.format_video.framerate, SPA_POD_TYPE_FRACTION, 25, 1, 0, 1, 30, 1), 0); @@ -239,14 +249,14 @@ static int impl_port_enum_formats(struct pw_port *port, return SPA_RESULT_OK; } -static int impl_port_set_format(struct pw_port *port, uint32_t flags, const struct spa_format *format) +static int impl_port_set_format(void *data, uint32_t flags, const struct spa_format *format) { - struct data *data = port->user_data; - struct pw_core *core = data->core; + struct data *d = data; + struct pw_type *t = d->t; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; Uint32 sdl_format; - void *d; + void *dest; if (format == NULL) { return SPA_RESULT_OK; @@ -254,146 +264,91 @@ static int impl_port_set_format(struct pw_port *port, uint32_t flags, const stru spa_debug_format(format); - spa_format_video_raw_parse(format, &data->format, &data->type.format_video); + spa_format_video_raw_parse(format, &d->format, &d->type.format_video); - sdl_format = id_to_sdl_format(data, data->format.format); + sdl_format = id_to_sdl_format(d, d->format.format); if (sdl_format == SDL_PIXELFORMAT_UNKNOWN) return SPA_RESULT_ERROR; - data->texture = SDL_CreateTexture(data->renderer, + d->texture = SDL_CreateTexture(d->renderer, sdl_format, SDL_TEXTUREACCESS_STREAMING, - data->format.size.width, - data->format.size.height); - SDL_LockTexture(data->texture, NULL, &d, &data->stride); - SDL_UnlockTexture(data->texture); + d->format.size.width, + d->format.size.height); + SDL_LockTexture(d->texture, NULL, &dest, &d->stride); + SDL_UnlockTexture(d->texture); - spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer)); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers, - PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, - data->stride * data->format.size.height), - PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, - data->stride), - PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + spa_pod_builder_init(&b, d->params_buffer, sizeof(d->params_buffer)); + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_buffers.Buffers, + PROP(&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, + d->stride * d->format.size.height), + PROP(&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, + d->stride), + PROP_U_MM(&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); - data->params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); + d->params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - core->type.meta.Header), - PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP(&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, + t->meta.Header), + PROP(&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof(struct spa_meta_header))); - data->params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); + d->params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); return SPA_RESULT_OK; } -static int impl_port_get_format(struct pw_port *port, const struct spa_format **format) +static int impl_port_get_info(void *data, const struct spa_port_info **info) { - return SPA_RESULT_NOT_IMPLEMENTED; -} + struct data *d = data; -static int impl_port_get_info(struct pw_port *port, const struct spa_port_info **info) -{ - struct data *data = port->user_data; + d->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; + d->port_info.rate = 0; + d->port_info.props = NULL; - data->port_info.flags = SPA_PORT_INFO_FLAG_CAN_USE_BUFFERS; - data->port_info.rate = 0; - data->port_info.props = NULL; - - *info = &data->port_info; + *info = &d->port_info; return SPA_RESULT_OK; } -static int impl_port_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param) +static int impl_port_enum_params(void *data, uint32_t index, struct spa_param **param) { - struct data *data = port->user_data; + struct data *d = data; if (index >= 2) return SPA_RESULT_ENUM_END; - *param = data->params[index]; + *param = d->params[index]; return SPA_RESULT_OK; } -static int impl_port_set_param(struct pw_port *port, struct spa_param *param) +static int impl_port_use_buffers(void *data, struct spa_buffer **buffers, uint32_t n_buffers) { - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers) -{ - struct data *data = port->user_data; + struct data *d = data; int i; for (i = 0; i < n_buffers; i++) - data->buffers[i] = buffers[i]; - data->n_buffers = n_buffers; + d->buffers[i] = buffers[i]; + d->n_buffers = n_buffers; return SPA_RESULT_OK; } -static int impl_port_alloc_buffers(struct pw_port *port, - struct spa_param **params, uint32_t n_params, - struct spa_buffer **buffers, uint32_t *n_buffers) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_reuse_buffer(struct pw_port *port, uint32_t buffer_id) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_port_send_command(struct pw_port *port, struct spa_command *command) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static const struct pw_port_implementation impl_port = { PW_VERSION_PORT_IMPLEMENTATION, - impl_port_enum_formats, - impl_port_set_format, - impl_port_get_format, - impl_port_get_info, - impl_port_enum_params, - impl_port_set_param, - impl_port_use_buffers, - impl_port_alloc_buffers, - impl_port_reuse_buffer, - impl_port_send_command, + .set_io = impl_port_set_io, + .enum_formats = impl_port_enum_formats, + .set_format = impl_port_set_format, + .get_info = impl_port_get_info, + .enum_params = impl_port_enum_params, + .use_buffers = impl_port_use_buffers, }; -static int impl_node_get_props(struct pw_node *node, struct spa_props **props) +static int impl_node_process_input(void *data) { - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_node_set_props(struct pw_node *node, const struct spa_props *props) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - -static int impl_node_send_command(struct pw_node *node, - const struct spa_command *command) -{ - return SPA_RESULT_OK; -} - -static struct pw_port* impl_node_add_port(struct pw_node *node, - enum pw_direction direction, - uint32_t port_id) -{ - return NULL; -} - -static int impl_node_process_input(struct pw_node *node) -{ - struct data *data = node->user_data; - struct pw_port *port = data->port; + struct data *d = data; struct spa_buffer *buf; uint8_t *map; void *sdata, *ddata; @@ -401,20 +356,20 @@ static int impl_node_process_input(struct pw_node *node) int i; uint8_t *src, *dst; - buf = port->buffers[port->io.buffer_id]; + buf = d->buffers[d->io->buffer_id]; - if (buf->datas[0].type == data->type.data.MemFd || - buf->datas[0].type == data->type.data.DmaBuf) { + if (buf->datas[0].type == d->type.data.MemFd || + buf->datas[0].type == d->type.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->type.data.MemPtr) { + } else if (buf->datas[0].type == d->type.data.MemPtr) { map = NULL; sdata = buf->datas[0].data; } else return SPA_RESULT_ERROR; - if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { + if (SDL_LockTexture(d->texture, NULL, &ddata, &dstride) < 0) { fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); return SPA_RESULT_ERROR; } @@ -423,40 +378,30 @@ static int impl_node_process_input(struct pw_node *node) src = sdata; dst = ddata; - for (i = 0; i < data->format.size.height; i++) { + for (i = 0; i < d->format.size.height; i++) { memcpy(dst, src, ostride); src += sstride; dst += dstride; } - SDL_UnlockTexture(data->texture); + SDL_UnlockTexture(d->texture); - SDL_RenderClear(data->renderer); - SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); - SDL_RenderPresent(data->renderer); + SDL_RenderClear(d->renderer); + SDL_RenderCopy(d->renderer, d->texture, NULL, NULL); + SDL_RenderPresent(d->renderer); if (map) munmap(map, buf->datas[0].maxsize); - handle_events(data); + handle_events(d); - port->io.status = SPA_RESULT_NEED_BUFFER; + d->io->status = SPA_RESULT_NEED_BUFFER; return SPA_RESULT_NEED_BUFFER; } -static int impl_node_process_output(struct pw_node *node) -{ - return SPA_RESULT_NOT_IMPLEMENTED; -} - static const struct pw_node_implementation impl_node = { PW_VERSION_NODE_IMPLEMENTATION, - impl_node_get_props, - impl_node_set_props, - impl_node_send_command, - impl_node_add_port, - impl_node_process_input, - impl_node_process_output, + .process_input = impl_node_process_input, }; static void make_nodes(struct data *data) @@ -465,12 +410,10 @@ static void make_nodes(struct data *data) struct pw_properties *props; data->node = pw_node_new(data->core, NULL, NULL, "SDL-sink", NULL, 0); - data->node->user_data = data; - data->node->implementation = &impl_node; + pw_node_set_implementation(data->node, &impl_node, data); data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0); - data->port->user_data = data; - data->port->implementation = &impl_port; + pw_port_set_implementation(data->port, &impl_port, data); pw_port_add(data->port, data->node); pw_node_register(data->node); @@ -498,13 +441,14 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; data.core = pw_core_new(data.loop, NULL); + data.t = pw_core_get_type(data.core); data.path = argc > 1 ? argv[1] : NULL; pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL); - init_type(&data.type, data.core->type.map); + init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.core->type.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()); diff --git a/src/examples/video-play.c b/src/examples/video-play.c index 7d2af808f..bf4762043 100644 --- a/src/examples/video-play.c +++ b/src/examples/video-play.c @@ -72,13 +72,12 @@ struct data { struct pw_loop *loop; struct pw_core *core; + struct pw_type *t; struct pw_remote *remote; - struct pw_listener on_state_changed; + struct pw_callback_info remote_callbacks; struct pw_stream *stream; - struct pw_listener on_stream_state_changed; - struct pw_listener on_stream_format_changed; - struct pw_listener on_stream_new_buffer; + struct pw_callback_info stream_callbacks; struct spa_video_info_raw format; int32_t stride; @@ -100,9 +99,10 @@ static void handle_events(struct data *data) } static void -on_stream_new_buffer(struct pw_listener *listener, struct pw_stream *stream, uint32_t id) +on_stream_new_buffer(void *_data, uint32_t id) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_new_buffer); + struct data *data = _data; + struct pw_stream *stream = data->stream; struct spa_buffer *buf; uint8_t *map; void *sdata, *ddata; @@ -110,7 +110,7 @@ on_stream_new_buffer(struct pw_listener *listener, struct pw_stream *stream, uin int i; uint8_t *src, *dst; - buf = pw_stream_peek_buffer(data->stream, id); + buf = pw_stream_peek_buffer(stream, id); if (buf->datas[0].type == data->type.data.MemFd) { map = mmap(NULL, buf->datas[0].maxsize + buf->datas[0].mapoffset, PROT_READ, @@ -145,14 +145,15 @@ on_stream_new_buffer(struct pw_listener *listener, struct pw_stream *stream, uin if (map) munmap(map, buf->datas[0].maxsize); - pw_stream_recycle_buffer(data->stream, id); + pw_stream_recycle_buffer(stream, id); handle_events(data); } -static void on_stream_state_changed(struct pw_listener *listener, struct pw_stream *stream) +static void on_stream_state_changed(void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error) { - printf("stream state: \"%s\"\n", pw_stream_state_as_string(stream->state)); + printf("stream state: \"%s\"\n", pw_stream_state_as_string(state)); } static struct { @@ -230,12 +231,11 @@ static Uint32 id_to_sdl_format(struct data *data, uint32_t id) SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) static void -on_stream_format_changed(struct pw_listener *listener, - struct pw_stream *stream, struct spa_format *format) +on_stream_format_changed(void *_data, struct spa_format *format) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed); - struct pw_remote *remote = stream->remote; - struct pw_core *core = remote->core; + struct data *data = _data; + struct pw_stream *stream = data->stream; + struct pw_type *t = data->t; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; struct spa_param *params[2]; @@ -266,35 +266,43 @@ on_stream_format_changed(struct pw_listener *listener, SDL_UnlockTexture(data->texture); spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer)); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers, - PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_buffers.Buffers, + PROP(&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, data->stride * data->format.size.height), - PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, data->stride), - PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + PROP_U_MM(&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - core->type.meta.Header), - PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP(&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, + t->meta.Header), + PROP(&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof(struct spa_meta_header))); params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2); } -static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote) -{ - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed); +static const struct pw_stream_callbacks stream_callbacks = { + PW_VERSION_STREAM_CALLBACKS, + .state_changed = on_stream_state_changed, + .format_changed = on_stream_format_changed, + .new_buffer = on_stream_new_buffer, +}; - switch (remote->state) { +static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) +{ + struct data *data = _data; + struct pw_remote *remote = data->remote; + + switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", remote->error); + printf("remote error: %s\n", error); data->running = false; break; @@ -307,8 +315,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem SDL_RendererInfo info; int i, c; - printf("remote state: \"%s\"\n", - pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); data->stream = pw_stream_new(remote, "video-play", NULL); @@ -351,12 +358,10 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem printf("supported formats:\n"); spa_debug_format(formats[0]); - pw_signal_add(&data->stream->state_changed, - &data->on_stream_state_changed, on_stream_state_changed); - pw_signal_add(&data->stream->format_changed, - &data->on_stream_format_changed, on_stream_format_changed); - pw_signal_add(&data->stream->new_buffer, - &data->on_stream_new_buffer, on_stream_new_buffer); + pw_stream_add_callbacks(data->stream, + &data->stream_callbacks, + &stream_callbacks, + data); pw_stream_connect(data->stream, PW_DIRECTION_INPUT, @@ -365,11 +370,16 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem break; } default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_state_changed, +}; + int main(int argc, char *argv[]) { struct data data = { 0, }; @@ -379,12 +389,13 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; data.core = pw_core_new(data.loop, NULL); + data.t = pw_core_get_type(data.core); data.remote = pw_remote_new(data.core, NULL); data.path = argc > 1 ? argv[1] : NULL; - init_type(&data.type, data.core->type.map); + init_type(&data.type, data.t->map); - spa_debug_set_type_map(data.core->type.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()); @@ -397,7 +408,7 @@ int main(int argc, char *argv[]) return -1; } - pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); + pw_remote_add_callbacks(data.remote, &data.remote_callbacks, &remote_callbacks, &data); pw_remote_connect(data.remote); diff --git a/src/examples/video-src.c b/src/examples/video-src.c index a4d7234c2..ce71bc9dc 100644 --- a/src/examples/video-src.c +++ b/src/examples/video-src.c @@ -65,12 +65,12 @@ struct data { struct spa_source *timer; struct pw_core *core; + struct pw_type *t; struct pw_remote *remote; - struct pw_listener on_state_changed; + struct pw_callback_info remote_callbacks; struct pw_stream *stream; - struct pw_listener on_stream_state_changed; - struct pw_listener on_stream_format_changed; + struct pw_callback_info stream_callbacks; struct spa_video_info_raw format; int32_t stride; @@ -137,13 +137,14 @@ static void on_timeout(struct spa_loop_utils *utils, struct spa_source *source, pw_stream_send_buffer(data->stream, id); } -static void on_stream_state_changed(struct pw_listener *listener, struct pw_stream *stream) +static void on_stream_state_changed(void *_data, enum pw_stream_state old, enum pw_stream_state state, + const char *error) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_state_changed); + struct data *data = _data; - printf("stream state: \"%s\"\n", pw_stream_state_as_string(stream->state)); + printf("stream state: \"%s\"\n", pw_stream_state_as_string(state)); - switch (stream->state) { + switch (state) { case PW_STREAM_STATE_PAUSED: pw_loop_update_timer(data->loop, data->timer, NULL, NULL, false); break; @@ -172,12 +173,11 @@ static void on_stream_state_changed(struct pw_listener *listener, struct pw_stre SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) static void -on_stream_format_changed(struct pw_listener *listener, - struct pw_stream *stream, struct spa_format *format) +on_stream_format_changed(void *_data, struct spa_format *format) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed); - struct pw_remote *remote = stream->remote; - struct pw_core *core = remote->core; + struct data *data = _data; + struct pw_stream *stream = data->stream; + struct pw_type *t = data->t; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; struct spa_param *params[2]; @@ -191,35 +191,42 @@ on_stream_format_changed(struct pw_listener *listener, data->stride = SPA_ROUND_UP_N(data->format.size.width * BPP, 4); spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer)); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers, - PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_buffers.Buffers, + PROP(&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, data->stride * data->format.size.height), - PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, data->stride), - PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + PROP_U_MM(&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); - spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - core->type.meta.Header), - PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + spa_pod_builder_object(&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP(&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, + t->meta.Header), + PROP(&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof(struct spa_meta_header))); params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param); pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2); } -static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote) -{ - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed); +static const struct pw_stream_callbacks stream_callbacks = { + PW_VERSION_STREAM_CALLBACKS, + .state_changed = on_stream_state_changed, + .format_changed = on_stream_format_changed, +}; - switch (remote->state) { +static void on_state_changed(void *_data, enum pw_remote_state old, enum pw_remote_state state, const char *error) +{ + struct data *data = _data; + struct pw_remote *remote = data->remote; + + switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", remote->error); + printf("remote error: %s\n", error); data->running = false; break; @@ -231,7 +238,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem struct spa_pod_frame f[2]; printf("remote state: \"%s\"\n", - pw_remote_state_as_string(remote->state)); + pw_remote_state_as_string(state)); data->stream = pw_stream_new(remote, "video-src", NULL); @@ -247,10 +254,10 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem 25, 1)); formats[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format); - pw_signal_add(&data->stream->state_changed, - &data->on_stream_state_changed, on_stream_state_changed); - pw_signal_add(&data->stream->format_changed, - &data->on_stream_format_changed, on_stream_format_changed); + pw_stream_add_callbacks(data->stream, + &data->stream_callbacks, + &stream_callbacks, + data); pw_stream_connect(data->stream, PW_DIRECTION_OUTPUT, @@ -259,11 +266,16 @@ static void on_state_changed(struct pw_listener *listener, struct pw_remote *rem break; } default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_state_changed, +}; + int main(int argc, char *argv[]) { struct data data = { 0, }; @@ -273,13 +285,14 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; data.core = pw_core_new(data.loop, NULL); + data.t = pw_core_get_type(data.core); data.remote = pw_remote_new(data.core, NULL); - init_type(&data.type, data.core->type.map); + init_type(&data.type, data.t->map); data.timer = pw_loop_add_timer(data.loop, on_timeout, &data); - pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); + pw_remote_add_callbacks(data.remote, &data.remote_callbacks, &remote_callbacks, &data); pw_remote_connect(data.remote); diff --git a/src/extensions/client-node.h b/src/extensions/client-node.h index f52e417b5..13a15186d 100644 --- a/src/extensions/client-node.h +++ b/src/extensions/client-node.h @@ -339,9 +339,11 @@ struct pw_client_node_events { static inline void pw_client_node_proxy_add_listener(struct pw_client_node_proxy *p, - void *object, const struct pw_client_node_events *events) + struct pw_callback_info *info, + const struct pw_client_node_events *events, + void *data) { - pw_proxy_add_listener(&p->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)p, info, events, data); } #define pw_client_node_resource_transport(r,...) pw_resource_notify(r,struct pw_client_node_events,transport,__VA_ARGS__) diff --git a/src/gst/gstpipewiredeviceprovider.c b/src/gst/gstpipewiredeviceprovider.c index b52cff48b..7ec8bcff5 100644 --- a/src/gst/gstpipewiredeviceprovider.c +++ b/src/gst/gstpipewiredeviceprovider.c @@ -201,13 +201,14 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info, uint struct spa_dict_item *item; GstPipeWireDeviceType type; int i; + struct pw_type *t = self->type; caps = gst_caps_new_empty (); if (info->max_input_ports > 0 && info->max_output_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SINK; for (i = 0; i < info->n_input_formats; i++) { - GstCaps *c1 = gst_caps_from_format (info->input_formats[i], self->core->type.map); + GstCaps *c1 = gst_caps_from_format (info->input_formats[i], t->map); if (c1) gst_caps_append (caps, c1); } @@ -215,7 +216,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info, uint else if (info->max_output_ports > 0 && info->max_input_ports == 0) { type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE; for (i = 0; i < info->n_output_formats; i++) { - GstCaps *c1 = gst_caps_from_format (info->output_formats[i], self->core->type.map); + GstCaps *c1 = gst_caps_from_format (info->output_formats[i], t->map); if (c1) gst_caps_append (caps, c1); } @@ -267,7 +268,7 @@ get_core_info (struct pw_remote *remote, void *user_data) { GstDeviceProvider *provider = user_data; - struct pw_core_info *info = remote->info; + const struct pw_core_info *info = pw_remote_get_core_info(remote); const gchar *value; if (info == NULL || info->props == NULL) @@ -291,25 +292,53 @@ get_core_info (struct pw_remote *remote, } static void -on_sync_reply (struct pw_listener *listener, struct pw_remote *remote, uint32_t seq) +on_sync_reply (void *data, uint32_t seq) { - GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, on_sync_reply); + GstPipeWireDeviceProvider *self = data; if (seq == 1) - pw_core_proxy_sync(self->remote->core_proxy, 2); + pw_core_proxy_sync(self->core_proxy, 2); else if (seq == 2) self->end = true; } +static void +on_state_changed (void *data, enum pw_remote_state old, enum pw_remote_state state, const char *error) +{ + GstPipeWireDeviceProvider *self = data; + + GST_DEBUG ("got remote state %d", state); + + switch (state) { + case PW_REMOTE_STATE_CONNECTING: + break; + case PW_REMOTE_STATE_UNCONNECTED: + case PW_REMOTE_STATE_CONNECTED: + break; + case PW_REMOTE_STATE_ERROR: + GST_ERROR_OBJECT (self, "remote error: %s", error); + break; + } + pw_thread_loop_signal (self->main_loop, FALSE); +} + + struct node_data { GstPipeWireDeviceProvider *self; + struct pw_node_proxy *node; uint32_t id; uint32_t parent_id; + struct pw_callback_info node_listener; }; -static void node_event_info(void *object, struct pw_node_info *info) +struct registry_data { + GstPipeWireDeviceProvider *self; + struct pw_registry_proxy *registry; + struct pw_callback_info registry_listener; +}; + +static void node_event_info(void *data, struct pw_node_info *info) { - struct pw_proxy *proxy = object; - struct node_data *node_data = proxy->user_data; + struct node_data *node_data = data; GstPipeWireDeviceProvider *self = node_data->self; GstDevice *dev; @@ -324,33 +353,32 @@ static void node_event_info(void *object, struct pw_node_info *info) static const struct pw_node_events node_events = { PW_VERSION_NODE_EVENTS, - &node_event_info + .info = node_event_info }; -static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, uint32_t permissions, +static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version) { - struct pw_registry_proxy *registry = object; - GstPipeWireDeviceProvider *self = registry->proxy.user_data; - struct pw_remote *remote = self->remote; - struct pw_core *core = remote->core; + struct registry_data *rd = data; + GstPipeWireDeviceProvider *self = rd->self; struct pw_node_proxy *node; - struct node_data *data; + struct node_data *nd; - if (type != core->type.node) + if (type != self->type->node) return; - node = pw_registry_proxy_bind(registry, id, core->type.node, PW_VERSION_NODE, - sizeof(struct node_data), NULL); + node = pw_registry_proxy_bind(rd->registry, id, self->type->node, PW_VERSION_NODE, sizeof(*nd)); if (node == NULL) goto no_mem; - data = node->proxy.user_data; - data->id = id; - data->parent_id = parent_id; - data->self = self; - pw_node_proxy_add_listener(node, node, &node_events); + 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); + return; no_mem: @@ -358,10 +386,9 @@ no_mem: return; } -static void registry_event_global_remove(void *object, uint32_t id) +static void registry_event_global_remove(void *data, uint32_t id) { - struct pw_registry_proxy *registry = object; - GstPipeWireDeviceProvider *self = registry->proxy.user_data; + GstPipeWireDeviceProvider *self = data; GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); GstPipeWireDevice *dev; @@ -374,8 +401,14 @@ static void registry_event_global_remove(void *object, uint32_t id) static const struct pw_registry_events registry_events = { PW_VERSION_REGISTRY_EVENTS, - registry_event_global, - registry_event_global_remove, + .global = registry_event_global, + .global_remove = registry_event_global_remove, +}; + +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_state_changed, + .sync_reply = on_sync_reply, }; static GList * @@ -384,8 +417,11 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider); struct pw_loop *l = NULL; 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 pw_callback_info callbacks; GST_DEBUG_OBJECT (self, "starting probe"); @@ -395,20 +431,23 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) if (!(c = pw_core_new (l, NULL))) return NULL; + t = pw_core_get_type(c); + if (!(r = pw_remote_new (c, NULL))) goto failed; - pw_signal_add(&r->sync_reply, &self->on_sync_reply, on_sync_reply); + pw_remote_add_callbacks(r, &callbacks, &remote_callbacks, self); pw_remote_connect (r); for (;;) { enum pw_remote_state state; + const char *error = NULL; - state = r->state; + state = pw_remote_get_state(r, &error); if (state <= 0) { - GST_ERROR_OBJECT (self, "Failed to connect: %s", r->error); + GST_ERROR_OBJECT (self, "Failed to connect: %s", error); goto failed; } @@ -426,13 +465,17 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) self->list_only = TRUE; self->devices = NULL; - reg = pw_core_proxy_get_registry(r->core_proxy, PW_VERSION_REGISTRY, 0, NULL); - reg->proxy.user_data = self; - pw_registry_proxy_add_listener(reg, reg, ®istry_events); - pw_core_proxy_sync(r->core_proxy, 1); + 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; + pw_registry_proxy_add_listener(reg, &data->registry_listener, ®istry_events, data); + pw_core_proxy_sync(self->core_proxy, 1); for (;;) { - if (r->state <= 0) + if (pw_remote_get_state(r, NULL) <= 0) break; if (self->end) break; @@ -451,34 +494,11 @@ failed: return NULL; } -static void -on_remote_state_changed (struct pw_listener *listener, - struct pw_remote *remote) -{ - GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, remote_state_changed); - enum pw_remote_state state; - - state= remote->state; - - GST_DEBUG ("got remote state %d", state); - - switch (state) { - case PW_REMOTE_STATE_CONNECTING: - break; - case PW_REMOTE_STATE_UNCONNECTED: - case PW_REMOTE_STATE_CONNECTED: - break; - case PW_REMOTE_STATE_ERROR: - GST_ERROR_OBJECT (self, "remote error: %s", remote->error); - break; - } - pw_thread_loop_signal (self->main_loop, FALSE); -} - static gboolean gst_pipewire_device_provider_start (GstDeviceProvider * provider) { GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider); + struct registry_data *data; GST_DEBUG_OBJECT (self, "starting provider"); @@ -494,6 +514,7 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) GST_ERROR_OBJECT (self, "Could not create PipeWire core"); goto failed_core; } + self->type = pw_core_get_type (self->core); if (pw_thread_loop_start (self->main_loop) != SPA_RESULT_OK) { GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop"); @@ -507,18 +528,17 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) goto failed_remote; } - pw_signal_add (&self->remote->state_changed, - &self->remote_state_changed, - on_remote_state_changed); + pw_remote_add_callbacks (self->remote, &self->remote_callbacks, &remote_callbacks, self); pw_remote_connect (self->remote); for (;;) { enum pw_remote_state state; + const char *error = NULL; - state = self->remote->state; + state = pw_remote_get_state(self->remote, &error); if (state <= 0) { - GST_WARNING_OBJECT (self, "Failed to connect: %s", self->remote->error); + GST_WARNING_OBJECT (self, "Failed to connect: %s", error); goto not_running; } @@ -531,10 +551,16 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) GST_DEBUG_OBJECT (self, "connected"); get_core_info (self->remote, self); - self->registry = pw_core_proxy_get_registry(self->remote->core_proxy, PW_VERSION_REGISTRY, 0, NULL); - self->registry->proxy.user_data = self; - pw_registry_proxy_add_listener(self->registry, self->registry, ®istry_events); - pw_core_proxy_sync(self->remote->core_proxy, 1); + 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)); + + data = pw_proxy_get_user_data((struct pw_proxy*)self->registry); + data->self = self; + data->registry = self->registry; + + pw_registry_proxy_add_listener(self->registry, &data->registry_listener, ®istry_events, data); + pw_core_proxy_sync(self->core_proxy, 1); pw_thread_loop_unlock (self->main_loop); @@ -548,6 +574,7 @@ failed_remote: failed_start: pw_core_destroy (self->core); self->core = NULL; + self->type = NULL; failed_core: pw_thread_loop_destroy (self->main_loop); self->main_loop = NULL; @@ -570,6 +597,7 @@ gst_pipewire_device_provider_stop (GstDeviceProvider * provider) if (self->core) { pw_core_destroy (self->core); self->core = NULL; + self->type = NULL; } if (self->main_loop) { pw_thread_loop_destroy (self->main_loop); diff --git a/src/gst/gstpipewiredeviceprovider.h b/src/gst/gstpipewiredeviceprovider.h index 38633084d..338fb46d0 100644 --- a/src/gst/gstpipewiredeviceprovider.h +++ b/src/gst/gstpipewiredeviceprovider.h @@ -85,13 +85,15 @@ struct _GstPipeWireDeviceProvider { struct pw_thread_loop *main_loop; struct pw_core *core; + struct pw_type *type; struct pw_remote *remote; + struct pw_core_proxy *core_proxy; struct pw_registry_proxy *registry; + gboolean end; gboolean list_only; GList **devices; - struct pw_listener remote_state_changed; - struct pw_listener on_sync_reply; + struct pw_callback_info remote_callbacks; }; struct _GstPipeWireDeviceProviderClass { diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c index 2d61fe8d3..492a26aee 100644 --- a/src/gst/gstpipewiresink.c +++ b/src/gst/gstpipewiresink.c @@ -235,8 +235,7 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass) static void pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) { - struct pw_remote *remote = sink->stream->remote; - struct pw_core *core = remote->core; + struct pw_type *t = sink->type; GstStructure *config; GstCaps *caps; guint size; @@ -251,36 +250,36 @@ pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers); spa_pod_builder_init (&b, buffer, sizeof (buffer)); - spa_pod_builder_push_object (&b, &f[0], 0, core->type.param_alloc_buffers.Buffers); + spa_pod_builder_push_object (&b, &f[0], 0, t->param_alloc_buffers.Buffers); if (size == 0) spa_pod_builder_add (&b, - PROP_U_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0); + PROP_U_MM (&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0); else spa_pod_builder_add (&b, - PROP_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0); + PROP_MM (&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0); spa_pod_builder_add (&b, - PROP_MM (&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, min_buffers, min_buffers, max_buffers ? max_buffers : INT32_MAX), - PROP (&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16), + PROP_MM (&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), + PROP_U_MM (&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, min_buffers, min_buffers, max_buffers ? max_buffers : INT32_MAX), + PROP (&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16), 0); spa_pod_builder_pop (&b, &f[0]); port_params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header), - PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); + spa_pod_builder_object (&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP (&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, t->meta.Header), + PROP (&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); port_params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Ringbuffer), - PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_ringbuffer)), - PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferSize, SPA_POD_TYPE_INT, - size * SPA_MAX (4, - SPA_MAX (min_buffers, max_buffers))), - PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0), - PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1), - PROP (&f[1], core->type.param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16)); + spa_pod_builder_object (&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP (&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, t->meta.Ringbuffer), + PROP (&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_ringbuffer)), + PROP (&f[1], t->param_alloc_meta_enable.ringbufferSize, SPA_POD_TYPE_INT, + size * SPA_MAX (4, + SPA_MAX (min_buffers, max_buffers))), + PROP (&f[1], t->param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0), + PROP (&f[1], t->param_alloc_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1), + PROP (&f[1], t->param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16)); port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); pw_thread_loop_lock (sink->main_loop); @@ -306,6 +305,7 @@ gst_pipewire_sink_init (GstPipeWireSink * sink) sink->loop = pw_loop_new (); 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); GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop); } @@ -434,16 +434,15 @@ process_mem_data_destroy (gpointer user_data) } static void -on_add_buffer (struct pw_listener *listener, - struct pw_stream *stream, - uint32_t id) +on_add_buffer (void *_data, + uint32_t id) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_add_buffer); + GstPipeWireSink *pwsink = _data; struct spa_buffer *b; GstBuffer *buf; uint32_t i; ProcessMemData data; - struct pw_core *core = pwsink->remote->core; + struct pw_type *t = pwsink->type; GST_LOG_OBJECT (pwsink, "add buffer"); @@ -457,20 +456,20 @@ on_add_buffer (struct pw_listener *listener, data.sink = gst_object_ref (pwsink); data.id = id; data.buf = b; - data.header = spa_buffer_find_meta (b, core->type.meta.Header); + 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 == core->type.data.MemFd || - d->type == core->type.data.DmaBuf) { + 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->chunk->offset + d->mapoffset, d->chunk->size); data.offset = d->mapoffset; } - else if (d->type == core->type.data.MemPtr) { + else if (d->type == t->data.MemPtr) { gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset, d->chunk->size, NULL, NULL); data.offset = 0; @@ -491,11 +490,10 @@ on_add_buffer (struct pw_listener *listener, } static void -on_remove_buffer (struct pw_listener *listener, - struct pw_stream *stream, - uint32_t id) +on_remove_buffer (void *data, + uint32_t id) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_remove_buffer); + GstPipeWireSink *pwsink = data; GstBuffer *buf; GST_LOG_OBJECT (pwsink, "remove buffer"); @@ -511,11 +509,10 @@ on_remove_buffer (struct pw_listener *listener, } static void -on_new_buffer (struct pw_listener *listener, - struct pw_stream *stream, - uint32_t id) +on_new_buffer (void *data, + uint32_t id) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_new_buffer); + GstPipeWireSink *pwsink = data; GstBuffer *buf; GST_LOG_OBJECT (pwsink, "got new buffer %u", id); @@ -569,24 +566,19 @@ do_send_buffer (GstPipeWireSink *pwsink) static void -on_need_buffer (struct pw_listener *listener, - struct pw_stream *stream) +on_need_buffer (void *data) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_need_buffer); - + GstPipeWireSink *pwsink = data; pwsink->need_ready++; GST_DEBUG ("need buffer %u", pwsink->need_ready); do_send_buffer (pwsink); } static void -on_state_changed (struct pw_listener *listener, - struct pw_stream *stream) +on_state_changed (void *data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_state_changed); - enum pw_stream_state state; + GstPipeWireSink *pwsink = data; - state = stream->state; GST_DEBUG ("got stream state %d", state); switch (state) { @@ -599,18 +591,16 @@ on_state_changed (struct pw_listener *listener, break; case PW_STREAM_STATE_ERROR: GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED, - ("stream error: %s", stream->error), (NULL)); + ("stream error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsink->main_loop, FALSE); } static void -on_format_changed (struct pw_listener *listener, - struct pw_stream *stream, - struct spa_format *format) +on_format_changed (void *data, struct spa_format *format) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, stream_format_changed); + GstPipeWireSink *pwsink = data; if (gst_buffer_pool_is_active (GST_BUFFER_POOL_CAST (pwsink->pool))) pool_activated (pwsink->pool, pwsink); @@ -622,14 +612,15 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) GstPipeWireSink *pwsink; GPtrArray *possible; enum pw_stream_state state; + const char *error = NULL; gboolean res = FALSE; pwsink = GST_PIPEWIRE_SINK (bsink); - possible = gst_caps_to_format_all (caps, pwsink->remote->core->type.map); + possible = gst_caps_to_format_all (caps, pwsink->type->map); pw_thread_loop_lock (pwsink->main_loop); - state = pwsink->stream->state; + state = pw_stream_get_state (pwsink->stream, &error); if (state == PW_STREAM_STATE_ERROR) goto start_error; @@ -649,7 +640,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) (const struct spa_format **) possible->pdata); while (TRUE) { - state = pwsink->stream->state; + state = pw_stream_get_state (pwsink->stream, &error); if (state == PW_STREAM_STATE_READY) break; @@ -670,7 +661,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) start_error: { - GST_ERROR ("could not start stream"); + GST_ERROR ("could not start stream: %s", error); pw_thread_loop_unlock (pwsink->main_loop); g_ptr_array_unref (possible); return FALSE; @@ -682,6 +673,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { GstPipeWireSink *pwsink; GstFlowReturn res = GST_FLOW_OK; + const char *error = NULL; pwsink = GST_PIPEWIRE_SINK (bsink); @@ -689,7 +681,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) goto not_negotiated; pw_thread_loop_lock (pwsink->main_loop); - if (pwsink->stream->state != PW_STREAM_STATE_STREAMING) + if (pw_stream_get_state (pwsink->stream, &error) != PW_STREAM_STATE_STREAMING) goto done; if (buffer->pool != GST_BUFFER_POOL_CAST (pwsink->pool)) { @@ -742,6 +734,16 @@ copy_properties (GQuark field_id, return TRUE; } +static const struct pw_stream_callbacks stream_callbacks = { + PW_VERSION_STREAM_CALLBACKS, + .state_changed = on_state_changed, + .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, +}; + static gboolean gst_pipewire_sink_start (GstBaseSink * basesink) { @@ -761,12 +763,11 @@ gst_pipewire_sink_start (GstBaseSink * basesink) pwsink->stream = pw_stream_new (pwsink->remote, pwsink->client_name, props); pwsink->pool->stream = pwsink->stream; - pw_signal_add (&pwsink->stream->state_changed, &pwsink->stream_state_changed, on_state_changed); - pw_signal_add (&pwsink->stream->format_changed, &pwsink->stream_format_changed, on_format_changed); - pw_signal_add (&pwsink->stream->add_buffer, &pwsink->stream_add_buffer, on_add_buffer); - pw_signal_add (&pwsink->stream->remove_buffer, &pwsink->stream_remove_buffer, on_remove_buffer); - pw_signal_add (&pwsink->stream->new_buffer, &pwsink->stream_new_buffer, on_new_buffer); - pw_signal_add (&pwsink->stream->need_buffer, &pwsink->stream_need_buffer, on_need_buffer); + pw_stream_add_callbacks(pwsink->stream, + &pwsink->stream_callbacks, + &stream_callbacks, + pwsink); + pw_thread_loop_unlock (pwsink->main_loop); return TRUE; @@ -792,13 +793,10 @@ gst_pipewire_sink_stop (GstBaseSink * basesink) } static void -on_remote_state_changed (struct pw_listener *listener, - struct pw_remote *remote) +on_remote_state_changed (void *data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, remote_state_changed); - enum pw_remote_state state; + GstPipeWireSink *pwsink = data; - state = remote->state; GST_DEBUG ("got remote state %d", state); switch (state) { @@ -808,27 +806,36 @@ on_remote_state_changed (struct pw_listener *listener, break; case PW_REMOTE_STATE_ERROR: GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED, - ("remote error: %s", remote->error), (NULL)); + ("remote error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsink->main_loop, FALSE); } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_remote_state_changed, +}; + static gboolean gst_pipewire_sink_open (GstPipeWireSink * pwsink) { + const char *error = NULL; + if (pw_thread_loop_start (pwsink->main_loop) != SPA_RESULT_OK) goto mainloop_error; pw_thread_loop_lock (pwsink->main_loop); pwsink->remote = pw_remote_new (pwsink->core, NULL); - pw_signal_add (&pwsink->remote->state_changed, &pwsink->remote_state_changed, on_remote_state_changed); + pw_remote_add_callbacks (pwsink->remote, + &pwsink->remote_callbacks, + &remote_callbacks, pwsink); pw_remote_connect (pwsink->remote); while (TRUE) { - enum pw_remote_state state = pwsink->remote->state; + enum pw_remote_state state = pw_remote_get_state (pwsink->remote, &error); if (state == PW_REMOTE_STATE_CONNECTED) break; @@ -859,6 +866,8 @@ connect_error: static gboolean gst_pipewire_sink_close (GstPipeWireSink * pwsink) { + const char *error = NULL; + pw_thread_loop_lock (pwsink->main_loop); if (pwsink->stream) { pw_stream_disconnect (pwsink->stream); @@ -867,7 +876,7 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink) pw_remote_disconnect (pwsink->remote); while (TRUE) { - enum pw_remote_state state = pwsink->remote->state; + enum pw_remote_state state = pw_remote_get_state (pwsink->remote, &error); if (state == PW_REMOTE_STATE_UNCONNECTED) break; diff --git a/src/gst/gstpipewiresink.h b/src/gst/gstpipewiresink.h index d4287d6f3..5d7041768 100644 --- a/src/gst/gstpipewiresink.h +++ b/src/gst/gstpipewiresink.h @@ -81,16 +81,12 @@ struct _GstPipeWireSink { struct pw_thread_loop *main_loop; struct pw_core *core; + struct pw_type *type; struct pw_remote *remote; - struct pw_listener remote_state_changed; + struct pw_callback_info remote_callbacks; struct pw_stream *stream; - struct pw_listener stream_state_changed; - struct pw_listener stream_format_changed; - struct pw_listener stream_add_buffer; - struct pw_listener stream_remove_buffer; - struct pw_listener stream_new_buffer; - struct pw_listener stream_need_buffer; + struct pw_callback_info stream_callbacks; GstAllocator *allocator; GstStructure *properties; diff --git a/src/gst/gstpipewiresrc.c b/src/gst/gstpipewiresrc.c index 6705dd4cf..6e61b580f 100644 --- a/src/gst/gstpipewiresrc.c +++ b/src/gst/gstpipewiresrc.c @@ -196,6 +196,7 @@ gst_pipewire_src_finalize (GObject * object) pw_core_destroy (pwsrc->core); pwsrc->core = NULL; + pwsrc->type = NULL; pw_thread_loop_destroy (pwsrc->main_loop); pwsrc->main_loop = NULL; pw_loop_destroy (pwsrc->loop); @@ -310,6 +311,7 @@ gst_pipewire_src_init (GstPipeWireSrc * src) src->loop = pw_loop_new (); 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); GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop); } @@ -353,17 +355,15 @@ buffer_recycle (GstMiniObject *obj) } static void -on_add_buffer (struct pw_listener *listener, - struct pw_stream *stream, - guint id) +on_add_buffer (void *_data, guint id) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_add_buffer); + GstPipeWireSrc *pwsrc = _data; struct spa_buffer *b; GstBuffer *buf; uint32_t i; ProcessMemData data; - struct pw_remote *remote = pwsrc->stream->remote; - struct pw_core *core = remote->core; + struct pw_core *core = pwsrc->core; + struct pw_type *t = pw_core_get_type(core); GST_LOG_OBJECT (pwsrc, "add buffer"); @@ -378,19 +378,19 @@ on_add_buffer (struct pw_listener *listener, data.src = gst_object_ref (pwsrc); data.id = id; data.buf = b; - data.header = spa_buffer_find_meta (b, core->type.meta.Header); + 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 == core->type.data.MemFd || d->type == core->type.data.DmaBuf) { + if (d->type == t->data.MemFd || d->type == t->data.DmaBuf) { 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->chunk->offset + d->mapoffset, d->chunk->size); data.offset = d->mapoffset; } - else if (d->type == core->type.data.MemPtr) { + else if (d->type == t->data.MemPtr) { gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset + d->mapoffset, d->chunk->size, NULL, NULL); data.offset = 0; @@ -408,11 +408,10 @@ on_add_buffer (struct pw_listener *listener, } static void -on_remove_buffer (struct pw_listener *listener, - struct pw_stream *stream, - guint id) +on_remove_buffer (void *data, + guint id) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_remove_buffer); + GstPipeWireSrc *pwsrc = data; GstBuffer *buf; GST_LOG_OBJECT (pwsrc, "remove buffer"); @@ -437,11 +436,10 @@ on_remove_buffer (struct pw_listener *listener, } static void -on_new_buffer (struct pw_listener *listener, - struct pw_stream *stream, - guint id) +on_new_buffer (void *_data, + guint id) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_new_buffer); + GstPipeWireSrc *pwsrc = _data; GstBuffer *buf; ProcessMemData *data; struct spa_meta_header *h; @@ -486,11 +484,11 @@ on_new_buffer (struct pw_listener *listener, } static void -on_state_changed (struct pw_listener *listener, - struct pw_stream *stream) +on_state_changed (void *data, + enum pw_stream_state old, + enum pw_stream_state state, const char *error) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_state_changed); - enum pw_stream_state state = stream->state; + GstPipeWireSrc *pwsrc = data; GST_DEBUG ("got stream state %s", pw_stream_state_as_string (state)); @@ -504,7 +502,7 @@ on_state_changed (struct pw_listener *listener, break; case PW_STREAM_STATE_ERROR: GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, - ("stream error: %s", stream->error), (NULL)); + ("stream error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsrc->main_loop, FALSE); @@ -535,10 +533,11 @@ parse_stream_properties (GstPipeWireSrc *pwsrc, struct pw_properties *props) static gboolean gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) { + const char *error = NULL; pw_thread_loop_lock (pwsrc->main_loop); GST_DEBUG_OBJECT (pwsrc, "doing stream start"); while (TRUE) { - enum pw_stream_state state = pwsrc->stream->state; + enum pw_stream_state state = pw_stream_get_state (pwsrc->stream, &error); GST_DEBUG_OBJECT (pwsrc, "waiting for STREAMING, now %s", pw_stream_state_as_string (state)); if (state == PW_STREAM_STATE_STREAMING) @@ -547,13 +546,13 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) if (state == PW_STREAM_STATE_ERROR) goto start_error; - if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR) + if (pw_remote_get_state(pwsrc->remote, &error) == PW_REMOTE_STATE_ERROR) goto start_error; pw_thread_loop_wait (pwsrc->main_loop); } - parse_stream_properties (pwsrc, pwsrc->stream->properties); + parse_stream_properties (pwsrc, pw_stream_get_properties (pwsrc->stream)); GST_DEBUG_OBJECT (pwsrc, "signal started"); pwsrc->started = TRUE; pw_thread_loop_signal (pwsrc->main_loop, FALSE); @@ -563,7 +562,7 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) start_error: { - GST_DEBUG_OBJECT (pwsrc, "error starting stream"); + GST_DEBUG_OBJECT (pwsrc, "error starting stream: %s", error); pw_thread_loop_unlock (pwsrc->main_loop); return FALSE; } @@ -573,10 +572,11 @@ static enum pw_stream_state wait_negotiated (GstPipeWireSrc *this) { enum pw_stream_state state; + const char *error = NULL; pw_thread_loop_lock (this->main_loop); while (TRUE) { - state = this->stream->state; + state = pw_stream_get_state (this->stream, &error); GST_DEBUG_OBJECT (this, "waiting for started signal, state now %s", pw_stream_state_as_string (state)); @@ -584,7 +584,7 @@ wait_negotiated (GstPipeWireSrc *this) if (state == PW_STREAM_STATE_ERROR) break; - if (this->remote->state == PW_REMOTE_STATE_ERROR) + if (pw_remote_get_state(this->remote, &error) == PW_REMOTE_STATE_ERROR) break; if (this->started) @@ -607,6 +607,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) GstCaps *peercaps = NULL; gboolean result = FALSE; GPtrArray *possible; + const char *error = NULL; /* first see what is possible on our source pad */ thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL); @@ -635,16 +636,16 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, caps); /* open a connection with these caps */ - possible = gst_caps_to_format_all (caps, pwsrc->remote->core->type.map); + possible = gst_caps_to_format_all (caps, pwsrc->type->map); gst_caps_unref (caps); /* first disconnect */ pw_thread_loop_lock (pwsrc->main_loop); - if (pwsrc->stream->state != PW_STREAM_STATE_UNCONNECTED) { + if (pw_stream_get_state(pwsrc->stream, &error) != PW_STREAM_STATE_UNCONNECTED) { GST_DEBUG_OBJECT (basesrc, "disconnect capture"); pw_stream_disconnect (pwsrc->stream); while (TRUE) { - enum pw_stream_state state = pwsrc->stream->state; + enum pw_stream_state state = pw_stream_get_state (pwsrc->stream, &error); GST_DEBUG_OBJECT (basesrc, "waiting for UNCONNECTED, now %s", pw_stream_state_as_string (state)); if (state == PW_STREAM_STATE_UNCONNECTED) @@ -670,7 +671,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) g_ptr_array_free (possible, TRUE); while (TRUE) { - enum pw_stream_state state = pwsrc->stream->state; + enum pw_stream_state state = pw_stream_get_state (pwsrc->stream, &error); GST_DEBUG_OBJECT (basesrc, "waiting for PAUSED, now %s", pw_stream_state_as_string (state)); if (state == PW_STREAM_STATE_PAUSED || @@ -680,7 +681,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) if (state == PW_STREAM_STATE_ERROR) goto connect_error; - if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR) + if (pw_remote_get_state(pwsrc->remote, &error) == PW_REMOTE_STATE_ERROR) goto connect_error; pw_thread_loop_wait (pwsrc->main_loop); @@ -732,15 +733,14 @@ connect_error: SPA_POD_PROP_RANGE_MIN_MAX,type,3,__VA_ARGS__) static void -on_format_changed (struct pw_listener *listener, - struct pw_stream *stream, - struct spa_format *format) +on_format_changed (void *data, + struct spa_format *format) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_format_changed); + GstPipeWireSrc *pwsrc = data; GstCaps *caps; gboolean res; - struct pw_remote *remote = stream->remote; - struct pw_core *core = remote->core; + struct pw_core *core = pwsrc->core; + struct pw_type *t = pw_core_get_type(core); if (format == NULL) { GST_DEBUG_OBJECT (pwsrc, "clear format"); @@ -748,7 +748,7 @@ on_format_changed (struct pw_listener *listener, return; } - caps = gst_caps_from_format (format, core->type.map); + caps = gst_caps_from_format (format, t->map); GST_DEBUG_OBJECT (pwsrc, "we got format %" GST_PTR_FORMAT, caps); res = gst_base_src_set_caps (GST_BASE_SRC (pwsrc), caps); gst_caps_unref (caps); @@ -760,16 +760,16 @@ on_format_changed (struct pw_listener *listener, struct spa_pod_frame f[2]; spa_pod_builder_init (&b, buffer, sizeof (buffer)); - spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_buffers.Buffers, - PROP_U_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 16, 0, INT32_MAX), - PROP (&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); + spa_pod_builder_object (&b, &f[0], 0, t->param_alloc_buffers.Buffers, + PROP_U_MM (&f[1], t->param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), + PROP_U_MM (&f[1], t->param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), + PROP_U_MM (&f[1], t->param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 16, 0, INT32_MAX), + PROP (&f[1], t->param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - spa_pod_builder_object (&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header), - PROP (&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); + spa_pod_builder_object (&b, &f[0], 0, t->param_alloc_meta_enable.MetaEnable, + PROP (&f[1], t->param_alloc_meta_enable.type, SPA_POD_TYPE_ID, t->meta.Header), + PROP (&f[1], t->param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); GST_DEBUG_OBJECT (pwsrc, "doing finish format"); @@ -882,6 +882,7 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) { GstPipeWireSrc *pwsrc; GstClockTime pts, dts, base_time; + const char *error = NULL; pwsrc = GST_PIPEWIRE_SRC (psrc); @@ -898,7 +899,7 @@ gst_pipewire_src_create (GstPushSrc * psrc, GstBuffer ** buffer) if (pwsrc->stream == NULL) goto streaming_error; - state = pwsrc->stream->state; + state = pw_stream_get_state (pwsrc->stream, &error); if (state == PW_STREAM_STATE_ERROR) goto streaming_error; @@ -974,11 +975,9 @@ gst_pipewire_src_stop (GstBaseSrc * basesrc) } static void -on_remote_state_changed (struct pw_listener *listener, - struct pw_remote *remote) +on_remote_state_changed (void *data, enum pw_remote_state old, enum pw_remote_state state, const char *error) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, remote_state_changed); - enum pw_remote_state state = remote->state; + GstPipeWireSrc *pwsrc = data; GST_DEBUG ("got remote state %s", pw_remote_state_as_string (state)); @@ -989,7 +988,7 @@ on_remote_state_changed (struct pw_listener *listener, break; case PW_REMOTE_STATE_ERROR: GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, - ("remote error: %s", remote->error), (NULL)); + ("remote error: %s", error), (NULL)); break; } pw_thread_loop_signal (pwsrc->main_loop, FALSE); @@ -1009,10 +1008,25 @@ copy_properties (GQuark field_id, return TRUE; } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .state_changed = on_remote_state_changed, +}; + +static const struct pw_stream_callbacks stream_callbacks = { + PW_VERSION_STREAM_CALLBACKS, + .state_changed = on_state_changed, + .format_changed = on_format_changed, + .add_buffer = on_add_buffer, + .remove_buffer = on_remove_buffer, + .new_buffer = on_new_buffer, +}; + static gboolean gst_pipewire_src_open (GstPipeWireSrc * pwsrc) { struct pw_properties *props; + const char *error = NULL; if (pw_thread_loop_start (pwsrc->main_loop) != SPA_RESULT_OK) goto mainloop_failed; @@ -1021,12 +1035,14 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) if ((pwsrc->remote = pw_remote_new (pwsrc->core, NULL)) == NULL) goto no_remote; - pw_signal_add (&pwsrc->remote->state_changed, &pwsrc->remote_state_changed, on_remote_state_changed); + pw_remote_add_callbacks (pwsrc->remote, + &pwsrc->remote_callbacks, + &remote_callbacks, pwsrc); pw_remote_connect (pwsrc->remote); while (TRUE) { - enum pw_remote_state state = pwsrc->remote->state; + enum pw_remote_state state = pw_remote_get_state(pwsrc->remote, &error); GST_DEBUG ("waiting for CONNECTED, now %s", pw_remote_state_as_string (state)); if (state == PW_REMOTE_STATE_CONNECTED) @@ -1048,11 +1064,12 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) if ((pwsrc->stream = pw_stream_new (pwsrc->remote, pwsrc->client_name, props)) == NULL) goto no_stream; - pw_signal_add (&pwsrc->stream->state_changed, &pwsrc->stream_state_changed, on_state_changed); - pw_signal_add (&pwsrc->stream->format_changed, &pwsrc->stream_format_changed, on_format_changed); - pw_signal_add (&pwsrc->stream->add_buffer, &pwsrc->stream_add_buffer, on_add_buffer); - pw_signal_add (&pwsrc->stream->remove_buffer, &pwsrc->stream_remove_buffer, on_remove_buffer); - pw_signal_add (&pwsrc->stream->new_buffer, &pwsrc->stream_new_buffer, on_new_buffer); + + pw_stream_add_callbacks(pwsrc->stream, + &pwsrc->stream_callbacks, + &stream_callbacks, + pwsrc); + pwsrc->clock = gst_pipewire_clock_new (pwsrc->stream); pw_thread_loop_unlock (pwsrc->main_loop); diff --git a/src/gst/gstpipewiresrc.h b/src/gst/gstpipewiresrc.h index f888bcca9..a2eb667bb 100644 --- a/src/gst/gstpipewiresrc.h +++ b/src/gst/gstpipewiresrc.h @@ -68,15 +68,12 @@ struct _GstPipeWireSrc { struct pw_thread_loop *main_loop; struct pw_core *core; + struct pw_type *type; struct pw_remote *remote; - struct pw_listener remote_state_changed; + struct pw_callback_info remote_callbacks; struct pw_stream *stream; - struct pw_listener stream_state_changed; - struct pw_listener stream_format_changed; - struct pw_listener stream_add_buffer; - struct pw_listener stream_remove_buffer; - struct pw_listener stream_new_buffer; + struct pw_callback_info stream_callbacks; GstAllocator *fd_allocator; GstStructure *properties; diff --git a/src/modules/module-autolink.c b/src/modules/module-autolink.c index 95ef95832..a0103456d 100644 --- a/src/modules/module-autolink.c +++ b/src/modules/module-autolink.c @@ -24,6 +24,7 @@ #include "config.h" #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/core.h" #include "pipewire/module.h" @@ -32,29 +33,27 @@ struct impl { struct pw_module *module; struct pw_properties *properties; - struct pw_listener global_added; - struct pw_listener global_removed; + struct pw_callback_info core_callbacks; struct spa_list node_list; }; struct node_info { + struct spa_list l; + struct impl *impl; struct pw_node *node; - struct spa_list link; - struct pw_listener state_changed; - struct pw_listener port_added; - struct pw_listener port_removed; - struct pw_listener port_unlinked; - struct pw_listener link_state_changed; - struct pw_listener link_destroy; + struct pw_callback_info node_callbacks; + + struct pw_link *link; + struct pw_callback_info link_callbacks; }; static struct node_info *find_node_info(struct impl *impl, struct pw_node *node) { struct node_info *info; - spa_list_for_each(info, &impl->node_list, link) { + spa_list_for_each(info, &impl->node_list, l) { if (info->node == node) return info; } @@ -63,22 +62,19 @@ static struct node_info *find_node_info(struct impl *impl, struct pw_node *node) static void node_info_free(struct node_info *info) { - spa_list_remove(&info->link); - pw_signal_remove(&info->state_changed); - pw_signal_remove(&info->port_added); - pw_signal_remove(&info->port_removed); - pw_signal_remove(&info->port_unlinked); - pw_signal_remove(&info->link_destroy); - pw_signal_remove(&info->link_state_changed); + spa_list_remove(&info->l); + pw_callback_remove(&info->node_callbacks); + pw_callback_remove(&info->link_callbacks); free(info); } static void try_link_port(struct pw_node *node, struct pw_port *port, struct node_info *info); static void -on_link_port_unlinked(struct pw_listener *listener, struct pw_link *link, struct pw_port *port) +link_port_unlinked(void *data, struct pw_port *port) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, port_unlinked); + struct node_info *info = data; + struct pw_link *link = info->link; struct impl *impl = info->impl; pw_log_debug("module %p: link %p: port %p unlinked", impl, link, port); @@ -87,10 +83,10 @@ on_link_port_unlinked(struct pw_listener *listener, struct pw_link *link, struct } static void -on_link_state_changed(struct pw_listener *listener, - struct pw_link *link, enum pw_link_state old, enum pw_link_state state) +link_state_changed(void *data, enum pw_link_state old, enum pw_link_state state, const char *error) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, link_state_changed); + struct node_info *info = data; + struct pw_link *link = info->link; struct impl *impl = info->impl; switch (state) { @@ -98,17 +94,16 @@ on_link_state_changed(struct pw_listener *listener, { struct pw_resource *resource; - pw_log_debug("module %p: link %p: state error: %s", impl, link, - link->error); + pw_log_debug("module %p: link %p: state error: %s", impl, link, error); spa_list_for_each(resource, &link->resource_list, link) { pw_core_resource_error(resource->client->core_resource, - resource->id, SPA_RESULT_ERROR, link->error); + resource->id, SPA_RESULT_ERROR, error); } if (info->node->owner) { pw_core_resource_error(info->node->owner->client->core_resource, info->node->owner->id, - SPA_RESULT_ERROR, link->error); + SPA_RESULT_ERROR, error); } break; } @@ -128,20 +123,24 @@ on_link_state_changed(struct pw_listener *listener, } static void -on_link_destroy(struct pw_listener *listener, struct pw_link *link) +link_destroy(void *data) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, link_destroy); + struct node_info *info = data; + struct pw_link *link = info->link; struct impl *impl = info->impl; pw_log_debug("module %p: link %p destroyed", impl, link); - pw_signal_remove(&info->port_unlinked); - pw_signal_remove(&info->link_state_changed); - pw_signal_remove(&info->link_destroy); - spa_list_init(&info->port_unlinked.link); - spa_list_init(&info->link_state_changed.link); - spa_list_init(&info->link_destroy.link); + pw_callback_remove(&info->link_callbacks); + spa_list_init(&info->link_callbacks.link); } +static const struct pw_link_callbacks link_callbacks = { + PW_VERSION_LINK_CALLBACKS, + .destroy = link_destroy, + .port_unlinked = link_port_unlinked, + .state_changed = link_state_changed, +}; + static void try_link_port(struct pw_node *node, struct pw_port *port, struct node_info *info) { struct impl *impl = info->impl; @@ -184,10 +183,9 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod if (link == NULL) goto error; - pw_signal_add(&link->port_unlinked, &info->port_unlinked, on_link_port_unlinked); - pw_signal_add(&link->state_changed, &info->link_state_changed, on_link_state_changed); - pw_signal_add(&link->destroy_signal, &info->link_destroy, on_link_destroy); + info->link = link; + pw_link_add_callbacks(link, &info->link_callbacks, &link_callbacks, info); pw_link_activate(link); return; @@ -202,15 +200,13 @@ static void try_link_port(struct pw_node *node, struct pw_port *port, struct nod return; } -static void on_port_added(struct pw_listener *listener, struct pw_node *node, struct pw_port *port) +static void node_port_added(void *data, struct pw_port *port) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, port_added); - - try_link_port(node, port, info); + struct node_info *info = data; + try_link_port(info->node, port, info); } -static void -on_port_removed(struct pw_listener *listener, struct pw_node *node, struct pw_port *port) +static void node_port_removed(void *data, struct pw_port *port) { } @@ -219,26 +215,32 @@ static void on_node_created(struct pw_node *node, struct node_info *info) struct pw_port *port; spa_list_for_each(port, &node->input_ports, link) - on_port_added(&info->port_added, node, port); + node_port_added(info, port); spa_list_for_each(port, &node->output_ports, link) - on_port_added(&info->port_added, node, port); + node_port_added(info, port); } static void -on_state_changed(struct pw_listener *listener, - struct pw_node *node, enum pw_node_state old, enum pw_node_state state) +node_state_changed(void *data, enum pw_node_state old, enum pw_node_state state, const char *error) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, state_changed); + struct node_info *info = data; if (old == PW_NODE_STATE_CREATING && state == PW_NODE_STATE_SUSPENDED) - on_node_created(node, info); + on_node_created(info->node, info); } +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .port_added = node_port_added, + .port_removed = node_port_removed, + .state_changed = node_state_changed, +}; + static void -on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) +core_global_added(void *data, struct pw_global *global) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_added); + struct impl *impl = data; if (global->type == impl->core->type.node) { struct pw_node *node = global->object; @@ -247,14 +249,11 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl ninfo = calloc(1, sizeof(struct node_info)); ninfo->impl = impl; ninfo->node = node; - spa_list_insert(impl->node_list.prev, &ninfo->link); - spa_list_init(&ninfo->port_unlinked.link); - spa_list_init(&ninfo->link_state_changed.link); - spa_list_init(&ninfo->link_destroy.link); - pw_signal_add(&node->port_added, &ninfo->port_added, on_port_added); - pw_signal_add(&node->port_removed, &ninfo->port_removed, on_port_removed); - pw_signal_add(&node->state_changed, &ninfo->state_changed, on_state_changed); + spa_list_insert(impl->node_list.prev, &ninfo->l); + + pw_node_add_callbacks(node, &ninfo->node_callbacks, &node_callbacks, ninfo); + spa_list_init(&ninfo->link_callbacks.link); pw_log_debug("module %p: node %p added", impl, node); @@ -264,9 +263,9 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl } static void -on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) +core_global_removed(void *data, struct pw_global *global) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_removed); + struct impl *impl = data; if (global->type == impl->core->type.node) { struct pw_node *node = global->object; @@ -279,6 +278,13 @@ on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_ } } + +const struct pw_core_callbacks core_callbacks = { + PW_VERSION_CORE_CALLBACKS, + .global_added = core_global_added, + .global_removed = core_global_removed, +}; + /** * module_new: * @core: #struct pw_core @@ -302,8 +308,7 @@ static bool module_init(struct pw_module *module, struct pw_properties *properti spa_list_init(&impl->node_list); - pw_signal_add(&core->global_added, &impl->global_added, on_global_added); - pw_signal_add(&core->global_removed, &impl->global_removed, on_global_removed); + pw_core_add_callbacks(core, &impl->core_callbacks, &core_callbacks, impl); return impl; } diff --git a/src/modules/module-client-node.c b/src/modules/module-client-node.c index dfe257fce..972adca7d 100644 --- a/src/modules/module-client-node.c +++ b/src/modules/module-client-node.c @@ -25,6 +25,7 @@ #include "config.h" #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/core.h" #include "pipewire/module.h" @@ -32,12 +33,12 @@ struct pw_protocol *pw_protocol_native_ext_client_node_init(struct pw_core *core); -struct impl { - struct pw_node_factory this; +struct factory_data { + struct pw_node_factory *this; struct pw_properties *properties; }; -static struct pw_node *create_node(struct pw_node_factory *factory, +static struct pw_node *create_node(void *_data, struct pw_resource *resource, const char *name, struct pw_properties *properties) @@ -59,32 +60,34 @@ static struct pw_node *create_node(struct pw_node_factory *factory, return NULL; } +static const struct pw_node_factory_implementation impl_factory = { + PW_VERSION_NODE_FACRORY_IMPLEMENTATION, + .create_node = create_node, +}; + static bool module_init(struct pw_module *module, struct pw_properties *properties) { struct pw_core *core = module->core; - struct impl *impl; + struct pw_node_factory *factory; + struct factory_data *data; - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) + factory = pw_node_factory_new(core, "client-node", sizeof(*data)); + if (factory == NULL) return false; - pw_log_debug("module %p: new", impl); + data = pw_node_factory_get_user_data(factory); + data->this = factory; + data->properties = properties; - impl->properties = properties; + pw_log_debug("module %p: new", module); - impl->this.core = core; - impl->this.name = "client-node"; - - pw_signal_init(&impl->this.destroy_signal); - impl->this.create_node = create_node; + pw_node_factory_set_implementation(factory, + &impl_factory, + data); pw_protocol_native_ext_client_node_init(core); - spa_list_insert(core->node_factory_list.prev, &impl->this.link); - - impl->this.global = pw_core_add_global(core, NULL, module->global, - core->type.node_factory, 0, - NULL, impl); + pw_node_factory_export(factory, NULL, module->global); return true; } diff --git a/src/modules/module-client-node/client-node.c b/src/modules/module-client-node/client-node.c index d2da92174..c73718cf7 100644 --- a/src/modules/module-client-node/client-node.c +++ b/src/modules/module-client-node/client-node.c @@ -33,6 +33,7 @@ #include "spa/lib/format.h" #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/interfaces.h" #include "pipewire/transport.h" @@ -120,8 +121,8 @@ struct impl { struct pw_transport *transport; - struct pw_listener node_free; - struct pw_listener initialized; + struct pw_callback_info node_callbacks; + struct pw_callback_info resource_callbacks; int fds[2]; int other_fds[2]; @@ -830,11 +831,9 @@ static int handle_node_event(struct proxy *this, struct spa_event *event) } static void -client_node_done(void *object, int seq, int res) +client_node_done(void *data, int seq, int res) { - struct pw_resource *resource = object; - struct pw_client_node *node = resource->object; - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); + struct impl *impl = data; struct proxy *this = &impl->proxy; this->callbacks->done(&this->node, seq, res, this->user_data); @@ -842,14 +841,12 @@ client_node_done(void *object, int seq, int res) static void -client_node_update(void *object, +client_node_update(void *data, uint32_t change_mask, uint32_t max_input_ports, uint32_t max_output_ports, const struct spa_props *props) { - struct pw_resource *resource = object; - struct pw_client_node *node = resource->object; - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); + struct impl *impl = data; struct proxy *this = &impl->proxy; if (change_mask & PW_CLIENT_NODE_UPDATE_MAX_INPUTS) @@ -862,7 +859,7 @@ client_node_update(void *object, } static void -client_node_port_update(void *object, +client_node_port_update(void *data, enum spa_direction direction, uint32_t port_id, uint32_t change_mask, @@ -872,9 +869,7 @@ client_node_port_update(void *object, uint32_t n_params, const struct spa_param **params, const struct spa_port_info *info) { - struct pw_resource *resource = object; - struct pw_client_node *node = resource->object; - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); + struct impl *impl = data; struct proxy *this = &impl->proxy; bool remove; @@ -896,30 +891,26 @@ client_node_port_update(void *object, } } -static void client_node_event(void *object, struct spa_event *event) +static void client_node_event(void *data, struct spa_event *event) { - struct pw_resource *resource = object; - struct pw_client_node *node = resource->object; - struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); + struct impl *impl = data; struct proxy *this = &impl->proxy; - this->callbacks->event(&this->node, event, this->user_data); } -static void client_node_destroy(void *object) +static void client_node_destroy(void *data) { - struct pw_resource *resource = object; - struct pw_client_node *node = resource->object; - pw_client_node_destroy(node); + struct impl *impl = data; + pw_client_node_destroy(&impl->this); } static struct pw_client_node_methods client_node_methods = { PW_VERSION_CLIENT_NODE_METHODS, - &client_node_done, - &client_node_update, - &client_node_port_update, - &client_node_event, - &client_node_destroy, + .done = client_node_done, + .update = client_node_update, + .port_update = client_node_port_update, + .event = client_node_event, + .destroy = client_node_destroy, }; static void proxy_on_data_fd_events(struct spa_source *source) @@ -1035,10 +1026,11 @@ static int client_node_get_fds(struct pw_client_node *node, int *readfd, int *wr return SPA_RESULT_OK; } -static void on_initialized(struct pw_listener *listener, struct pw_node *node) +static void node_initialized(void *data) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, initialized); + struct impl *impl = data; struct pw_client_node *this = &impl->this; + struct pw_node *node = this->node; struct pw_transport_info info; int readfd, writefd; @@ -1072,10 +1064,10 @@ static int proxy_clear(struct proxy *this) return SPA_RESULT_OK; } -static void client_node_resource_destroy(struct pw_resource *resource) +static void client_node_resource_destroy(void *data) { - struct pw_client_node *this = resource->object; - struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); + struct impl *impl = data; + struct pw_client_node *this = &impl->this; struct proxy *proxy = &impl->proxy; pw_log_debug("client-node %p: destroy", impl); @@ -1083,26 +1075,24 @@ static void client_node_resource_destroy(struct pw_resource *resource) impl->proxy.resource = this->resource = NULL; - pw_signal_remove(&impl->initialized); - if (proxy->data_source.fd != -1) spa_loop_remove_source(proxy->data_loop, &proxy->data_source); pw_node_destroy(this->node); } -static void on_node_free(struct pw_listener *listener, struct pw_node *node) +static void node_free(void *data) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, node_free); + struct impl *impl = data; pw_log_debug("client-node %p: free", &impl->this); proxy_clear(&impl->proxy); - pw_signal_remove(&impl->node_free); - if (impl->transport) pw_transport_destroy(impl->transport); + pw_callback_remove(&impl->node_callbacks); + if (impl->fds[0] != -1) close(impl->fds[0]); if (impl->fds[1] != -1) @@ -1110,6 +1100,17 @@ static void on_node_free(struct pw_listener *listener, struct pw_node *node) free(impl); } +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .free = node_free, + .initialized = node_initialized, +}; + +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = client_node_resource_destroy, +}; + /** Create a new client node * \param client an owner \ref pw_client * \param id an id @@ -1156,14 +1157,17 @@ struct pw_client_node *pw_client_node_new(struct pw_resource *resource, if (this->node == NULL) goto error_no_node; - this->resource->destroy = (pw_destroy_t) client_node_resource_destroy; + pw_resource_add_callbacks(this->resource, + &impl->resource_callbacks, + &resource_callbacks, + impl); pw_resource_set_implementation(this->resource, - this, &client_node_methods); + &client_node_methods, + impl); impl->proxy.resource = this->resource; - pw_signal_add(&this->node->free_signal, &impl->node_free, on_node_free); - pw_signal_add(&this->node->initialized, &impl->initialized, on_initialized); + pw_node_add_callbacks(this->node, &impl->node_callbacks, &node_callbacks, impl); return this; diff --git a/src/modules/module-client-node/protocol-native.c b/src/modules/module-client-node/protocol-native.c index d5589b637..eb7f89769 100644 --- a/src/modules/module-client-node/protocol-native.c +++ b/src/modules/module-client-node/protocol-native.c @@ -25,6 +25,7 @@ #include "pipewire/interfaces.h" #include "pipewire/protocol.h" #include "pipewire/client.h" +#include "pipewire/private.h" #include "extensions/protocol-native.h" #include "extensions/client-node.h" diff --git a/src/modules/module-flatpak.c b/src/modules/module-flatpak.c index f6a712c6b..adc8537d9 100644 --- a/src/modules/module-flatpak.c +++ b/src/modules/module-flatpak.c @@ -30,6 +30,7 @@ #include #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/utils.h" #include "pipewire/core.h" @@ -41,8 +42,7 @@ struct impl { DBusConnection *bus; - struct pw_listener global_added; - struct pw_listener global_removed; + struct pw_callback_info core_callbacks; struct spa_list client_list; @@ -57,8 +57,7 @@ struct client_info { const struct pw_core_methods *old_methods; struct pw_core_methods core_methods; struct spa_list async_pending; - struct pw_listener resource_impl; - struct pw_listener resource_removed; + struct pw_callback_info client_callback; }; struct async_pending { @@ -139,6 +138,7 @@ static void client_info_free(struct client_info *cinfo) spa_list_for_each_safe(p, tmp, &cinfo->async_pending, link) free_pending(p); + pw_callback_remove(&cinfo->client_callback); spa_list_remove(&cinfo->link); free(cinfo); } @@ -432,11 +432,10 @@ do_create_link(void *object, new_id); } -static void on_resource_impl(struct pw_listener *listener, - struct pw_client *client, - struct pw_resource *resource) +static void client_resource_impl(void *data, struct pw_resource *resource) { - struct client_info *cinfo = SPA_CONTAINER_OF(listener, struct client_info, resource_impl); + struct client_info *cinfo = data; + struct pw_client *client = cinfo->client; if (resource->type == client->core->type.core) { cinfo->old_methods = resource->implementation; @@ -448,10 +447,15 @@ static void on_resource_impl(struct pw_listener *listener, } } +const struct pw_client_callbacks client_callbacks = { + PW_VERSION_CLIENT_CALLBACKS, + .resource_impl = client_resource_impl, +}; + static void -on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) +core_global_added(void *data, struct pw_global *global) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_added); + struct impl *impl = data; if (global->type == impl->core->type.client) { struct pw_client *client = global->object; @@ -463,7 +467,7 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl cinfo->is_sandboxed = client_is_sandboxed(client); spa_list_init(&cinfo->async_pending); - pw_signal_add(&client->resource_impl, &cinfo->resource_impl, on_resource_impl); + pw_client_add_callbacks(client, &cinfo->client_callback, &client_callbacks, cinfo); spa_list_insert(impl->client_list.prev, &cinfo->link); @@ -472,9 +476,9 @@ on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_gl } static void -on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) +core_global_removed(void *data, struct pw_global *global) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_removed); + struct impl *impl = data; if (global->type == impl->core->type.client) { struct pw_client *client = global->object; @@ -487,6 +491,12 @@ on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_ } } +const struct pw_core_callbacks core_callbacks = { + PW_VERSION_CORE_CALLBACKS, + .global_added = core_global_added, + .global_removed = core_global_removed, +}; + static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source, void *userdata) { struct impl *impl = userdata; @@ -689,8 +699,8 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope spa_list_init(&impl->client_list); - pw_signal_add(&core->global_added, &impl->global_added, on_global_added); - pw_signal_add(&core->global_removed, &impl->global_removed, on_global_removed); + pw_core_add_callbacks(core, &impl->core_callbacks, &core_callbacks, impl); + core->permission_func = do_permission; core->permission_data = impl; diff --git a/src/modules/module-jack.c b/src/modules/module-jack.c index 41762d13e..6cf7aab19 100644 --- a/src/modules/module-jack.c +++ b/src/modules/module-jack.c @@ -35,6 +35,7 @@ #include "config.h" #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/log.h" #include "pipewire/interfaces.h" @@ -97,15 +98,14 @@ struct client { struct pw_client *client; int fd; struct spa_source *source; - struct pw_listener busy_changed; + struct pw_callback_info client_callbacks; }; static int process_messages(struct client *client); static void client_destroy(void *data) { - struct pw_client *client = data; - struct client *this = client->user_data; + struct client *this = data; pw_loop_destroy_source(this->impl->core->main_loop, this->source); spa_list_remove(&this->link); @@ -399,18 +399,17 @@ process_messages(struct client *client) } static void -on_busy_changed(struct pw_listener *listener, - struct pw_client *client) +client_busy_changed(void *data, bool busy) { - struct client *c = SPA_CONTAINER_OF(listener, struct client, busy_changed); + struct client *c = data; enum spa_io mask = SPA_IO_ERR | SPA_IO_HUP; - if (!client->busy) + if (!busy) mask |= SPA_IO_IN; pw_loop_update_io(c->impl->core->main_loop, c->source, mask); - if (!client->busy) + if (!busy) process_messages(c); } @@ -430,6 +429,12 @@ connection_data(struct spa_loop_utils *utils, process_messages(client); } +static const struct pw_client_callbacks client_callbacks = { + PW_VERSION_CLIENT_CALLBACKS, + .destroy = client_destroy, + .busy_changed = client_busy_changed, +}; + static struct client *client_new(struct impl *impl, int fd) { struct client *this; @@ -449,8 +454,6 @@ static struct client *client_new(struct impl *impl, int fd) if (client == NULL) goto no_client; - client->destroy = client_destroy; - this = client->user_data; this->impl = impl; this->fd = fd; @@ -464,7 +467,7 @@ static struct client *client_new(struct impl *impl, int fd) spa_list_insert(impl->client_list.prev, &this->link); - pw_signal_add(&client->busy_changed, &this->busy_changed, on_busy_changed); + pw_client_add_callbacks(client, &this->client_callbacks, &client_callbacks, this); pw_log_error("module-jack %p: added new client", impl); diff --git a/src/modules/module-mixer.c b/src/modules/module-mixer.c index dad580fe7..dae2a2388 100644 --- a/src/modules/module-mixer.c +++ b/src/modules/module-mixer.c @@ -25,6 +25,7 @@ #include "config.h" #include "pipewire/core.h" +#include "pipewire/private.h" #include "pipewire/module.h" #include "modules/spa/spa-node.h" diff --git a/src/modules/module-protocol-native.c b/src/modules/module-protocol-native.c index f0f761566..6b30b6069 100644 --- a/src/modules/module-protocol-native.c +++ b/src/modules/module-protocol-native.c @@ -30,6 +30,7 @@ #include "config.h" #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/log.h" #include "pipewire/interfaces.h" #include "pipewire/core.h" @@ -86,10 +87,11 @@ struct listener { }; struct client_data { + struct pw_client *client; int fd; struct spa_source *source; struct pw_protocol_native_connection *connection; - struct pw_listener busy_changed; + struct pw_callback_info client_callbacks; }; static void @@ -162,18 +164,18 @@ process_messages(struct pw_client *client) } static void -on_busy_changed(struct pw_listener *listener, - struct pw_client *client) +client_busy_changed(void *data, bool busy) { - struct client_data *data = SPA_CONTAINER_OF(listener, struct client_data, busy_changed); + struct pw_client *client = data; + struct client_data *c = client->user_data; enum spa_io mask = SPA_IO_ERR | SPA_IO_HUP; - if (!client->busy) + if (!busy) mask |= SPA_IO_IN; - pw_loop_update_io(client->core->main_loop, data->source, mask); + pw_loop_update_io(client->core->main_loop, c->source, mask); - if (!client->busy) + if (busy) process_messages(client); } @@ -207,7 +209,7 @@ connection_data(struct spa_loop_utils *utils, process_messages(client); } -static void client_destroy(void *data) +static void client_free(void *data) { struct pw_client *client = data; struct client_data *this = client->user_data; @@ -219,6 +221,12 @@ static void client_destroy(void *data) close(this->fd); } +static const struct pw_client_callbacks client_callbacks = { + PW_VERSION_CLIENT_CALLBACKS, + .free = client_free, + .busy_changed = client_busy_changed, +}; + static struct pw_client *client_new(struct listener *l, int fd) { struct client_data *this; @@ -240,9 +248,8 @@ static struct pw_client *client_new(struct listener *l, int fd) if (client == NULL) goto no_client; - client->destroy = client_destroy; - - this = client->user_data; + this = pw_client_get_user_data(client); + this->client = client; this->fd = fd; this->source = pw_loop_add_io(protocol->core->main_loop, this->fd, @@ -257,7 +264,7 @@ static struct pw_client *client_new(struct listener *l, int fd) client->protocol = protocol; spa_list_insert(l->this.client_list.prev, &client->protocol_link); - pw_signal_add(&client->busy_changed, &this->busy_changed, on_busy_changed); + pw_client_add_callbacks(client, &this->client_callbacks, &client_callbacks, client); pw_global_bind(protocol->core->global, client, PW_PERM_RWX, PW_VERSION_CORE, 0); @@ -474,7 +481,7 @@ on_remote_data(struct spa_loop_utils *utils, pw_log_trace("protocol-native %p: got message %d from %u", this, opcode, id); proxy = pw_map_lookup(&this->objects, id); - if (proxy == NULL) { + if (proxy == NULL || proxy->marshal == NULL) { pw_log_error("protocol-native %p: could not find proxy %u", this, id); continue; } @@ -764,7 +771,7 @@ static bool module_init(struct pw_module *module, struct pw_properties *properti pw_log_debug("protocol-native %p: new", this); - d = this->user_data; + d = pw_protocol_get_user_data(this); d->module = module; if ((val = pw_properties_get(core->properties, "pipewire.daemon"))) { diff --git a/src/modules/module-protocol-native/connection.c b/src/modules/module-protocol-native/connection.c index 1959f2c0c..ad7d62e41 100644 --- a/src/modules/module-protocol-native/connection.c +++ b/src/modules/module-protocol-native/connection.c @@ -28,11 +28,10 @@ #include #include +#include #include "connection.h" -/** \cond */ - #define MAX_BUFFER_SIZE (1024 * 32) #define MAX_FDS 28 diff --git a/src/modules/module-protocol-native/protocol-native.c b/src/modules/module-protocol-native/protocol-native.c index 7bf43fa72..4b5fe26db 100644 --- a/src/modules/module-protocol-native/protocol-native.c +++ b/src/modules/module-protocol-native/protocol-native.c @@ -23,6 +23,7 @@ #include "spa/pod-iter.h" #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/protocol.h" #include "pipewire/interfaces.h" #include "pipewire/resource.h" diff --git a/src/modules/module-suspend-on-idle.c b/src/modules/module-suspend-on-idle.c index 208a3b5e5..3624be8ff 100644 --- a/src/modules/module-suspend-on-idle.c +++ b/src/modules/module-suspend-on-idle.c @@ -28,20 +28,19 @@ struct impl { struct pw_core *core; + struct pw_type *t; struct pw_properties *properties; - struct pw_listener global_added; - struct pw_listener global_removed; + struct pw_callback_info core_callbacks; struct spa_list node_list; }; struct node_info { + struct spa_list link; struct impl *impl; struct pw_node *node; - struct spa_list link; - struct pw_listener node_state_request; - struct pw_listener node_state_changed; + struct pw_callback_info node_callbacks; struct spa_source *idle_timeout; }; @@ -59,7 +58,7 @@ static struct node_info *find_node_info(struct impl *impl, struct pw_node *node) static void remove_idle_timeout(struct node_info *info) { if (info->idle_timeout) { - pw_loop_destroy_source(info->impl->core->main_loop, info->idle_timeout); + pw_loop_destroy_source(pw_core_get_main_loop(info->impl->core), info->idle_timeout); info->idle_timeout = NULL; } } @@ -68,8 +67,7 @@ static void node_info_free(struct node_info *info) { spa_list_remove(&info->link); remove_idle_timeout(info); - pw_signal_remove(&info->node_state_request); - pw_signal_remove(&info->node_state_changed); + pw_callback_remove(&info->node_callbacks); free(info); } @@ -83,63 +81,65 @@ static void idle_timeout(struct spa_loop_utils *utils, struct spa_source *source } static void -on_node_state_request(struct pw_listener *listener, struct pw_node *node, enum pw_node_state state) +node_state_request(void *data, enum pw_node_state state) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, node_state_request); + struct node_info *info = data; remove_idle_timeout(info); } static void -on_node_state_changed(struct pw_listener *listener, - struct pw_node *node, enum pw_node_state old, enum pw_node_state state) +node_state_changed(void *data, enum pw_node_state old, enum pw_node_state state, const char *error) { - struct node_info *info = SPA_CONTAINER_OF(listener, struct node_info, node_state_changed); + struct node_info *info = data; struct impl *impl = info->impl; if (state != PW_NODE_STATE_IDLE) { remove_idle_timeout(info); } else { struct timespec value; + struct pw_loop *main_loop = pw_core_get_main_loop(impl->core); - pw_log_debug("module %p: node %p became idle", impl, node); - info->idle_timeout = pw_loop_add_timer(impl->core->main_loop, - idle_timeout, info); + pw_log_debug("module %p: node %p became idle", impl, info->node); + info->idle_timeout = pw_loop_add_timer(main_loop, idle_timeout, info); value.tv_sec = 3; value.tv_nsec = 0; - pw_loop_update_timer(impl->core->main_loop, - info->idle_timeout, &value, NULL, false); + pw_loop_update_timer(main_loop, info->idle_timeout, &value, NULL, false); } } -static void -on_global_added(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) -{ - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_added); +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .state_request = node_state_request, + .state_changed = node_state_changed, +}; - if (global->type == impl->core->type.node) { - struct pw_node *node = global->object; +static void +core_global_added(void *data, struct pw_global *global) +{ + struct impl *impl = data; + + if (pw_global_get_type(global) == impl->t->node) { + struct pw_node *node = pw_global_get_object(global); struct node_info *info; info = calloc(1, sizeof(struct node_info)); info->impl = impl; info->node = node; spa_list_insert(impl->node_list.prev, &info->link); - pw_signal_add(&node->state_request, &info->node_state_request, - on_node_state_request); - pw_signal_add(&node->state_changed, &info->node_state_changed, - on_node_state_changed); + + pw_node_add_callbacks(node, &info->node_callbacks, &node_callbacks, info); pw_log_debug("module %p: node %p added", impl, node); } } static void -on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_global *global) +core_global_removed(void *data, struct pw_global *global) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, global_removed); + struct impl *impl = data; - if (global->type == impl->core->type.node) { - struct pw_node *node = global->object; + if (pw_global_get_type(global) == impl->t->node) { + struct pw_node *node = pw_global_get_object(global); struct node_info *info; if ((info = find_node_info(impl, node))) @@ -149,6 +149,11 @@ on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_ } } +const struct pw_core_callbacks core_callbacks = { + PW_VERSION_CORE_CALLBACKS, + .global_added = core_global_added, + .global_removed = core_global_removed, +}; /** * module_new: @@ -159,20 +164,20 @@ on_global_removed(struct pw_listener *listener, struct pw_core *core, struct pw_ * * Returns: a new #struct impl */ -static struct impl *module_new(struct pw_core *core, struct pw_properties *properties) +static bool module_init(struct pw_module *module, struct pw_properties *properties) { struct impl *impl; impl = calloc(1, sizeof(struct impl)); pw_log_debug("module %p: new", impl); - impl->core = core; + impl->core = pw_module_get_core(module); + impl->t = pw_core_get_type(impl->core); impl->properties = properties; spa_list_init(&impl->node_list); - pw_signal_add(&core->global_added, &impl->global_added, on_global_added); - pw_signal_add(&core->global_removed, &impl->global_removed, on_global_removed); + pw_core_add_callbacks(impl->core, &impl->core_callbacks, &core_callbacks, impl); return impl; } @@ -190,6 +195,5 @@ static void module_destroy(struct impl *impl) bool pipewire__module_init(struct pw_module *module, const char *args) { - module_new(module->core, NULL); - return true; + return module_init(module, NULL); } diff --git a/src/modules/spa/module-monitor.c b/src/modules/spa/module-monitor.c index 31d3bb853..a61dd6c0f 100644 --- a/src/modules/spa/module-monitor.c +++ b/src/modules/spa/module-monitor.c @@ -49,7 +49,9 @@ bool pipewire__module_init(struct pw_module *module, const char *args) if ((dir = getenv("SPA_PLUGIN_DIR")) == NULL) dir = PLUGINDIR; - pw_spa_monitor_load(module->core, module->global, dir, argv[0], argv[1], argv[2]); + pw_spa_monitor_load(pw_module_get_core(module), + pw_module_get_global(module), + dir, argv[0], argv[1], argv[2]); pw_free_strv(argv); diff --git a/src/modules/spa/module-node-factory.c b/src/modules/spa/module-node-factory.c index fbf5990ff..82ee534b8 100644 --- a/src/modules/spa/module-node-factory.c +++ b/src/modules/spa/module-node-factory.c @@ -25,21 +25,24 @@ #include "config.h" #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/core.h" #include "pipewire/module.h" #include "spa-node.h" -struct impl { - struct pw_node_factory this; +struct factory_data { + struct pw_core *core; + struct pw_node_factory *this; struct pw_properties *properties; }; -static struct pw_node *create_node(struct pw_node_factory *factory, +static struct pw_node *create_node(void *_data, struct pw_resource *resource, const char *name, struct pw_properties *properties) { + struct factory_data *data = _data; struct pw_node *node; const char *lib, *factory_name; @@ -52,7 +55,7 @@ static struct pw_node *create_node(struct pw_node_factory *factory, if(lib == NULL || factory_name == NULL) goto no_properties; - node = pw_spa_node_load(factory->core, + node = pw_spa_node_load(data->core, NULL, NULL, lib, @@ -82,28 +85,32 @@ static struct pw_node *create_node(struct pw_node_factory *factory, return NULL; } +static const struct pw_node_factory_implementation impl_factory = { + PW_VERSION_NODE_FACRORY_IMPLEMENTATION, + .create_node = create_node, +}; + static bool module_init(struct pw_module *module, struct pw_properties *properties) { struct pw_core *core = module->core; - struct impl *impl; + struct pw_node_factory *factory; + struct factory_data *data; - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) + factory = pw_node_factory_new(core, "spa-node-factory", sizeof(*data)); + if (factory == NULL) return false; - pw_log_debug("module %p: new", impl); + data = pw_node_factory_get_user_data(factory); + data->this = factory; + data->properties = properties; - impl->properties = properties; + pw_log_debug("module %p: new", module); - impl->this.core = core; - impl->this.name = "spa-node-factory"; - pw_signal_init(&impl->this.destroy_signal); - impl->this.create_node = create_node; + pw_node_factory_set_implementation(factory, + &impl_factory, + data); - spa_list_insert(core->node_factory_list.prev, &impl->this.link); - - impl->this.global = pw_core_add_global(core, NULL, module->global, core->type.node_factory, 0, - NULL, impl); + pw_node_factory_export(factory, NULL, module->global); return true; } diff --git a/src/modules/spa/module-node.c b/src/modules/spa/module-node.c index 95737ff49..c59ece896 100644 --- a/src/modules/spa/module-node.c +++ b/src/modules/spa/module-node.c @@ -60,7 +60,7 @@ bool pipewire__module_init(struct pw_module *module, const char *args) pw_free_strv(prop); } - pw_spa_node_load(module->core, NULL, module->global, argv[0], argv[1], argv[2], props); + pw_spa_node_load(pw_module_get_core(module), NULL, pw_module_get_global(module), argv[0], argv[1], argv[2], props); pw_free_strv(argv); diff --git a/src/modules/spa/spa-monitor.c b/src/modules/spa/spa-monitor.c index 88fc2919e..588d64b21 100644 --- a/src/modules/spa/spa-monitor.c +++ b/src/modules/spa/spa-monitor.c @@ -47,6 +47,7 @@ struct impl { struct pw_spa_monitor this; struct pw_core *core; + struct pw_type *t; struct pw_global *parent; void *hnd; @@ -66,13 +67,16 @@ static void add_item(struct pw_spa_monitor *this, struct spa_monitor_item *item) const char *name, *id, *klass; struct spa_handle_factory *factory; struct spa_pod *info = NULL; + struct pw_type *t = pw_core_get_type(impl->core); + const struct spa_support *support; + uint32_t n_support; spa_pod_object_query(&item->object, - impl->core->type.monitor.name, SPA_POD_TYPE_STRING, &name, - impl->core->type.monitor.id, SPA_POD_TYPE_STRING, &id, - impl->core->type.monitor.klass, SPA_POD_TYPE_STRING, &klass, - impl->core->type.monitor.factory, SPA_POD_TYPE_POINTER, &factory, - impl->core->type.monitor.info, SPA_POD_TYPE_STRUCT, &info, 0); + t->monitor.name, SPA_POD_TYPE_STRING, &name, + t->monitor.id, SPA_POD_TYPE_STRING, &id, + t->monitor.klass, SPA_POD_TYPE_STRING, &klass, + t->monitor.factory, SPA_POD_TYPE_POINTER, &factory, + t->monitor.info, SPA_POD_TYPE_STRUCT, &info, 0); pw_log_debug("monitor %p: add: \"%s\" (%s)", this, name, id); @@ -92,19 +96,22 @@ static void add_item(struct pw_spa_monitor *this, struct spa_monitor_item *item) } pw_properties_set(props, "media.class", klass); + support = pw_core_get_support(impl->core, &n_support); + handle = calloc(1, factory->size); if ((res = spa_handle_factory_init(factory, handle, &props->dict, - impl->core->support, impl->core->n_support)) < 0) { + support, + n_support)) < 0) { pw_log_error("can't make factory instance: %d", res); return; } - if ((res = spa_handle_get_interface(handle, impl->core->type.spa_node, &node_iface)) < 0) { + if ((res = spa_handle_get_interface(handle, t->spa_node, &node_iface)) < 0) { pw_log_error("can't get NODE interface: %d", res); return; } - if ((res = spa_handle_get_interface(handle, impl->core->type.spa_clock, &clock_iface)) < 0) { + if ((res = spa_handle_get_interface(handle, t->spa_clock, &clock_iface)) < 0) { pw_log_info("no CLOCK interface: %d", res); } @@ -143,10 +150,11 @@ static void remove_item(struct pw_spa_monitor *this, struct spa_monitor_item *it struct impl *impl = SPA_CONTAINER_OF(this, struct impl, this); struct monitor_item *mitem; const char *name, *id; + struct pw_type *t = pw_core_get_type(impl->core); spa_pod_object_query(&item->object, - impl->core->type.monitor.name, SPA_POD_TYPE_STRING, &name, - impl->core->type.monitor.id, SPA_POD_TYPE_STRING, &id, 0); + t->monitor.name, SPA_POD_TYPE_STRING, &name, + t->monitor.id, SPA_POD_TYPE_STRING, &id, 0); pw_log_debug("monitor %p: remove: \"%s\" (%s)", this, name, id); mitem = find_item(this, id); @@ -158,19 +166,20 @@ static void on_monitor_event(struct spa_monitor *monitor, struct spa_event *even { struct impl *impl = user_data; struct pw_spa_monitor *this = &impl->this; + struct pw_type *t = pw_core_get_type(impl->core); - if (SPA_EVENT_TYPE(event) == impl->core->type.monitor.Added) { + if (SPA_EVENT_TYPE(event) == t->monitor.Added) { struct spa_monitor_item *item = SPA_POD_CONTENTS(struct spa_event, event); add_item(this, item); - } else if (SPA_EVENT_TYPE(event) == impl->core->type.monitor.Removed) { + } else if (SPA_EVENT_TYPE(event) == t->monitor.Removed) { struct spa_monitor_item *item = SPA_POD_CONTENTS(struct spa_event, event); remove_item(this, item); - } else if (SPA_EVENT_TYPE(event) == impl->core->type.monitor.Changed) { + } else if (SPA_EVENT_TYPE(event) == t->monitor.Changed) { struct spa_monitor_item *item = SPA_POD_CONTENTS(struct spa_event, event); const char *name; spa_pod_object_query(&item->object, - impl->core->type.monitor.name, SPA_POD_TYPE_STRING, &name, 0); + t->monitor.name, SPA_POD_TYPE_STRING, &name, 0); pw_log_debug("monitor %p: changed: \"%s\"", this, name); } @@ -180,10 +189,13 @@ static void update_monitor(struct pw_core *core, const char *name) { const char *monitors; struct spa_dict_item item; + const struct spa_dict *props; struct spa_dict dict = SPA_DICT_INIT(1, &item); - if (core->properties) - monitors = pw_properties_get(core->properties, "monitors"); + props = pw_core_get_properties(core); + + if (props) + monitors = spa_dict_lookup(props, "monitors"); else monitors = NULL; @@ -220,6 +232,9 @@ struct pw_spa_monitor *pw_spa_monitor_load(struct pw_core *core, spa_handle_factory_enum_func_t enum_func; const struct spa_handle_factory *factory; char *filename; + const struct spa_support *support; + uint32_t n_support; + struct pw_type *t = pw_core_get_type(core); asprintf(&filename, "%s/%s.so", dir, lib); @@ -241,13 +256,14 @@ struct pw_spa_monitor *pw_spa_monitor_load(struct pw_core *core, if (strcmp(factory->name, factory_name) == 0) break; } + support = pw_core_get_support(core, &n_support); handle = calloc(1, factory->size); if ((res = spa_handle_factory_init(factory, - handle, NULL, core->support, core->n_support)) < 0) { + handle, NULL, support, n_support)) < 0) { pw_log_error("can't make factory instance: %d", res); goto init_failed; } - if ((res = spa_handle_get_interface(handle, core->type.spa_monitor, &iface)) < 0) { + if ((res = spa_handle_get_interface(handle, t->spa_monitor, &iface)) < 0) { free(handle); pw_log_error("can't get MONITOR interface: %d", res); goto interface_failed; @@ -255,6 +271,7 @@ struct pw_spa_monitor *pw_spa_monitor_load(struct pw_core *core, impl = calloc(1, sizeof(struct impl)); impl->core = core; + impl->t = t; impl->parent = parent; impl->hnd = hnd; diff --git a/src/modules/spa/spa-node.c b/src/modules/spa/spa-node.c index d5bd60cc6..0b0aba87f 100644 --- a/src/modules/spa/spa-node.c +++ b/src/modules/spa/spa-node.c @@ -30,6 +30,7 @@ #include #include "spa-node.h" +#include "pipewire/private.h" struct impl { struct pw_node *this; @@ -41,101 +42,111 @@ struct impl { struct spa_node *node; /**< handle to SPA node */ char *lib; char *factory_name; + + struct pw_callback_info node_callbacks; }; struct port { struct pw_port *port; - + enum pw_direction direction; + uint32_t port_id; struct spa_node *node; }; -static int port_impl_enum_formats(struct pw_port *port, +static int port_impl_set_io(void *data, struct spa_port_io *io) +{ + struct port *p = data; + return spa_node_port_set_io(p->node, p->direction, p->port_id, io); +} + +static int port_impl_enum_formats(void *data, struct spa_format **format, const struct spa_format *filter, int32_t index) { - struct port *p = port->user_data; - return spa_node_port_enum_formats(p->node, port->direction, port->port_id, format, filter, index); + struct port *p = data; + return spa_node_port_enum_formats(p->node, p->direction, p->port_id, format, filter, index); } -static int port_impl_set_format(struct pw_port *port, uint32_t flags, const struct spa_format *format) +static int port_impl_set_format(void *data, uint32_t flags, const struct spa_format *format) { - struct port *p = port->user_data; - return spa_node_port_set_format(p->node, port->direction, port->port_id, flags, format); + struct port *p = data; + return spa_node_port_set_format(p->node, p->direction, p->port_id, flags, format); } -static int port_impl_get_format(struct pw_port *port, const struct spa_format **format) +static int port_impl_get_format(void *data, const struct spa_format **format) { - struct port *p = port->user_data; - return spa_node_port_get_format(p->node, port->direction, port->port_id, format); + struct port *p = data; + return spa_node_port_get_format(p->node, p->direction, p->port_id, format); } -static int port_impl_get_info(struct pw_port *port, const struct spa_port_info **info) +static int port_impl_get_info(void *data, const struct spa_port_info **info) { - struct port *p = port->user_data; - return spa_node_port_get_info(p->node, port->direction, port->port_id, info); + struct port *p = data; + return spa_node_port_get_info(p->node, p->direction, p->port_id, info); } -static int port_impl_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param) +static int port_impl_enum_params(void *data, uint32_t index, struct spa_param **param) { - struct port *p = port->user_data; - return spa_node_port_enum_params(p->node, port->direction, port->port_id, index, param); + struct port *p = data; + return spa_node_port_enum_params(p->node, p->direction, p->port_id, index, param); } -static int port_impl_set_param(struct pw_port *port, struct spa_param *param) +static int port_impl_set_param(void *data, struct spa_param *param) { - struct port *p = port->user_data; - return spa_node_port_set_param(p->node, port->direction, port->port_id, param); + struct port *p = data; + return spa_node_port_set_param(p->node, p->direction, p->port_id, param); } -static int port_impl_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers) +static int port_impl_use_buffers(void *data, struct spa_buffer **buffers, uint32_t n_buffers) { - struct port *p = port->user_data; - return spa_node_port_use_buffers(p->node, port->direction, port->port_id, buffers, n_buffers); + struct port *p = data; + return spa_node_port_use_buffers(p->node, p->direction, p->port_id, buffers, n_buffers); } -static int port_impl_alloc_buffers(struct pw_port *port, +static int port_impl_alloc_buffers(void *data, struct spa_param **params, uint32_t n_params, struct spa_buffer **buffers, uint32_t *n_buffers) { - struct port *p = port->user_data; - return spa_node_port_alloc_buffers(p->node, port->direction, port->port_id, + struct port *p = data; + return spa_node_port_alloc_buffers(p->node, p->direction, p->port_id, params, n_params, buffers, n_buffers); } -static int port_impl_reuse_buffer(struct pw_port *port, uint32_t buffer_id) +static int port_impl_reuse_buffer(void *data, uint32_t buffer_id) { - struct port *p = port->user_data; - return spa_node_port_reuse_buffer(p->node, port->port_id, buffer_id); + struct port *p = data; + return spa_node_port_reuse_buffer(p->node, p->port_id, buffer_id); } -static int port_impl_send_command(struct pw_port *port, struct spa_command *command) +static int port_impl_send_command(void *data, struct spa_command *command) { - struct port *p = port->user_data; + struct port *p = data; return spa_node_port_send_command(p->node, - port->direction, - port->port_id, + p->direction, + p->port_id, command); } const struct pw_port_implementation port_impl = { PW_VERSION_PORT_IMPLEMENTATION, - port_impl_enum_formats, - port_impl_set_format, - port_impl_get_format, - port_impl_get_info, - port_impl_enum_params, - port_impl_set_param, - port_impl_use_buffers, - port_impl_alloc_buffers, - port_impl_reuse_buffer, - port_impl_send_command, + .set_io = port_impl_set_io, + .enum_formats = port_impl_enum_formats, + .set_format = port_impl_set_format, + .get_format = port_impl_get_format, + .get_info = port_impl_get_info, + .enum_params = port_impl_enum_params, + .set_param = port_impl_set_param, + .use_buffers = port_impl_use_buffers, + .alloc_buffers = port_impl_alloc_buffers, + .reuse_buffer = port_impl_reuse_buffer, + .send_command = port_impl_send_command, }; static struct pw_port * -make_port(struct pw_node *node, enum pw_direction direction, uint32_t port_id) +make_port(struct impl *impl, enum pw_direction direction, uint32_t port_id) { - struct impl *impl = node->user_data; + struct pw_node *node = impl->this; struct pw_port *port; struct port *p; @@ -143,13 +154,13 @@ make_port(struct pw_node *node, enum pw_direction direction, uint32_t port_id) if (port == NULL) return NULL; - p = port->user_data; + p = pw_port_get_user_data(port); + p->port = port; + p->direction = direction; + p->port_id = port_id; p->node = impl->node; - port->implementation = &port_impl; - - spa_node_port_set_io(impl->node, direction, port_id, &port->io); - + pw_port_set_implementation(port, &port_impl, p); pw_port_add(port, node); return port; @@ -192,7 +203,7 @@ static void update_port_ids(struct impl *impl) || i < n_input_ports) { struct pw_port *np; pw_log_debug("node %p: input port added %d", this, input_port_ids[i]); - np = make_port(this, PW_DIRECTION_INPUT, input_port_ids[i]); + np = make_port(impl, PW_DIRECTION_INPUT, input_port_ids[i]); ports = np->link.next; i++; @@ -220,7 +231,7 @@ static void update_port_ids(struct impl *impl) || i < n_output_ports) { struct pw_port *np; pw_log_debug("node %p: output port added %d", this, output_port_ids[i]); - np = make_port(this, PW_DIRECTION_OUTPUT, output_port_ids[i]); + np = make_port(impl, PW_DIRECTION_OUTPUT, output_port_ids[i]); ports = np->link.next; i++; } else if (p) { @@ -235,66 +246,66 @@ static void update_port_ids(struct impl *impl) } -static int node_impl_get_props(struct pw_node *node, struct spa_props **props) +static int node_impl_get_props(void *data, struct spa_props **props) { - struct impl *impl = node->user_data; + struct impl *impl = data; return spa_node_get_props(impl->node, props); } -static int node_impl_set_props(struct pw_node *node, const struct spa_props *props) +static int node_impl_set_props(void *data, const struct spa_props *props) { - struct impl *impl = node->user_data; + struct impl *impl = data; return spa_node_set_props(impl->node, props); } -static int node_impl_send_command(struct pw_node *node, const struct spa_command *command) +static int node_impl_send_command(void *data, const struct spa_command *command) { - struct impl *impl = node->user_data; + struct impl *impl = data; return spa_node_send_command(impl->node, command); } static struct pw_port* -node_impl_add_port(struct pw_node *node, +node_impl_add_port(void *data, enum pw_direction direction, uint32_t port_id) { - struct impl *impl = node->user_data; + struct impl *impl = data; int res; if ((res = spa_node_add_port(impl->node, direction, port_id)) < 0) { - pw_log_error("node %p: could not add port %d %d", node, port_id, res); + pw_log_error("node %p: could not add port %d %d", impl->this, port_id, res); return NULL; } - return make_port(node, direction, port_id); + return make_port(impl, direction, port_id); } -static int node_impl_schedule_input(struct pw_node *node) +static int node_impl_process_input(void *data) { - struct impl *impl = node->user_data; + struct impl *impl = data; return spa_node_process_input(impl->node); } -static int node_impl_schedule_output(struct pw_node *node) +static int node_impl_process_output(void *data) { - struct impl *impl = node->user_data; + struct impl *impl = data; return spa_node_process_output(impl->node); } static const struct pw_node_implementation node_impl = { PW_VERSION_NODE_IMPLEMENTATION, - node_impl_get_props, - node_impl_set_props, - node_impl_send_command, - node_impl_add_port, - node_impl_schedule_input, - node_impl_schedule_output, + .get_props = node_impl_get_props, + .set_props = node_impl_set_props, + .send_command = node_impl_send_command, + .add_port = node_impl_add_port, + .process_input = node_impl_process_input, + .process_output = node_impl_process_output, }; -static void pw_spa_node_destroy(void *object) +static void pw_spa_node_destroy(void *data) { - struct pw_node *node = object; - struct impl *impl = node->user_data; + struct impl *impl = data; + struct pw_node *node = impl->this; pw_log_debug("spa-node %p: destroy", node); @@ -326,7 +337,7 @@ static void on_node_done(struct spa_node *node, int seq, int res, void *user_dat } pw_log_debug("spa-node %p: async complete event %d %d", this, seq, res); - pw_signal_emit(&this->async_complete, this, seq, res); + pw_callback_emit(&this->callback_list, struct pw_node_callbacks, async_complete, seq, res); } static void on_node_event(struct spa_node *node, struct spa_event *event, void *user_data) @@ -334,21 +345,21 @@ static void on_node_event(struct spa_node *node, struct spa_event *event, void * struct impl *impl = user_data; struct pw_node *this = impl->this; - pw_signal_emit(&this->event, this, event); + pw_callback_emit(&this->callback_list, struct pw_node_callbacks, event, event); } static void on_node_need_input(struct spa_node *node, void *user_data) { struct impl *impl = user_data; struct pw_node *this = impl->this; - pw_signal_emit(&this->need_input, this); + pw_callback_emit_na(&this->callback_list, struct pw_node_callbacks, need_input); } static void on_node_have_output(struct spa_node *node, void *user_data) { struct impl *impl = user_data; struct pw_node *this = impl->this; - pw_signal_emit(&this->have_output, this); + pw_callback_emit_na(&this->callback_list, struct pw_node_callbacks, have_output); } static void @@ -370,13 +381,18 @@ on_node_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id } } -static const struct spa_node_callbacks node_callbacks = { +static const struct spa_node_callbacks spa_node_callbacks = { SPA_VERSION_NODE_CALLBACKS, - &on_node_done, - &on_node_event, - &on_node_need_input, - &on_node_have_output, - &on_node_reuse_buffer, + .done = on_node_done, + .event = on_node_event, + .need_input = on_node_need_input, + .have_output = on_node_have_output, + .reuse_buffer = on_node_reuse_buffer, +}; + +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .destroy = pw_spa_node_destroy, }; struct pw_node * @@ -411,8 +427,6 @@ pw_spa_node_new(struct pw_core *core, if (this == NULL) return NULL; - this->destroy = pw_spa_node_destroy; - this->implementation = &node_impl; this->clock = clock; impl = this->user_data; @@ -420,7 +434,11 @@ pw_spa_node_new(struct pw_core *core, impl->node = node; impl->async_init = async; - if (spa_node_set_callbacks(impl->node, &node_callbacks, impl) < 0) + pw_node_add_callbacks(this, &impl->node_callbacks, &node_callbacks, impl); + + pw_node_set_implementation(this, &node_impl, impl); + + if (spa_node_set_callbacks(impl->node, &spa_node_callbacks, impl) < 0) pw_log_warn("spa-node %p: error setting callback", this); if (!async) { diff --git a/src/pipewire/callback.h b/src/pipewire/callback.h new file mode 100644 index 000000000..510b769b7 --- /dev/null +++ b/src/pipewire/callback.h @@ -0,0 +1,84 @@ +/* PipeWire + * Copyright (C) 2017 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_CALLBACK_H__ +#define __PIPEWIRE_CALLBACK_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +struct pw_callback_list { + struct spa_list list; +}; + +struct pw_callback_info { + struct spa_list link; + const void *callbacks; + void *data; +}; + +static inline void pw_callback_init(struct pw_callback_list *list) +{ + spa_list_init(&list->list); +} + +/** Add a callback \memberof pw_callback */ +static inline void pw_callback_add(struct pw_callback_list *list, + struct pw_callback_info *info, + const void *callbacks, void *data) +{ + info->callbacks = callbacks; + info->data = data; + spa_list_insert(list->list.prev, &info->link); +} + +/** Remove a signal listener \memberof pw_callback */ +static inline void pw_callback_remove(struct pw_callback_info *info) +{ + spa_list_remove(&info->link); +} + +#define pw_callback_emit(l,type,method,...) ({ \ + struct pw_callback_list *list = l; \ + struct pw_callback_info *ci, *t; \ + spa_list_for_each_safe(ci, t, &list->list, link) { \ + const type *cb = ci->callbacks; \ + if (cb->method) \ + cb->method(ci->data, __VA_ARGS__); \ + } \ +}); + +#define pw_callback_emit_na(l,type,method) ({ \ + struct pw_callback_list *list = l; \ + struct pw_callback_info *ci, *t; \ + spa_list_for_each_safe(ci, t, &list->list, link) { \ + const type *cb = ci->callbacks; \ + if (cb->method) \ + cb->method(ci->data); \ + } \ +}); + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_CALLBACK_H__ */ diff --git a/src/pipewire/client.c b/src/pipewire/client.c index 90cd53134..8bb9fcaab 100644 --- a/src/pipewire/client.c +++ b/src/pipewire/client.c @@ -23,12 +23,18 @@ #include "pipewire/interfaces.h" #include "pipewire/client.h" +#include "pipewire/private.h" #include "pipewire/resource.h" /** \cond */ struct impl { struct pw_client this; }; + +struct resource_data { + struct pw_callback_info resource_callbacks; +}; + /** \endcond */ static void client_unbind_func(void *data) @@ -37,6 +43,11 @@ static void client_unbind_func(void *data) spa_list_remove(&resource->link); } +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = client_unbind_func, +}; + static int client_bind_func(struct pw_global *global, struct pw_client *client, uint32_t permissions, @@ -44,12 +55,14 @@ client_bind_func(struct pw_global *global, { struct pw_client *this = global->object; struct pw_resource *resource; + struct resource_data *data; - resource = pw_resource_new(client, id, permissions, global->type, version, 0, client_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); if (resource == NULL) goto no_mem; - pw_resource_set_implementation(resource, this, NULL); + data = pw_resource_get_user_data(resource); + pw_resource_add_callbacks(resource, &data->resource_callbacks, &resource_callbacks, resource); pw_log_debug("client %p: bound to %d", this, resource->id); @@ -102,15 +115,10 @@ struct pw_client *pw_client_new(struct pw_core *core, this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); spa_list_init(&this->resource_list); - pw_signal_init(&this->properties_changed); - pw_signal_init(&this->resource_added); - pw_signal_init(&this->resource_impl); - pw_signal_init(&this->resource_removed); - pw_signal_init(&this->busy_changed); + pw_callback_init(&this->callback_list); pw_map_init(&this->objects, 0, 32); pw_map_init(&this->types, 0, 32); - pw_signal_init(&this->destroy_signal); spa_list_insert(core->client_list.prev, &this->link); @@ -122,6 +130,11 @@ struct pw_client *pw_client_new(struct pw_core *core, return this; } +void *pw_client_get_user_data(struct pw_client *client) +{ + return client->user_data; +} + static void destroy_resource(void *object, void *data) { pw_resource_destroy(object); @@ -139,7 +152,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); - pw_signal_emit(&client->destroy_signal, client); + pw_callback_emit_na(&client->callback_list, struct pw_client_callbacks, destroy); spa_list_remove(&client->link); pw_global_destroy(client->global); @@ -149,11 +162,9 @@ void pw_client_destroy(struct pw_client *client) pw_map_for_each(&client->objects, destroy_resource, client); + pw_callback_emit_na(&client->callback_list, struct pw_client_callbacks, free); pw_log_debug("client %p: free", impl); - if (client->destroy) - client->destroy(client); - pw_map_clear(&client->objects); pw_map_clear(&client->types); @@ -163,6 +174,19 @@ void pw_client_destroy(struct pw_client *client) free(impl); } +void pw_client_add_callbacks(struct pw_client *client, + struct pw_callback_info *info, + const struct pw_client_callbacks *callbacks, + void *data) +{ + pw_callback_add(&client->callback_list, info, callbacks, data); +} + +const struct pw_client_info *pw_client_get_info(struct pw_client *client) +{ + return &client->info; +} + /** Update client properties * * \param client the client @@ -189,20 +213,21 @@ void pw_client_update_properties(struct pw_client *client, const struct spa_dict dict->items[i].key, dict->items[i].value); } - client->info.change_mask = 1 << 0; + client->info.change_mask |= 1 << 0; client->info.props = client->properties ? &client->properties->dict : NULL; - pw_signal_emit(&client->properties_changed, client); + pw_callback_emit(&client->callback_list, struct pw_client_callbacks, info_changed, &client->info); - spa_list_for_each(resource, &client->resource_list, link) { + spa_list_for_each(resource, &client->resource_list, link) pw_client_resource_info(resource, &client->info); - } + + client->info.change_mask = 0; } void pw_client_set_busy(struct pw_client *client, bool busy) { if (client->busy != busy) { client->busy = busy; - pw_signal_emit(&client->busy_changed, client); + pw_callback_emit(&client->callback_list, struct pw_client_callbacks, busy_changed, busy); } } diff --git a/src/pipewire/client.h b/src/pipewire/client.h index 3451329c3..a8c6114d6 100644 --- a/src/pipewire/client.h +++ b/src/pipewire/client.h @@ -30,10 +30,23 @@ extern "C" { #include +/** \class pw_client + * + * \brief PipeWire client object class. + * + * The client object represents a client connection with the PipeWire + * server. + * + * Each client has its own list of resources it is bound to along with + * a mapping between the client types and server types. + */ +struct pw_client; + #include #include #include #include +#include #include #define PW_TYPE__Client PW_TYPE_OBJECT_BASE "Client" @@ -69,60 +82,23 @@ extern "C" { * See also \ref page_resource */ -/** \class pw_client - * - * \brief PipeWire client object class. - * - * The client object represents a client connection with the PipeWire - * server. - * - * Each client has its own list of resources it is bound to along with - * a mapping between the client types and server types. - */ -struct pw_client { - struct pw_core *core; /**< core object */ - struct spa_list link; /**< link in core object client list */ - struct pw_global *global; /**< global object created for this client */ +struct pw_client_callbacks { +#define PW_VERSION_CLIENT_CALLBACKS 0 + uint32_t version; - struct pw_properties *properties; /**< Client properties */ - /** Emited when the properties changed */ - PW_SIGNAL(properties_changed, (struct pw_listener *listener, struct pw_client *client)); + void (*destroy) (void *data); - struct pw_client_info info; /**< client info */ - bool ucred_valid; /**< if the ucred member is valid */ - struct ucred ucred; /**< ucred information */ + void (*free) (void *data); - struct pw_resource *core_resource; /**< core resource object */ + void (*info_changed) (void *data, struct pw_client_info *info); - struct pw_map objects; /**< list of resource objects */ - uint32_t n_types; /**< number of client types */ - struct pw_map types; /**< map of client types */ + void (*resource_added) (void *data, struct pw_resource *resource); - struct spa_list resource_list; /**< The list of resources of this client */ - /** Emited when a resource is added */ - PW_SIGNAL(resource_added, (struct pw_listener *listener, - struct pw_client *client, struct pw_resource *resource)); - /** Emited when a resource implementation is set */ - PW_SIGNAL(resource_impl, (struct pw_listener *listener, - struct pw_client *client, struct pw_resource *resource)); - /** Emited when a resource is removed */ - PW_SIGNAL(resource_removed, (struct pw_listener *listener, - struct pw_client *client, struct pw_resource *resource)); + void (*resource_impl) (void *data, struct pw_resource *resource); - bool busy; - /** Emited when the client starts/stops an async operation that should - * block/resume all methods for this client */ - PW_SIGNAL(busy_changed, (struct pw_listener *listener, struct pw_client *client)); + void (*resource_removed) (void *data, struct pw_resource *resource); - /** Emited when the client is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client *client)); - - struct pw_protocol *protocol; /**< protocol in use */ - struct spa_list protocol_link; /**< link in the protocol client_list */ - void *protocol_private; /**< private data for the protocol */ - - void *user_data; /**< extra user data */ - pw_destroy_t destroy; /**< function to clean up the object */ + void (*busy_changed) (void *data, bool busy); }; struct pw_client * @@ -132,12 +108,22 @@ pw_client_new(struct pw_core *core, struct pw_properties *properties, size_t user_data_size); -void -pw_client_destroy(struct pw_client *client); +void pw_client_destroy(struct pw_client *client); -void -pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict); +void *pw_client_get_user_data(struct pw_client *client); +void pw_client_add_callbacks(struct pw_client *client, + struct pw_callback_info *info, + const struct pw_client_callbacks *callbacks, + void *data); + + +const struct pw_client_info *pw_client_get_info(struct pw_client *client); + +void pw_client_update_properties(struct pw_client *client, const struct spa_dict *dict); + +/** Mark the client busy. This can be used when an asynchronous operation is + * started and no further processing is allowed to happen for the client */ void pw_client_set_busy(struct pw_client *client, bool busy); #ifdef __cplusplus diff --git a/src/pipewire/command.c b/src/pipewire/command.c index edda2351b..cad98f161 100644 --- a/src/pipewire/command.c +++ b/src/pipewire/command.c @@ -26,6 +26,7 @@ #include #include "command.h" +#include "private.h" /** \cond */ typedef bool(*pw_command_func_t) (struct pw_command *command, struct pw_core *core, char **err); diff --git a/src/pipewire/command.h b/src/pipewire/command.h index d64f3c69c..383acdc6e 100644 --- a/src/pipewire/command.h +++ b/src/pipewire/command.h @@ -25,17 +25,13 @@ extern "C" { #endif -#include - /** \class pw_command * * A configuration command */ -struct pw_command { - struct spa_list link; /**< link in list of commands */ +struct pw_command; - const char *name; /**< command name */ -}; +#include struct pw_command * diff --git a/src/pipewire/core.c b/src/pipewire/core.c index 75ce60231..a67a0c209 100644 --- a/src/pipewire/core.c +++ b/src/pipewire/core.c @@ -24,6 +24,8 @@ #include #include +#include +#include #include #include #include @@ -34,11 +36,8 @@ struct global_impl { struct pw_global this; }; -struct impl { - struct pw_core this; - - struct spa_support support[4]; - struct pw_data_loop *data_loop; +struct resource_data { + struct pw_callback_info resource_callbacks; }; /** \endcond */ @@ -108,9 +107,9 @@ static void registry_bind(void *object, uint32_t id, return; } -static struct pw_registry_methods registry_methods = { +static const struct pw_registry_methods registry_methods = { PW_VERSION_REGISTRY_METHODS, - ®istry_bind + .bind = registry_bind }; static void destroy_registry_resource(void *object) @@ -119,10 +118,14 @@ static void destroy_registry_resource(void *object) spa_list_remove(&resource->link); } +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = destroy_registry_resource +}; + static void core_client_update(void *object, const struct spa_dict *props) { struct pw_resource *resource = object; - pw_client_update_properties(resource->client, props); } @@ -140,19 +143,26 @@ static void core_get_registry(void *object, uint32_t version, uint32_t new_id) struct pw_core *this = resource->core; struct pw_global *global; struct pw_resource *registry_resource; + struct resource_data *data; registry_resource = pw_resource_new(client, new_id, PW_PERM_RWX, this->type.registry, version, - 0, destroy_registry_resource); + sizeof(*data)); if (registry_resource == NULL) goto no_mem; + data = pw_resource_get_user_data(registry_resource); + pw_resource_add_callbacks(registry_resource, + &data->resource_callbacks, + &resource_callbacks, + registry_resource); + pw_resource_set_implementation(registry_resource, - registry_resource, - ®istry_methods); + ®istry_methods, + registry_resource); spa_list_insert(this->registry_resource_list.prev, ®istry_resource->link); @@ -195,7 +205,7 @@ core_create_node(void *object, if (factory == NULL) goto no_factory; - node_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0, NULL); + node_resource = pw_resource_new(client, new_id, PW_PERM_RWX, type, version, 0); if (node_resource == NULL) goto no_resource; @@ -281,6 +291,11 @@ static void core_unbind_func(void *data) spa_list_remove(&resource->link); } +static const struct pw_resource_callbacks core_resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = core_unbind_func, +}; + static int core_bind_func(struct pw_global *global, struct pw_client *client, @@ -290,12 +305,16 @@ core_bind_func(struct pw_global *global, { struct pw_core *this = global->object; struct pw_resource *resource; + struct resource_data *data; - resource = pw_resource_new(client, id, permissions, global->type, version, 0, core_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); if (resource == NULL) goto no_mem; - pw_resource_set_implementation(resource, resource, &core_methods); + data = pw_resource_get_user_data(resource); + pw_resource_add_callbacks(resource, &data->resource_callbacks, &core_resource_callbacks, resource); + + pw_resource_set_implementation(resource, &core_methods, resource); spa_list_insert(this->resource_list.prev, &resource->link); client->core_resource = resource; @@ -322,20 +341,18 @@ core_bind_func(struct pw_global *global, */ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *properties) { - struct impl *impl; struct pw_core *this; const char *name; - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) + this = calloc(1, sizeof(struct pw_core)); + if (this == NULL) return NULL; - this = &impl->this; - impl->data_loop = pw_data_loop_new(); - if (impl->data_loop == NULL) + this->data_loop_impl = pw_data_loop_new(); + if (this->data_loop_impl == NULL) goto no_data_loop; - this->data_loop = impl->data_loop->loop; + this->data_loop = pw_data_loop_get_loop(this->data_loop_impl); this->main_loop = main_loop; pw_type_init(&this->type); @@ -346,14 +363,13 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro spa_debug_set_type_map(this->type.map); - impl->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, this->type.map); - impl->support[1] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__DataLoop, this->data_loop->loop); - impl->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop); - impl->support[3] = SPA_SUPPORT_INIT(SPA_TYPE__Log, pw_log_get()); - this->support = impl->support; + 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__Log, pw_log_get()); this->n_support = 4; - pw_data_loop_start(impl->data_loop); + pw_data_loop_start(this->data_loop_impl); spa_list_init(&this->protocol_list); spa_list_init(&this->remote_list); @@ -365,10 +381,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro spa_list_init(&this->node_list); spa_list_init(&this->node_factory_list); spa_list_init(&this->link_list); - pw_signal_init(&this->info_changed); - pw_signal_init(&this->destroy_signal); - pw_signal_init(&this->global_added); - pw_signal_init(&this->global_removed); + pw_callback_init(&this->callback_list); this->info.change_mask = 0; this->info.user_name = pw_get_user_name(); @@ -394,7 +407,7 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro return this; no_data_loop: - free(impl); + free(this); return NULL; } @@ -406,17 +419,15 @@ struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *pro */ void pw_core_destroy(struct pw_core *core) { - struct impl *impl = SPA_CONTAINER_OF(core, struct impl, this); - pw_log_debug("core %p: destroy", core); - pw_signal_emit(&core->destroy_signal, core); + pw_callback_emit(&core->callback_list, struct pw_core_callbacks, destroy, core); - pw_data_loop_destroy(impl->data_loop); + pw_data_loop_destroy(core->data_loop_impl); pw_map_clear(&core->globals); pw_log_debug("core %p: free", core); - free(impl); + free(core); } /** Create and add a new global to the core @@ -459,8 +470,6 @@ pw_core_add_global(struct pw_core *core, this->bind = bind; this->object = object; - pw_signal_init(&this->destroy_signal); - this->id = pw_map_insert_new(&core->globals, this); if (owner) @@ -472,7 +481,8 @@ pw_core_add_global(struct pw_core *core, this->parent = parent; spa_list_insert(core->global_list.prev, &this->link); - pw_signal_emit(&core->global_added, core, this); + + pw_callback_emit(&core->callback_list, struct pw_core_callbacks, global_added, this); pw_log_debug("global %p: new %u %s, owner %p", this, this->id, spa_type_map_get_type(core->type.map, this->type), owner); @@ -490,6 +500,21 @@ pw_core_add_global(struct pw_core *core, return this; } +uint32_t pw_global_get_type(struct pw_global *global) +{ + return global->type; +} + +uint32_t pw_global_get_version(struct pw_global *global) +{ + return global->version; +} + +void * pw_global_get_object(struct pw_global *global) +{ + return global->object; +} + /** Bind to a global * * \param global the global to bind to @@ -546,7 +571,6 @@ void pw_global_destroy(struct pw_global *global) struct pw_resource *registry; pw_log_debug("global %p: destroy %u", global, global->id); - pw_signal_emit(&global->destroy_signal, global); spa_list_for_each(registry, &core->registry_resource_list, link) { uint32_t permissions = pw_global_permissions(global, registry->client); @@ -557,12 +581,41 @@ void pw_global_destroy(struct pw_global *global) pw_map_remove(&core->globals, global->id); spa_list_remove(&global->link); - pw_signal_emit(&core->global_removed, core, global); + pw_callback_emit(&core->callback_list, struct pw_core_callbacks, global_removed, global); pw_log_debug("global %p: free", global); free(global); } +void pw_core_add_callbacks(struct pw_core *core, + struct pw_callback_info *info, + const struct pw_core_callbacks *callbacks, + void *data) +{ + pw_callback_add(&core->callback_list, info, callbacks, data); +} + +struct pw_type *pw_core_get_type(struct pw_core *core) +{ + return &core->type; +} + +const struct spa_support *pw_core_get_support(struct pw_core *core, uint32_t *n_support) +{ + *n_support = core->n_support; + return core->support; +} + +struct pw_loop *pw_core_get_main_loop(struct pw_core *core) +{ + return core->main_loop; +} + +const struct spa_dict *pw_core_get_properties(struct pw_core *core) +{ + return &core->properties->dict; +} + /** Update core properties * * \param core a core @@ -590,7 +643,7 @@ void 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 ? &core->properties->dict : NULL; - pw_signal_emit(&core->info_changed, core); + pw_callback_emit(&core->callback_list, struct pw_core_callbacks, info_changed, &core->info); spa_list_for_each(resource, &core->resource_list, link) { pw_core_resource_info(resource, &core->info); diff --git a/src/pipewire/core.h b/src/pipewire/core.h index 1392b5559..31e70a66c 100644 --- a/src/pipewire/core.h +++ b/src/pipewire/core.h @@ -29,7 +29,19 @@ extern "C" { struct pw_global; +/** \class pw_core + * + * \brief the core PipeWire object + * + * The server core object manages all resources available on the + * server. + * + * See \ref page_server_api + */ +struct pw_core; + #include +#include #include #include #include @@ -126,91 +138,40 @@ typedef uint32_t (*pw_permission_func_t) (struct pw_global *global, * * See \ref page_server_api */ -struct pw_global { - struct pw_core *core; /**< the core */ - struct pw_client *owner; /**< the owner of this object, NULL when the - * PipeWire server is the owner */ +struct pw_global; - struct spa_list link; /**< link in core list of globals */ - uint32_t id; /**< server id of the object */ - struct pw_global *parent; /**< parent global */ +struct pw_core_callbacks { +#define PW_VERSION_CORE_CALLBACKS 0 + uint32_t version; - uint32_t type; /**< type of interface */ - uint32_t version; /**< version of interface */ - pw_bind_func_t bind; /**< function to bind to the interface */ + void (*destroy) (void *data, struct pw_core *core); - void *object; /**< object associated with the interface */ + void (*info_changed) (void *data, struct pw_core_info *info); - /** Emited when the global is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_global *global)); -}; + void (*global_added) (void *data, struct pw_global *global); -/** \class pw_core - * - * \brief the core PipeWire object - * - * The server core object manages all resources available on the - * server. - * - * See \ref page_server_api - */ -struct pw_core { - struct pw_global *global; /**< the global of the core */ - - struct pw_core_info info; /**< info about the core */ - /** Emited when the core info is updated */ - PW_SIGNAL(info_changed, (struct pw_listener *listener, struct pw_core *core)); - - struct pw_properties *properties; /**< properties of the core */ - - struct pw_type type; /**< type map and common types */ - - pw_permission_func_t permission_func; /**< get permissions of an object */ - void *permission_data; /**< data passed to permission function */ - - struct pw_map globals; /**< map of globals */ - - struct spa_list protocol_list; /**< list of protocols */ - struct spa_list remote_list; /**< list of remote connections */ - struct spa_list resource_list; /**< list of core resources */ - struct spa_list registry_resource_list; /**< list of registry resources */ - struct spa_list module_list; /**< list of modules */ - struct spa_list global_list; /**< list of globals */ - struct spa_list client_list; /**< list of clients */ - struct spa_list node_list; /**< list of nodes */ - struct spa_list node_factory_list; /**< list of node factories */ - struct spa_list link_list; /**< list of links */ - - struct pw_loop *main_loop; /**< main loop for control */ - struct pw_loop *data_loop; /**< data loop for data passing */ - - struct spa_support *support; /**< support for spa plugins */ - uint32_t n_support; /**< number of support items */ - - /** Emited when the core is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_core *core)); - - /** Emited when a global is added */ - PW_SIGNAL(global_added, (struct pw_listener *listener, - struct pw_core *core, struct pw_global *global)); - /** Emited when a global is removed */ - PW_SIGNAL(global_removed, (struct pw_listener *listener, - struct pw_core *core, struct pw_global *global)); - - struct { - struct spa_graph_scheduler sched; - struct spa_graph graph; - } rt; + void (*global_removed) (void *data, struct pw_global *global); }; struct pw_core * pw_core_new(struct pw_loop *main_loop, struct pw_properties *props); -void -pw_core_destroy(struct pw_core *core); +void pw_core_destroy(struct pw_core *core); -void -pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict); +void pw_core_add_callbacks(struct pw_core *core, + struct pw_callback_info *info, + const struct pw_core_callbacks *callbacks, + void *data); + +struct pw_type *pw_core_get_type(struct pw_core *core); + +const struct spa_dict *pw_core_get_properties(struct pw_core *core); + +const struct spa_support *pw_core_get_support(struct pw_core *core, uint32_t *n_support); + +struct pw_loop *pw_core_get_main_loop(struct pw_core *core); + +void pw_core_update_properties(struct pw_core *core, const struct spa_dict *dict); struct pw_global * pw_core_add_global(struct pw_core *core, @@ -221,6 +182,16 @@ pw_core_add_global(struct pw_core *core, pw_bind_func_t bind, void *object); +struct pw_client * pw_global_get_owner(struct pw_global *global); + +struct pw_global * pw_global_get_parent(struct pw_global *global); + +uint32_t pw_global_get_type(struct pw_global *global); + +uint32_t pw_global_get_version(struct pw_global *global); + +void * pw_global_get_object(struct pw_global *global); + int pw_global_bind(struct pw_global *global, struct pw_client *client, diff --git a/src/pipewire/data-loop.c b/src/pipewire/data-loop.c index 4998c8143..a8bf3c3f4 100644 --- a/src/pipewire/data-loop.c +++ b/src/pipewire/data-loop.c @@ -24,17 +24,7 @@ #include "pipewire/log.h" #include "pipewire/rtkit.h" #include "pipewire/data-loop.h" - -/** \cond */ -struct impl { - struct pw_data_loop this; - - struct spa_source *event; - - bool running; - pthread_t thread; -}; -/** \endcond */ +#include "pipewire/private.h" static void make_realtime(struct pw_data_loop *this) { @@ -81,21 +71,20 @@ static void make_realtime(struct pw_data_loop *this) static void *do_loop(void *user_data) { - struct impl *impl = user_data; - struct pw_data_loop *this = &impl->this; + struct pw_data_loop *this = user_data; int res; make_realtime(this); pw_log_debug("data-loop %p: enter thread", this); - pw_loop_enter(impl->this.loop); + pw_loop_enter(this->loop); - while (impl->running) { + while (this->running) { if ((res = pw_loop_iterate(this->loop, -1)) < 0) pw_log_warn("data-loop %p: iterate error %d", this, res); } pw_log_debug("data-loop %p: leave thread", this); - pw_loop_leave(impl->this.loop); + pw_loop_leave(this->loop); return NULL; } @@ -103,8 +92,8 @@ static void *do_loop(void *user_data) static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data) { - struct impl *impl = data; - impl->running = false; + struct pw_data_loop *this = data; + this->running = false; } /** Create a new \ref pw_data_loop. @@ -114,27 +103,26 @@ static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uin */ struct pw_data_loop *pw_data_loop_new(void) { - struct impl *impl; struct pw_data_loop *this; - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) + this = calloc(1, sizeof(struct pw_data_loop)); + if (this == NULL) return NULL; - pw_log_debug("data-loop %p: new", impl); + pw_log_debug("data-loop %p: new", this); - this = &impl->this; this->loop = pw_loop_new(); if (this->loop == NULL) goto no_loop; - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); + + this->event = pw_loop_add_event(this->loop, do_stop, this); - impl->event = pw_loop_add_event(this->loop, do_stop, impl); return this; no_loop: - free(impl); + free(this); return NULL; } @@ -144,16 +132,29 @@ struct pw_data_loop *pw_data_loop_new(void) */ void pw_data_loop_destroy(struct pw_data_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); + pw_log_debug("data-loop %p: destroy", loop); - pw_log_debug("data-loop %p: destroy", impl); - pw_signal_emit(&loop->destroy_signal, loop); + pw_callback_emit_na(&loop->callback_list, struct pw_data_loop_callbacks, destroy); pw_data_loop_stop(loop); - pw_loop_destroy_source(loop->loop, impl->event); + pw_loop_destroy_source(loop->loop, loop->event); pw_loop_destroy(loop->loop); - free(impl); + free(loop); +} + +void pw_data_loop_add_callbacks(struct pw_data_loop *loop, + struct pw_callback_info *info, + const struct pw_data_loop_callbacks *callbacks, + void *data) +{ + pw_callback_add(&loop->callback_list, info, callbacks, data); +} + +struct pw_loop * +pw_data_loop_get_loop(struct pw_data_loop *loop) +{ + return loop->loop; } /** Start a data loop @@ -166,15 +167,13 @@ void pw_data_loop_destroy(struct pw_data_loop *loop) */ int pw_data_loop_start(struct pw_data_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); - - if (!impl->running) { + if (!loop->running) { int err; - impl->running = true; - if ((err = pthread_create(&impl->thread, NULL, do_loop, impl)) != 0) { - pw_log_warn("data-loop %p: can't create thread: %s", impl, strerror(err)); - impl->running = false; + loop->running = true; + if ((err = pthread_create(&loop->thread, NULL, do_loop, loop)) != 0) { + pw_log_warn("data-loop %p: can't create thread: %s", loop, strerror(err)); + loop->running = false; return SPA_RESULT_ERROR; } } @@ -191,12 +190,10 @@ int pw_data_loop_start(struct pw_data_loop *loop) */ int pw_data_loop_stop(struct pw_data_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); + if (loop->running) { + pw_loop_signal_event(loop->loop, loop->event); - if (impl->running) { - pw_loop_signal_event(impl->this.loop, impl->event); - - pthread_join(impl->thread, NULL); + pthread_join(loop->thread, NULL); } return SPA_RESULT_OK; } @@ -209,6 +206,5 @@ int pw_data_loop_stop(struct pw_data_loop *loop) */ bool pw_data_loop_in_thread(struct pw_data_loop * loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); - return pthread_equal(impl->thread, pthread_self()); + return pthread_equal(loop->thread, pthread_self()); } diff --git a/src/pipewire/data-loop.h b/src/pipewire/data-loop.h index 64a4c2412..b98cc4346 100644 --- a/src/pipewire/data-loop.h +++ b/src/pipewire/data-loop.h @@ -24,22 +24,33 @@ extern "C" { #endif -#include - /** \class pw_data_loop * * PipeWire rt-loop object. */ -struct pw_data_loop { - struct pw_loop *loop; /**< wrapped loop object */ +struct pw_data_loop; - /** Emited when the data loop is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_data_loop *loop)); +#include +#include + +struct pw_data_loop_callbacks { +#define PW_VERSION_DATA_LOOP_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data); }; struct pw_data_loop * pw_data_loop_new(void); +void pw_data_loop_add_callbacks(struct pw_data_loop *loop, + struct pw_callback_info *info, + const struct pw_data_loop_callbacks *callbacks, + void *data); + +struct pw_loop * +pw_data_loop_get_loop(struct pw_data_loop *loop); + void pw_data_loop_destroy(struct pw_data_loop *loop); diff --git a/src/pipewire/interfaces.h b/src/pipewire/interfaces.h index ee38dabb3..a9e107e66 100644 --- a/src/pipewire/interfaces.h +++ b/src/pipewire/interfaces.h @@ -36,12 +36,12 @@ extern "C" { #include #include -struct pw_core_proxy { struct pw_proxy proxy; }; -struct pw_registry_proxy { struct pw_proxy proxy; }; -struct pw_module_proxy { struct pw_proxy proxy; }; -struct pw_node_proxy { struct pw_proxy proxy; }; -struct pw_client_proxy { struct pw_proxy proxy; }; -struct pw_link_proxy { struct pw_proxy proxy; }; +struct pw_core_proxy; +struct pw_registry_proxy; +struct pw_module_proxy; +struct pw_node_proxy; +struct pw_client_proxy; +struct pw_link_proxy; /** * \page page_pipewire_protocol The PipeWire protocol @@ -128,7 +128,7 @@ struct pw_core_methods { void (*client_update) (void *object, const struct spa_dict *props); /** * Create a new node on the PipeWire server from a factory. - * Use a \a fectory_name of "client-node" to create a + * Use a \a factory_name of "client-node" to create a * \ref pw_client_node. * * \param factory_name the factory name to use @@ -169,29 +169,27 @@ struct pw_core_methods { static inline void pw_core_proxy_update_types(struct pw_core_proxy *core, uint32_t first_id, uint32_t n_types, const char **types) { - pw_proxy_do(&core->proxy, struct pw_core_methods, update_types, first_id, n_types, types); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, update_types, first_id, n_types, types); } static inline void pw_core_proxy_sync(struct pw_core_proxy *core, uint32_t seq) { - pw_proxy_do(&core->proxy, struct pw_core_methods, sync, seq); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, sync, seq); } static inline struct pw_registry_proxy * -pw_core_proxy_get_registry(struct pw_core_proxy *core, uint32_t version, size_t user_data_size, pw_destroy_t destroy) +pw_core_proxy_get_registry(struct pw_core_proxy *core, uint32_t type, uint32_t version, size_t user_data_size) { - struct pw_core *c = core->proxy.remote->core; - struct pw_proxy *p = pw_proxy_new(core->proxy.remote, SPA_ID_INVALID, c->type.registry, - user_data_size, destroy); - pw_proxy_do(&core->proxy, struct pw_core_methods, get_registry, version, p->id); + struct pw_proxy *p = pw_proxy_new((struct pw_proxy*)core, type, user_data_size); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, get_registry, version, pw_proxy_get_id(p)); return (struct pw_registry_proxy *) p; } static inline void pw_core_proxy_client_update(struct pw_core_proxy *core, const struct spa_dict *props) { - pw_proxy_do(&core->proxy, struct pw_core_methods, client_update, props); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, client_update, props); } static inline void * @@ -201,31 +199,28 @@ pw_core_proxy_create_node(struct pw_core_proxy *core, uint32_t type, uint32_t version, const struct spa_dict *props, - size_t user_data_size, - pw_destroy_t destroy) + size_t user_data_size) { - struct pw_proxy *p = pw_proxy_new(core->proxy.remote, SPA_ID_INVALID, type, user_data_size, destroy); - pw_proxy_do(&core->proxy, struct pw_core_methods, create_node, factory_name, - name, type, version, props, p->id); + struct pw_proxy *p = pw_proxy_new((struct pw_proxy*)core, type, user_data_size); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, create_node, factory_name, + name, type, version, props, pw_proxy_get_id(p)); return p; } static inline struct pw_link_proxy * pw_core_proxy_create_link(struct pw_core_proxy *core, + uint32_t type, uint32_t output_node_id, uint32_t output_port_id, uint32_t input_node_id, uint32_t input_port_id, const struct spa_format *filter, const struct spa_dict *prop, - size_t user_data_size, - pw_destroy_t destroy) + size_t user_data_size) { - struct pw_core *c = core->proxy.remote->core; - struct pw_proxy *p = pw_proxy_new(core->proxy.remote, SPA_ID_INVALID, c->type.link, - user_data_size, destroy); - pw_proxy_do(&core->proxy, struct pw_core_methods, create_link, output_node_id, output_port_id, - input_node_id, input_port_id, filter, prop, p->id); + struct pw_proxy *p = pw_proxy_new((struct pw_proxy*)core, type, user_data_size); + pw_proxy_do((struct pw_proxy*)core, struct pw_core_methods, create_link, output_node_id, output_port_id, + input_node_id, input_port_id, filter, prop, pw_proxy_get_id(p)); return (struct pw_link_proxy*) p; } @@ -299,9 +294,11 @@ struct pw_core_events { static inline void pw_core_proxy_add_listener(struct pw_core_proxy *core, - void *object, const struct pw_core_events *events) + struct pw_callback_info *info, + const struct pw_core_events *events, + void *data) { - pw_proxy_add_listener(&core->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)core, info, events, data); } @@ -341,11 +338,11 @@ struct pw_registry_methods { static inline void * pw_registry_proxy_bind(struct pw_registry_proxy *registry, uint32_t id, uint32_t type, uint32_t version, - size_t user_data_size, pw_destroy_t destroy) + size_t user_data_size) { - struct pw_proxy *p = pw_proxy_new(registry->proxy.remote, SPA_ID_INVALID, - type, user_data_size, destroy); - pw_proxy_do(®istry->proxy, struct pw_registry_methods, bind, id, type, version, p->id); + struct pw_proxy *reg = (struct pw_proxy*)registry; + struct pw_proxy *p = pw_proxy_new(reg, type, user_data_size); + pw_proxy_do(reg, struct pw_registry_methods, bind, id, type, version, pw_proxy_get_id(p)); return p; } @@ -385,9 +382,11 @@ struct pw_registry_events { static inline void pw_registry_proxy_add_listener(struct pw_registry_proxy *registry, - void *object, const struct pw_registry_events *events) + struct pw_callback_info *info, + const struct pw_registry_events *events, + void *data) { - pw_proxy_add_listener(®istry->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)registry, info, events, data); } #define pw_registry_resource_global(r,...) pw_resource_notify(r,struct pw_registry_events,global,__VA_ARGS__) @@ -413,9 +412,11 @@ struct pw_module_events { static inline void pw_module_proxy_add_listener(struct pw_module_proxy *module, - void *object, const struct pw_module_events *events) + struct pw_callback_info *info, + const struct pw_module_events *events, + void *data) { - pw_proxy_add_listener(&module->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)module, info, events, data); } #define pw_module_resource_info(r,...) pw_resource_notify(r,struct pw_module_events,info,__VA_ARGS__) @@ -439,9 +440,11 @@ struct pw_node_events { static inline void pw_node_proxy_add_listener(struct pw_node_proxy *node, - void *object, const struct pw_node_events *events) + struct pw_callback_info *info, + const struct pw_node_events *events, + void *data) { - pw_proxy_add_listener(&node->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)node, info, events, data); } #define pw_node_resource_info(r,...) pw_resource_notify(r,struct pw_node_events,info,__VA_ARGS__) @@ -466,9 +469,11 @@ struct pw_client_events { /** Client */ static inline void pw_client_proxy_add_listener(struct pw_client_proxy *client, - void *object, const struct pw_client_events *events) + struct pw_callback_info *info, + const struct pw_client_events *events, + void *data) { - pw_proxy_add_listener(&client->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)client, info, events, data); } #define pw_client_resource_info(r,...) pw_resource_notify(r,struct pw_client_events,info,__VA_ARGS__) @@ -494,9 +499,11 @@ struct pw_link_events { /** Link */ static inline void pw_link_proxy_add_listener(struct pw_link_proxy *link, - void *object, const struct pw_link_events *events) + struct pw_callback_info *info, + const struct pw_link_events *events, + void *data) { - pw_proxy_add_listener(&link->proxy, object, events); + pw_proxy_add_listener((struct pw_proxy*)link, info, events, data); } #define pw_link_resource_info(r,...) pw_resource_notify(r,struct pw_link_events,info,__VA_ARGS__) diff --git a/src/pipewire/introspect.h b/src/pipewire/introspect.h index 68e272d02..52238e45b 100644 --- a/src/pipewire/introspect.h +++ b/src/pipewire/introspect.h @@ -163,6 +163,7 @@ struct pw_link_info { uint32_t input_node_id; /**< server side input node id */ uint32_t input_port_id; /**< input port id */ struct spa_format *format; /**< format over link */ + struct spa_dict *props; /**< the properties of the link */ }; struct pw_link_info * diff --git a/src/pipewire/link.c b/src/pipewire/link.c index ffbdb7f7d..ad9ccbd54 100644 --- a/src/pipewire/link.c +++ b/src/pipewire/link.c @@ -27,7 +27,9 @@ #include #include +#include "callback.h" #include "pipewire.h" +#include "private.h" #include "interfaces.h" #include "link.h" #include "work-queue.h" @@ -45,10 +47,10 @@ struct impl { struct spa_format *format_filter; struct pw_properties *properties; - struct pw_listener input_port_destroy; - struct pw_listener input_async_complete; - struct pw_listener output_port_destroy; - struct pw_listener output_async_complete; + struct pw_callback_info input_port_callbacks; + struct pw_callback_info input_node_callbacks; + struct pw_callback_info output_port_callbacks; + struct pw_callback_info output_node_callbacks; void *buffer_owner; struct pw_memblock buffer_mem; @@ -56,6 +58,10 @@ struct impl { uint32_t n_buffers; }; +struct resource_data { + struct pw_callback_info resource_callbacks; +}; + /** \endcond */ static void pw_link_update_state(struct pw_link *link, enum pw_link_state state, char *error) @@ -71,7 +77,7 @@ static void pw_link_update_state(struct pw_link *link, enum pw_link_state state, free(link->error); link->error = error; - pw_signal_emit(&link->state_changed, link, old, state); + pw_callback_emit(&link->callback_list, struct pw_link_callbacks, state_changed, old, state, error); } } @@ -730,20 +736,20 @@ static int check_states(struct pw_link *this, void *user_data, int res) } static void -on_input_async_complete_notify(struct pw_listener *listener, - struct pw_node *node, uint32_t seq, int res) +input_node_async_complete(void *data, uint32_t seq, int res) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, input_async_complete); + struct impl *impl = data; + struct pw_node *node = impl->this.input->node; pw_log_debug("link %p: node %p async complete %d %d", impl, node, seq, res); pw_work_queue_complete(impl->work, node, seq, res); } static void -on_output_async_complete_notify(struct pw_listener *listener, - struct pw_node *node, uint32_t seq, int res) +output_node_async_complete(void *data, uint32_t seq, int res) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, output_async_complete); + struct impl *impl = data; + struct pw_node *node = impl->this.output->node; pw_log_debug("link %p: node %p async complete %d %d", impl, node, seq, res); pw_work_queue_complete(impl->work, node, seq, res); @@ -771,8 +777,8 @@ static void input_remove(struct pw_link *this, struct pw_port *port) struct impl *impl = (struct impl *) this; pw_log_debug("link %p: remove input port %p", this, port); - pw_signal_remove(&impl->input_port_destroy); - pw_signal_remove(&impl->input_async_complete); + pw_callback_remove(&impl->input_port_callbacks); + pw_callback_remove(&impl->input_node_callbacks); pw_loop_invoke(port->node->data_loop, do_remove_input, 1, 0, NULL, true, this); @@ -794,8 +800,8 @@ static void output_remove(struct pw_link *this, struct pw_port *port) struct impl *impl = (struct impl *) this; pw_log_debug("link %p: remove output port %p", this, port); - pw_signal_remove(&impl->output_port_destroy); - pw_signal_remove(&impl->output_async_complete); + pw_callback_remove(&impl->output_port_callbacks); + pw_callback_remove(&impl->output_node_callbacks); pw_loop_invoke(port->node->data_loop, do_remove_output, 1, 0, NULL, true, this); @@ -826,24 +832,22 @@ static void on_port_destroy(struct pw_link *this, struct pw_port *port) impl->buffer_owner = NULL; } - pw_signal_emit(&this->port_unlinked, this, port); + pw_callback_emit(&this->callback_list, struct pw_link_callbacks, port_unlinked, port); pw_link_update_state(this, PW_LINK_STATE_UNLINKED, NULL); pw_link_destroy(this); } -static void on_input_port_destroy(struct pw_listener *listener, struct pw_port *port) +static void input_port_destroy(void *data) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, input_port_destroy); - - on_port_destroy(&impl->this, port); + struct impl *impl = data; + on_port_destroy(&impl->this, impl->this.input); } -static void on_output_port_destroy(struct pw_listener *listener, struct pw_port *port) +static void output_port_destroy(void *data) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, output_port_destroy); - - on_port_destroy(&impl->this, port); + struct impl *impl = data; + on_port_destroy(&impl->this, impl->this.output); } static int @@ -938,6 +942,11 @@ static void link_unbind_func(void *data) spa_list_remove(&resource->link); } +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = link_unbind_func, +}; + static int link_bind_func(struct pw_global *global, struct pw_client *client, uint32_t permissions, @@ -945,13 +954,14 @@ link_bind_func(struct pw_global *global, { struct pw_link *this = global->object; struct pw_resource *resource; + struct resource_data *data; - resource = pw_resource_new(client, id, permissions, global->type, version, 0, link_unbind_func); - + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); if (resource == NULL) goto no_mem; - pw_resource_set_implementation(resource, this, NULL); + data = pw_resource_get_user_data(resource); + pw_resource_add_callbacks(resource, &data->resource_callbacks, &resource_callbacks, resource); pw_log_debug("link %p: bound to %d", this, resource->id); @@ -986,6 +996,26 @@ do_add_link(struct spa_loop *loop, return SPA_RESULT_OK; } +static const struct pw_port_callbacks input_port_callbacks = { + PW_VERSION_PORT_CALLBACKS, + .destroy = input_port_destroy, +}; + +static const struct pw_port_callbacks output_port_callbacks = { + PW_VERSION_PORT_CALLBACKS, + .destroy = output_port_destroy, +}; + +static const struct pw_node_callbacks input_node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .async_complete = input_node_async_complete, +}; + +static const struct pw_node_callbacks output_node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .async_complete = output_node_async_complete, +}; + struct pw_link *pw_link_new(struct pw_core *core, struct pw_global *parent, struct pw_port *output, @@ -1024,23 +1054,14 @@ struct pw_link *pw_link_new(struct pw_core *core, output_node = output->node; spa_list_init(&this->resource_list); - pw_signal_init(&this->port_unlinked); - pw_signal_init(&this->state_changed); - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); impl->format_filter = format_filter; - pw_signal_add(&input->destroy_signal, - &impl->input_port_destroy, on_input_port_destroy); - - pw_signal_add(&input_node->async_complete, - &impl->input_async_complete, on_input_async_complete_notify); - - pw_signal_add(&output->destroy_signal, - &impl->output_port_destroy, on_output_port_destroy); - - pw_signal_add(&output_node->async_complete, - &impl->output_async_complete, on_output_async_complete_notify); + pw_port_add_callbacks(input, &impl->input_port_callbacks, &input_port_callbacks, impl); + pw_node_add_callbacks(input_node, &impl->input_node_callbacks, &input_node_callbacks, impl); + pw_port_add_callbacks(output, &impl->output_port_callbacks, &output_port_callbacks, impl); + pw_node_add_callbacks(output_node, &impl->output_node_callbacks, &output_node_callbacks, impl); pw_log_debug("link %p: constructed %p:%d -> %p:%d", impl, output_node, output->port_id, input_node, input->port_id); @@ -1103,7 +1124,7 @@ void pw_link_destroy(struct pw_link *link) struct pw_resource *resource, *tmp; pw_log_debug("link %p: destroy", impl); - pw_signal_emit(&link->destroy_signal, link); + pw_callback_emit_na(&link->callback_list, struct pw_link_callbacks, destroy); pw_link_deactivate(link); @@ -1132,6 +1153,14 @@ void pw_link_destroy(struct pw_link *link) free(impl); } +void pw_link_add_callbacks(struct pw_link *link, + struct pw_callback_info *info, + const struct pw_link_callbacks *callbacks, + void *data) +{ + pw_callback_add(&link->callback_list, info, callbacks, data); +} + struct pw_link *pw_link_find(struct pw_port *output_port, struct pw_port *input_port) { struct pw_link *pl; diff --git a/src/pipewire/link.h b/src/pipewire/link.h index 791edda02..a68b77db2 100644 --- a/src/pipewire/link.h +++ b/src/pipewire/link.h @@ -26,6 +26,12 @@ extern "C" { #include +/** \class pw_link + * + * PipeWire link interface. + */ +struct pw_link; + #include #include @@ -48,49 +54,20 @@ extern "C" { * the nodes. */ -/** \class pw_link - * - * PipeWire link interface. - */ -struct pw_link { - struct pw_core *core; /**< core object */ - struct spa_list link; /**< link in core link_list */ - struct pw_global *global; /**< global for this link */ +struct pw_link_callbacks { +#define PW_VERSION_LINK_CALLBACKS 0 + uint32_t version; - struct pw_properties *properties; /**< extra link properties */ + void (*destroy) (void *data); - struct pw_link_info info; /**< introspectable link info */ + void (*info_changed) (void *data, const struct pw_link_info *info); - enum pw_link_state state; /**< link state */ - char *error; /**< error message when state error */ - /** Emited when the link state changed */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, - struct pw_link *link, - enum pw_link_state old, enum pw_link_state state)); + void (*state_changed) (void *data, enum pw_link_state old, + enum pw_link_state state, const char *error); - /** Emited when the link is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *, struct pw_link *)); - - struct spa_list resource_list; /**< list of bound resources */ - - struct spa_port_io io; /**< link io area */ - - struct pw_port *output; /**< output port */ - struct spa_list output_link; /**< link in output port links */ - struct pw_port *input; /**< input port */ - struct spa_list input_link; /**< link in input port links */ - - /** Emited when the port is unlinked */ - PW_SIGNAL(port_unlinked, (struct pw_listener *listener, - struct pw_link *link, struct pw_port *port)); - - struct { - struct spa_graph_port out_port; - struct spa_graph_port in_port; - } rt; + void (*port_unlinked) (void *data, struct pw_port *port); }; - /** Make a new link between two ports \memberof pw_link * \return a newly allocated link */ struct pw_link * @@ -100,11 +77,16 @@ pw_link_new(struct pw_core *core, /**< the core object */ struct pw_port *input, /**< an input port */ struct spa_format *format_filter, /**< an optional format filter */ struct pw_properties *properties /**< extra properties */, - char **error /**< error string */); + char **error /**< error string when result is NULL */); /** Destroy a link \memberof pw_link */ void pw_link_destroy(struct pw_link *link); +void pw_link_add_callbacks(struct pw_link *link, + struct pw_callback_info *info, + const struct pw_link_callbacks *callbacks, + void *data); + /** Find the link between 2 ports \memberof pw_link */ struct pw_link * pw_link_find(struct pw_port *output, struct pw_port *input); diff --git a/src/pipewire/loop.c b/src/pipewire/loop.c index 39084c3c3..0bd5cd9dc 100644 --- a/src/pipewire/loop.c +++ b/src/pipewire/loop.c @@ -72,8 +72,6 @@ struct pw_loop *pw_loop_new(void) this = &impl->this; - pw_signal_init(&this->destroy_signal); - if ((res = spa_handle_factory_init(factory, impl->handle, NULL, @@ -122,8 +120,6 @@ void pw_loop_destroy(struct pw_loop *loop) { struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); - pw_signal_emit(&loop->destroy_signal, loop); - spa_handle_clear(impl->handle); free(impl); } diff --git a/src/pipewire/loop.h b/src/pipewire/loop.h index dceb4cfee..e41a7fddb 100644 --- a/src/pipewire/loop.h +++ b/src/pipewire/loop.h @@ -38,9 +38,6 @@ struct pw_loop { struct spa_loop *loop; /**< wrapped loop */ struct spa_loop_control *control; /**< loop control */ struct spa_loop_utils *utils; /**< loop utils */ - - /** Emited when the loop is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_loop *loop)); }; struct pw_loop * diff --git a/src/pipewire/main-loop.c b/src/pipewire/main-loop.c index f1aca16cb..3ae43c9cf 100644 --- a/src/pipewire/main-loop.c +++ b/src/pipewire/main-loop.c @@ -19,14 +19,7 @@ #include "pipewire/log.h" #include "pipewire/main-loop.h" - -/** \cond */ -struct impl { - struct pw_main_loop this; - - bool running; -}; -/** \endcond */ +#include "pipewire/private.h" /** Create a new new main loop * \return a newly allocated \ref pw_main_loop @@ -35,26 +28,24 @@ struct impl { */ struct pw_main_loop *pw_main_loop_new(void) { - struct impl *impl; struct pw_main_loop *this; - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) + this = calloc(1, sizeof(struct pw_main_loop)); + if (this == NULL) return NULL; - pw_log_debug("main-loop %p: new", impl); - this = &impl->this; + pw_log_debug("main-loop %p: new", this); this->loop = pw_loop_new(); if (this->loop == NULL) goto no_loop; - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); return this; no_loop: - free(impl); + free(this); return NULL; } @@ -65,14 +56,25 @@ struct pw_main_loop *pw_main_loop_new(void) */ void pw_main_loop_destroy(struct pw_main_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); - - pw_log_debug("main-loop %p: destroy", impl); - pw_signal_emit(&loop->destroy_signal, loop); + pw_log_debug("main-loop %p: destroy", loop); + pw_callback_emit_na(&loop->callback_list, struct pw_main_loop_callbacks, destroy); pw_loop_destroy(loop->loop); - free(impl); + free(loop); +} + +void pw_main_loop_add_callbacks(struct pw_main_loop *loop, + struct pw_callback_info *info, + const struct pw_main_loop_callbacks *callbacks, + void *data) +{ + pw_callback_add(&loop->callback_list, info, callbacks, data); +} + +struct pw_loop * pw_main_loop_get_loop(struct pw_main_loop *loop) +{ + return loop->loop; } /** Stop a main loop @@ -84,9 +86,8 @@ void pw_main_loop_destroy(struct pw_main_loop *loop) */ void pw_main_loop_quit(struct pw_main_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); - pw_log_debug("main-loop %p: quit", impl); - impl->running = false; + pw_log_debug("main-loop %p: quit", loop); + loop->running = false; } /** Start a main loop @@ -99,13 +100,11 @@ void pw_main_loop_quit(struct pw_main_loop *loop) */ void pw_main_loop_run(struct pw_main_loop *loop) { - struct impl *impl = SPA_CONTAINER_OF(loop, struct impl, this); + pw_log_debug("main-loop %p: run", loop); - pw_log_debug("main-loop %p: run", impl); - - impl->running = true; + loop->running = true; pw_loop_enter(loop->loop); - while (impl->running) { + while (loop->running) { pw_loop_iterate(loop->loop, -1); } pw_loop_leave(loop->loop); diff --git a/src/pipewire/main-loop.h b/src/pipewire/main-loop.h index be5e279d0..59fd1065f 100644 --- a/src/pipewire/main-loop.h +++ b/src/pipewire/main-loop.h @@ -24,26 +24,36 @@ extern "C" { #endif -#include - /** \class pw_main_loop * * \brief PipeWire main-loop interface. * * A main loop object */ - /** A main loop object \memberof pw_main_loop */ -struct pw_main_loop { - struct pw_loop *loop; /**< the wrapped loop */ +struct pw_main_loop; - /** Emited when the loop is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_main_loop *loop)); +#include +#include + +struct pw_main_loop_callbacks { +#define PW_VERSION_MAIN_LOOP_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data); }; struct pw_main_loop * pw_main_loop_new(void); +void pw_main_loop_add_callbacks(struct pw_main_loop *loop, + struct pw_callback_info *info, + const struct pw_main_loop_callbacks *callbacks, + void *data); + +struct pw_loop * +pw_main_loop_get_loop(struct pw_main_loop *loop); + void pw_main_loop_destroy(struct pw_main_loop *loop); diff --git a/src/pipewire/module.c b/src/pipewire/module.c index 39cdafaee..3672e33f8 100644 --- a/src/pipewire/module.c +++ b/src/pipewire/module.c @@ -29,6 +29,7 @@ #include #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/interfaces.h" #include "pipewire/utils.h" #include "pipewire/module.h" @@ -38,6 +39,12 @@ struct impl { struct pw_module this; void *hnd; }; + +struct resource_data { + struct pw_callback_info resource_callbacks; +}; + + /** \endcond */ static char *find_module(const char *path, const char *name) @@ -87,6 +94,17 @@ static char *find_module(const char *path, const char *name) return filename; } +static void module_unbind_func(void *data) +{ + struct pw_resource *resource = data; + spa_list_remove(&resource->link); +} + +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = module_unbind_func, +}; + static int module_bind_func(struct pw_global *global, struct pw_client *client, uint32_t permissions, @@ -94,15 +112,19 @@ module_bind_func(struct pw_global *global, { struct pw_module *this = global->object; struct pw_resource *resource; + struct resource_data *data; - resource = pw_resource_new(client, id, permissions, global->type, version, 0, NULL); + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); if (resource == NULL) goto no_mem; - pw_resource_set_implementation(resource, this, NULL); + data = pw_resource_get_user_data(resource); + pw_resource_add_callbacks(resource, &data->resource_callbacks, &resource_callbacks, resource); pw_log_debug("module %p: bound to %d", this, resource->id); + spa_list_insert(this->resource_list.prev, &resource->link); + this->info.change_mask = ~0; pw_module_resource_info(resource, &this->info); this->info.change_mask = 0; @@ -187,7 +209,8 @@ struct pw_module *pw_module_load(struct pw_core *core, const char *name, const c this = &impl->this; this->core = core; - pw_signal_init(&this->destroy_signal); + spa_list_init(&this->resource_list); + pw_callback_init(&this->callback_list); this->info.name = name ? strdup(name) : NULL; this->info.filename = filename; @@ -232,8 +255,12 @@ struct pw_module *pw_module_load(struct pw_core *core, const char *name, const c void pw_module_destroy(struct pw_module *module) { struct impl *impl = SPA_CONTAINER_OF(module, struct impl, this); + struct pw_resource *resource, *tmp; - pw_signal_emit(&module->destroy_signal, module); + pw_callback_emit(&module->callback_list, struct pw_module_callbacks, destroy, 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); @@ -247,3 +274,28 @@ void pw_module_destroy(struct pw_module *module) dlclose(impl->hnd); free(impl); } + +struct pw_core * +pw_module_get_core(struct pw_module *module) +{ + return module->core; +} + +struct pw_global * pw_module_get_global(struct pw_module *module) +{ + return module->global; +} + +const struct pw_module_info * +pw_module_get_info(struct pw_module *module) +{ + return &module->info; +} + +void pw_module_add_callbacks(struct pw_module *module, + struct pw_callback_info *info, + const struct pw_module_callbacks *callbacks, + void *data) +{ + pw_callback_add(&module->callback_list, info, callbacks, data); +} diff --git a/src/pipewire/module.h b/src/pipewire/module.h index ded805673..f6e334335 100644 --- a/src/pipewire/module.h +++ b/src/pipewire/module.h @@ -36,18 +36,7 @@ extern "C" { * * A dynamically loadable module */ -struct pw_module { - struct pw_core *core; /**< the core object */ - struct spa_list link; /**< link in the core module_list */ - struct pw_global *global; /**< global object for this module */ - - struct pw_module_info info; /**< introspectable module info */ - - void *user_data; /**< module user_data */ - - /** Emited when the module is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_module *module)); -}; +struct pw_module; /** Module init function signature * @@ -62,9 +51,28 @@ struct pw_module { */ typedef bool (*pw_module_init_func_t) (struct pw_module *module, char *args); +struct pw_module_callbacks { +#define PW_VERSION_MODULE_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data, struct pw_module *module); +}; + struct pw_module * pw_module_load(struct pw_core *core, const char *name, const char *args); +struct pw_core * pw_module_get_core(struct pw_module *module); + +struct pw_global * pw_module_get_global(struct pw_module *module); + +const struct pw_module_info * +pw_module_get_info(struct pw_module *module); + +void pw_module_add_callbacks(struct pw_module *module, + struct pw_callback_info *info, + const struct pw_module_callbacks *callbacks, + void *data); + void pw_module_destroy(struct pw_module *module); diff --git a/src/pipewire/node-factory.c b/src/pipewire/node-factory.c index 616384af9..9b69d3747 100644 --- a/src/pipewire/node-factory.c +++ b/src/pipewire/node-factory.c @@ -19,3 +19,51 @@ #include "pipewire/pipewire.h" #include "pipewire/node-factory.h" +#include "pipewire/private.h" + +struct pw_node_factory *pw_node_factory_new(struct pw_core *core, + const char *name, + size_t user_data_size) +{ + struct pw_node_factory *this; + + this = calloc(1, sizeof(*this) + user_data_size); + this->core = core; + this->name = strdup(name); + + if (user_data_size > 0) + this->user_data = SPA_MEMBER(this, sizeof(*this), void); + + return this; +} + +void pw_node_factory_export(struct pw_node_factory *factory, + struct pw_client *owner, + struct pw_global *parent) +{ + struct pw_core *core = factory->core; + spa_list_insert(core->node_factory_list.prev, &factory->link); + factory->global = pw_core_add_global(core, owner, parent, core->type.node_factory, 0, NULL, factory); +} + +void *pw_node_factory_get_user_data(struct pw_node_factory *factory) +{ + return factory->user_data; +} + +void pw_node_factory_set_implementation(struct pw_node_factory *factory, + const struct pw_node_factory_implementation *implementation, + void *data) +{ + factory->implementation = implementation; + factory->implementation_data = data; +} + +struct pw_node *pw_node_factory_create_node(struct pw_node_factory *factory, + struct pw_resource *resource, + const char *name, + struct pw_properties *properties) +{ + return factory->implementation->create_node(factory->implementation_data, + resource, name, properties); +} diff --git a/src/pipewire/node-factory.h b/src/pipewire/node-factory.h index 808ce31ab..c7aca63f2 100644 --- a/src/pipewire/node-factory.h +++ b/src/pipewire/node-factory.h @@ -27,33 +27,46 @@ extern "C" { #define PW_TYPE_INTERFACE__NodeFactory PW_TYPE_INTERFACE_BASE "NodeFactory" #define PW_TYPE_NODE_FACTORY_BASE PW_TYPE_INTERFACE__NodeFactory ":" -#include -#include - /** \class pw_node_factory * * \brief PipeWire node factory interface. * * The factory object is used to make nodes on demand. */ -struct pw_node_factory { - struct pw_core *core; /**< the core */ - struct spa_list link; /**< link in core node_factory_list */ - struct pw_global *global; /**< global for this factory */ +struct pw_node_factory; - const char *name; /**< the factory name */ +#include +#include - /** Emited when the factory is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object)); +struct pw_node_factory_implementation { +#define PW_VERSION_NODE_FACRORY_IMPLEMENTATION 0 + uint32_t version; /** The function to create a node from this factory */ - struct pw_node *(*create_node) (struct pw_node_factory *factory, + struct pw_node *(*create_node) (void *data, struct pw_resource *resource, const char *name, struct pw_properties *properties); }; -#define pw_node_factory_create_node(f,...) (f)->create_node((f),__VA_ARGS__) +struct pw_node_factory *pw_node_factory_new(struct pw_core *core, + const char *name, + size_t user_data_size); + +void pw_node_factory_export(struct pw_node_factory *factory, + struct pw_client *owner, + struct pw_global *parent); + +void *pw_node_factory_get_user_data(struct pw_node_factory *factory); + +void pw_node_factory_set_implementation(struct pw_node_factory *factory, + const struct pw_node_factory_implementation *implementation, + void *data); + +struct pw_node *pw_node_factory_create_node(struct pw_node_factory *factory, + struct pw_resource *resource, + const char *name, + struct pw_properties *properties); #ifdef __cplusplus } diff --git a/src/pipewire/node.c b/src/pipewire/node.c index fce9f8cef..e0b50bb82 100644 --- a/src/pipewire/node.c +++ b/src/pipewire/node.c @@ -24,6 +24,7 @@ #include "pipewire/pipewire.h" #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/node.h" #include "pipewire/data-loop.h" @@ -37,14 +38,16 @@ struct impl { struct pw_global *parent; struct pw_work_queue *work; - struct pw_listener on_async_complete; - struct pw_listener on_event; - struct pw_listener on_need_input; - struct pw_listener on_have_output; + + struct pw_callback_info node_callbacks; bool registered; }; +struct resource_data { + struct pw_callback_info resource_callbacks; +}; + /** \endcond */ static int pause_node(struct pw_node *this) @@ -55,8 +58,13 @@ static int pause_node(struct pw_node *this) return SPA_RESULT_OK; pw_log_debug("node %p: pause node", this); - if ((res = this->implementation->send_command(this, - &SPA_COMMAND_INIT(this->core->type.command_node.Pause))) < 0) + if (this->implementation->send_command) + res = this->implementation->send_command(this->implementation_data, + &SPA_COMMAND_INIT(this->core->type.command_node.Pause)); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + + if (res < 0) pw_log_debug("node %p: send command error %d", this, res); return res; @@ -67,8 +75,13 @@ static int start_node(struct pw_node *this) int res = SPA_RESULT_OK; pw_log_debug("node %p: start node", this); - if ((res = this->implementation->send_command(this, - &SPA_COMMAND_INIT(this->core->type.command_node.Start))) < 0) + if (this->implementation->send_command) + res = this->implementation->send_command(this->implementation_data, + &SPA_COMMAND_INIT(this->core->type.command_node.Start)); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + + if (res < 0) pw_log_debug("node %p: send command error %d", this, res); return res; @@ -95,10 +108,9 @@ static int suspend_node(struct pw_node *this) return res; } -static void on_async_complete(struct pw_listener *listener, - struct pw_node *node, uint32_t seq, int res) +static void node_async_complete(void *data, uint32_t seq, int res) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, on_async_complete); + struct impl *impl = data; struct pw_node *this = &impl->this; pw_log_debug("node %p: async complete event %d %d", this, seq, res); @@ -130,14 +142,18 @@ static void send_clock_update(struct pw_node *this) &cu.body.ticks.value, &cu.body.monotonic_time.value); } - if ((res = this->implementation->send_command(this, (struct spa_command *) &cu)) < 0) + if (this->implementation->send_command) + res = this->implementation->send_command(this->implementation_data, (struct spa_command *) &cu); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + + if (res < 0) pw_log_debug("node %p: send clock update error %d", this, res); } -static void on_event(struct pw_listener *listener, - struct pw_node *node, const struct spa_event *event) +static void node_event(void *data, const struct spa_event *event) { - struct impl *impl = SPA_CONTAINER_OF(listener, struct impl, on_event); + struct impl *impl = data; struct pw_node *this = &impl->this; pw_log_trace("node %p: event %d", this, SPA_EVENT_TYPE(event)); @@ -146,18 +162,22 @@ static void on_event(struct pw_listener *listener, } } -static void on_need_input(struct pw_listener *listener, - struct pw_node *node) +static void node_need_input(void *data) { - spa_graph_scheduler_pull(node->rt.sched, &node->rt.node); - while (spa_graph_scheduler_iterate(node->rt.sched)); + struct impl *impl = data; + struct pw_node *this = &impl->this; + + spa_graph_scheduler_pull(this->rt.sched, &this->rt.node); + while (spa_graph_scheduler_iterate(this->rt.sched)); } -static void on_have_output(struct pw_listener *listener, - struct pw_node *node) +static void node_have_output(void *data) { - spa_graph_scheduler_push(node->rt.sched, &node->rt.node); - while (spa_graph_scheduler_iterate(node->rt.sched)); + struct impl *impl = data; + struct pw_node *this = &impl->this; + + spa_graph_scheduler_push(this->rt.sched, &this->rt.node); + while (spa_graph_scheduler_iterate(this->rt.sched)); } static void node_unbind_func(void *data) @@ -227,6 +247,11 @@ clear_info(struct pw_node *this) } +static const struct pw_resource_callbacks resource_callbacks = { + PW_VERSION_RESOURCE_CALLBACKS, + .destroy = node_unbind_func, +}; + static int node_bind_func(struct pw_global *global, struct pw_client *client, uint32_t permissions, @@ -234,12 +259,14 @@ node_bind_func(struct pw_global *global, { struct pw_node *this = global->object; struct pw_resource *resource; + struct resource_data *data; - resource = pw_resource_new(client, id, permissions, global->type, version, 0, node_unbind_func); + resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data)); if (resource == NULL) goto no_mem; - pw_resource_set_implementation(resource, this, NULL); + data = pw_resource_get_user_data(resource); + pw_resource_add_callbacks(resource, &data->resource_callbacks, &resource_callbacks, resource); pw_log_debug("node %p: bound to %d", this, resource->id); @@ -288,7 +315,7 @@ void pw_node_register(struct pw_node *this) node_bind_func, this); impl->registered = true; - pw_signal_emit(&this->initialized, this); + pw_callback_emit_na(&this->callback_list, struct pw_node_callbacks, initialized); pw_node_update_state(this, PW_NODE_STATE_SUSPENDED, NULL); } @@ -297,14 +324,24 @@ static int graph_impl_process_input(struct spa_graph_node *node, void *user_data) { struct pw_node *this = user_data; - return this->implementation->process_input(this); + int res; + if (this->implementation->process_input) + res = this->implementation->process_input(this->implementation_data); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + return res; } static int graph_impl_process_output(struct spa_graph_node *node, void *user_data) { struct pw_node *this = user_data; - return this->implementation->process_output(this); + int res; + if (this->implementation->process_output) + res = this->implementation->process_output(this->implementation_data); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + return res; } static const struct spa_graph_node_methods graph_methods = { @@ -313,6 +350,14 @@ static const struct spa_graph_node_methods graph_methods = { graph_impl_process_output, }; +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .async_complete = node_async_complete, + .event = node_event, + .need_input = node_need_input, + .have_output = node_have_output, +}; + struct pw_node *pw_node_new(struct pw_core *core, struct pw_resource *owner, struct pw_global *parent, @@ -352,22 +397,9 @@ struct pw_node *pw_node_new(struct pw_core *core, spa_list_init(&this->resource_list); - pw_signal_init(&this->state_request); - pw_signal_init(&this->state_changed); - pw_signal_init(&this->initialized); - pw_signal_init(&this->port_added); - pw_signal_init(&this->port_removed); - pw_signal_init(&this->destroy_signal); - pw_signal_init(&this->free_signal); - pw_signal_init(&this->async_complete); - pw_signal_init(&this->event); - pw_signal_init(&this->need_input); - pw_signal_init(&this->have_output); + pw_callback_init(&this->callback_list); - pw_signal_add(&this->async_complete, &impl->on_async_complete, on_async_complete); - pw_signal_add(&this->event, &impl->on_event, on_event); - pw_signal_add(&this->need_input, &impl->on_need_input, on_need_input); - pw_signal_add(&this->have_output, &impl->on_have_output, on_have_output); + pw_node_add_callbacks(this, &impl->node_callbacks, &node_callbacks, impl); this->info.state = PW_NODE_STATE_CREATING; @@ -388,6 +420,32 @@ struct pw_node *pw_node_new(struct pw_core *core, return NULL; } +void * pw_node_get_user_data(struct pw_node *node) +{ + return node->user_data; +} + +struct pw_core * pw_node_get_core(struct pw_node *node) +{ + return node->core; +} + +void pw_node_set_implementation(struct pw_node *node, + const struct pw_node_implementation *implementation, + void *data) +{ + node->implementation = implementation; + node->implementation_data = data; +} + +void pw_node_add_callbacks(struct pw_node *node, + struct pw_callback_info *info, + const struct pw_node_callbacks *callbacks, + void *data) +{ + pw_callback_add(&node->callback_list, info, callbacks, data); +} + static int do_node_remove(struct spa_loop *loop, bool async, uint32_t seq, size_t size, const void *data, void *user_data) @@ -416,7 +474,7 @@ void pw_node_destroy(struct pw_node *node) struct pw_port *port, *tmpp; pw_log_debug("node %p: destroy", impl); - pw_signal_emit(&node->destroy_signal, node); + pw_callback_emit_na(&node->callback_list, struct pw_node_callbacks, destroy); pw_loop_invoke(node->data_loop, do_node_remove, 1, 0, NULL, true, node); @@ -431,20 +489,17 @@ 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) { - pw_signal_emit(&node->port_removed, node, port); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, port_removed, port); pw_port_destroy(port); } spa_list_for_each_safe(port, tmpp, &node->output_ports, link) { - pw_signal_emit(&node->port_removed, node, port); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, port_removed, port); pw_port_destroy(port); } pw_log_debug("node %p: free", node); - pw_signal_emit(&node->free_signal, node); - - if (node->destroy) - node->destroy(node); + pw_callback_emit_na(&node->callback_list, struct pw_node_callbacks, free); pw_work_queue_destroy(impl->work); @@ -519,7 +574,11 @@ 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); - port = node->implementation->add_port(node, direction, port_id); + if (node->implementation->add_port) + port = node->implementation->add_port(node->implementation_data, direction, port_id); + else + port = NULL; + if (port == NULL) goto no_mem; } else { @@ -593,7 +652,7 @@ int pw_node_set_state(struct pw_node *node, enum pw_node_state state) int res = SPA_RESULT_OK; struct impl *impl = SPA_CONTAINER_OF(node, struct impl, this); - pw_signal_emit(&node->state_request, node, state); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, state_request, state); pw_log_debug("node %p: set state %s", node, pw_node_state_as_string(state)); @@ -656,11 +715,15 @@ void pw_node_update_state(struct pw_node *node, enum pw_node_state state, char * if (state == PW_NODE_STATE_IDLE) node_deactivate(node); - pw_signal_emit(&node->state_changed, node, old, state); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, state_changed, + old, state, error); node->info.change_mask |= 1 << 5; + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, info_changed, &node->info); + spa_list_for_each(resource, &node->resource_list, link) pw_node_resource_info(resource, &node->info); + node->info.change_mask = 0; } } diff --git a/src/pipewire/node.h b/src/pipewire/node.h index 837a933fc..972ff60d4 100644 --- a/src/pipewire/node.h +++ b/src/pipewire/node.h @@ -30,38 +30,6 @@ extern "C" { #include #include -#include -#include -#include - -#include -#include -#include -#include -#include - -struct pw_node; - -struct pw_node_implementation { -#define PW_VERSION_NODE_IMPLEMENTATION 0 - uint32_t version; - - int (*get_props) (struct pw_node *node, struct spa_props **props); - - int (*set_props) (struct pw_node *node, const struct spa_props *props); - - int (*send_command) (struct pw_node *node, - const struct spa_command *command); - - struct pw_port* (*add_port) (struct pw_node *node, - enum pw_direction direction, - uint32_t port_id); - - int (*process_input) (struct pw_node *node); - - int (*process_output) (struct pw_node *node); -}; - /** \page page_node Node * * \section page_node_overview Overview @@ -74,79 +42,74 @@ struct pw_node_implementation { * * PipeWire node class. */ -struct pw_node { - struct pw_core *core; /**< core object */ - struct spa_list link; /**< link in core node_list */ - struct pw_global *global; /**< global for this node */ +struct pw_node; - struct pw_resource *owner; /**< owner resource if any */ - struct pw_properties *properties; /**< properties of the node */ +#include +#include +#include - struct pw_node_info info; /**< introspectable node info */ +#include +#include +#include +#include +#include +#include - /** Emited when a state change is started */ - PW_SIGNAL(state_request, (struct pw_listener *listener, - struct pw_node *object, enum pw_node_state state)); - /** Emited when a stat change is completed */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, - struct pw_node *object, - enum pw_node_state old, enum pw_node_state state)); +struct pw_node_implementation { +#define PW_VERSION_NODE_IMPLEMENTATION 0 + uint32_t version; - bool live; /**< if the node is live */ - struct spa_clock *clock; /**< handle to SPA clock if any */ + int (*get_props) (void *data, struct spa_props **props); - struct spa_list resource_list; /**< list of resources for this node */ + int (*set_props) (void *data, const struct spa_props *props); - /** Implementation of core node functions */ - const struct pw_node_implementation *implementation; + int (*send_command) (void *data, + const struct spa_command *command); - /** Emited when the node is initialized */ - PW_SIGNAL(initialized, (struct pw_listener *listener, struct pw_node *object)); + struct pw_port* (*add_port) (void *data, + enum pw_direction direction, + uint32_t port_id); - struct spa_list input_ports; /**< list of input ports */ - struct pw_map input_port_map; /**< map from port_id to port */ - uint32_t n_used_input_links; /**< number of active input links */ - uint32_t idle_used_input_links; /**< number of active input to be idle */ + int (*process_input) (void *data); - struct spa_list output_ports; /**< list of output ports */ - struct pw_map output_port_map; /**< map from port_id to port */ - uint32_t n_used_output_links; /**< number of active output links */ - uint32_t idle_used_output_links; /**< number of active output to be idle */ + int (*process_output) (void *data); +}; - /** Emited when a new port is added */ - PW_SIGNAL(port_added, (struct pw_listener *listener, - struct pw_node *node, struct pw_port *port)); - /** Emited when a port is removed */ - PW_SIGNAL(port_removed, (struct pw_listener *listener, - struct pw_node *node, struct pw_port *port)); - /** Emited when the node is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node *object)); - /** Emited when the node is free */ - PW_SIGNAL(free_signal, (struct pw_listener *listener, struct pw_node *object)); +struct pw_node_callbacks { +#define PW_VERSION_NODE_CALLBACKS 0 + uint32_t version; - /** an async operation on the node completed */ - PW_SIGNAL(async_complete, (struct pw_listener *listener, - struct pw_node *node, uint32_t seq, int res)); + /** the node is destroyed */ + void (*destroy) (void *data); + /** the node is about to be freed */ + void (*free) (void *data); + /** the node is initialized */ + void (*initialized) (void *data); - /** an event is emited */ - PW_SIGNAL(event, (struct pw_listener *listener, - struct pw_node *node, const struct spa_event *event)); + /** a port was added */ + void (*port_added) (void *data, struct pw_port *port); + /** a port was removed */ + void (*port_removed) (void *data, struct pw_port *port); - /** the node wants input */ - PW_SIGNAL(need_input, (struct pw_listener *listener, struct pw_node *node)); - /** the node has output */ - PW_SIGNAL(have_output, (struct pw_listener *listener, struct pw_node *node)); + /** the node info changed */ + void (*info_changed) (void *data, struct pw_node_info *info); + /** a new state is requested on the node */ + void (*state_request) (void *data, enum pw_node_state state); + /** the state of the node changed */ + void (*state_changed) (void *data, enum pw_node_state old, + enum pw_node_state state, const char *error); - struct pw_loop *data_loop; /**< the data loop for this node */ + /** an async operation completed on the node */ + void (*async_complete) (void *data, uint32_t seq, int res); - struct { - struct spa_graph_scheduler *sched; - struct spa_graph_node node; - } rt; + /** an event is emited */ + void (*event) (void *data, const struct spa_event *event); - void *user_data; /**< extra user data */ - pw_destroy_t destroy; /**< function to clean up the object */ + /** the node wants input */ + void (*need_input) (void *data); + /** the node has output */ + void (*have_output) (void *data); }; /** Create a new node \memberof pw_node */ @@ -164,6 +127,19 @@ void pw_node_register(struct pw_node *node); /** Destroy a node */ void pw_node_destroy(struct pw_node *node); +void * pw_node_get_user_data(struct pw_node *node); + +struct pw_core * pw_node_get_core(struct pw_node *node); + +void pw_node_set_implementation(struct pw_node *node, + const struct pw_node_implementation *implementation, + void *data); + +void pw_node_add_callbacks(struct pw_node *node, + struct pw_callback_info *info, + const struct pw_node_callbacks *callbacks, + void *data); + /** Find the port with direction and port_id or NULL when not found */ struct pw_port * pw_node_find_port(struct pw_node *node, enum pw_direction direction, uint32_t port_id); diff --git a/src/pipewire/pipewire.c b/src/pipewire/pipewire.c index cfa3b6caa..60f0ff2bb 100644 --- a/src/pipewire/pipewire.c +++ b/src/pipewire/pipewire.c @@ -30,6 +30,7 @@ #include #include "pipewire/pipewire.h" +#include "pipewire/private.h" static char **categories = NULL; diff --git a/src/pipewire/port.c b/src/pipewire/port.c index 988f3e80b..3ee90acb0 100644 --- a/src/pipewire/port.c +++ b/src/pipewire/port.c @@ -22,6 +22,7 @@ #include #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/port.h" /** \cond */ @@ -36,7 +37,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; - pw_signal_emit(&port->state_changed, port); + pw_callback_emit(&port->callback_list, struct pw_port_callbacks, state_changed, state); } } @@ -159,8 +160,7 @@ struct pw_port *pw_port_new(enum pw_direction direction, spa_list_init(&this->links); - pw_signal_init(&this->state_changed); - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); spa_graph_port_init(&this->rt.port, this->direction, @@ -186,6 +186,27 @@ struct pw_port *pw_port_new(enum pw_direction direction, return this; } +void pw_port_set_implementation(struct pw_port *port, + const struct pw_port_implementation *implementation, + void *data) +{ + port->implementation = implementation; + port->implementation_data = data; +} + +void pw_port_add_callbacks(struct pw_port *port, + struct pw_callback_info *info, + const struct pw_port_callbacks *callbacks, + void *data) +{ + pw_callback_add(&port->callback_list, info, callbacks, data); +} + +void * pw_port_get_user_data(struct pw_port *port) +{ + return port->user_data; +} + static int do_add_port(struct spa_loop *loop, bool async, uint32_t seq, size_t size, const void *data, void *user_data) { @@ -217,12 +238,15 @@ void pw_port_add(struct pw_port *port, struct pw_node *node) node->info.change_mask |= 1 << 3; } + if (port->implementation->set_io) + port->implementation->set_io(port->implementation_data, &port->io); + port->rt.graph = node->rt.sched->graph; pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, 0, NULL, false, port); port_update_state(port, PW_PORT_STATE_CONFIGURE); - pw_signal_emit(&node->port_added, node, port); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, port_added, port); } static int do_remove_port(struct spa_loop *loop, @@ -249,7 +273,7 @@ void pw_port_destroy(struct pw_port *port) pw_log_debug("port %p: destroy", port); - pw_signal_emit(&port->destroy_signal, port); + pw_callback_emit_na(&port->callback_list, struct pw_port_callbacks, destroy); if (node) { pw_loop_invoke(port->node->data_loop, do_remove_port, SPA_ID_INVALID, 0, NULL, true, port); @@ -263,12 +287,8 @@ void pw_port_destroy(struct pw_port *port) node->info.n_output_ports--; } spa_list_remove(&port->link); - pw_signal_emit(&node->port_removed, node, port); + pw_callback_emit(&node->callback_list, struct pw_node_callbacks, port_removed, port); } - - if (port->destroy) - port->destroy(port); - free(port); } @@ -277,9 +297,14 @@ do_port_pause(struct spa_loop *loop, bool async, uint32_t seq, size_t size, const void *data, void *user_data) { struct pw_port *port = user_data; + int res; - return port->implementation->send_command(port, - &SPA_COMMAND_INIT(port->node->core->type.command_node.Pause)); + if (port->implementation->send_command) + res = port->implementation->send_command(port->implementation_data, + &SPA_COMMAND_INIT(port->node->core->type.command_node.Pause)); + else + res = SPA_RESULT_OK; + return res; } int pw_port_enum_formats(struct pw_port *port, @@ -287,14 +312,23 @@ int pw_port_enum_formats(struct pw_port *port, const struct spa_format *filter, int32_t index) { - return port->implementation->enum_formats(port, format, filter, index); + int res; + if (port->implementation->enum_formats) + res = port->implementation->enum_formats(port->implementation_data, format, filter, index); + else + res = SPA_RESULT_ENUM_END; + return res; } int pw_port_set_format(struct pw_port *port, uint32_t flags, const struct spa_format *format) { int res; - res = port->implementation->set_format(port, flags, format); + if (port->implementation->set_format) + res = port->implementation->set_format(port->implementation_data, flags, format); + else + res = SPA_RESULT_OK; + pw_log_debug("port %p: set format %d", port, res); if (!SPA_RESULT_IS_ASYNC(res)) { @@ -317,22 +351,42 @@ int pw_port_set_format(struct pw_port *port, uint32_t flags, const struct spa_fo int pw_port_get_format(struct pw_port *port, const struct spa_format **format) { - return port->implementation->get_format(port, format); + int res; + if (port->implementation->get_format) + res = port->implementation->get_format(port->implementation_data, format); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + return res; } int pw_port_get_info(struct pw_port *port, const struct spa_port_info **info) { - return port->implementation->get_info(port, info); + int res; + if (port->implementation->get_info) + res = port->implementation->get_info(port->implementation_data, info); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + return res; } int pw_port_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param) { - return port->implementation->enum_params(port, index, param); + int res; + if (port->implementation->enum_params) + res = port->implementation->enum_params(port->implementation_data, index, param); + else + res = SPA_RESULT_ENUM_END; + return res; } int pw_port_set_param(struct pw_port *port, struct spa_param *param) { - return port->implementation->set_param(port, param); + int res; + if (port->implementation->set_param) + res = port->implementation->set_param(port->implementation_data, param); + else + res = SPA_RESULT_NOT_IMPLEMENTED; + return res; } int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers) @@ -353,7 +407,11 @@ int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint3 } pw_log_debug("port %p: use %d buffers", port, n_buffers); - res = port->implementation->use_buffers(port, buffers, n_buffers); + + if (port->implementation->use_buffers) + res = port->implementation->use_buffers(port->implementation_data, buffers, n_buffers); + else + res = SPA_RESULT_NOT_IMPLEMENTED; size = sizeof(struct spa_buffer *) * n_buffers; @@ -390,7 +448,11 @@ int pw_port_alloc_buffers(struct pw_port *port, } pw_log_debug("port %p: alloc %d buffers", port, *n_buffers); - res = port->implementation->alloc_buffers(port, params, n_params, buffers, n_buffers); + + if (port->implementation->alloc_buffers) + res = port->implementation->alloc_buffers(port->implementation_data, params, n_params, buffers, n_buffers); + else + res = SPA_RESULT_NOT_IMPLEMENTED; size = sizeof(struct spa_buffer *) * *n_buffers; diff --git a/src/pipewire/port.h b/src/pipewire/port.h index f5de222d0..85b83a1d8 100644 --- a/src/pipewire/port.h +++ b/src/pipewire/port.h @@ -27,55 +27,6 @@ extern "C" { #define PW_TYPE__Port "PipeWire:Object:Port" #define PW_TYPE_PORT_BASE PW_TYPE__Port ":" -#include - -#include -#include -#include - -#include -#include - -enum pw_port_state { - PW_PORT_STATE_ERROR = -1, - PW_PORT_STATE_INIT = 0, - PW_PORT_STATE_CONFIGURE = 1, - PW_PORT_STATE_READY = 2, - PW_PORT_STATE_PAUSED = 3, - PW_PORT_STATE_STREAMING = 4, -}; - -struct pw_port; - -struct pw_port_implementation { -#define PW_VERSION_PORT_IMPLEMENTATION 0 - uint32_t version; - - int (*enum_formats) (struct pw_port *port, - struct spa_format **format, - const struct spa_format *filter, - int32_t index); - - int (*set_format) (struct pw_port *port, uint32_t flags, const struct spa_format *format); - - int (*get_format) (struct pw_port *port, const struct spa_format **format); - - int (*get_info) (struct pw_port *port, const struct spa_port_info **info); - - int (*enum_params) (struct pw_port *port, uint32_t index, struct spa_param **param); - - int (*set_param) (struct pw_port *port, struct spa_param *param); - - int (*use_buffers) (struct pw_port *port, struct spa_buffer **buffers, uint32_t n_buffers); - - int (*alloc_buffers) (struct pw_port *port, - struct spa_param **params, uint32_t n_params, - struct spa_buffer **buffers, uint32_t *n_buffers); - int (*reuse_buffer) (struct pw_port *port, uint32_t buffer_id); - - int (*send_command) (struct pw_port *port, struct spa_command *command); -}; - /** \page page_port Port * * \section page_node_overview Overview @@ -86,42 +37,65 @@ struct pw_port_implementation { * * The port object */ -struct pw_port { - struct spa_list link; /**< link in node port_list */ +struct pw_port; - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_port *)); +#include - struct pw_node *node; /**< owner node */ +#include +#include +#include - enum pw_direction direction; /**< port direction */ - uint32_t port_id; /**< port id */ +#include +#include +#include - enum pw_port_state state; /**< state of the port */ - /** Emited when the port state changes */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_port *port)); +enum pw_port_state { + PW_PORT_STATE_ERROR = -1, + PW_PORT_STATE_INIT = 0, + PW_PORT_STATE_CONFIGURE = 1, + PW_PORT_STATE_READY = 2, + PW_PORT_STATE_PAUSED = 3, + PW_PORT_STATE_STREAMING = 4, +}; - const struct pw_port_implementation *implementation; +struct pw_port_implementation { +#define PW_VERSION_PORT_IMPLEMENTATION 0 + uint32_t version; - struct spa_port_io io; /**< io area of the port */ + int (*set_io) (void *data, struct spa_port_io *io); - bool allocated; /**< if buffers are allocated */ - struct pw_memblock buffer_mem; /**< allocated buffer memory */ - struct spa_buffer **buffers; /**< port buffers */ - uint32_t n_buffers; /**< number of port buffers */ + int (*enum_formats) (void *data, + struct spa_format **format, + const struct spa_format *filter, + int32_t index); - struct spa_list links; /**< list of \ref pw_link */ + int (*set_format) (void *data, uint32_t flags, const struct spa_format *format); - void *mix; /**< optional port buffer mix/split */ + int (*get_format) (void *data, const struct spa_format **format); - struct { - struct spa_graph *graph; - struct spa_graph_port port; - struct spa_graph_port mix_port; - struct spa_graph_node mix_node; - } rt; /**< data only accessed from the data thread */ + int (*get_info) (void *data, const struct spa_port_info **info); - void *user_data; /**< extra user data */ - pw_destroy_t destroy; /**< function to clean up the object */ + int (*enum_params) (void *data, uint32_t index, struct spa_param **param); + + int (*set_param) (void *data, struct spa_param *param); + + int (*use_buffers) (void *data, struct spa_buffer **buffers, uint32_t n_buffers); + + int (*alloc_buffers) (void *data, + struct spa_param **params, uint32_t n_params, + struct spa_buffer **buffers, uint32_t *n_buffers); + int (*reuse_buffer) (void *data, uint32_t buffer_id); + + int (*send_command) (void *data, struct spa_command *command); +}; + +struct pw_port_callbacks { +#define PW_VERSION_PORT_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data); + + void (*state_changed) (void *data, enum pw_port_state state); }; /** Create a new port \memberof pw_port @@ -134,9 +108,20 @@ pw_port_new(enum pw_direction direction, /** Add a port to a node \memberof pw_port */ void pw_port_add(struct pw_port *port, struct pw_node *node); +void pw_port_set_implementation(struct pw_port *port, + const struct pw_port_implementation *implementation, + void *data); + +void pw_port_add_callbacks(struct pw_port *port, + struct pw_callback_info *info, + const struct pw_port_callbacks *callbacks, + void *data); + /** Destroy a port \memberof pw_port */ void pw_port_destroy(struct pw_port *port); +void * pw_port_get_user_data(struct pw_port *port); + /** Get the current format on a port \memberof pw_port */ int pw_port_enum_formats(struct pw_port *port, struct spa_format **format, diff --git a/src/pipewire/private.h b/src/pipewire/private.h new file mode 100644 index 000000000..109526ff7 --- /dev/null +++ b/src/pipewire/private.h @@ -0,0 +1,356 @@ +/* PipeWire + * Copyright (C) 2015 Wim Taymans + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __PIPEWIRE_PRIVATE_H__ +#define __PIPEWIRE_PRIVATE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +#include "pipewire/pipewire.h" +#include "pipewire/introspect.h" + +struct pw_command { + struct spa_list link; /**< link in list of commands */ + const char *name; /**< command name */ +}; + +struct pw_client { + struct pw_core *core; /**< core object */ + struct spa_list link; /**< link in core object client list */ + struct pw_global *global; /**< global object created for this 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 */ + + struct pw_map objects; /**< list of resource objects */ + uint32_t n_types; /**< number of client types */ + struct pw_map types; /**< map of client types */ + + struct spa_list resource_list; /**< The list of resources of this client */ + + bool busy; + + struct pw_callback_list callback_list; + + struct pw_protocol *protocol; /**< protocol in use */ + struct spa_list protocol_link; /**< link in the protocol client_list */ + void *protocol_private; /**< private data for the protocol */ + + void *user_data; /**< extra user data */ +}; + +struct pw_global { + struct pw_core *core; /**< the core */ + struct pw_client *owner; /**< the owner of this object, NULL when the + * PipeWire server is the owner */ + + struct spa_list link; /**< link in core list of globals */ + uint32_t id; /**< server id of the object */ + struct pw_global *parent; /**< parent global */ + + uint32_t type; /**< type of interface */ + uint32_t version; /**< version of interface */ + pw_bind_func_t bind; /**< function to bind to the interface */ + + void *object; /**< object associated with the interface */ +}; + +struct pw_core { + struct pw_global *global; /**< the global of the core */ + + struct pw_core_info info; /**< info about the core */ + + struct pw_properties *properties; /**< properties of the core */ + + struct pw_type type; /**< type map and common types */ + + pw_permission_func_t permission_func; /**< get permissions of an object */ + void *permission_data; /**< data passed to permission function */ + + struct pw_map globals; /**< map of globals */ + + struct spa_list protocol_list; /**< list of protocols */ + struct spa_list remote_list; /**< list of remote connections */ + struct spa_list resource_list; /**< list of core resources */ + struct spa_list registry_resource_list; /**< list of registry resources */ + struct spa_list module_list; /**< list of modules */ + struct spa_list global_list; /**< list of globals */ + struct spa_list client_list; /**< list of clients */ + struct spa_list node_list; /**< list of nodes */ + struct spa_list node_factory_list; /**< list of node factories */ + struct spa_list link_list; /**< list of links */ + struct pw_callback_list callback_list; + + struct pw_loop *main_loop; /**< main loop for control */ + struct pw_loop *data_loop; /**< data loop for data passing */ + struct pw_data_loop *data_loop_impl; + + struct spa_support support[4]; /**< support for spa plugins */ + uint32_t n_support; /**< number of support items */ + + struct { + struct spa_graph_scheduler sched; + struct spa_graph graph; + } rt; +}; + +struct pw_data_loop { + struct pw_loop *loop; + + struct pw_callback_list callback_list; + + struct spa_source *event; + + bool running; + pthread_t thread; +}; + +struct pw_main_loop { + struct pw_loop *loop; + + struct pw_callback_list callback_list; + + bool running; +}; + +struct pw_link { + struct pw_core *core; /**< core object */ + struct spa_list link; /**< link in core link_list */ + struct pw_global *global; /**< global for this link */ + + struct pw_link_info info; /**< introspectable link info */ + struct pw_properties *properties; /**< extra link properties */ + + enum pw_link_state state; /**< link state */ + char *error; /**< error message when state error */ + + struct spa_list resource_list; /**< list of bound resources */ + + struct spa_port_io io; /**< link io area */ + + struct pw_port *output; /**< output port */ + struct spa_list output_link; /**< link in output port links */ + struct pw_port *input; /**< input port */ + struct spa_list input_link; /**< link in input port links */ + + struct pw_callback_list callback_list; + + struct { + struct spa_graph_port out_port; + struct spa_graph_port in_port; + } rt; +}; + +struct pw_module { + struct pw_core *core; /**< the core object */ + struct spa_list link; /**< link in the core module_list */ + struct pw_global *global; /**< global object for this module */ + + struct pw_module_info info; /**< introspectable module info */ + + struct spa_list resource_list; /**< list of resources for this module */ + + struct pw_callback_list callback_list; + + void *user_data; /**< module user_data */ +}; + +struct pw_node { + struct pw_core *core; /**< core object */ + struct spa_list link; /**< link in core node_list */ + struct pw_global *global; /**< global for this node */ + + struct pw_resource *owner; /**< owner resource if any */ + struct pw_properties *properties; /**< properties of the node */ + + struct pw_node_info info; /**< introspectable node info */ + + bool live; /**< if the node is live */ + struct spa_clock *clock; /**< handle to SPA clock if any */ + + struct spa_list resource_list; /**< list of resources for this node */ + + /** Implementation of core node functions */ + const struct pw_node_implementation *implementation; + void *implementation_data; + + struct spa_list input_ports; /**< list of input ports */ + struct pw_map input_port_map; /**< map from port_id to port */ + uint32_t n_used_input_links; /**< number of active input links */ + uint32_t idle_used_input_links; /**< number of active input to be idle */ + + struct spa_list output_ports; /**< list of output ports */ + struct pw_map output_port_map; /**< map from port_id to port */ + uint32_t n_used_output_links; /**< number of active output links */ + uint32_t idle_used_output_links; /**< number of active output to be idle */ + + struct pw_callback_list callback_list; + + struct pw_loop *data_loop; /**< the data loop for this node */ + + struct { + struct spa_graph_scheduler *sched; + struct spa_graph_node node; + } rt; + + void *user_data; /**< extra user data */ +}; + +struct pw_port { + struct spa_list link; /**< link in node port_list */ + + struct pw_node *node; /**< owner node */ + + enum pw_direction direction; /**< port direction */ + uint32_t port_id; /**< port id */ + + enum pw_port_state state; /**< state of the port */ + + const struct pw_port_implementation *implementation; + void *implementation_data; + + struct spa_port_io io; /**< io area of the port */ + + bool allocated; /**< if buffers are allocated */ + struct pw_memblock buffer_mem; /**< allocated buffer memory */ + struct spa_buffer **buffers; /**< port buffers */ + uint32_t n_buffers; /**< number of port buffers */ + + struct spa_list links; /**< list of \ref pw_link */ + + struct pw_callback_list callback_list; + + void *mix; /**< optional port buffer mix/split */ + + struct { + struct spa_graph *graph; + struct spa_graph_port port; + struct spa_graph_port mix_port; + struct spa_graph_node mix_node; + } rt; /**< data only accessed from the data thread */ + + void *user_data; /**< extra user data */ +}; + + +struct pw_resource { + struct pw_core *core; /**< the core object */ + struct spa_list link; /**< link in object resource_list */ + + struct pw_client *client; /**< owner client */ + + uint32_t id; /**< per client unique id, index in client objects */ + uint32_t permissions; /**< resource permissions */ + uint32_t type; /**< type of the client interface */ + uint32_t version; /**< version of the client interface */ + + const void *implementation; + void *implementation_data; + + struct pw_callback_list callback_list; + + const struct pw_protocol_marshal *marshal; + + void *access_private; /**< private data for access control */ + void *user_data; /**< extra user data */ +}; + + +struct pw_proxy { + struct pw_remote *remote; /**< the owner remote of this proxy */ + struct spa_list link; /**< link in the remote */ + + uint32_t id; /**< client side id */ + + struct pw_callback_list callback_list; + struct pw_callback_list listener_list; + + const struct pw_protocol_marshal *marshal; /**< protocol specific marshal functions */ + + void *user_data; /**< extra user data */ +}; + +struct pw_remote { + struct pw_core *core; /**< core */ + struct spa_list link; /**< link in core remote_list */ + struct pw_properties *properties; /**< extra properties */ + + struct pw_core_proxy *core_proxy; /**< proxy for the core object */ + struct pw_map objects; /**< map of client side proxy objects + * indexed with the client id */ + struct pw_core_info *info; /**< info about the remote core */ + + uint32_t n_types; /**< number of client types */ + struct pw_map types; /**< client types */ + + struct spa_list proxy_list; /**< list of \ref pw_proxy objects */ + struct spa_list stream_list; /**< list of \ref pw_stream objects */ + struct spa_list remote_node_list; /**< list of \ref pw_remote_node objects */ + + struct pw_protocol_connection *conn; /**< the protocol connection */ + + enum pw_remote_state state; + char *error; + + struct pw_callback_list callback_list; +}; + + +struct pw_stream { + struct pw_remote *remote; /**< the owner remote */ + struct spa_list link; /**< link in the remote */ + + char *name; /**< the name of the stream */ + uint32_t node_id; /**< node id for remote node, available from + * CONFIGURE state and higher */ + struct pw_properties *properties; /**< properties of the stream */ + + enum pw_stream_state state; /**< stream state */ + char *error; /**< error reason when state is in error */ + + struct pw_callback_list callback_list; +}; + +struct pw_node_factory { + struct pw_core *core; /**< the core */ + struct spa_list link; /**< link in core node_factory_list */ + struct pw_global *global; /**< global for this factory */ + + const char *name; /**< the factory name */ + + const struct pw_node_factory_implementation *implementation; + void *implementation_data; + + void *user_data; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_PRIVATE_H__ */ diff --git a/src/pipewire/protocol.c b/src/pipewire/protocol.c index a9b572ab0..0c7097e2f 100644 --- a/src/pipewire/protocol.c +++ b/src/pipewire/protocol.c @@ -18,6 +18,7 @@ */ #include +#include struct impl { struct pw_protocol this; @@ -55,6 +56,11 @@ struct pw_protocol *pw_protocol_new(struct pw_core *core, return protocol; } +void *pw_protocol_get_user_data(struct pw_protocol *protocol) +{ + return protocol->user_data; +} + void pw_protocol_destroy(struct pw_protocol *protocol) { struct impl *impl = SPA_CONTAINER_OF(protocol, struct impl, this); @@ -96,7 +102,8 @@ pw_protocol_add_marshal(struct pw_protocol *protocol, spa_list_insert(protocol->marshal_list.prev, &impl->link); - pw_log_info("Add marshal %s:%d to protocol %s", marshal->type, marshal->version, protocol->name); + pw_log_info("Add marshal %s:%d to protocol %s", marshal->type, marshal->version, + protocol->name); } const struct pw_protocol_marshal * diff --git a/src/pipewire/protocol.h b/src/pipewire/protocol.h index e87c8ea4f..729dafae6 100644 --- a/src/pipewire/protocol.h +++ b/src/pipewire/protocol.h @@ -113,6 +113,8 @@ struct pw_protocol { struct pw_protocol *pw_protocol_new(struct pw_core *core, const char *name, size_t user_data_size); +void *pw_protocol_get_user_data(struct pw_protocol *protocol); + /** \class pw_protocol * * \brief Manages protocols and their implementation diff --git a/src/pipewire/proxy.c b/src/pipewire/proxy.c index e5a48b151..ad6556164 100644 --- a/src/pipewire/proxy.c +++ b/src/pipewire/proxy.c @@ -21,6 +21,7 @@ #include #include #include +#include /** \cond */ struct proxy { @@ -30,7 +31,7 @@ struct proxy { /** Create a proxy object with a given id and type * - * \param remote Remote object + * \param proxy another proxy object that serves as a factory * \param id Id of the new object, SPA_ID_INVALID will choose a new id * \param type Type of the proxy object * \return A newly allocated proxy object or NULL on failure @@ -42,14 +43,13 @@ struct proxy { * * \memberof pw_proxy */ -struct pw_proxy *pw_proxy_new(struct pw_remote *remote, - uint32_t id, +struct pw_proxy *pw_proxy_new(struct pw_proxy *proxy, uint32_t type, - size_t user_data_size, - pw_destroy_t destroy) + size_t user_data_size) { struct proxy *impl; struct pw_proxy *this; + struct pw_remote *remote = proxy->remote; impl = calloc(1, sizeof(struct proxy) + user_data_size); if (impl == NULL) @@ -58,16 +58,10 @@ struct pw_proxy *pw_proxy_new(struct pw_remote *remote, this = &impl->this; this->remote = remote; - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); + pw_callback_init(&this->listener_list); - if (id == SPA_ID_INVALID) { - id = pw_map_insert_new(&remote->objects, this); - } else if (!pw_map_insert_at(&remote->objects, id, this)) - goto in_use; - - this->id = id; - this->type = type; - this->destroy = destroy; + this->id = pw_map_insert_new(&remote->objects, this); if (user_data_size > 0) this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void); @@ -76,21 +70,35 @@ struct pw_proxy *pw_proxy_new(struct pw_remote *remote, spa_list_insert(&this->remote->proxy_list, &this->link); - pw_log_debug("proxy %p: new %u, remote %p", this, this->id, remote); + pw_log_debug("proxy %p: new %u, remote %p, marshal %p", this, this->id, remote, this->marshal); return this; +} - in_use: - pw_log_error("proxy %p: id %u in use for remote %p", this, id, remote); - free(impl); - return NULL; +void *pw_proxy_get_user_data(struct pw_proxy *proxy) +{ + return proxy->user_data; +} + +uint32_t pw_proxy_get_id(struct pw_proxy *proxy) +{ + return proxy->id; +} + +void pw_proxy_add_callbacks(struct pw_proxy *proxy, + struct pw_callback_info *info, + const struct pw_proxy_callbacks *callbacks, + void *data) +{ + pw_callback_add(&proxy->callback_list, info, callbacks, data); } void pw_proxy_add_listener(struct pw_proxy *proxy, - void *object, const void *listener) + struct pw_callback_info *info, + const void *callbacks, + void *data) { - proxy->object = object; - proxy->listener = listener; + pw_callback_add(&proxy->listener_list, info, callbacks, data); } /** Destroy a proxy object @@ -106,13 +114,20 @@ 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); - pw_signal_emit(&proxy->destroy_signal, proxy); + pw_callback_emit_na(&proxy->callback_list, struct pw_proxy_callbacks, destroy); pw_map_remove(&proxy->remote->objects, proxy->id); spa_list_remove(&proxy->link); - if (proxy->destroy) - proxy->destroy(proxy); - free(impl); } + +struct pw_callback_list *pw_proxy_get_listeners(struct pw_proxy *proxy) +{ + return &proxy->listener_list; +} + +const void *pw_proxy_get_implementation(struct pw_proxy *proxy) +{ + return proxy->marshal->method_marshal; +} diff --git a/src/pipewire/proxy.h b/src/pipewire/proxy.h index 94b6215d6..5e55fabb6 100644 --- a/src/pipewire/proxy.h +++ b/src/pipewire/proxy.h @@ -24,9 +24,6 @@ extern "C" { #endif -#include -#include - struct pw_remote; /** \page page_proxy Proxy @@ -87,45 +84,52 @@ struct pw_remote; * * See \ref page_proxy */ -struct pw_proxy { - struct pw_remote *remote; /**< the owner remote of this proxy */ - struct spa_list link; /**< link in the remote */ +struct pw_proxy; - uint32_t id; /**< client side id */ - uint32_t type; /**< type id */ +#include +#include +#include - const void *listener; /**< event listener */ - void *object; /**< object associated with proxy */ +struct pw_proxy_callbacks { +#define PW_VERSION_PROXY_CALLBACKS 0 + uint32_t version; - const struct pw_protocol_marshal *marshal; /**< protocol specific marshal functions */ - - /** destroy is emited when the proxy is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_proxy *proxy)); - - void *user_data; /**< extra user data */ - pw_destroy_t destroy; /**< optional destroy function to clean up the user_data */ + void (*destroy) (void *data); }; /** Make a new proxy object. The id can be used to bind to a remote object. */ struct pw_proxy * -pw_proxy_new(struct pw_remote *remote, /**< remote this proxy is from */ - uint32_t id, /**< local id, SPA_ID_INVALID to have one automatically - * allocated for you */ - uint32_t type, /**< interface type id */ - size_t user_data_size, /**< size of user data */ - pw_destroy_t destroy /**< destroy function for user data */); +pw_proxy_new(struct pw_proxy *proxy, /**< proxy as factory */ + uint32_t type, /**< interface type */ + size_t user_data_size /**< size of user data */); + +void +pw_proxy_add_callbacks(struct pw_proxy *proxy, + struct pw_callback_info *info, + const struct pw_proxy_callbacks *callbacks, + void *data); void pw_proxy_add_listener(struct pw_proxy *proxy, /**< the proxy */ - void *object, /**< object associated with proxy */ - const void *events /**< events */); + struct pw_callback_info *info, + const void *callbacks, /**< events */ + void *data /**< data passed to events */); void pw_proxy_destroy(struct pw_proxy *proxy); -#define pw_proxy_notify(p,type,event,...) ((type*) (p)->listener)->event(p, __VA_ARGS__) -#define pw_proxy_notify_na(p,type,event) ((type*) (p)->listener)->event(p) -#define pw_proxy_do(p,type,method,...) ((type*) (p)->marshal->method_marshal)->method(p, __VA_ARGS__) -#define pw_proxy_do_na(p,type,method) ((type*) (p)->marshal->method_marshal)->method(p) +void *pw_proxy_get_user_data(struct pw_proxy *proxy); + +uint32_t pw_proxy_get_id(struct pw_proxy *proxy); + +struct pw_callback_list *pw_proxy_get_listeners(struct pw_proxy *proxy); + +const void *pw_proxy_get_implementation(struct pw_proxy *proxy); + +#define pw_proxy_notify(p,type,event,...) pw_callback_emit(pw_proxy_get_listeners(p),type,event,__VA_ARGS__) +#define pw_proxy_notify_na(p,type,event) pw_callback_emit_na(pw_proxy_get_listeners(p),type,event) + +#define pw_proxy_do(p,type,method,...) ((type*) pw_proxy_get_implementation(p))->method(p, __VA_ARGS__) +#define pw_proxy_do_na(p,type,method) ((type*) pw_proxy_get_implementation(p))->method(p) #ifdef __cplusplus } diff --git a/src/pipewire/remote.c b/src/pipewire/remote.c index 43bc45ffd..2f44231cc 100644 --- a/src/pipewire/remote.c +++ b/src/pipewire/remote.c @@ -27,6 +27,7 @@ #include #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/introspect.h" #include "pipewire/interfaces.h" #include "pipewire/remote.h" @@ -41,6 +42,7 @@ struct remote { struct pw_remote this; uint32_t type_client_node; + struct pw_callback_info core_callbacks; }; struct mem_id { @@ -61,6 +63,9 @@ struct buffer_id { struct node_data { struct pw_node *node; + struct pw_remote *remote; + struct pw_core *core; + struct pw_type *t; struct pw_client_node_proxy *node_proxy; uint32_t node_id; @@ -70,8 +75,8 @@ struct node_data { struct pw_transport *trans; struct pw_listener node_proxy_destroy; - struct pw_listener node_need_input; - struct pw_listener node_have_output; + struct pw_callback_info node_callbacks; + struct pw_callback_info node_listener; struct pw_array mem_ids; struct pw_array buffer_ids; @@ -104,7 +109,9 @@ const char *pw_remote_state_as_string(enum pw_remote_state state) void pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...) { - if (remote->state != state) { + enum pw_remote_state old = remote->state; + + if (old != state) { if (remote->error) free(remote->error); @@ -121,47 +128,45 @@ pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, con remote->error = NULL; } pw_log_debug("remote %p: update state from %s -> %s (%s)", remote, - pw_remote_state_as_string(remote->state), + pw_remote_state_as_string(old), pw_remote_state_as_string(state), remote->error); remote->state = state; - pw_signal_emit(&remote->state_changed, remote); + pw_callback_emit(&remote->callback_list, struct pw_remote_callbacks, state_changed, + old, state, remote->error); } } -static void core_event_info(void *object, struct pw_core_info *info) +static void core_event_info(void *data, struct pw_core_info *info) { - struct pw_proxy *proxy = object; - struct pw_remote *this = proxy->object; + struct pw_remote *this = data; pw_log_debug("got core info"); this->info = pw_core_info_update(this->info, info); - pw_signal_emit(&this->info_changed, this); + pw_callback_emit(&this->callback_list, struct pw_remote_callbacks, info_changed, info); } -static void core_event_done(void *object, uint32_t seq) +static void core_event_done(void *data, uint32_t seq) { - struct pw_proxy *proxy = object; - struct pw_remote *this = proxy->object; + struct pw_remote *this = data; pw_log_debug("core event done %d", seq); if (seq == 0) pw_remote_update_state(this, PW_REMOTE_STATE_CONNECTED, NULL); - pw_signal_emit(&this->sync_reply, this, seq); + pw_callback_emit(&this->callback_list, struct pw_remote_callbacks, sync_reply, seq); } -static void core_event_error(void *object, uint32_t id, int res, const char *error, ...) +static void core_event_error(void *data, uint32_t id, int res, const char *error, ...) { - struct pw_proxy *proxy = object; - struct pw_remote *this = proxy->object; + struct pw_remote *this = data; pw_remote_update_state(this, PW_REMOTE_STATE_ERROR, error); } -static void core_event_remove_id(void *object, uint32_t id) +static void core_event_remove_id(void *data, uint32_t id) { - struct pw_proxy *proxy = object; - struct pw_remote *this = proxy->object; + struct pw_remote *this = data; + struct pw_proxy *proxy; proxy = pw_map_lookup(&this->objects, id); if (proxy) { @@ -171,10 +176,9 @@ static void core_event_remove_id(void *object, uint32_t id) } static void -core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const char **types) +core_event_update_types(void *data, uint32_t first_id, uint32_t n_types, const char **types) { - struct pw_proxy *proxy = object; - struct pw_remote *this = proxy->object; + struct pw_remote *this = data; int i; for (i = 0; i < n_types; i++, first_id++) { @@ -186,11 +190,11 @@ core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const static const struct pw_core_events core_events = { PW_VERSION_CORE_EVENTS, - &core_event_update_types, - &core_event_done, - &core_event_error, - &core_event_remove_id, - &core_event_info, + .update_types = core_event_update_types, + .done = core_event_done, + .error = core_event_error, + .remove_id = core_event_remove_id, + .info = core_event_info, }; struct pw_remote *pw_remote_new(struct pw_core *core, @@ -227,10 +231,7 @@ struct pw_remote *pw_remote_new(struct pw_core *core, spa_list_init(&this->proxy_list); spa_list_init(&this->stream_list); - pw_signal_init(&this->info_changed); - pw_signal_init(&this->sync_reply); - pw_signal_init(&this->state_changed); - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); if ((protocol_name = pw_properties_get(properties, "pipewire.protocol")) == NULL) { if (!pw_module_load(core, "libpipewire-module-protocol-native", NULL)) @@ -267,7 +268,7 @@ void pw_remote_destroy(struct pw_remote *remote) struct pw_stream *stream, *s2; pw_log_debug("remote %p: destroy", remote); - pw_signal_emit(&remote->destroy_signal, remote); + pw_callback_emit_na(&remote->callback_list, struct pw_remote_callbacks, destroy); if (remote->state != PW_REMOTE_STATE_UNCONNECTED) pw_remote_disconnect(remote); @@ -285,13 +286,38 @@ void pw_remote_destroy(struct pw_remote *remote) free(impl); } +struct pw_core *pw_remote_get_core(struct pw_remote *remote) +{ + return remote->core; +} + +enum pw_remote_state pw_remote_get_state(struct pw_remote *remote, const char **error) +{ + if (error) + *error = remote->error; + return remote->state; +} + +void pw_remote_add_callbacks(struct pw_remote *remote, + struct pw_callback_info *info, + const struct pw_remote_callbacks *callbacks, + void *data) +{ + pw_callback_add(&remote->callback_list, info, callbacks, data); +} + static int do_connect(struct pw_remote *remote) { - remote->core_proxy = (struct pw_core_proxy*)pw_proxy_new(remote, 0, remote->core->type.core, 0, NULL); + struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this); + struct pw_proxy dummy; + + dummy.remote = remote; + + remote->core_proxy = (struct pw_core_proxy*)pw_proxy_new(&dummy, remote->core->type.core, 0); if (remote->core_proxy == NULL) goto no_proxy; - pw_proxy_add_listener(&remote->core_proxy->proxy, remote, &core_events); + pw_core_proxy_add_listener(remote->core_proxy, &impl->core_callbacks, &core_events, remote); pw_core_proxy_client_update(remote->core_proxy, &remote->properties->dict); pw_core_proxy_sync(remote->core_proxy, 0); @@ -304,6 +330,16 @@ static int do_connect(struct pw_remote *remote) return -1; } +struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote) +{ + return remote->core_proxy; +} + +const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote) +{ + return remote->info; +} + int pw_remote_connect(struct pw_remote *remote) { int res; @@ -872,39 +908,37 @@ client_node_port_command(void *object, static const struct pw_client_node_events client_node_events = { PW_VERSION_CLIENT_NODE_EVENTS, - &client_node_transport, - &client_node_set_props, - &client_node_event, - &client_node_add_port, - &client_node_remove_port, - &client_node_set_format, - &client_node_set_param, - &client_node_add_mem, - &client_node_use_buffers, - &client_node_node_command, - &client_node_port_command, + .transport = client_node_transport, + .set_props = client_node_set_props, + .event = client_node_event, + .add_port = client_node_add_port, + .remove_port = client_node_remove_port, + .set_format = client_node_set_format, + .set_param = client_node_set_param, + .add_mem = client_node_add_mem, + .use_buffers = client_node_use_buffers, + .node_command = client_node_node_command, + .port_command = client_node_port_command, }; -static void node_need_input(struct pw_listener *listener, struct pw_node *node) +static void node_need_input(void *data) { - struct node_data *data = SPA_CONTAINER_OF(listener, struct node_data, node_need_input); - struct pw_core *core = node->core; + struct node_data *d = data; uint64_t cmd = 1; - pw_transport_add_event(data->trans, - &SPA_EVENT_INIT(core->type.event_transport.NeedInput)); - write(data->rtwritefd, &cmd, 8); + pw_transport_add_event(d->trans, + &SPA_EVENT_INIT(d->t->event_transport.NeedInput)); + write(d->rtwritefd, &cmd, 8); } -static void node_have_output(struct pw_listener *listener, struct pw_node *node) +static void node_have_output(void *data) { - struct node_data *data = SPA_CONTAINER_OF(listener, struct node_data, node_have_output); - struct pw_core *core = node->core; + struct node_data *d = data; uint64_t cmd = 1; - pw_transport_add_event(data->trans, - &SPA_EVENT_INIT(core->type.event_transport.HaveOutput)); - write(data->rtwritefd, &cmd, 8); + pw_transport_add_event(d->trans, + &SPA_EVENT_INIT(d->t->event_transport.HaveOutput)); + write(d->rtwritefd, &cmd, 8); } static void do_node_init(struct pw_proxy *proxy) @@ -933,6 +967,12 @@ static void do_node_init(struct pw_proxy *proxy) pw_client_node_proxy_done(data->node_proxy, 0, SPA_RESULT_OK); } +static const struct pw_node_callbacks node_callbacks = { + PW_VERSION_NODE_CALLBACKS, + .need_input = node_need_input, + .have_output = node_have_output, +}; + struct pw_proxy *pw_remote_export(struct pw_remote *remote, struct pw_node *node) { @@ -946,21 +986,25 @@ struct pw_proxy *pw_remote_export(struct pw_remote *remote, impl->type_client_node, PW_VERSION_CLIENT_NODE, &node->properties->dict, - sizeof(struct node_data), NULL); + sizeof(struct node_data)); if (proxy == NULL) return NULL; - data = proxy->user_data; + data = pw_proxy_get_user_data(proxy); + data->remote = remote; data->node = node; + data->core = pw_node_get_core(node); + data->t = pw_core_get_type(data->core); data->node_proxy = (struct pw_client_node_proxy *)proxy; + pw_array_init(&data->mem_ids, 64); pw_array_ensure_size(&data->mem_ids, sizeof(struct mem_id) * 64); pw_array_init(&data->buffer_ids, 32); pw_array_ensure_size(&data->buffer_ids, sizeof(struct buffer_id) * 64); - pw_signal_add(&node->need_input, &data->node_need_input, node_need_input); - pw_signal_add(&node->have_output, &data->node_have_output, node_have_output); - pw_client_node_proxy_add_listener(data->node_proxy, proxy, &client_node_events); + pw_node_add_callbacks(node, &data->node_callbacks, &node_callbacks, data); + + pw_client_node_proxy_add_listener(data->node_proxy, &data->node_listener, &client_node_events, proxy); do_node_init(proxy); return proxy; diff --git a/src/pipewire/remote.h b/src/pipewire/remote.h index 78854b7df..9c862114f 100644 --- a/src/pipewire/remote.h +++ b/src/pipewire/remote.h @@ -24,14 +24,6 @@ extern "C" { #endif -#include -#include -#include -#include -#include -#include -#include - /** \page page_remote_api Remote API * * \section sec_remote_api_overview Overview @@ -94,6 +86,25 @@ extern "C" { * * Use pw_remote_disconnect() to disconnect from the remote. */ +/** \class pw_remote + * + * \brief Represents a connection with the PipeWire server + * + * a \ref pw_remote is created and used to connect to the server. + * A \ref pw_proxy for the core object will automatically be created + * when connecting. + * + * See also \ref page_client_api + */ +struct pw_remote; + +#include +#include +#include +#include +#include +#include +#include /** \enum pw_remote_state The state of a \ref pw_remote \memberof pw_remote */ enum pw_remote_state { @@ -106,47 +117,18 @@ enum pw_remote_state { /** Convert a \ref pw_remote_state to a readable string \memberof pw_remote */ const char *pw_remote_state_as_string(enum pw_remote_state state); -/** \class pw_remote - * - * \brief Represents a connection with the PipeWire server - * - * a \ref pw_remote is created and used to connect to the server. - * A \ref pw_proxy for the core object will automatically be created - * when connecting. - * - * See also \ref page_client_api - */ -struct pw_remote { - struct pw_core *core; /**< core */ - struct spa_list link; /**< link in core remote_list */ - struct pw_properties *properties; /**< extra properties */ +struct pw_remote_callbacks { +#define PW_VERSION_REMOTE_CALLBACKS 0 + uint32_t version; - struct pw_core_proxy *core_proxy; /**< proxy for the core object */ - struct pw_map objects; /**< map of client side proxy objects - * indexed with the client id */ - struct pw_core_info *info; /**< info about the remote core */ - /** Signal emited when the core info changed */ - PW_SIGNAL(info_changed, (struct pw_listener *listener, struct pw_remote *remote)); - - /** Signal emited when a reply to a sync was received */ - PW_SIGNAL(sync_reply, (struct pw_listener *listener, struct pw_remote *remote, uint32_t seq)); - - uint32_t n_types; /**< number of client types */ - struct pw_map types; /**< client types */ - - struct spa_list proxy_list; /**< list of \ref pw_proxy objects */ - struct spa_list stream_list; /**< list of \ref pw_stream objects */ - struct spa_list remote_node_list; /**< list of \ref pw_remote_node objects */ - - struct pw_protocol_connection *conn; /**< the protocol connection */ - - enum pw_remote_state state; - char *error; - /** Signal emited when the state changes */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_remote *remote)); - - /** Signal emited when the remote is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_remote *remote)); + void (*destroy) (void *data); + /** emited when the remote core info changed */ + void (*info_changed) (void *data, const struct pw_core_info *info); + /** emited when a reply to a sync was received */ + void (*sync_reply) (void *data, uint32_t seq); + /** emited when the state changes */ + void (*state_changed) (void *data, enum pw_remote_state old, + enum pw_remote_state state, const char *error); }; /** Create a new unconnected remote \memberof pw_remote @@ -159,6 +141,18 @@ pw_remote_new(struct pw_core *core, /**< a \ref pw_core */ /** Destroy a remote \memberof pw_remote */ void pw_remote_destroy(struct pw_remote *remote); +/** Get the core used to construct this remote */ +struct pw_core *pw_remote_get_core(struct pw_remote *remote); + +/** Get the current state, \a error is set when state is \ref PW_REMOTE_STATE_ERROR */ +enum pw_remote_state pw_remote_get_state(struct pw_remote *remote, const char **error); + +/** Add callbacks to the remote */ +void pw_remote_add_callbacks(struct pw_remote *remote, + struct pw_callback_info *info, + const struct pw_remote_callbacks *callbacks, + void *data); + /** Connect to a remote PipeWire \memberof pw_remote * \return true on success. */ int pw_remote_connect(struct pw_remote *remote); @@ -168,14 +162,20 @@ int pw_remote_connect(struct pw_remote *remote); * \return true on success. */ int pw_remote_connect_fd(struct pw_remote *remote, int fd); +/** Get the core proxy, can only be called when connected */ +struct pw_core_proxy * pw_remote_get_core_proxy(struct pw_remote *remote); + +/** Get the remote core info, can only be called when connected */ +const struct pw_core_info *pw_remote_get_core_info(struct pw_remote *remote); + /** Disconnect from the remote PipeWire. \memberof pw_remote */ void pw_remote_disconnect(struct pw_remote *remote); /** Update the state of the remote, mostly used by protocols */ void pw_remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...); -struct pw_proxy *pw_remote_export(struct pw_remote *remote, - struct pw_node *node); +/** run a local node in a remote graph */ +struct pw_proxy *pw_remote_export(struct pw_remote *remote, struct pw_node *node); #ifdef __cplusplus } diff --git a/src/pipewire/resource.c b/src/pipewire/resource.c index dbdea341a..50f213cef 100644 --- a/src/pipewire/resource.c +++ b/src/pipewire/resource.c @@ -20,6 +20,7 @@ #include #include "pipewire/interfaces.h" +#include "pipewire/private.h" #include "pipewire/protocol.h" #include "pipewire/resource.h" @@ -34,8 +35,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client, uint32_t permissions, uint32_t type, uint32_t version, - size_t user_data_size, - pw_destroy_t destroy) + size_t user_data_size) { struct impl *impl; struct pw_resource *this; @@ -51,7 +51,7 @@ struct pw_resource *pw_resource_new(struct pw_client *client, this->type = type; this->version = version; - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); if (id == SPA_ID_INVALID) { id = pw_map_insert_new(&client->objects, this); @@ -63,12 +63,10 @@ struct pw_resource *pw_resource_new(struct pw_client *client, if (user_data_size > 0) this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); - this->destroy = destroy; - this->marshal = pw_protocol_get_marshal(client->protocol, type); pw_log_debug("resource %p: new for client %p id %u", this, client, id); - pw_signal_emit(&client->resource_added, client, this); + pw_callback_emit(&client->callback_list, struct pw_client_callbacks, resource_added, this); return this; @@ -78,17 +76,27 @@ struct pw_resource *pw_resource_new(struct pw_client *client, return NULL; } -int -pw_resource_set_implementation(struct pw_resource *resource, - void *object, const void *implementation) +void *pw_resource_get_user_data(struct pw_resource *resource) +{ + return resource->user_data; +} + +void pw_resource_add_callbacks(struct pw_resource *resource, + struct pw_callback_info *info, + const struct pw_resource_callbacks *callbacks, + void *data) +{ + pw_callback_add(&resource->callback_list, info, callbacks, data); +} + +void pw_resource_set_implementation(struct pw_resource *resource, + const void *implementation, + void *data) { struct pw_client *client = resource->client; - - resource->object = object; resource->implementation = implementation; - pw_signal_emit(&client->resource_impl, client, resource); - - return SPA_RESULT_OK; + resource->implementation_data = data; + pw_callback_emit(&client->callback_list, struct pw_client_callbacks, resource_impl, resource); } void pw_resource_destroy(struct pw_resource *resource) @@ -96,16 +104,14 @@ void pw_resource_destroy(struct pw_resource *resource) struct pw_client *client = resource->client; pw_log_trace("resource %p: destroy %u", resource, resource->id); - pw_signal_emit(&resource->destroy_signal, resource); + pw_callback_emit_na(&resource->callback_list, struct pw_resource_callbacks, destroy); pw_map_insert_at(&client->objects, resource->id, NULL); - pw_signal_emit(&client->resource_removed, client, resource); - - if (resource->destroy) - resource->destroy(resource); + pw_callback_emit(&client->callback_list, struct pw_client_callbacks, resource_removed, resource); if (client->core_resource) pw_core_resource_remove_id(client->core_resource, resource->id); + pw_log_trace("resource %p: free", resource); free(resource); } diff --git a/src/pipewire/resource.h b/src/pipewire/resource.h index 7d8bcefef..a0d90fb92 100644 --- a/src/pipewire/resource.h +++ b/src/pipewire/resource.h @@ -29,10 +29,6 @@ extern "C" { #include -#include -#include -#include - /** \page page_resource Resource * * \section sec_page_resource Overview @@ -48,6 +44,7 @@ extern "C" { * destroyed. * */ + /** \class pw_resource * * \brief Client owned objects @@ -57,29 +54,17 @@ extern "C" { * * See also \ref page_resource */ -struct pw_resource { - struct pw_core *core; /**< the core object */ - struct spa_list link; /**< link in object resource_list */ +struct pw_resource; - struct pw_client *client; /**< owner client */ +#include +#include +#include - uint32_t id; /**< per client unique id, index in client objects */ - uint32_t permissions; /**< resource permissions */ - uint32_t type; /**< type of the client interface */ - uint32_t version; /**< version of the client interface */ +struct pw_resource_callbacks { +#define PW_VERSION_RESOURCE_CALLBACKS 0 + uint32_t version; - void *object; - const void *implementation; - - pw_destroy_t destroy; /**< function to clean up the object */ - - const struct pw_protocol_marshal *marshal; - - /** Emited when the resource is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_resource *resource)); - - void *access_private; /**< private data for access control */ - void *user_data; /**< extra user data */ + void (*destroy) (void *data); }; /** Make a new resource for client */ @@ -89,19 +74,24 @@ pw_resource_new(struct pw_client *client, /**< the client owning the resource */ uint32_t permissions, /**< permissions on this resource */ uint32_t type, /**< interface of the resource */ uint32_t version, /**< requested interface version */ - size_t user_data_size, /**< extra user data size */ - pw_destroy_t destroy /**< destroy function for user data */); + size_t user_data_size /**< extra user data size */); +void *pw_resource_get_user_data(struct pw_resource *resource); -int -pw_resource_set_implementation(struct pw_resource *resource, - void *object, const void *implementation); +void pw_resource_add_callbacks(struct pw_resource *resource, + struct pw_callback_info *info, + const struct pw_resource_callbacks *callbacks, + void *data); + +void pw_resource_set_implementation(struct pw_resource *resource, + const void *implementation, + void *data); void pw_resource_destroy(struct pw_resource *resource); -#define pw_resource_do(r,type,method,...) ((type*) r->implementation)->method(r, __VA_ARGS__) -#define pw_resource_do_na(r,type,method) ((type*) r->implementation)->method(r) +#define pw_resource_do(r,type,method,...) ((type*) r->implementation)->method(r->implementation_data, __VA_ARGS__) +#define pw_resource_do_na(r,type,method) ((type*) r->implementation)->method(r->implementation_data) #define pw_resource_notify(r,type,event,...) ((type*) r->marshal->event_marshal)->event(r, __VA_ARGS__) #define pw_resource_notify_na(r,type,event) ((type*) r->marshal->event_marshal)->event(r) diff --git a/src/pipewire/stream.c b/src/pipewire/stream.c index ff0d57d72..fa838d80b 100644 --- a/src/pipewire/stream.c +++ b/src/pipewire/stream.c @@ -27,6 +27,7 @@ #include "spa/lib/debug.h" #include "pipewire/pipewire.h" +#include "pipewire/private.h" #include "pipewire/interfaces.h" #include "pipewire/array.h" #include "pipewire/stream.h" @@ -84,7 +85,8 @@ struct stream { struct pw_client_node_proxy *node_proxy; bool disconnecting; - struct pw_listener node_proxy_destroy; + struct pw_callback_info node_listener; + struct pw_callback_info proxy_callbacks; struct pw_transport *trans; @@ -129,7 +131,7 @@ static void clear_buffers(struct pw_stream *stream) pw_log_debug("stream %p: clear buffers", stream); pw_array_for_each(bid, &impl->buffer_ids) { - pw_signal_emit(&stream->remove_buffer, stream, bid->id); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, remove_buffer, bid->id); free(bid->buf); bid->buf = NULL; bid->used = false; @@ -141,18 +143,20 @@ static void clear_buffers(struct pw_stream *stream) static bool stream_set_state(struct pw_stream *stream, enum pw_stream_state state, char *error) { - bool res = stream->state != state; + enum pw_stream_state old = stream->state; + bool res = old != state; if (res) { if (stream->error) free(stream->error); stream->error = error; pw_log_debug("stream %p: update state from %s -> %s (%s)", stream, - pw_stream_state_as_string(stream->state), + pw_stream_state_as_string(old), pw_stream_state_as_string(state), stream->error); stream->state = state; - pw_signal_emit(&stream->state_changed, stream); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, state_changed, + old, state, error); } return res; } @@ -205,13 +209,7 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, this->name = strdup(name); impl->type_client_node = spa_type_map_get_id(remote->core->type.map, PW_TYPE_INTERFACE__ClientNode); - pw_signal_init(&this->destroy_signal); - pw_signal_init(&this->state_changed); - pw_signal_init(&this->format_changed); - pw_signal_init(&this->add_buffer); - pw_signal_init(&this->remove_buffer); - pw_signal_init(&this->new_buffer); - pw_signal_init(&this->need_buffer); + pw_callback_init(&this->callback_list); this->state = PW_STREAM_STATE_UNCONNECTED; @@ -231,6 +229,26 @@ struct pw_stream *pw_stream_new(struct pw_remote *remote, return NULL; } +enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error) +{ + if (error) + *error = stream->error; + return stream->state; +} + +struct pw_properties *pw_stream_get_properties(struct pw_stream *stream) +{ + return stream->properties; +} + +void pw_stream_add_callbacks(struct pw_stream *stream, + struct pw_callback_info *info, + const struct pw_stream_callbacks *callbacks, + void *data) +{ + pw_callback_add(&stream->callback_list, info, callbacks, data); +} + static void unhandle_socket(struct pw_stream *stream) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); @@ -291,14 +309,14 @@ void pw_stream_destroy(struct pw_stream *stream) pw_log_debug("stream %p: destroy", stream); - pw_signal_emit(&stream->destroy_signal, stream); + pw_callback_emit_na(&stream->callback_list, struct pw_stream_callbacks, destroy); unhandle_socket(stream); spa_list_remove(&stream->link); if (impl->node_proxy) - pw_signal_remove(&impl->node_proxy_destroy); + pw_callback_remove(&impl->proxy_callbacks); set_possible_formats(stream, 0, NULL); set_params(stream, 0, NULL); @@ -457,7 +475,7 @@ static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) pw_log_trace("stream %p: reuse buffer %u", stream, id); bid->used = false; spa_list_insert(impl->free.prev, &bid->link); - pw_signal_emit(&stream->new_buffer, stream, id); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, new_buffer, id); } } @@ -477,7 +495,8 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even if (input->buffer_id == SPA_ID_INVALID) continue; - pw_signal_emit(&stream->new_buffer, stream, input->buffer_id); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, + new_buffer, input->buffer_id); input->buffer_id = SPA_ID_INVALID; } send_need_input(stream); @@ -495,7 +514,7 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even } pw_log_trace("stream %p: process output", stream); impl->in_need_buffer = true; - pw_signal_emit(&stream->need_buffer, stream); + pw_callback_emit_na(&stream->callback_list, struct pw_stream_callbacks, need_buffer); impl->in_need_buffer = false; } else if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.ReuseBuffer) { struct pw_event_transport_reuse_buffer *p = @@ -589,7 +608,8 @@ handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_com send_need_input(stream); else { impl->in_need_buffer = true; - pw_signal_emit(&stream->need_buffer, stream); + pw_callback_emit_na(&stream->callback_list, struct pw_stream_callbacks, + need_buffer); impl->in_need_buffer = false; } stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL); @@ -614,37 +634,36 @@ handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_com } static void -client_node_set_props(void *object, uint32_t seq, const struct spa_props *props) +client_node_set_props(void *data, uint32_t seq, const struct spa_props *props) { pw_log_warn("set property not implemented"); } -static void client_node_event(void *object, const struct spa_event *event) +static void client_node_event(void *data, const struct spa_event *event) { pw_log_warn("unhandled node event %d", SPA_EVENT_TYPE(event)); } static void -client_node_add_port(void *object, uint32_t seq, enum spa_direction direction, uint32_t port_id) +client_node_add_port(void *data, uint32_t seq, enum spa_direction direction, uint32_t port_id) { pw_log_warn("add port not supported"); } static void -client_node_remove_port(void *object, uint32_t seq, enum spa_direction direction, uint32_t port_id) +client_node_remove_port(void *data, uint32_t seq, enum spa_direction direction, uint32_t port_id) { pw_log_warn("remove port not supported"); } static void -client_node_set_format(void *object, +client_node_set_format(void *data, uint32_t seq, enum spa_direction direction, uint32_t port_id, uint32_t flags, const struct spa_format *format) { - struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->object; - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct stream *impl = data; + struct pw_stream *stream = &impl->this; pw_log_debug("stream %p: format changed %d", stream, seq); @@ -653,7 +672,7 @@ client_node_set_format(void *object, impl->format = format ? spa_format_copy(format) : NULL; impl->pending_seq = seq; - pw_signal_emit(&stream->format_changed, stream, impl->format); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, format_changed, impl->format); if (format) stream_set_state(stream, PW_STREAM_STATE_READY, NULL); @@ -662,7 +681,7 @@ client_node_set_format(void *object, } static void -client_node_set_param(void *object, +client_node_set_param(void *data, uint32_t seq, enum spa_direction direction, uint32_t port_id, @@ -672,15 +691,14 @@ client_node_set_param(void *object, } static void -client_node_add_mem(void *object, +client_node_add_mem(void *data, enum spa_direction direction, uint32_t port_id, uint32_t mem_id, uint32_t type, int memfd, uint32_t flags, uint32_t offset, uint32_t size) { - struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->object; - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct stream *impl = data; + struct pw_stream *stream = &impl->this; struct mem_id *m; m = find_mem(stream, mem_id); @@ -702,14 +720,13 @@ client_node_add_mem(void *object, } static void -client_node_use_buffers(void *object, +client_node_use_buffers(void *data, uint32_t seq, enum spa_direction direction, uint32_t port_id, uint32_t n_buffers, struct pw_client_node_buffer *buffers) { - struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->object; - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct stream *impl = data; + struct pw_stream *stream = &impl->this; struct buffer_id *bid; uint32_t i, j, len; struct spa_buffer *b; @@ -804,7 +821,7 @@ client_node_use_buffers(void *object, pw_log_warn("unknown buffer data type %d", d->type); } } - pw_signal_emit(&stream->add_buffer, stream, bid->id); + pw_callback_emit(&stream->callback_list, struct pw_stream_callbacks, add_buffer, bid->id); } add_async_complete(stream, seq, SPA_RESULT_OK); @@ -817,15 +834,15 @@ client_node_use_buffers(void *object, } } -static void client_node_node_command(void *object, uint32_t seq, const struct spa_command *command) +static void client_node_node_command(void *data, uint32_t seq, const struct spa_command *command) { - struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->object; - handle_node_command(stream, seq, command); + struct stream *impl = data; + struct pw_stream *this = &impl->this; + handle_node_command(this, seq, command); } static void -client_node_port_command(void *object, +client_node_port_command(void *data, uint32_t direction, uint32_t port_id, const struct spa_command *command) @@ -833,12 +850,11 @@ client_node_port_command(void *object, pw_log_warn("port command not supported"); } -static void client_node_transport(void *object, uint32_t node_id, +static void client_node_transport(void *data, uint32_t node_id, int readfd, int writefd, int memfd, uint32_t offset, uint32_t size) { - struct pw_proxy *proxy = object; - struct pw_stream *stream = proxy->object; - struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + struct stream *impl = data; + struct pw_stream *stream = &impl->this; struct pw_transport_info info; stream->node_id = node_id; @@ -862,30 +878,37 @@ static void client_node_transport(void *object, uint32_t node_id, static const struct pw_client_node_events client_node_events = { PW_VERSION_CLIENT_NODE_EVENTS, - &client_node_transport, - &client_node_set_props, - &client_node_event, - &client_node_add_port, - &client_node_remove_port, - &client_node_set_format, - &client_node_set_param, - &client_node_add_mem, - &client_node_use_buffers, - &client_node_node_command, - &client_node_port_command, + .transport = client_node_transport, + .set_props = client_node_set_props, + .event = client_node_event, + .add_port = client_node_add_port, + .remove_port = client_node_remove_port, + .set_format = client_node_set_format, + .set_param = client_node_set_param, + .add_mem = client_node_add_mem, + .use_buffers = client_node_use_buffers, + .node_command = client_node_node_command, + .port_command = client_node_port_command, }; -static void on_node_proxy_destroy(struct pw_listener *listener, struct pw_proxy *proxy) +static void on_node_proxy_destroy(void *data) { - struct stream *impl = SPA_CONTAINER_OF(listener, struct stream, node_proxy_destroy); + struct stream *impl = data; struct pw_stream *this = &impl->this; impl->disconnecting = false; impl->node_proxy = NULL; - pw_signal_remove(&impl->node_proxy_destroy); + + pw_callback_remove(&impl->proxy_callbacks); + stream_set_state(this, PW_STREAM_STATE_UNCONNECTED, NULL); } +static const struct pw_proxy_callbacks proxy_callbacks = { + PW_VERSION_PROXY_CALLBACKS, + .destroy = on_node_proxy_destroy, +}; + bool pw_stream_connect(struct pw_stream *stream, enum pw_direction direction, @@ -918,14 +941,12 @@ pw_stream_connect(struct pw_stream *stream, "client-node", impl->type_client_node, PW_VERSION_CLIENT_NODE, - &stream->properties->dict, 0, NULL); + &stream->properties->dict, 0); if (impl->node_proxy == NULL) return false; - pw_client_node_proxy_add_listener(impl->node_proxy, stream, &client_node_events); - - pw_signal_add(&impl->node_proxy->proxy.destroy_signal, - &impl->node_proxy_destroy, on_node_proxy_destroy); + pw_client_node_proxy_add_listener(impl->node_proxy, &impl->node_listener, &client_node_events, impl); + pw_proxy_add_callbacks((struct pw_proxy*)impl->node_proxy, &impl->proxy_callbacks, &proxy_callbacks, impl); do_node_init(stream); diff --git a/src/pipewire/stream.h b/src/pipewire/stream.h index 1463ff717..77b02e3cc 100644 --- a/src/pipewire/stream.h +++ b/src/pipewire/stream.h @@ -20,11 +20,6 @@ #ifndef __PIPEWIRE_STREAM_H__ #define __PIPEWIRE_STREAM_H__ -#include -#include - -#include - #ifdef __cplusplus extern "C" { #endif @@ -156,6 +151,21 @@ extern "C" { * * Use \ref pw_stream_disconnect() to disconnect a stream after use. */ +/** \class pw_stream + * + * \brief PipeWire stream object class + * + * The stream object provides a convenient way to send and + * receive data streams from/to PipeWire. + * + * See also \ref page_streams and \ref page_client_api + */ +struct pw_stream; + +#include +#include + +#include /** \enum pw_stream_state The state of a stream \memberof pw_stream */ enum pw_stream_state { @@ -169,6 +179,30 @@ enum pw_stream_state { PW_STREAM_STATE_STREAMING = 5 /**< streaming */ }; +struct pw_stream_callbacks { +#define PW_VERSION_STREAM_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data); + /** when the stream state changes */ + void (*state_changed) (void *data, enum pw_stream_state old, + enum pw_stream_state state, const char *error); + /** when the format changed. The listener should call + * pw_stream_finish_format() from within this callbaclk or later to complete + * the format negotiation */ + void (*format_changed) (void *data, struct spa_format *format); + + /** when a new buffer was created for this stream */ + void (*add_buffer) (void *data, uint32_t id); + /** 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); +}; + /** Convert a stream state to a readable string \memberof pw_stream */ const char * pw_stream_state_as_string(enum pw_stream_state state); @@ -194,52 +228,6 @@ struct pw_time { int32_t rate; /**< the rate of \a ticks */ }; -/** \class pw_stream - * - * \brief PipeWire stream object class - * - * The stream object provides a convenient way to send and - * receive data streams from/to PipeWire. - * - * See also \ref page_streams and \ref page_client_api - */ -struct pw_stream { - struct pw_remote *remote; /**< the owner remote */ - struct spa_list link; /**< link in the remote */ - - char *name; /**< the name of the stream */ - uint32_t node_id; /**< node id for remote node, available from - * CONFIGURE state and higher */ - struct pw_properties *properties; /**< properties of the stream */ - - /** Emited when the stream is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_stream *stream)); - - enum pw_stream_state state; /**< stream state */ - char *error; /**< error reason when state is in error */ - /** Emited when the stream state changes */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_stream *stream)); - - /** Emited when the format changed. The listener should call - * pw_stream_finish_format() from within this signal or later to complete - * the format negotiation */ - PW_SIGNAL(format_changed, (struct pw_listener *listener, - struct pw_stream *stream, struct spa_format *format)); - - /** Emited when a new buffer was created for this stream */ - PW_SIGNAL(add_buffer, (struct pw_listener *listener, - struct pw_stream *stream, uint32_t id)); - /** Emited when a buffer was destroyed for this stream */ - PW_SIGNAL(remove_buffer, (struct pw_listener *listener, - struct pw_stream *stream, uint32_t id)); - /** Emited when a buffer can be reused (for playback streams) or - * is filled (for capture streams */ - PW_SIGNAL(new_buffer, (struct pw_listener *listener, - struct pw_stream *stream, uint32_t id)); - /** Emited when a buffer is needed (for playback streams) */ - PW_SIGNAL(need_buffer, (struct pw_listener *listener, struct pw_stream *stream)); -}; - /** Create a new unconneced \ref pw_stream \memberof pw_stream * \return a newly allocated \ref pw_stream */ struct pw_stream * @@ -250,6 +238,15 @@ pw_stream_new(struct pw_remote *remote, /**< a \ref pw_remote */ /** Destroy a stream \memberof pw_stream */ void pw_stream_destroy(struct pw_stream *stream); +void pw_stream_add_callbacks(struct pw_stream *stream, + struct pw_callback_info *info, + const struct pw_stream_callbacks *callbacks, + void *data); + +enum pw_stream_state pw_stream_get_state(struct pw_stream *stream, const char **error); + +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 true on success. * diff --git a/src/pipewire/thread-loop.c b/src/pipewire/thread-loop.c index 7f57e87ff..f4f487a45 100644 --- a/src/pipewire/thread-loop.c +++ b/src/pipewire/thread-loop.c @@ -23,11 +23,12 @@ #include "thread-loop.h" /** \cond */ -struct thread_loop { - struct pw_thread_loop this; - +struct pw_thread_loop { + struct pw_loop *loop; char *name; + struct pw_callback_list callback_list; + pthread_mutex_t lock; pthread_cond_t cond; pthread_cond_t accept_cond; @@ -47,14 +48,14 @@ struct thread_loop { static void before(const struct spa_loop_control_hooks *hooks) { - struct thread_loop *impl = SPA_CONTAINER_OF(hooks, struct thread_loop, hooks); - pthread_mutex_unlock(&impl->lock); + struct pw_thread_loop *this = SPA_CONTAINER_OF(hooks, struct pw_thread_loop, hooks); + pthread_mutex_unlock(&this->lock); } static void after(const struct spa_loop_control_hooks *hooks) { - struct thread_loop *impl = SPA_CONTAINER_OF(hooks, struct thread_loop, hooks); - pthread_mutex_lock(&impl->lock); + struct pw_thread_loop *this = SPA_CONTAINER_OF(hooks, struct pw_thread_loop, hooks); + pthread_mutex_lock(&this->lock); } static const struct spa_loop_control_hooks impl_hooks = { @@ -66,8 +67,8 @@ static const struct spa_loop_control_hooks impl_hooks = { static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data) { - struct thread_loop *impl = data; - impl->running = false; + struct pw_thread_loop *this = data; + this->running = false; } /** Create a new \ref pw_thread_loop @@ -86,32 +87,30 @@ static void do_stop(struct spa_loop_utils *utils, struct spa_source *source, uin */ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, const char *name) { - struct thread_loop *impl; struct pw_thread_loop *this; pthread_mutexattr_t attr; - impl = calloc(1, sizeof(struct thread_loop)); - if (impl == NULL) + this = calloc(1, sizeof(struct pw_thread_loop)); + if (this == NULL) return NULL; - this = &impl->this; - pw_log_debug("thread-loop %p: new", impl); + pw_log_debug("thread-loop %p: new", this); this->loop = loop; this->name = name ? strdup(name) : NULL; - impl->hooks = impl_hooks; - pw_loop_add_hooks(loop, &impl->hooks); + this->hooks = impl_hooks; + pw_loop_add_hooks(loop, &this->hooks); - pw_signal_init(&this->destroy_signal); + pw_callback_init(&this->callback_list); pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&impl->lock, &attr); - pthread_cond_init(&impl->cond, NULL); - pthread_cond_init(&impl->accept_cond, NULL); + pthread_mutex_init(&this->lock, &attr); + pthread_cond_init(&this->cond, NULL); + pthread_cond_init(&this->accept_cond, NULL); - impl->event = pw_loop_add_event(this->loop, do_stop, impl); + this->event = pw_loop_add_event(this->loop, do_stop, this); return this; } @@ -119,40 +118,51 @@ struct pw_thread_loop *pw_thread_loop_new(struct pw_loop *loop, const char *name /** Destroy a threaded loop \memberof pw_thread_loop */ void pw_thread_loop_destroy(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - pw_signal_emit(&loop->destroy_signal, loop); + pw_callback_emit_na(&loop->callback_list, struct pw_thread_loop_callbacks, destroy); pw_thread_loop_stop(loop); if (loop->name) free(loop->name); - pthread_mutex_destroy(&impl->lock); - pthread_cond_destroy(&impl->cond); - pthread_cond_destroy(&impl->accept_cond); + pthread_mutex_destroy(&loop->lock); + pthread_cond_destroy(&loop->cond); + pthread_cond_destroy(&loop->accept_cond); - spa_list_remove(&impl->hooks.link); + spa_list_remove(&loop->hooks.link); - free(impl); + free(loop); +} + +void pw_thread_loop_add_callbacks(struct pw_thread_loop *loop, + struct pw_callback_info *info, + const struct pw_thread_loop_callbacks *callbacks, + void *data) +{ + pw_callback_add(&loop->callback_list, info, callbacks, data); +} + +struct pw_loop * +pw_thread_loop_get_loop(struct pw_thread_loop *loop) +{ + return loop->loop; } static void *do_loop(void *user_data) { - struct thread_loop *impl = user_data; - struct pw_thread_loop *this = &impl->this; + struct pw_thread_loop *this = user_data; int res; - pthread_mutex_lock(&impl->lock); + pthread_mutex_lock(&this->lock); pw_log_debug("thread-loop %p: enter thread", this); pw_loop_enter(this->loop); - while (impl->running) { + while (this->running) { if ((res = pw_loop_iterate(this->loop, -1)) < 0) pw_log_warn("thread-loop %p: iterate error %d", this, res); } pw_log_debug("thread-loop %p: leave thread", this); pw_loop_leave(this->loop); - pthread_mutex_unlock(&impl->lock); + pthread_mutex_unlock(&this->lock); return NULL; } @@ -166,16 +176,14 @@ static void *do_loop(void *user_data) */ int pw_thread_loop_start(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - if (!impl->running) { + if (!loop->running) { int err; - impl->running = true; - if ((err = pthread_create(&impl->thread, NULL, do_loop, impl)) != 0) { - pw_log_warn("thread-loop %p: can't create thread: %s", impl, + loop->running = true; + if ((err = pthread_create(&loop->thread, NULL, do_loop, loop)) != 0) { + pw_log_warn("thread-loop %p: can't create thread: %s", loop, strerror(err)); - impl->running = false; + loop->running = false; return SPA_RESULT_ERROR; } } @@ -190,18 +198,16 @@ int pw_thread_loop_start(struct pw_thread_loop *loop) */ void pw_thread_loop_stop(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - pw_log_debug("thread-loop: %p stopping", impl); - if (impl->running) { - pw_log_debug("thread-loop: %p signal", impl); - pw_loop_signal_event(loop->loop, impl->event); - pw_log_debug("thread-loop: %p join", impl); - pthread_join(impl->thread, NULL); - pw_log_debug("thread-loop: %p joined", impl); - impl->running = false; + pw_log_debug("thread-loop: %p stopping", loop); + if (loop->running) { + pw_log_debug("thread-loop: %p signal", loop); + pw_loop_signal_event(loop->loop, loop->event); + pw_log_debug("thread-loop: %p join", loop); + pthread_join(loop->thread, NULL); + pw_log_debug("thread-loop: %p joined", loop); + loop->running = false; } - pw_log_debug("thread-loop: %p stopped", impl); + pw_log_debug("thread-loop: %p stopped", loop); } /** Lock the mutex associated with \a loop @@ -212,8 +218,7 @@ void pw_thread_loop_stop(struct pw_thread_loop *loop) */ void pw_thread_loop_lock(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - pthread_mutex_lock(&impl->lock); + pthread_mutex_lock(&loop->lock); } /** Unlock the mutex associated with \a loop @@ -224,8 +229,7 @@ void pw_thread_loop_lock(struct pw_thread_loop *loop) */ void pw_thread_loop_unlock(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - pthread_mutex_unlock(&impl->lock); + pthread_mutex_unlock(&loop->lock); } /** Signal the thread @@ -240,16 +244,14 @@ void pw_thread_loop_unlock(struct pw_thread_loop *loop) */ void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - if (impl->n_waiting > 0) - pthread_cond_broadcast(&impl->cond); + if (loop->n_waiting > 0) + pthread_cond_broadcast(&loop->cond); if (wait_for_accept) { - impl->n_waiting_for_accept++; + loop->n_waiting_for_accept++; - while (impl->n_waiting_for_accept > 0) - pthread_cond_wait(&impl->accept_cond, &impl->lock); + while (loop->n_waiting_for_accept > 0) + pthread_cond_wait(&loop->accept_cond, &loop->lock); } } @@ -261,12 +263,9 @@ void pw_thread_loop_signal(struct pw_thread_loop *loop, bool wait_for_accept) */ void pw_thread_loop_wait(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - impl->n_waiting++; - - pthread_cond_wait(&impl->cond, &impl->lock); - impl->n_waiting--; + loop->n_waiting++; + pthread_cond_wait(&loop->cond, &loop->lock); + loop->n_waiting--; } /** Signal the loop thread waiting for accept with \ref pw_thread_loop_signal() @@ -277,10 +276,8 @@ void pw_thread_loop_wait(struct pw_thread_loop *loop) */ void pw_thread_loop_accept(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - - impl->n_waiting_for_accept--; - pthread_cond_signal(&impl->accept_cond); + loop->n_waiting_for_accept--; + pthread_cond_signal(&loop->accept_cond); } /** Check if we are inside the thread of the loop @@ -292,6 +289,5 @@ void pw_thread_loop_accept(struct pw_thread_loop *loop) */ bool pw_thread_loop_in_thread(struct pw_thread_loop *loop) { - struct thread_loop *impl = SPA_CONTAINER_OF(loop, struct thread_loop, this); - return pthread_self() == impl->thread; + return pthread_self() == loop->thread; } diff --git a/src/pipewire/thread-loop.h b/src/pipewire/thread-loop.h index 954edcec2..b65442248 100644 --- a/src/pipewire/thread-loop.h +++ b/src/pipewire/thread-loop.h @@ -87,13 +87,13 @@ extern "C" { * * See also \ref page_thread_loop */ -struct pw_thread_loop { - struct pw_loop *loop; /**< the \ref pw_loop that is wrapped */ - char *name; /**< the thread name */ +struct pw_thread_loop; - /** Emited when the threaded loop is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, - struct pw_thread_loop *loop)); +struct pw_thread_loop_callbacks { +#define PW_VERSION_THREAD_LOOP_CALLBACKS 0 + uint32_t version; + + void (*destroy) (void *data); }; struct pw_thread_loop * @@ -102,6 +102,13 @@ pw_thread_loop_new(struct pw_loop *loop, const char *name); void pw_thread_loop_destroy(struct pw_thread_loop *loop); +void pw_thread_loop_add_callbacks(struct pw_thread_loop *loop, + struct pw_callback_info *info, + const struct pw_thread_loop_callbacks *callbacks, + void *data); +struct pw_loop * +pw_thread_loop_get_loop(struct pw_thread_loop *loop); + int pw_thread_loop_start(struct pw_thread_loop *loop); diff --git a/src/pipewire/work-queue.c b/src/pipewire/work-queue.c index 5eb0c3873..e0337b340 100644 --- a/src/pipewire/work-queue.c +++ b/src/pipewire/work-queue.c @@ -34,8 +34,8 @@ struct work_item { struct spa_list link; }; -struct impl { - struct pw_work_queue this; +struct pw_work_queue { + struct pw_loop *loop; struct spa_source *wakeup; uint32_t counter; @@ -49,33 +49,32 @@ struct impl { static void process_work_queue(struct spa_loop_utils *utils, struct spa_source *source, uint64_t count, void *data) { - struct impl *impl = data; - struct pw_work_queue *this = &impl->this; + struct pw_work_queue *this = data; struct work_item *item, *tmp; - spa_list_for_each_safe(item, tmp, &impl->work_list, link) { + spa_list_for_each_safe(item, tmp, &this->work_list, link) { if (item->seq != SPA_ID_INVALID) { pw_log_debug("work-queue %p: %d waiting for item %p %d", this, - impl->n_queued, item->obj, item->seq); + this->n_queued, item->obj, item->seq); continue; } if (item->res == SPA_RESULT_WAIT_SYNC && - item != spa_list_first(&impl->work_list, struct work_item, link)) { + item != spa_list_first(&this->work_list, struct work_item, link)) { pw_log_debug("work-queue %p: %d sync item %p not head", this, - impl->n_queued, item->obj); + this->n_queued, item->obj); continue; } spa_list_remove(&item->link); - impl->n_queued--; + this->n_queued--; if (item->func) { pw_log_debug("work-queue %p: %d process work item %p %d %d", this, - impl->n_queued, item->obj, item->seq, item->res); + this->n_queued, item->obj, item->seq, item->res); item->func(item->obj, item->data, item->res, item->id); } - spa_list_insert(impl->free_list.prev, &item->link); + spa_list_insert(this->free_list.prev, &item->link); } } @@ -88,20 +87,17 @@ static void process_work_queue(struct spa_loop_utils *utils, struct spa_source * */ struct pw_work_queue *pw_work_queue_new(struct pw_loop *loop) { - struct impl *impl; struct pw_work_queue *this; - impl = calloc(1, sizeof(struct impl)); - pw_log_debug("work-queue %p: new", impl); + this = calloc(1, sizeof(struct pw_work_queue)); + pw_log_debug("work-queue %p: new", this); - this = &impl->this; this->loop = loop; - pw_signal_init(&this->destroy_signal); - impl->wakeup = pw_loop_add_event(this->loop, process_work_queue, impl); + this->wakeup = pw_loop_add_event(this->loop, process_work_queue, this); - spa_list_init(&impl->work_list); - spa_list_init(&impl->free_list); + spa_list_init(&this->work_list); + spa_list_init(&this->free_list); return this; } @@ -113,23 +109,21 @@ struct pw_work_queue *pw_work_queue_new(struct pw_loop *loop) */ void pw_work_queue_destroy(struct pw_work_queue *queue) { - struct impl *impl = SPA_CONTAINER_OF(queue, struct impl, this); struct work_item *item, *tmp; - pw_log_debug("work-queue %p: destroy", impl); - pw_signal_emit(&queue->destroy_signal, queue); + pw_log_debug("work-queue %p: destroy", queue); - pw_loop_destroy_source(queue->loop, impl->wakeup); + pw_loop_destroy_source(queue->loop, queue->wakeup); - spa_list_for_each_safe(item, tmp, &impl->work_list, link) { + spa_list_for_each_safe(item, tmp, &queue->work_list, link) { pw_log_warn("work-queue %p: cancel work item %p %d %d", queue, item->obj, item->seq, item->res); free(item); } - spa_list_for_each_safe(item, tmp, &impl->free_list, link) + spa_list_for_each_safe(item, tmp, &queue->free_list, link) free(item); - free(impl); + free(queue); } /** Add an item to the work queue @@ -145,19 +139,18 @@ void pw_work_queue_destroy(struct pw_work_queue *queue) uint32_t pw_work_queue_add(struct pw_work_queue *queue, void *obj, int res, pw_work_func_t func, void *data) { - struct impl *impl = SPA_CONTAINER_OF(queue, struct impl, this); struct work_item *item; bool have_work = false; - if (!spa_list_is_empty(&impl->free_list)) { - item = spa_list_first(&impl->free_list, struct work_item, link); + if (!spa_list_is_empty(&queue->free_list)) { + item = spa_list_first(&queue->free_list, struct work_item, link); spa_list_remove(&item->link); } else { item = malloc(sizeof(struct work_item)); if (item == NULL) return SPA_ID_INVALID; } - item->id = ++impl->counter; + item->id = ++queue->counter; item->obj = obj; item->func = func; item->data = data; @@ -177,11 +170,11 @@ pw_work_queue_add(struct pw_work_queue *queue, void *obj, int res, pw_work_func_ have_work = true; pw_log_debug("work-queue %p: defer object %p", queue, obj); } - spa_list_insert(impl->work_list.prev, &item->link); - impl->n_queued++; + spa_list_insert(queue->work_list.prev, &item->link); + queue->n_queued++; if (have_work) - pw_loop_signal_event(impl->this.loop, impl->wakeup); + pw_loop_signal_event(queue->loop, queue->wakeup); return item->id; } @@ -195,11 +188,10 @@ pw_work_queue_add(struct pw_work_queue *queue, void *obj, int res, pw_work_func_ */ void pw_work_queue_cancel(struct pw_work_queue *queue, void *obj, uint32_t id) { - struct impl *impl = SPA_CONTAINER_OF(queue, struct impl, this); bool have_work = false; struct work_item *item; - spa_list_for_each(item, &impl->work_list, link) { + spa_list_for_each(item, &queue->work_list, link) { if ((id == SPA_ID_INVALID || item->id == id) && (obj == NULL || item->obj == obj)) { pw_log_debug("work-queue %p: cancel defer %d for object %p", queue, item->seq, item->obj); @@ -209,7 +201,7 @@ void pw_work_queue_cancel(struct pw_work_queue *queue, void *obj, uint32_t id) } } if (have_work) - pw_loop_signal_event(impl->this.loop, impl->wakeup); + pw_loop_signal_event(queue->loop, queue->wakeup); } /** Complete a work item @@ -223,10 +215,9 @@ void pw_work_queue_cancel(struct pw_work_queue *queue, void *obj, uint32_t id) bool pw_work_queue_complete(struct pw_work_queue *queue, void *obj, uint32_t seq, int res) { struct work_item *item; - struct impl *impl = SPA_CONTAINER_OF(queue, struct impl, this); bool have_work = false; - spa_list_for_each(item, &impl->work_list, link) { + spa_list_for_each(item, &queue->work_list, link) { if (item->obj == obj && item->seq == seq) { pw_log_debug("work-queue %p: found defered %d for object %p", queue, seq, obj); @@ -238,7 +229,7 @@ bool pw_work_queue_complete(struct pw_work_queue *queue, void *obj, uint32_t seq if (!have_work) { pw_log_debug("work-queue %p: no defered %d found for object %p", queue, seq, obj); } else { - pw_loop_signal_event(impl->this.loop, impl->wakeup); + pw_loop_signal_event(queue->loop, queue->wakeup); } return have_work; } diff --git a/src/pipewire/work-queue.h b/src/pipewire/work-queue.h index ccd8a5ded..aace0c7c4 100644 --- a/src/pipewire/work-queue.h +++ b/src/pipewire/work-queue.h @@ -24,20 +24,15 @@ extern "C" { #endif -#include - -typedef void (*pw_work_func_t) (void *obj, void *data, int res, uint32_t id); - /** \class pw_work_queue * * PipeWire work queue object */ -struct pw_work_queue { - struct pw_loop *loop; /**< the loop used for handling work */ +struct pw_work_queue; - /** Emited when the work queue is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_work_queue *queue)); -}; +#include + +typedef void (*pw_work_func_t) (void *obj, void *data, int res, uint32_t id); struct pw_work_queue * pw_work_queue_new(struct pw_loop *loop); diff --git a/src/tools/pipewire-monitor.c b/src/tools/pipewire-monitor.c index 8fb5863d2..dc315e315 100644 --- a/src/tools/pipewire-monitor.c +++ b/src/tools/pipewire-monitor.c @@ -30,19 +30,27 @@ struct data { bool running; struct pw_loop *loop; struct pw_core *core; - struct pw_remote *remote; - struct pw_registry_proxy *registry_proxy; - struct pw_listener on_info_changed; - struct pw_listener on_state_changed; + struct pw_remote *remote; + struct pw_callback_info remote_callbacks; + + struct pw_core_proxy *core_proxy; + + struct pw_registry_proxy *registry_proxy; + struct pw_callback_info registry_listener; }; struct proxy_data { + struct pw_proxy *proxy; uint32_t id; uint32_t parent_id; uint32_t permissions; uint32_t version; + uint32_t type; void *info; + pw_destroy_t destroy; + struct pw_callback_info proxy_listener; + struct pw_callback_info proxy_callbacks; }; static void print_properties(struct spa_dict *props, char mark) @@ -60,9 +68,8 @@ static void print_properties(struct spa_dict *props, char mark) #define MARK_CHANGE(f) ((print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ') -static void on_info_changed(struct pw_listener *listener, struct pw_remote *remote) +static void on_info_changed(void *data, const struct pw_core_info *info) { - struct pw_core_info *info = remote->info; bool print_all = true, print_mark = false; printf("\ttype: %s\n", PW_TYPE_INTERFACE__Core); @@ -79,7 +86,7 @@ static void on_info_changed(struct pw_listener *listener, struct pw_remote *remo static void module_event_info(void *object, struct pw_module_info *info) { struct pw_proxy *proxy = object; - struct proxy_data *data = proxy->user_data; + struct proxy_data *data = pw_proxy_get_user_data(proxy); bool print_all, print_mark; print_all = true; @@ -110,13 +117,13 @@ static void module_event_info(void *object, struct pw_module_info *info) static const struct pw_module_events module_events = { PW_VERSION_MODULE_EVENTS, - &module_event_info, + .info = module_event_info, }; static void node_event_info(void *object, struct pw_node_info *info) { struct pw_proxy *proxy = object; - struct proxy_data *data = proxy->user_data; + struct proxy_data *data = pw_proxy_get_user_data(proxy); bool print_all, print_mark; print_all = true; @@ -162,13 +169,13 @@ static void node_event_info(void *object, struct pw_node_info *info) static const struct pw_node_events node_events = { PW_VERSION_NODE_EVENTS, - &node_event_info + .info = node_event_info }; static void client_event_info(void *object, struct pw_client_info *info) { struct pw_proxy *proxy = object; - struct proxy_data *data = proxy->user_data; + struct proxy_data *data = pw_proxy_get_user_data(proxy); bool print_all, print_mark; print_all = true; @@ -196,13 +203,13 @@ static void client_event_info(void *object, struct pw_client_info *info) static const struct pw_client_events client_events = { PW_VERSION_CLIENT_EVENTS, - &client_event_info + .info = client_event_info }; static void link_event_info(void *object, struct pw_link_info *info) { struct pw_proxy *proxy = object; - struct proxy_data *data = proxy->user_data; + struct proxy_data *data = pw_proxy_get_user_data(proxy); bool print_all, print_mark; print_all = true; @@ -238,63 +245,58 @@ static void link_event_info(void *object, struct pw_link_info *info) static const struct pw_link_events link_events = { PW_VERSION_LINK_EVENTS, - &link_event_info + .info = link_event_info }; static void destroy_proxy (void *data) { - struct pw_proxy *proxy = data; - struct pw_core *core = proxy->remote->core; - struct proxy_data *user_data = proxy->user_data; + struct proxy_data *user_data = data; if (user_data->info == NULL) return; - if (proxy->type == core->type.core) { - pw_core_info_free (user_data->info); - } - else if (proxy->type == core->type.node) { - pw_node_info_free (user_data->info); - } - else if (proxy->type == core->type.module) { - pw_module_info_free (user_data->info); - } - else if (proxy->type == core->type.client) { - pw_client_info_free (user_data->info); - } - else if (proxy->type == core->type.link) { - pw_link_info_free (user_data->info); - } + if (user_data->destroy) + user_data->destroy(user_data->info); user_data->info = NULL; } +static const struct pw_proxy_callbacks proxy_callbacks = { + PW_VERSION_PROXY_CALLBACKS, + .destroy = destroy_proxy, +}; -static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, +static void registry_event_global(void *data, uint32_t id, uint32_t parent_id, uint32_t permissions, uint32_t type, uint32_t version) { - struct pw_proxy *proxy = object; - struct data *data = proxy->object; + struct data *d = data; + struct pw_proxy *proxy; uint32_t client_version; const void *events; - struct pw_core *core = data->core; + struct pw_core *core = d->core; + struct pw_type *t = pw_core_get_type(core); struct proxy_data *pd; + pw_destroy_t destroy; - if (type == core->type.node) { + if (type == t->node) { events = &node_events; client_version = PW_VERSION_NODE; + destroy = (pw_destroy_t) pw_node_info_free; } - else if (type == core->type.module) { + else if (type == t->module) { events = &module_events; client_version = PW_VERSION_MODULE; + destroy = (pw_destroy_t) pw_module_info_free; } - else if (type == core->type.client) { + else if (type == t->client) { events = &client_events; client_version = PW_VERSION_CLIENT; + destroy = (pw_destroy_t) pw_client_info_free; } - else if (type == core->type.link) { + else if (type == t->link) { events = &link_events; client_version = PW_VERSION_LINK; + destroy = (pw_destroy_t) pw_link_info_free; } else { printf("added:\n"); @@ -303,21 +305,25 @@ static void registry_event_global(void *object, uint32_t id, uint32_t parent_id, printf("\tpermissions: %c%c%c\n", permissions & PW_PERM_R ? 'r' : '-', permissions & PW_PERM_W ? 'w' : '-', permissions & PW_PERM_X ? 'x' : '-'); - printf("\ttype: %s (version %d)\n", spa_type_map_get_type(core->type.map, type), version); + printf("\ttype: %s (version %d)\n", spa_type_map_get_type(t->map, type), version); return; } - proxy = pw_registry_proxy_bind(data->registry_proxy, id, type, - client_version, sizeof(struct proxy_data), destroy_proxy); + proxy = pw_registry_proxy_bind(d->registry_proxy, id, type, + client_version, + sizeof(struct proxy_data)); if (proxy == NULL) goto no_mem; - pd = proxy->user_data; + pd = pw_proxy_get_user_data(proxy); + pd->proxy = proxy; pd->id = id; pd->parent_id = parent_id; pd->permissions = permissions; pd->version = version; - pw_proxy_add_listener(proxy, proxy, events); + pd->destroy = destroy; + pw_proxy_add_listener(proxy, &pd->proxy_listener, events, pd); + pw_proxy_add_callbacks(proxy, &pd->proxy_callbacks, &proxy_callbacks, pd); return; @@ -334,35 +340,46 @@ static void registry_event_global_remove(void *object, uint32_t id) static const struct pw_registry_events registry_events = { PW_VERSION_REGISTRY_EVENTS, - registry_event_global, - registry_event_global_remove, + .global = registry_event_global, + .global_remove = registry_event_global_remove, }; -static void on_state_changed(struct pw_listener *listener, struct pw_remote *remote) +static void on_state_changed(void *_data, enum pw_remote_state old, + enum pw_remote_state state, const char *error) { - struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed); + struct data *data = _data; + struct pw_type *t = pw_core_get_type(data->core); - switch (remote->state) { + switch (state) { case PW_REMOTE_STATE_ERROR: - printf("remote error: %s\n", remote->error); + printf("remote error: %s\n", error); data->running = false; break; case PW_REMOTE_STATE_CONNECTED: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); - data->registry_proxy = pw_core_proxy_get_registry(data->remote->core_proxy, - PW_VERSION_REGISTRY, 0, NULL); + data->core_proxy = pw_remote_get_core_proxy(data->remote); + data->registry_proxy = pw_core_proxy_get_registry(data->core_proxy, + t->registry, + PW_VERSION_REGISTRY, 0); pw_registry_proxy_add_listener(data->registry_proxy, - data, ®istry_events); + &data->registry_listener, + ®istry_events, data); break; default: - printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(state)); break; } } +static const struct pw_remote_callbacks remote_callbacks = { + PW_VERSION_REMOTE_CALLBACKS, + .info_changed = on_info_changed, + .state_changed = on_state_changed, +}; + int main(int argc, char *argv[]) { struct data data = { 0 }; @@ -374,9 +391,7 @@ int main(int argc, char *argv[]) data.core = pw_core_new(data.loop, NULL); data.remote = pw_remote_new(data.core, NULL); - pw_signal_add(&data.remote->info_changed, &data.on_info_changed, on_info_changed); - pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); - + pw_remote_add_callbacks(data.remote, &data.remote_callbacks, &remote_callbacks, &data); pw_remote_connect(data.remote); pw_loop_enter(data.loop);