From 847cef83b665fcdeb7d50fe02ea51df460c857c4 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 11 Jul 2017 12:24:03 +0200 Subject: [PATCH] Work on unifying client and server Remove context and extensions, make client API also use the core. Make a new pw_remote object that keeps connections with remote instances. Remove introspection API, it's just as easy to connect to the registry and get updates like that. Expand the protocol a little to make it useful for making listeners and connections. Move protocol specific connection to the module. Make some new convenience methods. Make a factory to create nodes from spa objects Add an example of a local pipeline displaying a v4l2 source. --- pipewire/client/context.c | 888 ------------------ pipewire/client/context.h | 208 ---- pipewire/client/extension.c | 143 --- pipewire/client/extension.h | 72 -- pipewire/client/introspect.c | 36 +- pipewire/client/introspect.h | 94 -- pipewire/client/meson.build | 7 - pipewire/client/protocol.c | 2 + pipewire/client/protocol.h | 28 + pipewire/client/proxy.c | 27 +- pipewire/client/proxy.h | 9 +- pipewire/client/stream.c | 59 +- pipewire/client/stream.h | 8 +- pipewire/client/subscribe.h | 63 -- pipewire/client/type.h | 21 + pipewire/daemon/main.c | 2 +- pipewire/examples/local-v4l2.c | 532 +++++++++++ pipewire/examples/meson.build | 9 +- pipewire/examples/video-play.c | 51 +- pipewire/examples/video-src.c | 53 +- pipewire/gst/gstpipewiredeviceprovider.c | 284 +++--- pipewire/gst/gstpipewiredeviceprovider.h | 11 +- pipewire/gst/gstpipewiresink.c | 99 +- pipewire/gst/gstpipewiresink.h | 5 +- pipewire/gst/gstpipewiresrc.c | 79 +- pipewire/gst/gstpipewiresrc.h | 5 +- pipewire/modules/extension-client-node.c | 66 -- pipewire/modules/extension-protocol-native.c | 66 -- pipewire/modules/meson.build | 6 +- pipewire/modules/module-client-node.c | 12 +- .../modules/module-client-node/client-node.c | 23 +- .../modules/module-client-node/client-node.h | 4 +- .../module-client-node/protocol-native.c | 264 ++---- pipewire/modules/module-flatpak.c | 22 +- pipewire/modules/module-jack.c | 10 +- pipewire/modules/module-protocol-native.c | 413 ++++++-- .../module-protocol-native}/connection.c | 139 ++- .../module-protocol-native}/connection.h | 14 +- .../module-protocol-native/protocol-native.c | 284 +++--- pipewire/modules/module-suspend-on-idle.c | 6 +- pipewire/modules/spa/meson.build | 10 + pipewire/modules/spa/module-node-factory.c | 117 +++ pipewire/modules/spa/spa-node.c | 26 +- pipewire/server/client.h | 4 + pipewire/server/core.c | 40 +- pipewire/server/core.h | 9 +- pipewire/server/link.c | 14 +- pipewire/server/link.h | 1 + pipewire/server/meson.build | 4 +- pipewire/server/node-factory.h | 6 +- pipewire/server/node.c | 33 +- pipewire/server/node.h | 8 +- pipewire/server/port.c | 49 +- pipewire/server/remote.c | 289 ++++++ pipewire/server/remote.h | 181 ++++ pipewire/server/resource.c | 1 + pipewire/server/resource.h | 1 + pipewire/tools/meson.build | 2 +- pipewire/tools/pipewire-monitor.c | 309 +++--- spa/include/spa/graph-scheduler1.h | 8 +- spa/include/spa/graph-scheduler3.h | 44 +- spa/include/spa/graph.h | 40 +- spa/tests/test-graph.c | 9 +- spa/tests/test-mixer.c | 12 +- spa/tests/test-perf.c | 6 +- 65 files changed, 2634 insertions(+), 2713 deletions(-) delete mode 100644 pipewire/client/context.c delete mode 100644 pipewire/client/context.h delete mode 100644 pipewire/client/extension.c delete mode 100644 pipewire/client/extension.h delete mode 100644 pipewire/client/subscribe.h create mode 100644 pipewire/examples/local-v4l2.c delete mode 100644 pipewire/modules/extension-client-node.c delete mode 100644 pipewire/modules/extension-protocol-native.c rename pipewire/{client => modules/module-protocol-native}/connection.c (73%) rename pipewire/{client => modules/module-protocol-native}/connection.h (87%) create mode 100644 pipewire/modules/spa/module-node-factory.c create mode 100644 pipewire/server/remote.c create mode 100644 pipewire/server/remote.h diff --git a/pipewire/client/context.c b/pipewire/client/context.c deleted file mode 100644 index 5209b164f..000000000 --- a/pipewire/client/context.c +++ /dev/null @@ -1,888 +0,0 @@ -/* 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. - */ - -#include -#include -#include -#include -#include - -#include "pipewire/client/pipewire.h" - -#include "pipewire/client/context.h" -#include "pipewire/client/extension.h" -#include "pipewire/client/introspect.h" -#include "pipewire/client/interfaces.h" -#include "pipewire/client/connection.h" -#include "pipewire/client/subscribe.h" - -#include - -/** \cond */ -struct context { - struct pw_context this; - - struct spa_support support[3]; - - bool no_proxy; - - int fd; - struct pw_connection *connection; - struct spa_source *source; - - bool disconnecting; - struct pw_listener need_flush; - struct spa_source *flush_event; -}; - -struct proxy_data { - void *info; -}; -/** \endcond */ - -const char *pw_context_state_as_string(enum pw_context_state state) -{ - switch (state) { - case PW_CONTEXT_STATE_ERROR: - return "error"; - case PW_CONTEXT_STATE_UNCONNECTED: - return "unconnected"; - case PW_CONTEXT_STATE_CONNECTING: - return "connecting"; - case PW_CONTEXT_STATE_CONNECTED: - return "connected"; - } - return "invalid-state"; -} - -static void -context_set_state(struct pw_context *context, enum pw_context_state state, const char *fmt, ...) -{ - if (context->state != state) { - - if (context->error) - free(context->error); - - if (fmt) { - va_list varargs; - - va_start(varargs, fmt); - if (vasprintf(&context->error, fmt, varargs) < 0) { - pw_log_debug("context %p: error formating message: %m", context); - context->error = NULL; - } - va_end(varargs); - } else { - context->error = NULL; - } - pw_log_debug("context %p: update state from %s -> %s (%s)", context, - pw_context_state_as_string(context->state), - pw_context_state_as_string(state), context->error); - - context->state = state; - pw_signal_emit(&context->state_changed, context); - } -} - -static void core_event_info(void *object, struct pw_core_info *info) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - enum pw_subscription_event event; - struct proxy_data *data = proxy->user_data; - - pw_log_debug("got core info"); - - if (data->info == NULL) - event = PW_SUBSCRIPTION_EVENT_NEW; - else - event = PW_SUBSCRIPTION_EVENT_CHANGE; - - data->info = pw_core_info_update(data->info, info); - - pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); -} - -static void core_event_done(void *object, uint32_t seq) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - - if (seq == 0) { - pw_core_do_sync(this->core_proxy, 1); - } else if (seq == 1) { - context_set_state(this, PW_CONTEXT_STATE_CONNECTED, NULL); - } -} - -static void core_event_error(void *object, uint32_t id, int res, const char *error, ...) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - context_set_state(this, PW_CONTEXT_STATE_ERROR, error); -} - -static void core_event_remove_id(void *object, uint32_t id) -{ - struct pw_proxy *core_proxy = object; - struct pw_context *this = core_proxy->context; - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&this->objects, id); - if (proxy) { - pw_log_debug("context %p: object remove %u", this, id); - pw_proxy_destroy(proxy); - } -} - -static void -core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const char **types) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - int i; - - for (i = 0; i < n_types; i++, first_id++) { - uint32_t this_id = spa_type_map_get_id(this->type.map, types[i]); - if (!pw_map_insert_at(&this->types, first_id, PW_MAP_ID_TO_PTR(this_id))) - pw_log_error("can't add type for client"); - } -} - -static const struct pw_core_events core_events = { - &core_event_update_types, - &core_event_done, - &core_event_error, - &core_event_remove_id, - &core_event_info, -}; - -static void module_event_info(void *object, struct pw_module_info *info) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - enum pw_subscription_event event; - struct proxy_data *data = proxy->user_data; - - pw_log_debug("got module info"); - - if (data->info == NULL) - event = PW_SUBSCRIPTION_EVENT_NEW; - else - event = PW_SUBSCRIPTION_EVENT_CHANGE; - - data->info = pw_module_info_update(data->info, info); - - pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); -} - -static const struct pw_module_events module_events = { - &module_event_info, -}; - -static void node_event_info(void *object, struct pw_node_info *info) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - enum pw_subscription_event event; - struct proxy_data *data = proxy->user_data; - - pw_log_debug("got node info"); - - if (data->info == NULL) - event = PW_SUBSCRIPTION_EVENT_NEW; - else - event = PW_SUBSCRIPTION_EVENT_CHANGE; - - data->info = pw_node_info_update(data->info, info); - - pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); -} - -static const struct pw_node_events node_events = { - &node_event_info -}; - -static void client_event_info(void *object, struct pw_client_info *info) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - enum pw_subscription_event event; - struct proxy_data *data = proxy->user_data; - - pw_log_debug("got client info"); - - if (data->info == NULL) - event = PW_SUBSCRIPTION_EVENT_NEW; - else - event = PW_SUBSCRIPTION_EVENT_CHANGE; - - data->info = pw_client_info_update(data->info, info); - - pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); -} - -static const struct pw_client_events client_events = { - &client_event_info -}; - -static void link_event_info(void *object, struct pw_link_info *info) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - enum pw_subscription_event event; - struct proxy_data *data = proxy->user_data; - - pw_log_debug("got link info"); - - if (data->info == NULL) - event = PW_SUBSCRIPTION_EVENT_NEW; - else - event = PW_SUBSCRIPTION_EVENT_CHANGE; - - data->info = pw_link_info_update(data->info, info); - - pw_signal_emit(&this->subscription, this, event, proxy->type, proxy->id); -} - -static const struct pw_link_events link_events = { - &link_event_info -}; - -static void -destroy_proxy (void *data) -{ - struct pw_proxy *proxy = data; - struct proxy_data *user_data = proxy->user_data; - - if (user_data->info == NULL) - return; - - if (proxy->type == proxy->context->type.core) { - pw_core_info_free (user_data->info); - } else if (proxy->type == proxy->context->type.node) { - pw_node_info_free (user_data->info); - } else if (proxy->type == proxy->context->type.module) { - pw_module_info_free (user_data->info); - } else if (proxy->type == proxy->context->type.client) { - pw_client_info_free (user_data->info); - } else if (proxy->type == proxy->context->type.link) { - pw_link_info_free (user_data->info); - } - user_data->info = NULL; -} - -static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version) -{ - struct pw_proxy *registry_proxy = object; - struct pw_context *this = registry_proxy->context; - struct context *impl = SPA_CONTAINER_OF(this, struct context, this); - struct pw_proxy *proxy = NULL; - uint32_t proxy_type, client_version; - const void *implementation; - - if (impl->no_proxy) - return; - - pw_log_debug("got global %u %s %u", id, type, version); - - if (!strcmp(type, PIPEWIRE_TYPE__Node)) { - proxy_type = this->type.node; - implementation = &node_events; - client_version = PW_VERSION_NODE; - } else if (!strcmp(type, PIPEWIRE_TYPE__Module)) { - proxy_type = this->type.module; - implementation = &module_events; - client_version = PW_VERSION_MODULE; - } else if (!strcmp(type, PIPEWIRE_TYPE__Client)) { - proxy_type = this->type.client; - implementation = &client_events; - client_version = PW_VERSION_CLIENT; - } else if (!strcmp(type, PIPEWIRE_TYPE__Link)) { - proxy_type = this->type.link; - implementation = &link_events; - client_version = PW_VERSION_LINK; - } else - return; - - proxy = pw_proxy_new(this, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data)); - if (proxy == NULL) - goto no_mem; - - pw_proxy_set_implementation(proxy, this, client_version, implementation, destroy_proxy); - - pw_registry_do_bind(registry_proxy, id, version, proxy->id); - - return; - - no_mem: - pw_log_error("context %p: failed to create proxy", this); - return; -} - -static void registry_event_global_remove(void *object, uint32_t id) -{ - struct pw_proxy *proxy = object; - struct pw_context *this = proxy->context; - - pw_log_debug("got global remove %u", id); - - pw_signal_emit(&this->subscription, this, PW_SUBSCRIPTION_EVENT_REMOVE, SPA_ID_INVALID, id); -} - -static const struct pw_registry_events registry_events = { - ®istry_event_global, - ®istry_event_global_remove -}; - -typedef bool(*demarshal_func_t) (void *object, void *data, size_t size); - -static void do_flush_event(struct spa_loop_utils *utils, struct spa_source *source, void *data) -{ - struct context *impl = data; - if (impl->connection) - if (!pw_connection_flush(impl->connection)) - pw_context_disconnect(&impl->this); -} - -static void on_need_flush(struct pw_listener *listener, struct pw_connection *connection) -{ - struct context *impl = SPA_CONTAINER_OF(listener, struct context, need_flush); - struct pw_context *this = &impl->this; - pw_loop_signal_event(this->loop, impl->flush_event); -} - -static void -on_context_data(struct spa_loop_utils *utils, - struct spa_source *source, int fd, enum spa_io mask, void *data) -{ - struct context *impl = data; - struct pw_context *this = &impl->this; - struct pw_connection *conn = impl->connection; - - if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { - context_set_state(this, PW_CONTEXT_STATE_ERROR, "connection closed"); - return; - } - - if (mask & SPA_IO_IN) { - uint8_t opcode; - uint32_t id; - uint32_t size; - void *message; - - while (!impl->disconnecting - && pw_connection_get_next(conn, &opcode, &id, &message, &size)) { - struct pw_proxy *proxy; - const demarshal_func_t *demarshal; - - pw_log_trace("context %p: got message %d from %u", this, opcode, id); - - proxy = pw_map_lookup(&this->objects, id); - if (proxy == NULL) { - pw_log_error("context %p: could not find proxy %u", this, id); - continue; - } - if (opcode >= proxy->iface->n_events) { - pw_log_error("context %p: invalid method %u for %u", this, opcode, - id); - continue; - } - - demarshal = proxy->iface->events; - if (demarshal[opcode]) { - if (!demarshal[opcode] (proxy, message, size)) - pw_log_error - ("context %p: invalid message received %u for %u", this, - opcode, id); - } else - pw_log_error("context %p: function %d not implemented on %u", this, - opcode, id); - - } - } -} - -struct pw_context *pw_context_new(struct pw_loop *loop, - const char *name, struct pw_properties *properties) -{ - struct context *impl; - struct pw_context *this; - - impl = calloc(1, sizeof(struct context)); - if (impl == NULL) - return NULL; - - impl->fd = -1; - - this = &impl->this; - pw_log_debug("context %p: new", impl); - - this->name = strdup(name); - - if (properties == NULL) - properties = pw_properties_new("application.name", name, NULL); - if (properties == NULL) - goto no_mem; - - pw_fill_context_properties(properties); - this->properties = properties; - - this->loop = loop; - - pw_type_init(&this->type); - - 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__MainLoop, this->loop->loop); - impl->support[2] = SPA_SUPPORT_INIT (SPA_TYPE__Log, pw_log_get()); - this->support = impl->support; - this->n_support = 3; - - impl->flush_event = pw_loop_add_event(loop, do_flush_event, impl); - - this->state = PW_CONTEXT_STATE_UNCONNECTED; - - pw_map_init(&this->objects, 64, 32); - pw_map_init(&this->types, 64, 32); - - spa_list_init(&this->extension_list); - spa_list_init(&this->stream_list); - spa_list_init(&this->proxy_list); - - pw_signal_init(&this->state_changed); - pw_signal_init(&this->subscription); - pw_signal_init(&this->destroy_signal); - - pw_extension_load(this, "libpipewire-module-protocol-native", NULL); - pw_extension_load(this, "libpipewire-module-client-node", NULL); - - this->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); - - return this; - - no_mem: - free(this->name); - free(impl); - return NULL; -} - -void pw_context_destroy(struct pw_context *context) -{ - struct context *impl = SPA_CONTAINER_OF(context, struct context, this); - struct pw_stream *stream, *t1; - struct pw_proxy *proxy, *t2; - struct pw_extension *ext, *t3; - - pw_log_debug("context %p: destroy", context); - pw_signal_emit(&context->destroy_signal, context); - - pw_loop_destroy_source(impl->this.loop, impl->flush_event); - - if (context->state != PW_CONTEXT_STATE_UNCONNECTED) - pw_context_disconnect(context); - - spa_list_for_each_safe(stream, t1, &context->stream_list, link) - pw_stream_destroy(stream); - spa_list_for_each_safe(proxy, t2, &context->proxy_list, link) - pw_proxy_destroy(proxy); - spa_list_for_each_safe(ext, t3, &context->extension_list, link) - pw_extension_destroy(ext); - - pw_map_clear(&context->objects); - pw_map_clear(&context->types); - - free(context->name); - if (context->properties) - pw_properties_free(context->properties); - free(context->error); - free(impl); -} - -bool pw_context_connect(struct pw_context *context, enum pw_context_flags flags) -{ - struct sockaddr_un addr; - socklen_t size; - const char *runtime_dir, *name = NULL; - int name_size, fd; - - if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { - context_set_state(context, - PW_CONTEXT_STATE_ERROR, - "connect failed: XDG_RUNTIME_DIR not set in the environment"); - return false; - } - - if (name == NULL) - name = getenv("PIPEWIRE_CORE"); - if (name == NULL) - name = "pipewire-0"; - - if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) - return false; - - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_LOCAL; - name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 1; - - if (name_size > (int) sizeof addr.sun_path) { - pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", - runtime_dir, name); - goto error_close; - }; - - size = offsetof(struct sockaddr_un, sun_path) + name_size; - - if (connect(fd, (struct sockaddr *) &addr, size) < 0) { - context_set_state(context, - PW_CONTEXT_STATE_ERROR, "connect failed: %s", strerror(errno)); - goto error_close; - } - - return pw_context_connect_fd(context, flags, fd); - - error_close: - close(fd); - return false; -} - -bool pw_context_connect_fd(struct pw_context *context, enum pw_context_flags flags, int fd) -{ - struct context *impl = SPA_CONTAINER_OF(context, struct context, this); - - context_set_state(context, PW_CONTEXT_STATE_CONNECTING, NULL); - - impl->connection = pw_connection_new(fd); - if (impl->connection == NULL) - goto error_close; - - context->protocol_private = impl->connection; - - pw_signal_add(&impl->connection->need_flush, &impl->need_flush, on_need_flush); - - impl->fd = fd; - - impl->source = pw_loop_add_io(context->loop, - fd, - SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, - false, on_context_data, impl); - - context->core_proxy = pw_proxy_new(context, 0, context->type.core, sizeof(struct proxy_data)); - if (context->core_proxy == NULL) - goto no_proxy; - - pw_proxy_set_implementation(context->core_proxy, context, PW_VERSION_CORE, - &core_events, destroy_proxy); - - pw_core_do_client_update(context->core_proxy, &context->properties->dict); - - if (!(flags & PW_CONTEXT_FLAG_NO_REGISTRY)) { - context->registry_proxy = pw_proxy_new(context, - SPA_ID_INVALID, context->type.registry, 0); - - if (context->registry_proxy == NULL) - goto no_registry; - - pw_proxy_set_implementation(context->registry_proxy, context, PW_VERSION_REGISTRY, - ®istry_events, NULL); - - pw_core_do_get_registry(context->core_proxy, context->registry_proxy->id); - } - impl->no_proxy = ! !(flags & PW_CONTEXT_FLAG_NO_PROXY); - - pw_core_do_sync(context->core_proxy, 0); - - return true; - - no_registry: - pw_proxy_destroy(context->core_proxy); - no_proxy: - pw_loop_destroy_source(context->loop, impl->source); - pw_connection_destroy(impl->connection); - error_close: - close(fd); - return false; -} - -void pw_context_disconnect(struct pw_context *context) -{ - struct context *impl = SPA_CONTAINER_OF(context, struct context, this); - - impl->disconnecting = true; - - if (impl->source) - pw_loop_destroy_source(context->loop, impl->source); - impl->source = NULL; - - if (context->registry_proxy) - pw_proxy_destroy(context->registry_proxy); - context->registry_proxy = NULL; - - if (context->core_proxy) - pw_proxy_destroy(context->core_proxy); - context->core_proxy = NULL; - - if (impl->connection) - pw_connection_destroy(impl->connection); - impl->connection = NULL; - context->protocol_private = NULL; - - if (impl->fd != -1) - close(impl->fd); - impl->fd = -1; - - context_set_state(context, PW_CONTEXT_STATE_UNCONNECTED, NULL); -} - -/** Get core information - * - * \param context A \ref pw_context - * \param cb the callback to call with the result - * \param user_data user data passed to \a cb - * - * \memberof pw_introspect - */ -void pw_context_get_core_info(struct pw_context *context, pw_core_info_cb_t cb, void *user_data) -{ - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&context->objects, 0); - if (proxy == NULL) { - cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.core) { - struct proxy_data *data = proxy->user_data; - struct pw_core_info *info = data->info; - if (info) { - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; - } - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} - -typedef void (*list_func_t) (struct pw_context *, int, void *, void *); - -static void do_list(struct pw_context *context, uint32_t type, list_func_t cb, void *user_data) -{ - union pw_map_item *item; - - pw_array_for_each(item, &context->objects.items) { - struct pw_proxy *proxy; - struct proxy_data *data; - - if (pw_map_item_is_free(item)) - continue; - - proxy = item->data; - if (proxy->type != type) - continue; - - data = proxy->user_data; - if (data->info) - cb(context, SPA_RESULT_OK, data->info, user_data); - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} - -/** Get all module information - * - * \param context A \ref pw_context - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for each module - * - * \memberof pw_introspect - */ -void -pw_context_list_module_info(struct pw_context *context, pw_module_info_cb_t cb, void *user_data) -{ - do_list(context, context->type.module, (list_func_t) cb, user_data); -} - -/** Get module information - * - * \param context A \ref pw_context - * \param id the client side id of the module to query - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for the module with \a id - * - * \memberof pw_introspect - */ -void -pw_context_get_module_info_by_id(struct pw_context *context, - uint32_t id, pw_module_info_cb_t cb, void *user_data) -{ - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&context->objects, id); - if (proxy == NULL) { - cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.module) { - struct proxy_data *data = proxy->user_data; - struct pw_module_info *info = data->info; - if (info) { - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; - } - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} - -/** Get all client information - * - * \param context A \ref pw_context - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for each client - * - * \memberof pw_introspect - */ -void -pw_context_list_client_info(struct pw_context *context, pw_client_info_cb_t cb, void *user_data) -{ - do_list(context, context->type.client, (list_func_t) cb, user_data); -} - -/** Get client information - * - * \param context A \ref pw_context - * \param id the client side id of the client to query - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for the client with \a id - * - * \memberof pw_introspect - */ -void -pw_context_get_client_info_by_id(struct pw_context *context, - uint32_t id, pw_client_info_cb_t cb, void *user_data) -{ - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&context->objects, id); - if (proxy == NULL) { - cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.client) { - struct proxy_data *data = proxy->user_data; - struct pw_client_info *info = data->info; - if (info) { - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; - } - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} - -/** Get all node information - * - * \param context A \ref pw_context - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for each node - * - * \memberof pw_introspect - */ -void pw_context_list_node_info(struct pw_context *context, pw_node_info_cb_t cb, void *user_data) -{ - do_list(context, context->type.node, (list_func_t) cb, user_data); -} - -/** Get node information - * - * \param context A \ref pw_context - * \param id the client side id of the node to query - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for the node with \a id - * - * \memberof pw_introspect - */ -void -pw_context_get_node_info_by_id(struct pw_context *context, - uint32_t id, pw_node_info_cb_t cb, void *user_data) -{ - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&context->objects, id); - if (proxy == NULL) { - cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.node) { - struct proxy_data *data = proxy->user_data; - struct pw_node_info *info = data->info; - if (info) { - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; - } - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} - -/** Get all link information - * - * \param context A \ref pw_context - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for each link - * - * \memberof pw_introspect - */ -void pw_context_list_link_info(struct pw_context *context, pw_link_info_cb_t cb, void *user_data) -{ - do_list(context, context->type.link, (list_func_t) cb, user_data); -} - -/** Get link information - * - * \param context A \ref pw_context - * \param id the client side id of the link to query - * \param cb the callback to call with the results - * \param user_data user data passed to \a cb - * - * \a cb is called for the link with \a id - * - * \memberof pw_introspect - */ -void -pw_context_get_link_info_by_id(struct pw_context *context, - uint32_t id, pw_link_info_cb_t cb, void *user_data) -{ - struct pw_proxy *proxy; - - proxy = pw_map_lookup(&context->objects, id); - if (proxy == NULL) { - cb(context, SPA_RESULT_INVALID_OBJECT_ID, NULL, user_data); - } else if (proxy->type == context->type.link) { - struct proxy_data *data = proxy->user_data; - struct pw_link_info *info = data->info; - if (info) { - cb(context, SPA_RESULT_OK, info, user_data); - info->change_mask = 0; - } - } - cb(context, SPA_RESULT_ENUM_END, NULL, user_data); -} diff --git a/pipewire/client/context.h b/pipewire/client/context.h deleted file mode 100644 index e73884f6a..000000000 --- a/pipewire/client/context.h +++ /dev/null @@ -1,208 +0,0 @@ -/* 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_CONTEXT_H__ -#define __PIPEWIRE_CONTEXT_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \page page_client_api Client API - * - * \section sec_client_api_overview Overview - * - * The client side API allows you to connect to the PipeWire server and - * perform actions on the PipeWire graph. This includes - * - * \li introspecting the objects on the server - * \li Creating nodes - * \li Linking nodes on their ports - * \li providing media to the server for playback or consumption - * \li retrieving media from the server - * - * \section sec_client_api_loop Event Loop Abstraction - * - * Most API is asynchronous and based around an event loop. Methods will - * start an operation which will cause a state change of the \ref pw_context - * object. Connect to the state_changed signal to be notified of these - * state changes. - * - * The most convenient way to deal with the asynchronous calls is probably - * with the thread loop (See \subpage page_thread_loop for more details). - * - * \subsection ssec_client_api_context_proxy Proxy - * - * Proxies are client side representations of server side resources. They - * allow communication between client and server objects. - * - * The context maintains a list of all proxies, including a core proxy - * object and a registry object. - * - * See also \subpage page_proxy - * - * \section sec_client_api_context Context - * - * \subsection ssec_context_create Create - * - * To create a new context use pw_context_new(). You will - * need to pass a \ref pw_loop implementation to use as the event loop. - * - * A typical loop would be created with pw_thread_loop_new() but - * other implementation are possible. - * - * You will also need to pass properties for the context. Use - * pw_fill_context_properties() to get a default set of properties. - * - * After creating the context, you can track the state of the context - * by listening for the state_changed signal. - * - * \subsection ssec_client_api_context_connect Connecting - * - * A context must be connected to a server before any operation can be - * issued. Calling pw_context_connect() will initiate the connection - * procedure. - * - * When connecting, the context will automatically create a registry - * proxy to get notified of server objects. This behaviour can be disabled - * by passing the \ref PW_CONTEXT_FLAG_NO_REGISTRY. You can create your - * own registry later from the core_proxy member of the context. - * - * The context will automatically create proxies for all remote objects - * and will bind to them. Use the subscription signal to reveive - * notifications about objects. You can also disable this behaviour - * with the \ref PW_CONTEXT_FLAG_NO_PROXY flag and manually bind to - * the objects you are interested in. - * - * \subsection ssec_client_api_context_functions Streams - * - * Data exchange with the PipeWire server is done with the \ref pw_stream - * object. \subpage page_streams - * - * \subsection ssec_client_api_context_disconnect Disconnect - * - * Use pw_context_disconnect() to disconnect from the server. - */ - -#include -#include -#include -#include -#include -#include -#include - -/** \enum pw_context_state The state of a \ref pw_context \memberof pw_context */ -enum pw_context_state { - PW_CONTEXT_STATE_ERROR = -1, /**< context is in error */ - PW_CONTEXT_STATE_UNCONNECTED = 0, /**< not connected */ - PW_CONTEXT_STATE_CONNECTING = 1, /**< connecting to PipeWire daemon */ - PW_CONTEXT_STATE_CONNECTED = 2, /**< context is connected and ready */ -}; - -/** Convert a \ref pw_context_state to a readable string \memberof pw_context */ -const char *pw_context_state_as_string(enum pw_context_state state); - -/** \enum pw_context_flags Extra flags passed to pw_context_connect() \memberof pw_context */ -enum pw_context_flags { - PW_CONTEXT_FLAG_NONE = 0, /**< no flags */ - PW_CONTEXT_FLAG_NO_REGISTRY = (1 << 0), /**< don't create the registry object */ - PW_CONTEXT_FLAG_NO_PROXY = (1 << 1), /**< don't automatically create proxies for - * server side objects */ -}; - -/** \class pw_context - * - * \brief Represents a connection with the PipeWire server - * - * a \ref pw_context 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_context { - char *name; /**< the application name */ - struct pw_properties *properties; /**< extra properties */ - - struct pw_type type; /**< the type map */ - - struct pw_loop *loop; /**< the loop */ - - struct spa_support *support; /**< support for spa plugins */ - uint32_t n_support; /**< number of support items */ - - struct pw_proxy *core_proxy; /**< proxy for the core object */ - struct pw_proxy *registry_proxy; /**< proxy for the registry object. Can - * be NULL when \ref PW_CONTEXT_FLAG_NO_PROXY - * was specified */ - struct pw_map objects; /**< map of client side proxy objects - * indexed with the client id */ - uint32_t n_types; /**< number of client types */ - struct pw_map types; /**< client types */ - - struct spa_list extension_list; /**< list of \ref pw_extension objects */ - struct spa_list stream_list; /**< list of \ref pw_stream objects */ - struct spa_list proxy_list; /**< list of \ref pw_proxy objects */ - - struct pw_protocol *protocol; /**< the protocol in use */ - void *protocol_private; /**< private data for the protocol */ - - enum pw_context_state state; /**< context state */ - char *error; /**< error string */ - /** Signal emited when the state changes */ - PW_SIGNAL(state_changed, (struct pw_listener *listener, struct pw_context *context)); - - /** Signal emited when a global is added/changed/removed */ - PW_SIGNAL(subscription, (struct pw_listener *listener, - struct pw_context *context, - enum pw_subscription_event event, uint32_t type, uint32_t id)); - - /** Signal emited when the context is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_context *context)); -}; - -/** Create a new unconnected context \memberof pw_context - * \return a new unconnected context */ -struct pw_context * -pw_context_new(struct pw_loop *loop, /**< a \ref pw_loop to use as event loop */ - const char *name, /**< an application name */ - struct pw_properties *properties /**< optional properties, ownership of - * the properties is taken.*/ ); - -/** Destroy a context \memberof pw_context */ -void pw_context_destroy(struct pw_context *context); - -/** Connect to the PipeWire daemon \memberof pw_context - * \return true on success. */ -bool pw_context_connect(struct pw_context *context, enum pw_context_flags flags); - -/** Connect to the PipeWire daemon on the given socket \memberof pw_context - * \param fd the connected socket to use - * \return true on success. */ -bool pw_context_connect_fd(struct pw_context *context, enum pw_context_flags flags, int fd); - -/** Disconnect from the daemon. \memberof pw_context */ -void pw_context_disconnect(struct pw_context *context); - -#ifdef __cplusplus -} -#endif - -#endif /* __PIPEWIRE_CONTEXT_H__ */ diff --git a/pipewire/client/extension.c b/pipewire/client/extension.c deleted file mode 100644 index 9fb773165..000000000 --- a/pipewire/client/extension.c +++ /dev/null @@ -1,143 +0,0 @@ -/* PipeWire - * Copyright (C) 2016 Axis Communications - * @author Linus Svensson - * - * 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. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -#include "pipewire/client/pipewire.h" -#include "pipewire/client/interfaces.h" -#include "pipewire/client/utils.h" -#include "pipewire/client/extension.h" - -/** \cond */ -struct impl { - struct pw_extension this; - void *hnd; -}; -/** \endcond */ - -/** Load an extension \memberof pw_extension - * - * \param context a \ref pw_context - * \param name name of the extension to load - * \param args A string with arguments for the extension - * \param[out] err Return location for an error string, or NULL - * \return A \ref pw_extension if the extension could be loaded, or NULL on failure. - */ -struct pw_extension *pw_extension_load(struct pw_context *context, - const char *name, const char *args) -{ - struct pw_extension *this; - struct impl *impl; - void *hnd; - char *filename = NULL; - const char *module_dir; - pw_extension_init_func_t init_func; - - module_dir = getenv("PIPEWIRE_MODULE_DIR"); - if (module_dir == NULL) - module_dir = MODULEDIR; - - pw_log_debug("PIPEWIRE_MODULE_DIR set to: %s", module_dir); - - if (asprintf(&filename, "%s/%s.so", module_dir, name) < 0) - goto no_filename; - - pw_log_debug("trying to load extension: %s (%s)", name, filename); - - hnd = dlopen(filename, RTLD_NOW | RTLD_LOCAL); - - if (hnd == NULL) - goto open_failed; - - if ((init_func = dlsym(hnd, PIPEWIRE_SYMBOL_EXTENSION_INIT)) == NULL) - goto no_pw_extension; - - impl = calloc(1, sizeof(struct impl)); - if (impl == NULL) - goto no_mem; - - impl->hnd = hnd; - - this = &impl->this; - this->context = context; - this->filename = filename; - this->args = args ? strdup(args) : NULL; - this->props = NULL; - - pw_signal_init(&this->destroy_signal); - - if (!init_func(this, (char *) args)) - goto init_failed; - - spa_list_insert(&context->extension_list, &this->link); - - pw_log_debug("loaded extension: %s", filename); - - return this; - - no_filename: - pw_log_error("Can't create filename: %m"); - return NULL; - open_failed: - pw_log_error("Failed to open module: \"%s\" %s", filename, dlerror()); - free(filename); - return NULL; - no_pw_extension: - pw_log_error("\"%s\" is not a pipewire extension", name); - dlclose(hnd); - free(filename); - return NULL; - no_mem: - pw_log_error("no memory"); - dlclose(hnd); - free(filename); - return NULL; - init_failed: - pw_log_error("\"%s\" failed to initialize", name); - pw_extension_destroy(this); - return NULL; -} - -/** Destroy a extension - * \param extension the extension to destroy - * \memberof pw_extension - */ -void pw_extension_destroy(struct pw_extension *extension) -{ - struct impl *impl = SPA_CONTAINER_OF(extension, struct impl, this); - - pw_signal_emit(&extension->destroy_signal, extension); - - if (extension->filename) - free((char *) extension->filename); - if (extension->args) - free((char *) extension->args); - if (extension->props) - pw_properties_free(extension->props); - dlclose(impl->hnd); - free(impl); -} diff --git a/pipewire/client/extension.h b/pipewire/client/extension.h deleted file mode 100644 index c6c2f9b67..000000000 --- a/pipewire/client/extension.h +++ /dev/null @@ -1,72 +0,0 @@ -/* PipeWire - * Copyright (C) 2016 Axis Communications - * @author Linus Svensson - * - * 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_EXTENSION_H__ -#define __PIPEWIRE_EXTENSION_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#include - -#define PIPEWIRE_SYMBOL_EXTENSION_INIT "pipewire__extension_init" - -/** \class pw_extension - * - * A dynamically loadable extension - */ -struct pw_extension { - struct pw_context *context; /**< the client context */ - struct spa_list link; /**< link in the context extension_list */ - - const char *filename; /**< filename of extension */ - const char *args; /**< argument for the extension */ - struct pw_properties *props; /**< extra properties */ - - void *user_data; /**< extension user_data */ - - /** Emited when the extension is destroyed */ - PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_extension *extension)); -}; - -/** Module init function signature \memberof pw_extension - * - * \param extension A \ref pw_extension - * \param args Arguments to the extension - * \return true on success, false otherwise - * - * A extension should provide an init function with this signature. This function - * will be called when a extension is loaded. - */ -typedef bool (*pw_extension_init_func_t) (struct pw_extension *extension, char *args); - -struct pw_extension * -pw_extension_load(struct pw_context *context, - const char *name, const char *args); - -void -pw_extension_destroy(struct pw_extension *extension); - -#ifdef __cplusplus -} -#endif - -#endif /* __PIPEWIRE_EXTENSION_H__ */ diff --git a/pipewire/client/introspect.c b/pipewire/client/introspect.c index b9cd8bbdc..27c0e9137 100644 --- a/pipewire/client/introspect.c +++ b/pipewire/client/introspect.c @@ -21,7 +21,7 @@ #include "pipewire/client/pipewire.h" -#include "pipewire/client/context.h" +#include "pipewire/server/remote.h" #include "pipewire/client/subscribe.h" const char *pw_node_state_as_string(enum pw_node_state state) @@ -118,8 +118,6 @@ static struct spa_dict *pw_spa_dict_copy(struct spa_dict *dict) struct pw_core_info *pw_core_info_update(struct pw_core_info *info, const struct pw_core_info *update) { - uint64_t change_mask; - if (update == NULL) return info; @@ -127,12 +125,9 @@ struct pw_core_info *pw_core_info_update(struct pw_core_info *info, info = calloc(1, sizeof(struct pw_core_info)); if (info == NULL) return NULL; - change_mask = ~0; - } else { - change_mask = info->change_mask | update->change_mask; } info->id = update->id; - info->change_mask = change_mask; + info->change_mask = update->change_mask; if (update->change_mask & (1 << 0)) { if (info->user_name) @@ -182,7 +177,6 @@ void pw_core_info_free(struct pw_core_info *info) struct pw_node_info *pw_node_info_update(struct pw_node_info *info, const struct pw_node_info *update) { - uint64_t change_mask; int i; if (update == NULL) @@ -192,12 +186,9 @@ struct pw_node_info *pw_node_info_update(struct pw_node_info *info, info = calloc(1, sizeof(struct pw_node_info)); if (info == NULL) return NULL; - change_mask = ~0; - } else { - change_mask = info->change_mask | update->change_mask; } info->id = update->id; - info->change_mask = change_mask; + info->change_mask = update->change_mask; if (update->change_mask & (1 << 0)) { if (info->name) @@ -285,8 +276,6 @@ void pw_node_info_free(struct pw_node_info *info) struct pw_module_info *pw_module_info_update(struct pw_module_info *info, const struct pw_module_info *update) { - uint64_t change_mask; - if (update == NULL) return info; @@ -294,12 +283,9 @@ struct pw_module_info *pw_module_info_update(struct pw_module_info *info, info = calloc(1, sizeof(struct pw_module_info)); if (info == NULL) return NULL; - change_mask = ~0; - } else { - change_mask = info->change_mask | update->change_mask; } info->id = update->id; - info->change_mask = change_mask; + info->change_mask = update->change_mask; if (update->change_mask & (1 << 0)) { if (info->name) @@ -341,8 +327,6 @@ void pw_module_info_free(struct pw_module_info *info) struct pw_client_info *pw_client_info_update(struct pw_client_info *info, const struct pw_client_info *update) { - uint64_t change_mask; - if (update == NULL) return info; @@ -350,12 +334,9 @@ struct pw_client_info *pw_client_info_update(struct pw_client_info *info, info = calloc(1, sizeof(struct pw_client_info)); if (info == NULL) return NULL; - change_mask = ~0; - } else { - change_mask = info->change_mask | update->change_mask; } info->id = update->id; - info->change_mask = change_mask; + info->change_mask = update->change_mask; if (update->change_mask & (1 << 0)) { if (info->props) @@ -375,8 +356,6 @@ void pw_client_info_free(struct pw_client_info *info) struct pw_link_info *pw_link_info_update(struct pw_link_info *info, const struct pw_link_info *update) { - uint64_t change_mask; - if (update == NULL) return info; @@ -384,12 +363,9 @@ struct pw_link_info *pw_link_info_update(struct pw_link_info *info, info = calloc(1, sizeof(struct pw_link_info)); if (info == NULL) return NULL; - change_mask = ~0; - } else { - change_mask = info->change_mask | update->change_mask; } info->id = update->id; - info->change_mask = change_mask; + info->change_mask = update->change_mask; if (update->change_mask & (1 << 0)) info->output_node_id = update->output_node_id; diff --git a/pipewire/client/introspect.h b/pipewire/client/introspect.h index ec2e05faa..fdeef50c2 100644 --- a/pipewire/client/introspect.h +++ b/pipewire/client/introspect.h @@ -27,9 +27,6 @@ extern "C" { #endif -struct pw_context; - -#include #include /** \enum pw_node_state The different node states \memberof pw_node */ @@ -102,19 +99,6 @@ pw_core_info_update(struct pw_core_info *info, /** Free a \ref pw_core_info \memberof pw_introspect */ void pw_core_info_free(struct pw_core_info *info); -/** Callback with information about the PipeWire core - * \param c A \ref pw_context - * \param res A result code - * \param info a \ref pw_core_info - * \param user_data user data as passed to \ref pw_context_get_core_info() - * - * \memberof pw_introspect - */ -typedef void (*pw_core_info_cb_t) (struct pw_context *c, - int res, const struct pw_core_info *info, void *user_data); - -void pw_context_get_core_info(struct pw_context *context, pw_core_info_cb_t cb, void *user_data); - /** The module information. Extra information can be added in later versions \memberof pw_introspect */ struct pw_module_info { uint32_t id; /**< server side id of the module */ @@ -133,28 +117,6 @@ pw_module_info_update(struct pw_module_info *info, /** Free a \ref pw_module_info \memberof pw_introspect */ void pw_module_info_free(struct pw_module_info *info); - - -/** Callback with information about a module - * \param c A \ref pw_context - * \param res A result code - * \param info a \ref pw_module_info - * \param user_data user data as passed to \ref pw_context_list_module_info() - * - * \memberof pw_introspect - */ -typedef void (*pw_module_info_cb_t) (struct pw_context *c, - int res, const struct pw_module_info *info, void *user_data); - -void -pw_context_list_module_info(struct pw_context *context, - pw_module_info_cb_t cb, void *user_data); - - -void -pw_context_get_module_info_by_id(struct pw_context *context, - uint32_t id, pw_module_info_cb_t cb, void *user_data); - /** The client information. Extra information can be added in later versions \memberof pw_introspect */ struct pw_client_info { uint32_t id; /**< server side id of the client */ @@ -171,25 +133,6 @@ pw_client_info_update(struct pw_client_info *info, void pw_client_info_free(struct pw_client_info *info); -/** Callback with information about a client - * \param c A \ref pw_context - * \param res A result code - * \param info a \ref pw_client_info - * \param user_data user data as passed to \ref pw_context_list_client_info() - * - * \memberof pw_introspect - */ -typedef void (*pw_client_info_cb_t) (struct pw_context *c, - int res, const struct pw_client_info *info, void *user_data); - -void -pw_context_list_client_info(struct pw_context *context, - pw_client_info_cb_t cb, void *user_data); - -void -pw_context_get_client_info_by_id(struct pw_context *context, - uint32_t id, pw_client_info_cb_t cb, void *user_data); - /** The node information. Extra information can be added in later versions \memberof pw_introspect */ struct pw_node_info { uint32_t id; /**< server side id of the node */ @@ -215,24 +158,6 @@ pw_node_info_update(struct pw_node_info *info, void pw_node_info_free(struct pw_node_info *info); -/** Callback with information about a node - * \param c A \ref pw_context - * \param res A result code - * \param info a \ref pw_node_info - * \param user_data user data as passed to \ref pw_context_list_node_info() - * - * \memberof pw_introspect - */ -typedef void (*pw_node_info_cb_t) (struct pw_context *c, - int res, const struct pw_node_info *info, void *user_data); - -void -pw_context_list_node_info(struct pw_context *context, pw_node_info_cb_t cb, void *user_data); - -void -pw_context_get_node_info_by_id(struct pw_context *context, - uint32_t id, pw_node_info_cb_t cb, void *user_data); - /** The link information. Extra information can be added in later versions \memberof pw_introspect */ struct pw_link_info { @@ -252,25 +177,6 @@ pw_link_info_update(struct pw_link_info *info, void pw_link_info_free(struct pw_link_info *info); - -/** Callback with information about a link - * \param c A \ref pw_context - * \param res A result code - * \param info a \ref pw_link_info - * \param user_data user data as passed to \ref pw_context_list_link_info() - * - * \memberof pw_introspect - */ -typedef void (*pw_link_info_cb_t) (struct pw_context *c, - int res, const struct pw_link_info *info, void *user_data); - -void -pw_context_list_link_info(struct pw_context *context, pw_link_info_cb_t cb, void *user_data); - -void -pw_context_get_link_info_by_id(struct pw_context *context, - uint32_t id, pw_link_info_cb_t cb, void *user_data); - #ifdef __cplusplus } #endif diff --git a/pipewire/client/meson.build b/pipewire/client/meson.build index a9c258b67..f455d4793 100644 --- a/pipewire/client/meson.build +++ b/pipewire/client/meson.build @@ -1,8 +1,5 @@ pipewire_headers = [ 'array.h', - 'connection.h', - 'context.h', - 'extension.h', 'interfaces.h', 'introspect.h', 'log.h', @@ -16,7 +13,6 @@ pipewire_headers = [ 'rtkit.h', 'sig.h', 'stream.h', - 'subscribe.h', 'thread-loop.h', 'transport.h', 'type.h', @@ -24,9 +20,6 @@ pipewire_headers = [ ] pipewire_sources = [ - 'connection.c', - 'context.c', - 'extension.c', 'introspect.c', 'log.c', 'loop.c', diff --git a/pipewire/client/protocol.c b/pipewire/client/protocol.c index 32ca2dc15..1b2aab607 100644 --- a/pipewire/client/protocol.c +++ b/pipewire/client/protocol.c @@ -46,6 +46,8 @@ struct pw_protocol *pw_protocol_get(const char *name) protocol = calloc(1, sizeof(struct pw_protocol)); protocol->name = name; spa_list_init(&protocol->iface_list); + spa_list_init(&protocol->connection_list); + spa_list_init(&protocol->listener_list); spa_list_insert(impl->protocol_list.prev, &protocol->link); pw_log_info("Created protocol %s", name); diff --git a/pipewire/client/protocol.h b/pipewire/client/protocol.h index 2c888a617..c709bfe3e 100644 --- a/pipewire/client/protocol.h +++ b/pipewire/client/protocol.h @@ -29,9 +29,27 @@ extern "C" { #include #include +#include #define PW_TYPE_PROTOCOL__Native PW_TYPE_PROTOCOL_BASE "Native" +struct pw_protocol_connection { + struct spa_list link; + struct pw_remote *remote; + + int (*connect) (struct pw_protocol_connection *conn); + int (*connect_fd) (struct pw_protocol_connection *conn, int fd); + int (*disconnect) (struct pw_protocol_connection *conn); + int (*destroy) (struct pw_protocol_connection *conn); +}; + +struct pw_protocol_listener { + struct spa_list link; + struct pw_core *core; + + int (*destroy) (struct pw_protocol_listener *listen); +}; + struct pw_protocol_iface { struct spa_list link; const struct pw_interface *client_iface; @@ -42,6 +60,16 @@ struct pw_protocol { struct spa_list link; const char *name; struct spa_list iface_list; + struct spa_list connection_list; + struct spa_list listener_list; + + struct pw_protocol_connection * (*new_connection) (struct pw_protocol *protocol, + struct pw_remote *remote, + struct pw_properties *properties); + struct pw_protocol_listener * (*add_listener) (struct pw_protocol *protocol, + struct pw_core *core, + struct pw_properties *properties); + void *protocol_private; }; struct pw_protocol *pw_protocol_get(const char *name); diff --git a/pipewire/client/proxy.c b/pipewire/client/proxy.c index 9f0db6ec5..f4ca87daa 100644 --- a/pipewire/client/proxy.c +++ b/pipewire/client/proxy.c @@ -19,6 +19,7 @@ #include #include +#include /** \cond */ struct proxy { @@ -28,7 +29,7 @@ struct proxy { /** Create a proxy object with a given id and type * - * \param context Context object + * \param remote Remote object * \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 @@ -36,11 +37,11 @@ struct proxy { * This function creates a new proxy object with the supplied id and type. The * proxy object will have an id assigned from the client id space. * - * \sa pw_context + * \sa pw_remote * * \memberof pw_proxy */ -struct pw_proxy *pw_proxy_new(struct pw_context *context, +struct pw_proxy *pw_proxy_new(struct pw_remote *remote, uint32_t id, uint32_t type, size_t user_data_size) { @@ -52,14 +53,14 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context, return NULL; this = &impl->this; - this->context = context; + this->remote = remote; this->type = type; pw_signal_init(&this->destroy_signal); if (id == SPA_ID_INVALID) { - id = pw_map_insert_new(&context->objects, this); - } else if (!pw_map_insert_at(&context->objects, id, this)) + id = pw_map_insert_new(&remote->objects, this); + } else if (!pw_map_insert_at(&remote->objects, id, this)) goto in_use; this->id = id; @@ -67,18 +68,18 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context, if (user_data_size > 0) this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void); - this->iface = pw_protocol_get_interface(context->protocol, - spa_type_map_get_type(context->type.map, type), + this->iface = pw_protocol_get_interface(remote->protocol, + spa_type_map_get_type(remote->core->type.map, type), false); - spa_list_insert(&this->context->proxy_list, &this->link); + spa_list_insert(&this->remote->proxy_list, &this->link); - pw_log_debug("proxy %p: new %u", this, this->id); + pw_log_debug("proxy %p: new %u, remote %p", this, this->id, remote); return this; in_use: - pw_log_error("proxy %p: id %u in use for context %p", this, id, context); + pw_log_error("proxy %p: id %u in use for remote %p", this, id, remote); free(impl); return NULL; } @@ -100,7 +101,7 @@ int pw_proxy_set_implementation(struct pw_proxy *proxy, * * \param proxy Proxy object to destroy * - * \note This is normally called by \ref pw_context when the server + * \note This is normally called by \ref pw_remote when the server * decides to destroy the server side object * \memberof pw_proxy */ @@ -111,7 +112,7 @@ void pw_proxy_destroy(struct pw_proxy *proxy) pw_log_debug("proxy %p: destroy %u", proxy, proxy->id); pw_signal_emit(&proxy->destroy_signal, proxy); - pw_map_remove(&proxy->context->objects, proxy->id); + pw_map_remove(&proxy->remote->objects, proxy->id); spa_list_remove(&proxy->link); if (proxy->destroy) diff --git a/pipewire/client/proxy.h b/pipewire/client/proxy.h index f91534faf..222ff895e 100644 --- a/pipewire/client/proxy.h +++ b/pipewire/client/proxy.h @@ -24,10 +24,9 @@ extern "C" { #endif -#include -#include #include #include +#include /** \page page_proxy Proxy * @@ -88,8 +87,8 @@ extern "C" { * See \ref page_proxy */ struct pw_proxy { - struct pw_context *context; /**< the owner context of this proxy */ - struct spa_list link; /**< link in the context */ + struct pw_remote *remote; /**< the owner remote of this proxy */ + struct spa_list link; /**< link in the remote */ uint32_t id; /**< client side id */ uint32_t type; /**< object type id */ @@ -107,7 +106,7 @@ struct pw_proxy { }; struct pw_proxy * -pw_proxy_new(struct pw_context *context, +pw_proxy_new(struct pw_remote *remote, uint32_t id, uint32_t type, size_t user_data_size); diff --git a/pipewire/client/stream.c b/pipewire/client/stream.c index e30c0b261..421f057aa 100644 --- a/pipewire/client/stream.c +++ b/pipewire/client/stream.c @@ -30,10 +30,10 @@ #include "pipewire/client/interfaces.h" #include "pipewire/client/array.h" #include "pipewire/client/connection.h" -#include "pipewire/client/context.h" #include "pipewire/client/stream.h" #include "pipewire/client/transport.h" #include "pipewire/client/utils.h" +#include "pipewire/client/stream.h" #include "pipewire/extensions/client-node.h" /** \cond */ @@ -180,7 +180,7 @@ const char *pw_stream_state_as_string(enum pw_stream_state state) return "invalid-state"; } -struct pw_stream *pw_stream_new(struct pw_context *context, +struct pw_stream *pw_stream_new(struct pw_remote *remote, const char *name, struct pw_properties *props) { struct stream *impl; @@ -203,9 +203,9 @@ struct pw_stream *pw_stream_new(struct pw_context *context, this->properties = props; - this->context = context; + this->remote = remote; this->name = strdup(name); - impl->type_client_node = spa_type_map_get_id(context->type.map, PIPEWIRE_TYPE_NODE_BASE "Client"); + impl->type_client_node = spa_type_map_get_id(remote->core->type.map, PIPEWIRE_TYPE_NODE_BASE "Client"); pw_signal_init(&this->destroy_signal); pw_signal_init(&this->state_changed); @@ -224,7 +224,7 @@ struct pw_stream *pw_stream_new(struct pw_context *context, impl->pending_seq = SPA_ID_INVALID; spa_list_init(&impl->free); - spa_list_insert(&context->stream_list, &this->link); + spa_list_insert(&remote->stream_list, &this->link); return this; @@ -238,11 +238,11 @@ static void unhandle_socket(struct pw_stream *stream) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); if (impl->rtsocket_source) { - pw_loop_destroy_source(stream->context->loop, impl->rtsocket_source); + pw_loop_destroy_source(stream->remote->core->data_loop, impl->rtsocket_source); impl->rtsocket_source = NULL; } if (impl->timeout_source) { - pw_loop_destroy_source(stream->context->loop, impl->timeout_source); + pw_loop_destroy_source(stream->remote->core->data_loop, impl->timeout_source); impl->timeout_source = NULL; } } @@ -349,6 +349,7 @@ static void add_port_update(struct pw_stream *stream, uint32_t change_mask) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); + pw_client_node_do_port_update(impl->node_proxy, impl->direction, impl->port_id, @@ -367,7 +368,7 @@ static inline void send_need_input(struct pw_stream *stream) uint64_t cmd = 1; pw_transport_add_event(impl->trans, - &SPA_EVENT_INIT(stream->context->type.event_transport.NeedInput)); + &SPA_EVENT_INIT(stream->remote->core->type.event_transport.NeedInput)); write(impl->rtwritefd, &cmd, 8); #endif } @@ -378,7 +379,7 @@ static inline void send_have_output(struct pw_stream *stream) uint64_t cmd = 1; pw_transport_add_event(impl->trans, - &SPA_EVENT_INIT(stream->context->type.event_transport.HaveOutput)); + &SPA_EVENT_INIT(stream->remote->core->type.event_transport.HaveOutput)); write(impl->rtwritefd, &cmd, 8); } @@ -387,7 +388,7 @@ static void add_request_clock_update(struct pw_stream *stream) struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); pw_client_node_do_event(impl->node_proxy, (struct spa_event *) - &SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->context->type. + &SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_INIT(stream->remote->core->type. event_node. RequestClockUpdate, SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_TIME, @@ -465,9 +466,9 @@ static inline void reuse_buffer(struct pw_stream *stream, uint32_t id) static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *event) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct pw_context *context = impl->this.context; + struct pw_remote *remote = impl->this.remote; - if (SPA_EVENT_TYPE(event) == context->type.event_transport.HaveOutput) { + if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.HaveOutput) { int i; for (i = 0; i < impl->trans->area->n_input_ports; i++) { @@ -482,7 +483,7 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even input->buffer_id = SPA_ID_INVALID; } send_need_input(stream); - } else if (SPA_EVENT_TYPE(event) == context->type.event_transport.NeedInput) { + } else if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.NeedInput) { int i; for (i = 0; i < impl->trans->area->n_output_ports; i++) { @@ -498,7 +499,7 @@ static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *even impl->in_need_buffer = true; pw_signal_emit(&stream->need_buffer, stream); impl->in_need_buffer = false; - } else if (SPA_EVENT_TYPE(event) == context->type.event_transport.ReuseBuffer) { + } else if (SPA_EVENT_TYPE(event) == remote->core->type.event_transport.ReuseBuffer) { struct pw_event_transport_reuse_buffer *p = (struct pw_event_transport_reuse_buffer *) event; @@ -547,15 +548,15 @@ static void handle_socket(struct pw_stream *stream, int rtreadfd, int rtwritefd) impl->rtreadfd = rtreadfd; impl->rtwritefd = rtwritefd; - impl->rtsocket_source = pw_loop_add_io(stream->context->loop, + impl->rtsocket_source = pw_loop_add_io(stream->remote->core->data_loop, impl->rtreadfd, SPA_IO_ERR | SPA_IO_HUP, true, on_rtsocket_condition, stream); - impl->timeout_source = pw_loop_add_timer(stream->context->loop, on_timeout, stream); + impl->timeout_source = pw_loop_add_timer(stream->remote->core->main_loop, on_timeout, stream); interval.tv_sec = 0; interval.tv_nsec = 100000000; - pw_loop_update_timer(stream->context->loop, impl->timeout_source, NULL, &interval, false); + pw_loop_update_timer(stream->remote->core->main_loop, impl->timeout_source, NULL, &interval, false); return; } @@ -563,26 +564,26 @@ static bool handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_command *command) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); - struct pw_context *context = stream->context; + struct pw_remote *remote = stream->remote; - if (SPA_COMMAND_TYPE(command) == context->type.command_node.Pause) { + if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.Pause) { add_async_complete(stream, seq, SPA_RESULT_OK); if (stream->state == PW_STREAM_STATE_STREAMING) { pw_log_debug("stream %p: pause %d", stream, seq); - pw_loop_update_io(stream->context->loop, + pw_loop_update_io(stream->remote->core->data_loop, impl->rtsocket_source, SPA_IO_ERR | SPA_IO_HUP); stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL); } - } else if (SPA_COMMAND_TYPE(command) == context->type.command_node.Start) { + } else if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.Start) { add_async_complete(stream, seq, SPA_RESULT_OK); if (stream->state == PW_STREAM_STATE_PAUSED) { pw_log_debug("stream %p: start %d %d", stream, seq, impl->direction); - pw_loop_update_io(stream->context->loop, + pw_loop_update_io(stream->remote->core->data_loop, impl->rtsocket_source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP); @@ -595,7 +596,7 @@ handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_com } stream_set_state(stream, PW_STREAM_STATE_STREAMING, NULL); } - } else if (SPA_COMMAND_TYPE(command) == context->type.command_node.ClockUpdate) { + } else if (SPA_COMMAND_TYPE(command) == remote->core->type.command_node.ClockUpdate) { struct spa_command_node_clock_update *cu = (__typeof__(cu)) command; if (cu->body.flags.value & SPA_COMMAND_NODE_CLOCK_UPDATE_FLAG_LIVE) { @@ -791,13 +792,13 @@ client_node_use_buffers(void *object, SPA_MEMBER(bid->buf_ptr, offset + sizeof(struct spa_chunk) * j, struct spa_chunk); - if (d->type == stream->context->type.data.Id) { + if (d->type == stream->remote->core->type.data.Id) { struct mem_id *bmid = find_mem(stream, SPA_PTR_TO_UINT32(d->data)); - d->type = stream->context->type.data.MemFd; + d->type = stream->remote->core->type.data.MemFd; d->data = NULL; d->fd = bmid->fd; pw_log_debug(" data %d %u -> fd %d", j, bmid->id, bmid->fd); - } else if (d->type == stream->context->type.data.MemPtr) { + } else if (d->type == stream->remote->core->type.data.MemPtr) { d->data = SPA_MEMBER(bid->buf_ptr, SPA_PTR_TO_INT(d->data), void); d->fd = -1; pw_log_debug(" data %d %u -> mem %p", j, bid->id, d->data); @@ -913,7 +914,7 @@ pw_stream_connect(struct pw_stream *stream, if (flags & PW_STREAM_FLAG_AUTOCONNECT) pw_properties_set(stream->properties, "pipewire.autoconnect", "1"); - impl->node_proxy = pw_proxy_new(stream->context, + impl->node_proxy = pw_proxy_new(stream->remote, SPA_ID_INVALID, impl->type_client_node, 0); @@ -927,7 +928,7 @@ pw_stream_connect(struct pw_stream *stream, pw_signal_add(&impl->node_proxy->destroy_signal, &impl->node_proxy_destroy, on_node_proxy_destroy); - pw_core_do_create_node(stream->context->core_proxy, + pw_core_do_create_node(stream->remote->core_proxy, "client-node", "client-node", &stream->properties->dict, @@ -1009,7 +1010,7 @@ bool pw_stream_recycle_buffer(struct pw_stream *stream, uint32_t id) { struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this); struct pw_event_transport_reuse_buffer rb = PW_EVENT_TRANSPORT_REUSE_BUFFER_INIT - (stream->context->type.event_transport.ReuseBuffer, impl->port_id, id); + (stream->remote->core->type.event_transport.ReuseBuffer, impl->port_id, id); struct buffer_id *bid; uint64_t cmd = 1; diff --git a/pipewire/client/stream.h b/pipewire/client/stream.h index 6cba5de38..25415f916 100644 --- a/pipewire/client/stream.h +++ b/pipewire/client/stream.h @@ -23,7 +23,7 @@ #include #include -#include +#include #ifdef __cplusplus extern "C" { @@ -204,8 +204,8 @@ struct pw_time { * See also \ref page_streams and \ref page_client_api */ struct pw_stream { - struct pw_context *context; /**< the owner context */ - struct spa_list link; /**< link in the context */ + 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 @@ -243,7 +243,7 @@ struct pw_stream { /** Create a new unconneced \ref pw_stream \memberof pw_stream * \return a newly allocated \ref pw_stream */ struct pw_stream * -pw_stream_new(struct pw_context *context, /**< a \ref pw_context */ +pw_stream_new(struct pw_remote *remote, /**< a \ref pw_remote */ const char *name, /**< a stream name */ struct pw_properties *props /**< stream properties, ownership is taken */); diff --git a/pipewire/client/subscribe.h b/pipewire/client/subscribe.h deleted file mode 100644 index 86bfcac8b..000000000 --- a/pipewire/client/subscribe.h +++ /dev/null @@ -1,63 +0,0 @@ -/* 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_SUBSCRIBE_H__ -#define __PIPEWIRE_SUBSCRIBE_H__ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define PIPEWIRE_TYPE__Core "PipeWire:Object:Core" -#define PIPEWIRE_TYPE_CORE_BASE PIPEWIRE_TYPE__Core ":" - -#define PIPEWIRE_TYPE__Registry "PipeWire:Object:Registry" -#define PIPEWIRE_TYPE_REGISYRY_BASE PIPEWIRE_TYPE__Registry ":" - -#define PIPEWIRE_TYPE__Node "PipeWire:Object:Node" -#define PIPEWIRE_TYPE_NODE_BASE PIPEWIRE_TYPE__Node ":" - -#define PIPEWIRE_TYPE__Client "PipeWire:Object:Client" -#define PIPEWIRE_TYPE_CLIENT_BASE PIPEWIRE_TYPE__Client ":" - -#define PIPEWIRE_TYPE__Link "PipeWire:Object:Link" -#define PIPEWIRE_TYPE_LINK_BASE PIPEWIRE_TYPE__Link ":" - -#define PIPEWIRE_TYPE__Module "PipeWire:Object:Module" -#define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":" - -#define PW_TYPE__Protocol "PipeWire:Protocol" -#define PW_TYPE_PROTOCOL_BASE PW_TYPE__Protocol ":" - -/** \enum pw_subscription_event - * subscription events - */ -enum pw_subscription_event { - PW_SUBSCRIPTION_EVENT_NEW = 0, - PW_SUBSCRIPTION_EVENT_CHANGE = 1, - PW_SUBSCRIPTION_EVENT_REMOVE = 2, -}; - -#ifdef __cplusplus -} -#endif - -#endif /* __PIPEWIRE_SUBSCRIBE_H__ */ diff --git a/pipewire/client/type.h b/pipewire/client/type.h index 5527e47cc..eaa96f25e 100644 --- a/pipewire/client/type.h +++ b/pipewire/client/type.h @@ -33,6 +33,27 @@ extern "C" { #include #include +#define PIPEWIRE_TYPE__Core "PipeWire:Object:Core" +#define PIPEWIRE_TYPE_CORE_BASE PIPEWIRE_TYPE__Core ":" + +#define PIPEWIRE_TYPE__Registry "PipeWire:Object:Registry" +#define PIPEWIRE_TYPE_REGISYRY_BASE PIPEWIRE_TYPE__Registry ":" + +#define PIPEWIRE_TYPE__Node "PipeWire:Object:Node" +#define PIPEWIRE_TYPE_NODE_BASE PIPEWIRE_TYPE__Node ":" + +#define PIPEWIRE_TYPE__Client "PipeWire:Object:Client" +#define PIPEWIRE_TYPE_CLIENT_BASE PIPEWIRE_TYPE__Client ":" + +#define PIPEWIRE_TYPE__Link "PipeWire:Object:Link" +#define PIPEWIRE_TYPE_LINK_BASE PIPEWIRE_TYPE__Link ":" + +#define PIPEWIRE_TYPE__Module "PipeWire:Object:Module" +#define PIPEWIRE_TYPE_MODULE_BASE PIPEWIRE_TYPE__Module ":" + +#define PW_TYPE__Protocol "PipeWire:Protocol" +#define PW_TYPE_PROTOCOL_BASE PW_TYPE__Protocol ":" + /** \class pw_interface * \brief The interface definition * diff --git a/pipewire/daemon/main.c b/pipewire/daemon/main.c index 7b13784f7..840552a1c 100644 --- a/pipewire/daemon/main.c +++ b/pipewire/daemon/main.c @@ -42,7 +42,7 @@ int main(int argc, char *argv[]) loop = pw_main_loop_new(); - core = pw_core_new(loop, NULL); + core = pw_core_new(loop->loop, NULL); pw_daemon_config_run_commands(config, core); diff --git a/pipewire/examples/local-v4l2.c b/pipewire/examples/local-v4l2.c new file mode 100644 index 000000000..5698aa84a --- /dev/null +++ b/pipewire/examples/local-v4l2.c @@ -0,0 +1,532 @@ +/* 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. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +struct type { + uint32_t format; + uint32_t props; + struct spa_type_meta meta; + struct spa_type_data data; + struct spa_type_media_type media_type; + struct spa_type_media_subtype media_subtype; + struct spa_type_format_video format_video; + struct spa_type_video_format video_format; +}; + +static inline void init_type(struct type *type, struct spa_type_map *map) +{ + type->format = spa_type_map_get_id(map, SPA_TYPE__Format); + type->props = spa_type_map_get_id(map, SPA_TYPE__Props); + spa_type_meta_map(map, &type->meta); + spa_type_data_map(map, &type->data); + spa_type_media_type_map(map, &type->media_type); + spa_type_media_subtype_map(map, &type->media_subtype); + spa_type_format_video_map(map, &type->format_video); + spa_type_video_format_map(map, &type->video_format); +} + +#define WIDTH 640 +#define HEIGHT 480 +#define BPP 3 + +struct data { + struct type type; + + const char *path; + + SDL_Renderer *renderer; + SDL_Window *window; + SDL_Texture *texture; + + bool running; + struct pw_loop *loop; + struct spa_source *timer; + + struct pw_core *core; + struct pw_node *node; + struct pw_port *port; + struct spa_port_info port_info; + + struct pw_node *v4l2; + + struct pw_link *link; + + uint8_t buffer[1024]; + + struct spa_video_info_raw format; + int32_t stride; + + uint8_t params_buffer[1024]; + struct spa_param *params[2]; + + struct spa_buffer *buffers[32]; + int n_buffers; +}; + +static void handle_events(struct data *data) +{ + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + exit(0); + break; + } + } +} + +static struct { + Uint32 format; + uint32_t id; +} video_formats[] = { + { + SDL_PIXELFORMAT_UNKNOWN, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX1LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_UNKNOWN, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX1LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX1MSB, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX4LSB, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX4MSB, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_INDEX8, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGB332, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGB444, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGB555, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_BGR555, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_ARGB4444, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGBA4444, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_ABGR4444, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_BGRA4444, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_ARGB1555, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGBA5551, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_ABGR1555, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_BGRA5551, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGB565, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_BGR565, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGB24, offsetof(struct spa_type_video_format, RGB),}, { + SDL_PIXELFORMAT_RGB888, offsetof(struct spa_type_video_format, RGB),}, { + SDL_PIXELFORMAT_RGBX8888, offsetof(struct spa_type_video_format, RGBx),}, { + SDL_PIXELFORMAT_BGR24, offsetof(struct spa_type_video_format, BGR),}, { + SDL_PIXELFORMAT_BGR888, offsetof(struct spa_type_video_format, BGR),}, { + SDL_PIXELFORMAT_BGRX8888, offsetof(struct spa_type_video_format, BGRx),}, { + SDL_PIXELFORMAT_ARGB2101010, offsetof(struct spa_type_video_format, UNKNOWN),}, { + SDL_PIXELFORMAT_RGBA8888, offsetof(struct spa_type_video_format, RGBA),}, { + SDL_PIXELFORMAT_ARGB8888, offsetof(struct spa_type_video_format, ARGB),}, { + SDL_PIXELFORMAT_BGRA8888, offsetof(struct spa_type_video_format, BGRA),}, { + SDL_PIXELFORMAT_ABGR8888, offsetof(struct spa_type_video_format, ABGR),}, { + SDL_PIXELFORMAT_YV12, offsetof(struct spa_type_video_format, YV12),}, { + SDL_PIXELFORMAT_IYUV, offsetof(struct spa_type_video_format, I420),}, { + SDL_PIXELFORMAT_YUY2, offsetof(struct spa_type_video_format, YUY2),}, { + SDL_PIXELFORMAT_UYVY, offsetof(struct spa_type_video_format, UYVY),}, { + SDL_PIXELFORMAT_YVYU, offsetof(struct spa_type_video_format, YVYU),}, { + SDL_PIXELFORMAT_NV12, offsetof(struct spa_type_video_format, NV12),}, { +SDL_PIXELFORMAT_NV21, offsetof(struct spa_type_video_format, NV21),}}; + +static uint32_t sdl_format_to_id(struct data *data, Uint32 format) +{ + int i; + + for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) { + if (video_formats[i].format == format) + return *SPA_MEMBER(&data->type.video_format, video_formats[i].id, uint32_t); + } + return data->type.video_format.UNKNOWN; +} + +static Uint32 id_to_sdl_format(struct data *data, uint32_t id) +{ + int i; + + for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) { + if (*SPA_MEMBER(&data->type.video_format, video_formats[i].id, uint32_t) == id) + return video_formats[i].format; + } + return SDL_PIXELFORMAT_UNKNOWN; +} + +#define PROP(f,key,type,...) \ + SPA_POD_PROP (f,key,0,type,1,__VA_ARGS__) +#define PROP_U_MM(f,key,type,...) \ + 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, + struct spa_format **format, + const struct spa_format *filter, + int32_t index) +{ + struct data *data = port->user_data; + const struct spa_format *formats[1]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(data->buffer, sizeof(data->buffer)); + struct spa_pod_frame f[2]; + SDL_RendererInfo info; + int i, c; + + if (index != 0) + return SPA_RESULT_ENUM_END; + + SDL_GetRendererInfo(data->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_prop(&b, &f[1], data->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]); + if (id == 0) + continue; + if (c++ == 0) + spa_pod_builder_id(&b, id); + spa_pod_builder_id(&b, id); + } + for (i = 0; i < SPA_N_ELEMENTS(video_formats); i++) { + uint32_t id = + *SPA_MEMBER(&data->type.video_format, video_formats[i].id, + uint32_t); + if (id != data->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, + 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, + 25, 1, + 0, 1, 30, 1), + 0); + spa_pod_builder_pop(&b, &f[0]); + formats[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_format); + + spa_debug_format(formats[0]); + + *format = (struct spa_format *)formats[0]; + + return SPA_RESULT_OK; +} + +static int impl_port_set_format(struct pw_port *port, uint32_t flags, struct spa_format *format) +{ + struct data *data = port->user_data; + struct pw_core *core = data->core; + struct spa_pod_builder b = { NULL }; + struct spa_pod_frame f[2]; + Uint32 sdl_format; + void *d; + + if (format == NULL) { + return SPA_RESULT_OK; + } + + spa_debug_format(format); + + spa_format_video_raw_parse(format, &data->format, &data->type.format_video); + + sdl_format = id_to_sdl_format(data, data->format.format); + if (sdl_format == SDL_PIXELFORMAT_UNKNOWN) + return SPA_RESULT_ERROR; + + data->texture = SDL_CreateTexture(data->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); + + 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, + 32, + 2, 32), + PROP(&f[1], core->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + 16)); + data->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))); + data->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) +{ + return SPA_RESULT_NOT_IMPLEMENTED; +} + +static int impl_port_get_info(struct pw_port *port, const struct spa_port_info **info) +{ + struct data *data = port->user_data; + + 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; + + return SPA_RESULT_OK; +} + +static int impl_port_enum_params(struct pw_port *port, uint32_t index, struct spa_param **param) +{ + struct data *data = port->user_data; + + if (index >= 2) + return SPA_RESULT_ENUM_END; + + *param = data->params[index]; + + return SPA_RESULT_OK; +} + +static int impl_port_set_param(struct pw_port *port, struct spa_param *param) +{ + 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; + int i; + for (i = 0; i < n_buffers; i++) + data->buffers[i] = buffers[i]; + data->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, +}; + +static int impl_node_get_props(struct pw_node *node, struct spa_props **props) +{ + 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, + 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 spa_buffer *buf; + uint8_t *map; + void *sdata, *ddata; + int sstride, dstride, ostride; + int i; + uint8_t *src, *dst; + + buf = port->buffers[port->io.buffer_id]; + + if (buf->datas[0].type == data->type.data.MemFd || + buf->datas[0].type == data->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) { + map = NULL; + sdata = buf->datas[0].data; + } else + return SPA_RESULT_ERROR; + + if (SDL_LockTexture(data->texture, NULL, &ddata, &dstride) < 0) { + fprintf(stderr, "Couldn't lock texture: %s\n", SDL_GetError()); + return SPA_RESULT_ERROR; + } + sstride = buf->datas[0].chunk->stride; + ostride = SPA_MIN(sstride, dstride); + + src = sdata; + dst = ddata; + for (i = 0; i < data->format.size.height; i++) { + memcpy(dst, src, ostride); + src += sstride; + dst += dstride; + } + SDL_UnlockTexture(data->texture); + + SDL_RenderClear(data->renderer); + SDL_RenderCopy(data->renderer, data->texture, NULL, NULL); + SDL_RenderPresent(data->renderer); + + if (map) + munmap(map, buf->datas[0].maxsize); + + handle_events(data); + + port->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, +}; + +static void make_nodes(struct data *data) +{ + struct pw_node_factory *factory; + struct pw_properties *props; + + data->node = pw_node_new(data->core, NULL, "SDL-sink", NULL, 0); + data->node->user_data = data; + data->node->implementation = &impl_node; + + data->port = pw_port_new(PW_DIRECTION_INPUT, 0, 0); + data->port->user_data = data; + data->port->implementation = &impl_port; + pw_port_add(data->port, data->node); + pw_node_export(data->node); + + factory = pw_core_find_node_factory(data->core, "spa-node-factory"); + + props = pw_properties_new("spa.library.name", "v4l2/libspa-v4l2", + "spa.factory.name", "v4l2-source", NULL); + data->v4l2 = pw_node_factory_create_node(factory, NULL, "v4l2-source", props); + + data->link = pw_link_new(data->core, + pw_node_get_free_port(data->v4l2, PW_DIRECTION_OUTPUT), + data->port, + NULL, + NULL, + NULL); + pw_link_activate(data->link); +} + +int main(int argc, char *argv[]) +{ + struct data data = { 0, }; + char *err; + + pw_init(&argc, &argv); + + data.loop = pw_loop_new(); + data.running = true; + data.core = pw_core_new(data.loop, NULL); + data.path = argc > 1 ? argv[1] : NULL; + + pw_module_load(data.core, "libpipewire-module-spa-node-factory", NULL, &err); + + init_type(&data.type, data.core->type.map); + + spa_debug_set_type_map(data.core->type.map); + + if (SDL_Init(SDL_INIT_VIDEO) < 0) { + printf("can't initialize SDL: %s\n", SDL_GetError()); + return -1; + } + + if (SDL_CreateWindowAndRenderer + (WIDTH, HEIGHT, SDL_WINDOW_RESIZABLE, &data.window, &data.renderer)) { + printf("can't create window: %s\n", SDL_GetError()); + return -1; + } + + make_nodes(&data); + + pw_loop_enter(data.loop); + while (data.running) { + pw_loop_iterate(data.loop, -1); + } + pw_loop_leave(data.loop); + + pw_loop_destroy(data.loop); + + return 0; +} diff --git a/pipewire/examples/meson.build b/pipewire/examples/meson.build index ff1353306..a4653a9f4 100644 --- a/pipewire/examples/meson.build +++ b/pipewire/examples/meson.build @@ -1,13 +1,18 @@ executable('video-src', 'video-src.c', install: false, - dependencies : [pipewire_dep], + dependencies : [pipewirecore_dep], ) if sdl_dep.found() executable('video-play', 'video-play.c', install: false, - dependencies : [pipewire_dep,sdl_dep], + dependencies : [pipewire_dep,pipewirecore_dep, sdl_dep], + ) + executable('local-v4l2', + 'local-v4l2.c', + install: false, + dependencies : [pipewire_dep,pipewirecore_dep, sdl_dep], ) endif diff --git a/pipewire/examples/video-play.c b/pipewire/examples/video-play.c index 8acc7a352..24779410f 100644 --- a/pipewire/examples/video-play.c +++ b/pipewire/examples/video-play.c @@ -72,7 +72,8 @@ struct data { struct pw_loop *loop; struct spa_source *timer; - struct pw_context *context; + struct pw_core *core; + struct pw_remote *remote; struct pw_listener on_state_changed; struct pw_stream *stream; @@ -234,7 +235,8 @@ on_stream_format_changed(struct pw_listener *listener, struct pw_stream *stream, struct spa_format *format) { struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed); - struct pw_context *ctx = stream->context; + struct pw_remote *remote = stream->remote; + struct pw_core *core = remote->core; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; struct spa_param *params[2]; @@ -265,35 +267,35 @@ 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, ctx->type.param_alloc_buffers.Buffers, - PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, + 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], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, + PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, data->stride), - PROP_U_MM(&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], core->type.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, ctx->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - ctx->type.meta.Header), - PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + 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))); 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_context *context) +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); - switch (context->state) { + switch (remote->state) { case PW_CONTEXT_STATE_ERROR: - printf("context error: %s\n", context->error); + printf("remote error: %s\n", remote->error); data->running = false; break; @@ -306,10 +308,10 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co SDL_RendererInfo info; int i, c; - printf("context state: \"%s\"\n", - pw_context_state_as_string(context->state)); + printf("remote state: \"%s\"\n", + pw_remote_state_as_string(remote->state)); - data->stream = pw_stream_new(context, "video-play", NULL); + data->stream = pw_stream_new(remote, "video-play", NULL); SDL_GetRendererInfo(data->renderer, &info); @@ -364,7 +366,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co break; } default: - printf("context state: \"%s\"\n", pw_context_state_as_string(context->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); break; } } @@ -377,12 +379,13 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; - data.context = pw_context_new(data.loop, "video-play", NULL); + data.core = pw_core_new(data.loop, NULL); + data.remote = pw_remote_new(data.core, NULL); data.path = argc > 1 ? argv[1] : NULL; - init_type(&data.type, data.context->type.map); + init_type(&data.type, data.core->type.map); - spa_debug_set_type_map(data.context->type.map); + spa_debug_set_type_map(data.core->type.map); if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("can't initialize SDL: %s\n", SDL_GetError()); @@ -395,9 +398,9 @@ int main(int argc, char *argv[]) return -1; } - pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed); + pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); - pw_context_connect(data.context, PW_CONTEXT_FLAG_NO_REGISTRY); + pw_remote_connect(data.remote); pw_loop_enter(data.loop); while (data.running) { @@ -405,7 +408,7 @@ int main(int argc, char *argv[]) } pw_loop_leave(data.loop); - pw_context_destroy(data.context); + pw_remote_destroy(data.remote); pw_loop_destroy(data.loop); return 0; diff --git a/pipewire/examples/video-src.c b/pipewire/examples/video-src.c index 728a411fc..ebcd16d36 100644 --- a/pipewire/examples/video-src.c +++ b/pipewire/examples/video-src.c @@ -64,7 +64,8 @@ struct data { struct pw_loop *loop; struct spa_source *timer; - struct pw_context *context; + struct pw_core *core; + struct pw_remote *remote; struct pw_listener on_state_changed; struct pw_stream *stream; @@ -175,7 +176,8 @@ on_stream_format_changed(struct pw_listener *listener, struct pw_stream *stream, struct spa_format *format) { struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed); - struct pw_context *ctx = stream->context; + struct pw_remote *remote = stream->remote; + struct pw_core *core = remote->core; struct spa_pod_builder b = { NULL }; struct spa_pod_frame f[2]; struct spa_param *params[2]; @@ -189,49 +191,49 @@ 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, ctx->type.param_alloc_buffers.Buffers, - PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, + 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], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, + PROP(&f[1], core->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, data->stride), - PROP_U_MM(&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, + PROP_U_MM(&f[1], core->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 32, 2, 32), - PROP(&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, + PROP(&f[1], core->type.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, ctx->type.param_alloc_meta_enable.MetaEnable, - PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, - ctx->type.meta.Header), - PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, + 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))); 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_context *context) +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); - switch (context->state) { - case PW_CONTEXT_STATE_ERROR: - printf("context error: %s\n", context->error); + switch (remote->state) { + case PW_REMOTE_STATE_ERROR: + printf("remote error: %s\n", remote->error); data->running = false; break; - case PW_CONTEXT_STATE_CONNECTED: + case PW_REMOTE_STATE_CONNECTED: { const struct spa_format *formats[1]; uint8_t buffer[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer)); struct spa_pod_frame f[2]; - printf("context state: \"%s\"\n", - pw_context_state_as_string(context->state)); + printf("remote state: \"%s\"\n", + pw_remote_state_as_string(remote->state)); - data->stream = pw_stream_new(context, "video-src", NULL); + data->stream = pw_stream_new(remote, "video-src", NULL); spa_pod_builder_format(&b, &f[0], data->type.format, data->type.media_type.video, @@ -257,7 +259,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co break; } default: - printf("context state: \"%s\"\n", pw_context_state_as_string(context->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); break; } } @@ -270,15 +272,16 @@ int main(int argc, char *argv[]) data.loop = pw_loop_new(); data.running = true; - data.context = pw_context_new(data.loop, "video-src", NULL); + data.core = pw_core_new(data.loop, NULL); + data.remote = pw_remote_new(data.core, NULL); - init_type(&data.type, data.context->type.map); + init_type(&data.type, data.core->type.map); data.timer = pw_loop_add_timer(data.loop, on_timeout, &data); - pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed); + pw_signal_add(&data.remote->state_changed, &data.on_state_changed, on_state_changed); - pw_context_connect(data.context, PW_CONTEXT_FLAG_NO_REGISTRY); + pw_remote_connect(data.remote); pw_loop_enter(data.loop); while (data.running) { @@ -286,7 +289,7 @@ int main(int argc, char *argv[]) } pw_loop_leave(data.loop); - pw_context_destroy(data.context); + pw_remote_destroy(data.remote); pw_loop_destroy(data.loop); return 0; diff --git a/pipewire/gst/gstpipewiredeviceprovider.c b/pipewire/gst/gstpipewiredeviceprovider.c index da8b5ac1e..1af784634 100644 --- a/pipewire/gst/gstpipewiredeviceprovider.c +++ b/pipewire/gst/gstpipewiredeviceprovider.c @@ -207,7 +207,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info) 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->context->type.map); + GstCaps *c1 = gst_caps_from_format (info->input_formats[i], self->core->type.map); if (c1) gst_caps_append (caps, c1); } @@ -215,7 +215,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info) 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->context->type.map); + GstCaps *c1 = gst_caps_from_format (info->output_formats[i], self->core->type.map); if (c1) gst_caps_append (caps, c1); } @@ -242,22 +242,6 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info) props); } -static void -get_node_info_cb (struct pw_context *context, - int res, - const struct pw_node_info *info, - gpointer user_data) -{ - GstPipeWireDeviceProvider *self = user_data; - - if (info) { - GstDevice *dev; - dev = new_node (self, info); - if (dev) - gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); - } -} - static GstPipeWireDevice * find_device (GstDeviceProvider *provider, uint32_t id) { @@ -279,66 +263,11 @@ find_device (GstDeviceProvider *provider, uint32_t id) } static void -on_context_subscription (struct pw_listener *listener, - struct pw_context *context, - enum pw_subscription_event event, - uint32_t type, - uint32_t id) -{ - GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, ctx_subscription); - GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); - GstPipeWireDevice *dev; - - if (type != context->type.node) - return; - - dev = find_device (provider, id); - - if (event == PW_SUBSCRIPTION_EVENT_NEW) { - if (dev == NULL) - pw_context_get_node_info_by_id (context, - id, - get_node_info_cb, - self); - } else if (event == PW_SUBSCRIPTION_EVENT_REMOVE) { - if (dev != NULL) { - gst_device_provider_device_remove (GST_DEVICE_PROVIDER (self), - GST_DEVICE (dev)); - } - } - if (dev) - gst_object_unref (dev); -} - -typedef struct { - GstPipeWireDeviceProvider *self; - gboolean end; - GList **devices; -} InfoData; - -static void -list_node_info_cb (struct pw_context *c, - int res, - const struct pw_node_info *info, - void *user_data) -{ - InfoData *data = user_data; - if (info) { - GstDevice *dev = new_node (data->self, info); - if (dev) - *data->devices = g_list_prepend (*data->devices, gst_object_ref_sink (dev)); - } else { - data->end = TRUE; - } -} - -static void -get_core_info_cb (struct pw_context *c, - int res, - const struct pw_core_info *info, - void *user_data) +get_core_info (struct pw_remote *remote, + void *user_data) { GstDeviceProvider *provider = user_data; + struct pw_core_info *info = remote->info; const gchar *value; if (info == NULL || info->props == NULL) @@ -361,35 +290,113 @@ get_core_info_cb (struct pw_context *c, } } +static void +on_sync_reply (struct pw_listener *listener, struct pw_remote *remote, uint32_t seq) +{ + GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, on_sync_reply); + if (seq == 1) + pw_core_do_sync(self->registry->remote->core_proxy, 2); + else if (seq == 2) + self->end = true; +} + +static void node_event_info(void *object, struct pw_node_info *info) +{ + struct pw_proxy *proxy = object; + GstPipeWireDeviceProvider *self = proxy->object; + GstDevice *dev; + + dev = new_node (self, info); + if (dev) { + if(self->list_only) + *self->devices = g_list_prepend (*self->devices, gst_object_ref_sink (dev)); + else + gst_device_provider_device_add (GST_DEVICE_PROVIDER (self), dev); + } +} + +static const struct pw_node_events node_events = { + &node_event_info +}; + +static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version) +{ + struct pw_proxy *registry = object; + GstPipeWireDeviceProvider *self = registry->object; + struct pw_remote *remote = registry->remote; + struct pw_core *core = remote->core; + struct pw_proxy *proxy = NULL; + + if (strcmp(type, PIPEWIRE_TYPE__Node)) + return; + + proxy = pw_proxy_new(remote, SPA_ID_INVALID, core->type.node, 0); + if (proxy == NULL) + goto no_mem; + + pw_proxy_set_implementation(proxy, self, PW_VERSION_NODE, &node_events, NULL); + pw_registry_do_bind(registry, id, version, proxy->id); + return; + +no_mem: + GST_ERROR_OBJECT(self, "failed to create proxy"); + return; +} + +static void registry_event_global_remove(void *object, uint32_t id) +{ + struct pw_proxy *registry = object; + GstPipeWireDeviceProvider *self = registry->object; + GstDeviceProvider *provider = GST_DEVICE_PROVIDER (self); + GstPipeWireDevice *dev; + + dev = find_device (provider, id); + if (dev != NULL) { + gst_device_provider_device_remove (provider, GST_DEVICE (dev)); + gst_object_unref (dev); + } +} + +static const struct pw_registry_events registry_events = { + registry_event_global, + registry_event_global_remove, +}; + static GList * gst_pipewire_device_provider_probe (GstDeviceProvider * provider) { GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider); struct pw_loop *l = NULL; - struct pw_context *c = NULL; - InfoData data; + struct pw_core *c = NULL; + struct pw_remote *r = NULL; + struct pw_proxy *reg = NULL; GST_DEBUG_OBJECT (self, "starting probe"); if (!(l = pw_loop_new ())) return NULL; - if (!(c = pw_context_new (l, self->client_name, NULL))) + if (!(c = pw_core_new (l, NULL))) + return NULL; + + if (!(r = pw_remote_new (c, NULL))) goto failed; - pw_context_connect (c, 0); + pw_signal_add(&r->sync_reply, &self->on_sync_reply, on_sync_reply); + + pw_remote_connect (r); for (;;) { - enum pw_context_state state; + enum pw_remote_state state; - state = c->state; + state = r->state; if (state <= 0) { - GST_ERROR_OBJECT (self, "Failed to connect: %s", c->error); + GST_ERROR_OBJECT (self, "Failed to connect: %s", r->error); goto failed; } - if (state == PW_CONTEXT_STATE_CONNECTED) + if (state == PW_REMOTE_STATE_CONNECTED) break; /* Wait until something happens */ @@ -397,30 +404,31 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider) } GST_DEBUG_OBJECT (self, "connected"); - pw_context_get_core_info (c, - get_core_info_cb, - self); + get_core_info (r, self); + self->end = FALSE; + self->list_only = TRUE; + self->devices = NULL; + + reg = pw_proxy_new(r, SPA_ID_INVALID, c->type.registry, 0); + pw_proxy_set_implementation(reg, self, PW_VERSION_REGISTRY, ®istry_events, NULL); + pw_core_do_get_registry(r->core_proxy, reg->id); + pw_core_do_sync(r->core_proxy, 1); - data.self = self; - data.end = FALSE; - data.devices = NULL; - pw_context_list_node_info (c, - list_node_info_cb, - &data); for (;;) { - if (c->state <= 0) + if (r->state <= 0) break; - if (data.end) + if (self->end) break; pw_loop_iterate (l, -1); } - pw_context_disconnect (c); - pw_context_destroy (c); + pw_remote_disconnect (r); + pw_remote_destroy (r); + pw_core_destroy (c); pw_loop_destroy (l); - return *data.devices; + return *self->devices; failed: pw_loop_destroy (l); @@ -428,24 +436,24 @@ failed: } static void -on_context_state_changed (struct pw_listener *listener, - struct pw_context *context) +on_remote_state_changed (struct pw_listener *listener, + struct pw_remote *remote) { - GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, ctx_state_changed); - enum pw_context_state state; + GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, remote_state_changed); + enum pw_remote_state state; - state= context->state; + state= remote->state; - GST_DEBUG ("got context state %d", state); + GST_DEBUG ("got remote state %d", state); switch (state) { - case PW_CONTEXT_STATE_CONNECTING: + case PW_REMOTE_STATE_CONNECTING: break; - case PW_CONTEXT_STATE_UNCONNECTED: - case PW_CONTEXT_STATE_CONNECTED: + case PW_REMOTE_STATE_UNCONNECTED: + case PW_REMOTE_STATE_CONNECTED: break; - case PW_CONTEXT_STATE_ERROR: - GST_ERROR_OBJECT (self, "context error: %s", context->error); + case PW_REMOTE_STATE_ERROR: + GST_ERROR_OBJECT (self, "remote error: %s", remote->error); break; } pw_thread_loop_signal (self->main_loop, FALSE); @@ -459,12 +467,18 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) GST_DEBUG_OBJECT (self, "starting provider"); self->loop = pw_loop_new (); + self->list_only = FALSE; if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) { GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop"); goto failed_main_loop; } + if (!(self->core = pw_core_new (self->loop, NULL))) { + GST_ERROR_OBJECT (self, "Could not create PipeWire core"); + goto failed_core; + } + if (pw_thread_loop_start (self->main_loop) != SPA_RESULT_OK) { GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop"); goto failed_start; @@ -472,49 +486,53 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider) pw_thread_loop_lock (self->main_loop); - if (!(self->context = pw_context_new (self->loop, self->client_name, NULL))) { - GST_ERROR_OBJECT (self, "Failed to create context"); - goto failed_context; + if (!(self->remote = pw_remote_new (self->core, NULL))) { + GST_ERROR_OBJECT (self, "Failed to create remote"); + goto failed_remote; } - pw_signal_add (&self->context->state_changed, - &self->ctx_state_changed, - on_context_state_changed); - pw_signal_add (&self->context->subscription, - &self->ctx_subscription, - on_context_subscription); + pw_signal_add (&self->remote->state_changed, + &self->remote_state_changed, + on_remote_state_changed); - pw_context_connect (self->context, 0); + pw_remote_connect (self->remote); for (;;) { - enum pw_context_state state; + enum pw_remote_state state; - state = self->context->state; + state = self->remote->state; if (state <= 0) { - GST_WARNING_OBJECT (self, "Failed to connect: %s", self->context->error); + GST_WARNING_OBJECT (self, "Failed to connect: %s", self->remote->error); goto not_running; } - if (state == PW_CONTEXT_STATE_CONNECTED) + if (state == PW_REMOTE_STATE_CONNECTED) break; /* Wait until something happens */ pw_thread_loop_wait (self->main_loop); } GST_DEBUG_OBJECT (self, "connected"); - pw_context_get_core_info (self->context, - get_core_info_cb, - self); + get_core_info (self->remote, self); + + self->registry = pw_proxy_new(self->remote, SPA_ID_INVALID, self->core->type.registry, 0); + pw_proxy_set_implementation(self->registry, self, PW_VERSION_REGISTRY, ®istry_events, NULL); + pw_core_do_get_registry(self->remote->core_proxy, self->registry->id); + pw_core_do_sync(self->remote->core_proxy, 1); + pw_thread_loop_unlock (self->main_loop); return TRUE; not_running: - pw_context_destroy (self->context); - self->context = NULL; -failed_context: + pw_remote_destroy (self->remote); + self->remote = NULL; +failed_remote: pw_thread_loop_unlock (self->main_loop); failed_start: + pw_core_destroy (self->core); + self->core = NULL; +failed_core: pw_thread_loop_destroy (self->main_loop); self->main_loop = NULL; failed_main_loop: @@ -528,10 +546,10 @@ gst_pipewire_device_provider_stop (GstDeviceProvider * provider) { GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider); - if (self->context) { - pw_context_disconnect (self->context); - pw_context_destroy (self->context); - self->context = NULL; + if (self->remote) { + pw_remote_disconnect (self->remote); + pw_remote_destroy (self->remote); + self->remote = NULL; } if (self->main_loop) { pw_thread_loop_destroy (self->main_loop); diff --git a/pipewire/gst/gstpipewiredeviceprovider.h b/pipewire/gst/gstpipewiredeviceprovider.h index 8f288d13a..a4ad23a11 100644 --- a/pipewire/gst/gstpipewiredeviceprovider.h +++ b/pipewire/gst/gstpipewiredeviceprovider.h @@ -84,9 +84,14 @@ struct _GstPipeWireDeviceProvider { struct pw_loop *loop; struct pw_thread_loop *main_loop; - struct pw_context *context; - struct pw_listener ctx_state_changed; - struct pw_listener ctx_subscription; + struct pw_core *core; + struct pw_remote *remote; + struct pw_proxy *registry; + gboolean end; + gboolean list_only; + GList **devices; + struct pw_listener remote_state_changed; + struct pw_listener on_sync_reply; }; struct _GstPipeWireDeviceProviderClass { diff --git a/pipewire/gst/gstpipewiresink.c b/pipewire/gst/gstpipewiresink.c index 1454b139d..2d61fe8d3 100644 --- a/pipewire/gst/gstpipewiresink.c +++ b/pipewire/gst/gstpipewiresink.c @@ -235,7 +235,8 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass) static void pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink) { - struct pw_context *ctx = sink->stream->context; + struct pw_remote *remote = sink->stream->remote; + struct pw_core *core = remote->core; GstStructure *config; GstCaps *caps; guint size; @@ -250,36 +251,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, ctx->type.param_alloc_buffers.Buffers); + spa_pod_builder_push_object (&b, &f[0], 0, core->type.param_alloc_buffers.Buffers); if (size == 0) spa_pod_builder_add (&b, - PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0); + PROP_U_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), 0); else spa_pod_builder_add (&b, - PROP_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0); + PROP_MM (&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, size, size, INT32_MAX), 0); spa_pod_builder_add (&b, - PROP_MM (&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, min_buffers, min_buffers, max_buffers ? max_buffers : INT32_MAX), - PROP (&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16), + 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), 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, ctx->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Header), - PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); + 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))); port_params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Ringbuffer), - PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_ringbuffer)), - PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferSize, SPA_POD_TYPE_INT, + 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], ctx->type.param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0), - PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferBlocks, SPA_POD_TYPE_INT, 1), - PROP (&f[1], ctx->type.param_alloc_meta_enable.ringbufferAlign, SPA_POD_TYPE_INT, 16)); + 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)); port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); pw_thread_loop_lock (sink->main_loop); @@ -304,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); GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop); } @@ -441,6 +443,7 @@ on_add_buffer (struct pw_listener *listener, GstBuffer *buf; uint32_t i; ProcessMemData data; + struct pw_core *core = pwsink->remote->core; GST_LOG_OBJECT (pwsink, "add buffer"); @@ -454,20 +457,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, stream->context->type.meta.Header); + data.header = spa_buffer_find_meta (b, core->type.meta.Header); for (i = 0; i < b->n_datas; i++) { struct spa_data *d = &b->datas[i]; GstMemory *gmem = NULL; - if (d->type == stream->context->type.data.MemFd || - d->type == stream->context->type.data.DmaBuf) { + if (d->type == core->type.data.MemFd || + d->type == core->type.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 == stream->context->type.data.MemPtr) { + else if (d->type == core->type.data.MemPtr) { gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset, d->chunk->size, NULL, NULL); data.offset = 0; @@ -623,7 +626,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps) pwsink = GST_PIPEWIRE_SINK (bsink); - possible = gst_caps_to_format_all (caps, pwsink->ctx->type.map); + possible = gst_caps_to_format_all (caps, pwsink->remote->core->type.map); pw_thread_loop_lock (pwsink->main_loop); state = pwsink->stream->state; @@ -755,7 +758,7 @@ gst_pipewire_sink_start (GstBaseSink * basesink) } pw_thread_loop_lock (pwsink->main_loop); - pwsink->stream = pw_stream_new (pwsink->ctx, pwsink->client_name, props); + 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); @@ -789,23 +792,23 @@ gst_pipewire_sink_stop (GstBaseSink * basesink) } static void -on_ctx_state_changed (struct pw_listener *listener, - struct pw_context *ctx) +on_remote_state_changed (struct pw_listener *listener, + struct pw_remote *remote) { - GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, ctx_state_changed); - enum pw_context_state state; + GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, remote_state_changed); + enum pw_remote_state state; - state = ctx->state; - GST_DEBUG ("got context state %d", state); + state = remote->state; + GST_DEBUG ("got remote state %d", state); switch (state) { - case PW_CONTEXT_STATE_UNCONNECTED: - case PW_CONTEXT_STATE_CONNECTING: - case PW_CONTEXT_STATE_CONNECTED: + case PW_REMOTE_STATE_UNCONNECTED: + case PW_REMOTE_STATE_CONNECTING: + case PW_REMOTE_STATE_CONNECTED: break; - case PW_CONTEXT_STATE_ERROR: + case PW_REMOTE_STATE_ERROR: GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED, - ("context error: %s", ctx->error), (NULL)); + ("remote error: %s", remote->error), (NULL)); break; } pw_thread_loop_signal (pwsink->main_loop, FALSE); @@ -818,19 +821,19 @@ gst_pipewire_sink_open (GstPipeWireSink * pwsink) goto mainloop_error; pw_thread_loop_lock (pwsink->main_loop); - pwsink->ctx = pw_context_new (pwsink->loop, g_get_application_name (), NULL); + pwsink->remote = pw_remote_new (pwsink->core, NULL); - pw_signal_add (&pwsink->ctx->state_changed, &pwsink->ctx_state_changed, on_ctx_state_changed); + pw_signal_add (&pwsink->remote->state_changed, &pwsink->remote_state_changed, on_remote_state_changed); - pw_context_connect (pwsink->ctx, PW_CONTEXT_FLAG_NO_REGISTRY); + pw_remote_connect (pwsink->remote); while (TRUE) { - enum pw_context_state state = pwsink->ctx->state; + enum pw_remote_state state = pwsink->remote->state; - if (state == PW_CONTEXT_STATE_CONNECTED) + if (state == PW_REMOTE_STATE_CONNECTED) break; - if (state == PW_CONTEXT_STATE_ERROR) + if (state == PW_REMOTE_STATE_ERROR) goto connect_error; pw_thread_loop_wait (pwsink->main_loop); @@ -860,16 +863,16 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink) if (pwsink->stream) { pw_stream_disconnect (pwsink->stream); } - if (pwsink->ctx) { - pw_context_disconnect (pwsink->ctx); + if (pwsink->remote) { + pw_remote_disconnect (pwsink->remote); while (TRUE) { - enum pw_context_state state = pwsink->ctx->state; + enum pw_remote_state state = pwsink->remote->state; - if (state == PW_CONTEXT_STATE_UNCONNECTED) + if (state == PW_REMOTE_STATE_UNCONNECTED) break; - if (state == PW_CONTEXT_STATE_ERROR) + if (state == PW_REMOTE_STATE_ERROR) break; pw_thread_loop_wait (pwsink->main_loop); @@ -884,9 +887,9 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink) pwsink->stream = NULL; } - if (pwsink->ctx) { - pw_context_destroy (pwsink->ctx); - pwsink->ctx = NULL; + if (pwsink->remote) { + pw_remote_destroy (pwsink->remote); + pwsink->remote = NULL; } return TRUE; diff --git a/pipewire/gst/gstpipewiresink.h b/pipewire/gst/gstpipewiresink.h index 936bfa287..85ba863ef 100644 --- a/pipewire/gst/gstpipewiresink.h +++ b/pipewire/gst/gstpipewiresink.h @@ -80,8 +80,9 @@ struct _GstPipeWireSink { struct pw_loop *loop; struct pw_thread_loop *main_loop; - struct pw_context *ctx; - struct pw_listener ctx_state_changed; + struct pw_core *core; + struct pw_remote *remote; + struct pw_listener remote_state_changed; struct pw_stream *stream; struct pw_listener stream_state_changed; diff --git a/pipewire/gst/gstpipewiresrc.c b/pipewire/gst/gstpipewiresrc.c index 89348824b..ae521862b 100644 --- a/pipewire/gst/gstpipewiresrc.c +++ b/pipewire/gst/gstpipewiresrc.c @@ -307,6 +307,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); GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop); } @@ -359,7 +360,8 @@ on_add_buffer (struct pw_listener *listener, GstBuffer *buf; uint32_t i; ProcessMemData data; - struct pw_context *ctx = pwsrc->stream->context; + struct pw_remote *remote = pwsrc->stream->remote; + struct pw_core *core = remote->core; GST_LOG_OBJECT (pwsrc, "add buffer"); @@ -374,19 +376,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, ctx->type.meta.Header); + data.header = spa_buffer_find_meta (b, core->type.meta.Header); for (i = 0; i < b->n_datas; i++) { struct spa_data *d = &b->datas[i]; GstMemory *gmem = NULL; - if (d->type == ctx->type.data.MemFd || d->type == ctx->type.data.DmaBuf) { + if (d->type == core->type.data.MemFd || d->type == core->type.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 == ctx->type.data.MemPtr) { + else if (d->type == core->type.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; @@ -543,7 +545,7 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc) if (state == PW_STREAM_STATE_ERROR) goto start_error; - if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR) + if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR) goto start_error; pw_thread_loop_wait (pwsrc->main_loop); @@ -583,7 +585,7 @@ wait_negotiated (GstPipeWireSrc *this) if (state == PW_STREAM_STATE_ERROR) break; - if (this->ctx->state == PW_CONTEXT_STATE_ERROR) + if (this->remote->state == PW_REMOTE_STATE_ERROR) break; if (this->started) @@ -634,7 +636,7 @@ 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->ctx->type.map); + possible = gst_caps_to_format_all (caps, pwsrc->remote->core->type.map); gst_caps_unref (caps); /* first disconnect */ @@ -679,7 +681,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc) if (state == PW_STREAM_STATE_ERROR) goto connect_error; - if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR) + if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR) goto connect_error; pw_thread_loop_wait (pwsrc->main_loop); @@ -738,7 +740,8 @@ on_format_changed (struct pw_listener *listener, GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_format_changed); GstCaps *caps; gboolean res; - struct pw_context *ctx = stream->context; + struct pw_remote *remote = stream->remote; + struct pw_core *core = remote->core; if (format == NULL) { GST_DEBUG_OBJECT (pwsrc, "clear format"); @@ -746,7 +749,7 @@ on_format_changed (struct pw_listener *listener, return; } - caps = gst_caps_from_format (format, pwsrc->ctx->type.map); + caps = gst_caps_from_format (format, core->type.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); @@ -758,16 +761,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, ctx->type.param_alloc_buffers.Buffers, - PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.stride, SPA_POD_TYPE_INT, 0, 0, INT32_MAX), - PROP_U_MM (&f[1], ctx->type.param_alloc_buffers.buffers, SPA_POD_TYPE_INT, 16, 0, INT32_MAX), - PROP (&f[1], ctx->type.param_alloc_buffers.align, SPA_POD_TYPE_INT, 16)); + 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)); params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); - spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_meta_enable.MetaEnable, - PROP (&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, ctx->type.meta.Header), - PROP (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_meta_header))); + 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))); params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param); GST_DEBUG_OBJECT (pwsrc, "doing finish format"); @@ -969,22 +972,22 @@ gst_pipewire_src_stop (GstBaseSrc * basesrc) } static void -on_ctx_state_changed (struct pw_listener *listener, - struct pw_context *ctx) +on_remote_state_changed (struct pw_listener *listener, + struct pw_remote *remote) { - GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, ctx_state_changed); - enum pw_context_state state = ctx->state; + GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, remote_state_changed); + enum pw_remote_state state = remote->state; - GST_DEBUG ("got context state %s", pw_context_state_as_string (state)); + GST_DEBUG ("got remote state %s", pw_remote_state_as_string (state)); switch (state) { - case PW_CONTEXT_STATE_UNCONNECTED: - case PW_CONTEXT_STATE_CONNECTING: - case PW_CONTEXT_STATE_CONNECTED: + case PW_REMOTE_STATE_UNCONNECTED: + case PW_REMOTE_STATE_CONNECTING: + case PW_REMOTE_STATE_CONNECTED: break; - case PW_CONTEXT_STATE_ERROR: + case PW_REMOTE_STATE_ERROR: GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED, - ("context error: %s", ctx->error), (NULL)); + ("remote error: %s", remote->error), (NULL)); break; } pw_thread_loop_signal (pwsrc->main_loop, FALSE); @@ -1013,20 +1016,20 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) goto mainloop_failed; pw_thread_loop_lock (pwsrc->main_loop); - pwsrc->ctx = pw_context_new (pwsrc->loop, g_get_application_name (), NULL); + pwsrc->remote = pw_remote_new (pwsrc->core, NULL); - pw_signal_add (&pwsrc->ctx->state_changed, &pwsrc->ctx_state_changed, on_ctx_state_changed); + pw_signal_add (&pwsrc->remote->state_changed, &pwsrc->remote_state_changed, on_remote_state_changed); - pw_context_connect (pwsrc->ctx, PW_CONTEXT_FLAG_NO_REGISTRY); + pw_remote_connect (pwsrc->remote); while (TRUE) { - enum pw_context_state state = pwsrc->ctx->state; + enum pw_remote_state state = pwsrc->remote->state; - GST_DEBUG ("waiting for CONNECTED, now %s", pw_context_state_as_string (state)); - if (state == PW_CONTEXT_STATE_CONNECTED) + GST_DEBUG ("waiting for CONNECTED, now %s", pw_remote_state_as_string (state)); + if (state == PW_REMOTE_STATE_CONNECTED) break; - if (state == PW_CONTEXT_STATE_ERROR) + if (state == PW_REMOTE_STATE_ERROR) goto connect_error; pw_thread_loop_wait (pwsrc->main_loop); @@ -1039,7 +1042,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc) props = NULL; } - pwsrc->stream = pw_stream_new (pwsrc->ctx, pwsrc->client_name, props); + pwsrc->stream = pw_stream_new (pwsrc->remote, pwsrc->client_name, props); 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); @@ -1075,8 +1078,8 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc) pw_stream_destroy (pwsrc->stream); pwsrc->stream = NULL; - pw_context_destroy (pwsrc->ctx); - pwsrc->ctx = NULL; + pw_remote_destroy (pwsrc->remote); + pwsrc->remote = NULL; GST_OBJECT_LOCK (pwsrc); g_clear_object (&pwsrc->clock); diff --git a/pipewire/gst/gstpipewiresrc.h b/pipewire/gst/gstpipewiresrc.h index dc2bf40fc..265dd3094 100644 --- a/pipewire/gst/gstpipewiresrc.h +++ b/pipewire/gst/gstpipewiresrc.h @@ -67,8 +67,9 @@ struct _GstPipeWireSrc { struct pw_loop *loop; struct pw_thread_loop *main_loop; - struct pw_context *ctx; - struct pw_listener ctx_state_changed; + struct pw_core *core; + struct pw_remote *remote; + struct pw_listener remote_state_changed; struct pw_stream *stream; struct pw_listener stream_state_changed; diff --git a/pipewire/modules/extension-client-node.c b/pipewire/modules/extension-client-node.c deleted file mode 100644 index ba2885fad..000000000 --- a/pipewire/modules/extension-client-node.c +++ /dev/null @@ -1,66 +0,0 @@ -/* 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. - */ - -#include -#include -#include -#include - -#include "config.h" - -#include "pipewire/client/interfaces.h" -#include "pipewire/client/context.h" -#include "pipewire/client/extension.h" - -struct pw_protocol *pw_protocol_native_ext_client_node_init(void); - -struct impl { - struct pw_context *context; - struct pw_properties *properties; -}; - -static struct impl *extension_new(struct pw_context *context, struct pw_properties *properties) -{ - struct impl *impl; - - impl = calloc(1, sizeof(struct impl)); - pw_log_debug("extension %p: new", impl); - - impl->context = context; - impl->properties = properties; - - pw_protocol_native_ext_client_node_init(); - - return impl; -} - -#if 0 -static void extension_destroy(struct impl *impl) -{ - pw_log_debug("extension %p: destroy", impl); - - free(impl); -} -#endif - -bool pipewire__extension_init(struct pw_extension *extension, const char *args) -{ - extension_new(extension->context, NULL); - return true; -} diff --git a/pipewire/modules/extension-protocol-native.c b/pipewire/modules/extension-protocol-native.c deleted file mode 100644 index a7f439ad5..000000000 --- a/pipewire/modules/extension-protocol-native.c +++ /dev/null @@ -1,66 +0,0 @@ -/* 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. - */ - -#include -#include -#include -#include - -#include "config.h" - -#include "pipewire/client/interfaces.h" -#include "pipewire/client/context.h" -#include "pipewire/client/extension.h" - -struct pw_protocol *pw_protocol_native_init(void); - -struct impl { - struct pw_context *context; - struct pw_properties *properties; -}; - -static struct impl *extension_new(struct pw_context *context, struct pw_properties *properties) -{ - struct impl *impl; - - impl = calloc(1, sizeof(struct impl)); - pw_log_debug("extension %p: new", impl); - - impl->context = context; - impl->properties = properties; - - pw_protocol_native_init(); - - return impl; -} - -#if 0 -static void extension_destroy(struct impl *impl) -{ - pw_log_debug("extension %p: destroy", impl); - - free(impl); -} -#endif - -bool pipewire__extension_init(struct pw_extension *extension, const char *args) -{ - extension_new(extension->context, NULL); - return true; -} diff --git a/pipewire/modules/meson.build b/pipewire/modules/meson.build index 5682ba78b..b32c4a5e9 100644 --- a/pipewire/modules/meson.build +++ b/pipewire/modules/meson.build @@ -37,8 +37,8 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node', [ 'module-client-node.c', 'module-client-node/client-node.c', 'module-client-node/protocol-native.c', - 'spa/spa-node.c', - 'extension-client-node.c', ], + 'module-protocol-native/connection.c', + 'spa/spa-node.c', ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], link_with : spalib, @@ -59,7 +59,7 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node', pipewire_module_protocol_native = shared_library('pipewire-module-protocol-native', [ 'module-protocol-native.c', 'module-protocol-native/protocol-native.c', - 'extension-protocol-native.c' ], + 'module-protocol-native/connection.c' ], c_args : pipewire_module_c_args, include_directories : [configinc, spa_inc], link_with : spalib, diff --git a/pipewire/modules/module-client-node.c b/pipewire/modules/module-client-node.c index df86505e8..e32fb866d 100644 --- a/pipewire/modules/module-client-node.c +++ b/pipewire/modules/module-client-node.c @@ -37,14 +37,13 @@ struct impl { }; static struct pw_node *create_node(struct pw_node_factory *factory, - struct pw_client *client, + struct pw_resource *resource, const char *name, - struct pw_properties *properties, - uint32_t new_id) + struct pw_properties *properties) { struct pw_client_node *node; - node = pw_client_node_new(client, new_id, name, properties); + node = pw_client_node_new(resource, name, properties); if (node == NULL) goto no_mem; @@ -52,8 +51,8 @@ static struct pw_node *create_node(struct pw_node_factory *factory, no_mem: pw_log_error("can't create node"); - pw_core_notify_error(client->core_resource, - client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory"); + pw_core_notify_error(resource->client->core_resource, + resource->client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory"); return NULL; } @@ -68,6 +67,7 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope impl->this.core = core; impl->this.name = "client-node"; + impl->this.type = spa_type_map_get_id(core->type.map, PIPEWIRE_TYPE__ClientNode); pw_signal_init(&impl->this.destroy_signal); impl->this.create_node = create_node; diff --git a/pipewire/modules/module-client-node/client-node.c b/pipewire/modules/module-client-node/client-node.c index a50da5fba..53338cbee 100644 --- a/pipewire/modules/module-client-node/client-node.c +++ b/pipewire/modules/module-client-node/client-node.c @@ -1132,41 +1132,33 @@ static void on_node_free(struct pw_listener *listener, struct pw_node *node) * * \memberof pw_client_node */ -struct pw_client_node *pw_client_node_new(struct pw_client *client, - uint32_t id, +struct pw_client_node *pw_client_node_new(struct pw_resource *resource, const char *name, struct pw_properties *properties) { struct impl *impl; struct pw_client_node *this; + struct pw_core *core = resource->client->core; impl = calloc(1, sizeof(struct impl)); if (impl == NULL) return NULL; this = &impl->this; - this->client = client; - impl->core = client->core; + impl->core = core; impl->fds[0] = impl->fds[1] = -1; pw_log_debug("client-node %p: new", impl); - impl->type_client_node = spa_type_map_get_id(client->core->type.map, PIPEWIRE_TYPE__ClientNode); + impl->type_client_node = spa_type_map_get_id(core->type.map, PIPEWIRE_TYPE__ClientNode); pw_signal_init(&this->destroy_signal); - proxy_init(&impl->proxy, NULL, client->core->support, client->core->n_support); + proxy_init(&impl->proxy, NULL, core->support, core->n_support); impl->proxy.impl = impl; - this->resource = pw_resource_new(client, - id, - impl->type_client_node, - 0); - - if (this->resource == NULL) - goto error_no_resource; - - this->node = pw_spa_node_new(client->core, + this->resource = resource; + this->node = pw_spa_node_new(core, this->resource, name, true, @@ -1192,7 +1184,6 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client, error_no_node: pw_resource_destroy(this->resource); - error_no_resource: proxy_clear(&impl->proxy); free(impl); return NULL; diff --git a/pipewire/modules/module-client-node/client-node.h b/pipewire/modules/module-client-node/client-node.h index 1d6754e7e..b64f2e6a3 100644 --- a/pipewire/modules/module-client-node/client-node.h +++ b/pipewire/modules/module-client-node/client-node.h @@ -34,15 +34,13 @@ extern "C" { struct pw_client_node { struct pw_node *node; - struct pw_client *client; struct pw_resource *resource; PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client_node *node)); }; struct pw_client_node * -pw_client_node_new(struct pw_client *client, - uint32_t id, +pw_client_node_new(struct pw_resource *resource, const char *name, struct pw_properties *properties); diff --git a/pipewire/modules/module-client-node/protocol-native.c b/pipewire/modules/module-client-node/protocol-native.c index 773d216b6..2a6cf35b9 100644 --- a/pipewire/modules/module-client-node/protocol-native.c +++ b/pipewire/modules/module-client-node/protocol-native.c @@ -24,93 +24,35 @@ #include "pipewire/client/interfaces.h" #include "pipewire/client/protocol.h" -#include "pipewire/client/connection.h" #include "pipewire/server/client.h" #include "pipewire/extensions/client-node.h" +#include "pipewire/modules/module-protocol-native/connection.h" + /** \cond */ -struct builder { - struct spa_pod_builder b; - struct pw_connection *connection; -}; typedef bool(*demarshal_func_t) (void *object, void *data, size_t size); /** \endcond */ -static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size) -{ - if (ref == -1) - ref = b->offset; - - if (b->size <= b->offset) { - b->size = SPA_ROUND_UP_N(b->offset + size, 4096); - b->data = pw_connection_begin_write(((struct builder *) b)->connection, b->size); - } - memcpy(b->data + ref, data, size); - return ref; -} - -static void core_update_map_client(struct pw_context *context) -{ - uint32_t diff, base, i; - const char **types; - - base = context->n_types; - diff = spa_type_map_get_size(context->type.map) - base; - if (diff == 0) - return; - - types = alloca(diff * sizeof(char *)); - for (i = 0; i < diff; i++, base++) - types[i] = spa_type_map_get_type(context->type.map, base); - - pw_core_do_update_types(context->core_proxy, context->n_types, diff, types); - context->n_types += diff; -} - -static void core_update_map_server(struct pw_client *client) -{ - uint32_t diff, base, i; - struct pw_core *core = client->core; - const char **types; - - base = client->n_types; - diff = spa_type_map_get_size(core->type.map) - base; - if (diff == 0) - return; - - types = alloca(diff * sizeof(char *)); - for (i = 0; i < diff; i++, base++) - types[i] = spa_type_map_get_type(core->type.map, base); - - pw_core_notify_update_types(client->core_resource, client->n_types, diff, types); - client->n_types += diff; -} - - static void client_node_marshal_done(void *object, int seq, int res) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DONE); - core_update_map_client(proxy->context); - - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, res); - pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_DONE, b.b.offset); + pw_connection_end_write(connection, b); } - static void client_node_marshal_update(void *object, uint32_t change_mask, @@ -118,21 +60,18 @@ client_node_marshal_update(void *object, uint32_t max_output_ports, const struct spa_props *props) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_UPDATE); - core_update_map_client(proxy->context); - - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, change_mask, SPA_POD_TYPE_INT, max_input_ports, SPA_POD_TYPE_INT, max_output_ports, SPA_POD_TYPE_POD, props); - pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_UPDATE, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -147,78 +86,68 @@ client_node_marshal_port_update(void *object, const struct spa_param **params, const struct spa_port_info *info) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f[2]; int i; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_PORT_UPDATE); - core_update_map_client(proxy->context); - - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f[0], SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id, SPA_POD_TYPE_INT, change_mask, SPA_POD_TYPE_INT, n_possible_formats, 0); for (i = 0; i < n_possible_formats; i++) - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, possible_formats[i], 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, possible_formats[i], 0); - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, format, SPA_POD_TYPE_INT, n_params, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, format, SPA_POD_TYPE_INT, n_params, 0); for (i = 0; i < n_params; i++) { const struct spa_param *p = params[i]; - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, p, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, p, 0); } if (info) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f[1], SPA_POD_TYPE_INT, info->flags, SPA_POD_TYPE_INT, info->rate, 0); - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f[1], 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f[1], 0); } else { - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, NULL, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, NULL, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f[0], 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f[0], 0); - pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_PORT_UPDATE, - b.b.offset); + pw_connection_end_write(connection, b); } static void client_node_marshal_event_method(void *object, struct spa_event *event) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_EVENT); - core_update_map_client(proxy->context); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_POD, event); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_POD, event); - - pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_EVENT, b.b.offset); + pw_connection_end_write(connection, b); } static void client_node_marshal_destroy(void *object) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DESTROY); - core_update_map_client(proxy->context); + spa_pod_builder_struct(b, &f, 0); - spa_pod_builder_struct(&b.b, &f, 0); - - pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_DESTROY, b.b.offset); + pw_connection_end_write(connection, b); } static bool client_node_demarshal_set_props(void *object, void *data, size_t size) @@ -245,7 +174,7 @@ static bool client_node_demarshal_event_event(void *object, void *data, size_t s const struct spa_event *event; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_OBJECT, &event, 0)) return false; @@ -295,7 +224,7 @@ static bool client_node_demarshal_set_format(void *object, void *data, size_t si const struct spa_format *format = NULL; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_INT, &direction, @@ -318,7 +247,7 @@ static bool client_node_demarshal_set_param(void *object, void *data, size_t siz const struct spa_param *param = NULL; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_INT, &direction, @@ -335,12 +264,12 @@ static bool client_node_demarshal_add_mem(void *object, void *data, size_t size) { struct pw_proxy *proxy = object; struct spa_pod_iter it; - struct pw_connection *connection = proxy->context->protocol_private; + struct pw_connection *connection = proxy->remote->protocol_private; uint32_t direction, port_id, mem_id, type, memfd_idx, flags, offset, sz; int memfd; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &direction, SPA_POD_TYPE_INT, &port_id, @@ -371,7 +300,7 @@ static bool client_node_demarshal_use_buffers(void *object, void *data, size_t s int i, j; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_INT, &direction, @@ -433,7 +362,7 @@ static bool client_node_demarshal_node_command(void *object, void *data, size_t uint32_t seq; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_OBJECT, &command, 0)) return false; @@ -449,7 +378,7 @@ static bool client_node_demarshal_port_command(void *object, void *data, size_t uint32_t direction, port_id; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &direction, SPA_POD_TYPE_INT, &port_id, @@ -467,7 +396,7 @@ static bool client_node_demarshal_transport(void *object, void *data, size_t siz { struct pw_proxy *proxy = object; struct spa_pod_iter it; - struct pw_connection *connection = proxy->context->protocol_private; + struct pw_connection *connection = proxy->remote->protocol_private; uint32_t node_id, ridx, widx, memfd_idx, offset, sz; int readfd, writefd, memfd; @@ -498,31 +427,30 @@ client_node_marshal_set_props(void *object, uint32_t seq, const struct spa_props { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_PROPS); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_POD, props); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PROPS, - b.b.offset); + pw_connection_end_write(connection, b); } static void client_node_marshal_event_event(void *object, const struct spa_event *event) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_EVENT); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_POD, event); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_POD, event); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_EVENT, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -531,17 +459,16 @@ client_node_marshal_add_port(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_ADD_PORT); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_ADD_PORT, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -550,17 +477,16 @@ client_node_marshal_remove_port(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_REMOVE_PORT); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_REMOVE_PORT, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -573,20 +499,19 @@ client_node_marshal_set_format(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_FORMAT); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id, SPA_POD_TYPE_INT, flags, SPA_POD_TYPE_POD, format); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_FORMAT, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -598,19 +523,18 @@ client_node_marshal_set_param(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_SET_PARAM); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id, SPA_POD_TYPE_POD, param); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PARAM, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -623,12 +547,12 @@ client_node_marshal_add_mem(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_ADD_MEM); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id, SPA_POD_TYPE_INT, mem_id, @@ -637,7 +561,7 @@ client_node_marshal_add_mem(void *object, SPA_POD_TYPE_INT, flags, SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_ADD_MEM, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -649,13 +573,13 @@ client_node_marshal_use_buffers(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, j; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_USE_BUFFERS); - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_INT, direction, @@ -664,7 +588,7 @@ client_node_marshal_use_buffers(void *object, for (i = 0; i < n_buffers; i++) { struct spa_buffer *buf = buffers[i].buffer; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_INT, buffers[i].mem_id, SPA_POD_TYPE_INT, buffers[i].offset, SPA_POD_TYPE_INT, buffers[i].size, @@ -672,13 +596,13 @@ client_node_marshal_use_buffers(void *object, for (j = 0; j < buf->n_metas; j++) { struct spa_meta *m = &buf->metas[j]; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_ID, m->type, SPA_POD_TYPE_INT, m->size, 0); } - spa_pod_builder_add(&b.b, SPA_POD_TYPE_INT, buf->n_datas, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_INT, buf->n_datas, 0); for (j = 0; j < buf->n_datas; j++) { struct spa_data *d = &buf->datas[j]; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_ID, d->type, SPA_POD_TYPE_INT, SPA_PTR_TO_UINT32(d->data), SPA_POD_TYPE_INT, d->flags, @@ -686,10 +610,9 @@ client_node_marshal_use_buffers(void *object, SPA_POD_TYPE_INT, d->maxsize, 0); } } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_USE_BUFFERS, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -697,15 +620,14 @@ client_node_marshal_node_command(void *object, uint32_t seq, const struct spa_co { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_NODE_COMMAND); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_POD, command); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq, SPA_POD_TYPE_POD, command); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_NODE_COMMAND, - b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -716,18 +638,17 @@ client_node_marshal_port_command(void *object, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_PORT_COMMAND); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id, SPA_POD_TYPE_POD, command); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_PORT_COMMAND, - b.b.offset); + pw_connection_end_write(connection, b); } static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd, @@ -735,20 +656,19 @@ static void client_node_marshal_transport(void *object, uint32_t node_id, int re { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_NODE_EVENT_TRANSPORT); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, node_id, SPA_POD_TYPE_INT, pw_connection_add_fd(connection, readfd), SPA_POD_TYPE_INT, pw_connection_add_fd(connection, writefd), SPA_POD_TYPE_INT, pw_connection_add_fd(connection, memfd), SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size); - pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_TRANSPORT, - b.b.offset); + pw_connection_end_write(connection, b); } diff --git a/pipewire/modules/module-flatpak.c b/pipewire/modules/module-flatpak.c index 5b4403524..6cca8e41b 100644 --- a/pipewire/modules/module-flatpak.c +++ b/pipewire/modules/module-flatpak.c @@ -484,14 +484,14 @@ static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source, struct impl *impl = userdata; if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE) - pw_loop_enable_idle(impl->core->main_loop->loop, source, false); + pw_loop_enable_idle(impl->core->main_loop, source, false); } static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata) { struct impl *impl = userdata; - pw_loop_enable_idle(impl->core->main_loop->loop, + pw_loop_enable_idle(impl->core->main_loop, impl->dispatch_event, status == DBUS_DISPATCH_COMPLETE ? false : true); } @@ -552,7 +552,7 @@ static dbus_bool_t add_watch(DBusWatch *watch, void *userdata) /* we dup because dbus tends to add the same fd multiple times and our epoll * implementation does not like that */ - source = pw_loop_add_io(impl->core->main_loop->loop, + source = pw_loop_add_io(impl->core->main_loop, dup(dbus_watch_get_unix_fd(watch)), dbus_to_io(watch), true, handle_io_event, watch); @@ -566,7 +566,7 @@ static void remove_watch(DBusWatch *watch, void *userdata) struct spa_source *source; if ((source = dbus_watch_get_data(watch))) - pw_loop_destroy_source(impl->core->main_loop->loop, source); + pw_loop_destroy_source(impl->core->main_loop, source); } static void toggle_watch(DBusWatch *watch, void *userdata) @@ -576,7 +576,7 @@ static void toggle_watch(DBusWatch *watch, void *userdata) source = dbus_watch_get_data(watch); - pw_loop_update_io(impl->core->main_loop->loop, source, dbus_to_io(watch)); + pw_loop_update_io(impl->core->main_loop, source, dbus_to_io(watch)); } static void @@ -606,14 +606,14 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata) if (!dbus_timeout_get_enabled(timeout)) return FALSE; - source = pw_loop_add_timer(impl->core->main_loop->loop, handle_timer_event, timeout); + source = pw_loop_add_timer(impl->core->main_loop, handle_timer_event, timeout); dbus_timeout_set_data(timeout, source, NULL); t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC; ts.tv_sec = t / SPA_NSEC_PER_SEC; ts.tv_nsec = t % SPA_NSEC_PER_SEC; - pw_loop_update_timer(impl->core->main_loop->loop, source, &ts, NULL, false); + pw_loop_update_timer(impl->core->main_loop, source, &ts, NULL, false); return TRUE; } @@ -623,7 +623,7 @@ static void remove_timeout(DBusTimeout *timeout, void *userdata) struct spa_source *source; if ((source = dbus_timeout_get_data(timeout))) - pw_loop_destroy_source(impl->core->main_loop->loop, source); + pw_loop_destroy_source(impl->core->main_loop, source); } static void toggle_timeout(DBusTimeout *timeout, void *userdata) @@ -642,14 +642,14 @@ static void toggle_timeout(DBusTimeout *timeout, void *userdata) } else { tsp = NULL; } - pw_loop_update_timer(impl->core->main_loop->loop, source, tsp, NULL, false); + pw_loop_update_timer(impl->core->main_loop, source, tsp, NULL, false); } static void wakeup_main(void *userdata) { struct impl *impl = userdata; - pw_loop_enable_idle(impl->core->main_loop->loop, impl->dispatch_event, true); + pw_loop_enable_idle(impl->core->main_loop, impl->dispatch_event, true); } static struct impl *module_new(struct pw_core *core, struct pw_properties *properties) @@ -669,7 +669,7 @@ static struct impl *module_new(struct pw_core *core, struct pw_properties *prope if (impl->bus == NULL) goto error; - impl->dispatch_event = pw_loop_add_idle(core->main_loop->loop, false, dispatch_cb, impl); + impl->dispatch_event = pw_loop_add_idle(core->main_loop, false, dispatch_cb, impl); dbus_connection_set_exit_on_disconnect(impl->bus, false); dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL); diff --git a/pipewire/modules/module-jack.c b/pipewire/modules/module-jack.c index 2d4c648e8..fd52c55c9 100644 --- a/pipewire/modules/module-jack.c +++ b/pipewire/modules/module-jack.c @@ -106,7 +106,7 @@ static void client_destroy(void *data) struct pw_client *client = data; struct client *this = client->user_data; - pw_loop_destroy_source(this->impl->core->main_loop->loop, this->source); + pw_loop_destroy_source(this->impl->core->main_loop, this->source); spa_list_remove(&this->link); close(this->fd); @@ -407,7 +407,7 @@ on_busy_changed(struct pw_listener *listener, if (!client->busy) mask |= SPA_IO_IN; - pw_loop_update_io(c->impl->core->main_loop->loop, c->source, mask); + pw_loop_update_io(c->impl->core->main_loop, c->source, mask); if (!client->busy) process_messages(c); @@ -453,7 +453,7 @@ static struct client *client_new(struct impl *impl, int fd) this = client->user_data; this->impl = impl; this->fd = fd; - this->source = pw_loop_add_io(impl->core->main_loop->loop, + this->source = pw_loop_add_io(impl->core->main_loop, this->fd, SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this); if (this->source == NULL) @@ -622,7 +622,7 @@ socket_data(struct spa_loop_utils *utils, return; } - pw_loop_update_io(impl->core->main_loop->loop, + pw_loop_update_io(impl->core->main_loop, client->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP); } @@ -644,7 +644,7 @@ static bool add_socket(struct impl *impl, struct socket *s) return false; } - s->loop = impl->core->main_loop->loop; + s->loop = impl->core->main_loop; s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl); if (s->source == NULL) return false; diff --git a/pipewire/modules/module-protocol-native.c b/pipewire/modules/module-protocol-native.c index 749531e6c..797105444 100644 --- a/pipewire/modules/module-protocol-native.c +++ b/pipewire/modules/module-protocol-native.c @@ -29,6 +29,7 @@ #include "config.h" +#include "pipewire/client/connection.h" #include "pipewire/client/pipewire.h" #include "pipewire/client/log.h" #include "pipewire/client/interfaces.h" @@ -54,7 +55,22 @@ struct pw_protocol *pw_protocol_native_init(void); typedef bool(*demarshal_func_t) (void *object, void *data, size_t size); -struct socket { +struct connection { + struct pw_protocol_connection this; + + int fd; + + struct spa_source *source; + struct pw_connection *connection; + + bool disconnecting; + struct pw_listener need_flush; + struct spa_source *flush_event; +}; + +struct listener { + struct pw_protocol_listener this; + int fd; int fd_lock; struct sockaddr_un addr; @@ -62,8 +78,6 @@ struct socket { struct pw_loop *loop; struct spa_source *source; - char *core_name; - struct spa_list link; }; struct impl { @@ -73,7 +87,6 @@ struct impl { struct pw_protocol *protocol; struct pw_properties *properties; - struct spa_list socket_list; struct spa_list client_list; struct spa_loop_control_hooks hooks; @@ -94,7 +107,7 @@ static void client_destroy(void *data) struct pw_client *client = data; struct native_client *this = client->user_data; - pw_loop_destroy_source(this->impl->core->main_loop->loop, this->source); + pw_loop_destroy_source(this->impl->core->main_loop, this->source); spa_list_remove(&this->link); pw_connection_destroy(this->connection); @@ -153,7 +166,7 @@ on_busy_changed(struct pw_listener *listener, if (!client->busy) mask |= SPA_IO_IN; - pw_loop_update_io(c->impl->core->main_loop->loop, c->source, mask); + pw_loop_update_io(c->impl->core->main_loop, c->source, mask); if (!client->busy) process_messages(c); @@ -209,7 +222,7 @@ static struct native_client *client_new(struct impl *impl, int fd) this = client->user_data; this->impl = impl; this->fd = fd; - this->source = pw_loop_add_io(impl->core->main_loop->loop, + this->source = pw_loop_add_io(impl->core->main_loop, this->fd, SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this); if (this->source == NULL) @@ -233,41 +246,29 @@ static struct native_client *client_new(struct impl *impl, int fd) return this; no_connection: - pw_loop_destroy_source(impl->core->main_loop->loop, this->source); + pw_loop_destroy_source(impl->core->main_loop, this->source); no_source: free(this); no_client: return NULL; } -static struct socket *create_socket(void) +static void destroy_listener(struct listener *l) { - struct socket *s; - - if ((s = calloc(1, sizeof(struct socket))) == NULL) - return NULL; - - s->fd = -1; - s->fd_lock = -1; - return s; + if (l->source) + pw_loop_destroy_source(l->loop, l->source); + if (l->addr.sun_path[0]) + unlink(l->addr.sun_path); + if (l->fd >= 0) + close(l->fd); + if (l->lock_addr[0]) + unlink(l->lock_addr); + if (l->fd_lock >= 0) + close(l->fd_lock); + free(l); } -static void destroy_socket(struct socket *s) -{ - if (s->source) - pw_loop_destroy_source(s->loop, s->source); - if (s->addr.sun_path[0]) - unlink(s->addr.sun_path); - if (s->fd >= 0) - close(s->fd); - if (s->lock_addr[0]) - unlink(s->lock_addr); - if (s->fd_lock >= 0) - close(s->fd_lock); - free(s); -} - -static bool init_socket_name(struct socket *s, const char *name) +static bool init_socket_name(struct listener *l, const char *name) { int name_size; const char *runtime_dir; @@ -277,57 +278,55 @@ static bool init_socket_name(struct socket *s, const char *name) return false; } - s->addr.sun_family = AF_LOCAL; - name_size = snprintf(s->addr.sun_path, sizeof(s->addr.sun_path), + l->addr.sun_family = AF_LOCAL; + name_size = snprintf(l->addr.sun_path, sizeof(l->addr.sun_path), "%s/%s", runtime_dir, name) + 1; - s->core_name = (s->addr.sun_path + name_size - 1) - strlen(name); - - if (name_size > (int) sizeof(s->addr.sun_path)) { + if (name_size > (int) sizeof(l->addr.sun_path)) { pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", runtime_dir, name); - *s->addr.sun_path = 0; + *l->addr.sun_path = 0; return false; } return true; } -static bool lock_socket(struct socket *s) +static bool lock_socket(struct listener *l) { struct stat socket_stat; - snprintf(s->lock_addr, sizeof(s->lock_addr), "%s%s", s->addr.sun_path, LOCK_SUFFIX); + snprintf(l->lock_addr, sizeof(l->lock_addr), "%s%s", l->addr.sun_path, LOCK_SUFFIX); - s->fd_lock = open(s->lock_addr, O_CREAT | O_CLOEXEC, + l->fd_lock = open(l->lock_addr, O_CREAT | O_CLOEXEC, (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)); - if (s->fd_lock < 0) { - pw_log_error("unable to open lockfile %s check permissions", s->lock_addr); + if (l->fd_lock < 0) { + pw_log_error("unable to open lockfile %s check permissions", l->lock_addr); goto err; } - if (flock(s->fd_lock, LOCK_EX | LOCK_NB) < 0) { + if (flock(l->fd_lock, LOCK_EX | LOCK_NB) < 0) { pw_log_error("unable to lock lockfile %s, maybe another daemon is running", - s->lock_addr); + l->lock_addr); goto err_fd; } - if (stat(s->addr.sun_path, &socket_stat) < 0) { + if (stat(l->addr.sun_path, &socket_stat) < 0) { if (errno != ENOENT) { - pw_log_error("did not manage to stat file %s\n", s->addr.sun_path); + pw_log_error("did not manage to stat file %s\n", l->addr.sun_path); goto err_fd; } } else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) { - unlink(s->addr.sun_path); + unlink(l->addr.sun_path); } return true; err_fd: - close(s->fd_lock); - s->fd_lock = -1; + close(l->fd_lock); + l->fd_lock = -1; err: - *s->lock_addr = 0; - *s->addr.sun_path = 0; + *l->lock_addr = 0; + *l->addr.sun_path = 0; return false; } @@ -355,83 +354,309 @@ socket_data(struct spa_loop_utils *utils, return; } - pw_loop_update_io(impl->core->main_loop->loop, + pw_loop_update_io(impl->core->main_loop, client->source, SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP); } -static bool add_socket(struct impl *impl, struct socket *s) +static bool add_socket(struct impl *impl, struct listener *l) { socklen_t size; - if ((s->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) + if ((l->fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) return false; - size = offsetof(struct sockaddr_un, sun_path) +strlen(s->addr.sun_path); - if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) { + size = offsetof(struct sockaddr_un, sun_path) + strlen(l->addr.sun_path); + if (bind(l->fd, (struct sockaddr *) &l->addr, size) < 0) { pw_log_error("bind() failed with error: %m"); return false; } - if (listen(s->fd, 128) < 0) { + if (listen(l->fd, 128) < 0) { pw_log_error("listen() failed with error: %m"); return false; } - s->loop = impl->core->main_loop->loop; - s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl); - if (s->source == NULL) + l->loop = impl->core->main_loop; + l->source = pw_loop_add_io(l->loop, l->fd, SPA_IO_IN, false, socket_data, impl); + if (l->source == NULL) return false; - spa_list_insert(impl->socket_list.prev, &s->link); - return true; } +static const char * +get_name(struct pw_properties *properties) +{ + const char *name = NULL; + + if (properties) + name = pw_properties_get(properties, "pipewire.core.name"); + if (name == NULL) + name = getenv("PIPEWIRE_CORE"); + if (name == NULL) + name = "pipewire-0"; + + return name; +} + +static int impl_connect(struct pw_protocol_connection *conn) +{ + struct sockaddr_un addr; + socklen_t size; + const char *runtime_dir, *name = NULL; + int name_size, fd; + + if ((runtime_dir = getenv("XDG_RUNTIME_DIR")) == NULL) { + pw_log_error("connect failed: XDG_RUNTIME_DIR not set in the environment"); + return -1; + } + + if (name == NULL) + name = getenv("PIPEWIRE_CORE"); + if (name == NULL) + name = "pipewire-0"; + + if ((fd = socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0)) < 0) + return -1; + + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_LOCAL; + name_size = snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s", runtime_dir, name) + 1; + + if (name_size > (int) sizeof addr.sun_path) { + pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes", + runtime_dir, name); + goto error_close; + }; + + size = offsetof(struct sockaddr_un, sun_path) + name_size; + + if (connect(fd, (struct sockaddr *) &addr, size) < 0) { + goto error_close; + } + + return conn->connect_fd(conn, fd); + + error_close: + close(fd); + return -1; +} + + +static void +on_remote_data(struct spa_loop_utils *utils, + struct spa_source *source, int fd, enum spa_io mask, void *data) +{ + struct connection *impl = data; + struct pw_remote *this = impl->this.remote; + struct pw_connection *conn = impl->connection; + + if (mask & (SPA_IO_ERR | SPA_IO_HUP)) { + return; + } + + if (mask & SPA_IO_IN) { + uint8_t opcode; + uint32_t id; + uint32_t size; + void *message; + + while (!impl->disconnecting + && pw_connection_get_next(conn, &opcode, &id, &message, &size)) { + struct pw_proxy *proxy; + const demarshal_func_t *demarshal; + + pw_log_trace("protocol-native %p: got message %d from %u", this, opcode, id); + + proxy = pw_map_lookup(&this->objects, id); + if (proxy == NULL) { + pw_log_error("protocol-native %p: could not find proxy %u", this, id); + continue; + } + if (opcode >= proxy->iface->n_events) { + pw_log_error("protocol-native %p: invalid method %u for %u", this, opcode, + id); + continue; + } + + demarshal = proxy->iface->events; + if (demarshal[opcode]) { + if (!demarshal[opcode] (proxy, message, size)) + pw_log_error + ("protocol-native %p: invalid message received %u for %u", this, + opcode, id); + } else + pw_log_error("protocol-native %p: function %d not implemented on %u", this, + opcode, id); + + } + } +} + + +static void do_flush_event(struct spa_loop_utils *utils, struct spa_source *source, void *data) +{ + struct connection *impl = data; + if (impl->connection) + if (!pw_connection_flush(impl->connection)) + impl->this.disconnect(&impl->this); +} + +static void on_need_flush(struct pw_listener *listener, struct pw_connection *connection) +{ + struct connection *impl = SPA_CONTAINER_OF(listener, struct connection, need_flush); + struct pw_remote *remote = impl->this.remote; + pw_loop_signal_event(remote->core->main_loop, impl->flush_event); +} + +static int impl_connect_fd(struct pw_protocol_connection *conn, int fd) +{ + struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this); + struct pw_remote *remote = impl->this.remote; + + impl->connection = pw_connection_new(fd); + if (impl->connection == NULL) + goto error_close; + + conn->remote->protocol_private = impl->connection; + + pw_signal_add(&impl->connection->need_flush, &impl->need_flush, on_need_flush); + + impl->fd = fd; + impl->source = pw_loop_add_io(remote->core->main_loop, + fd, + SPA_IO_IN | SPA_IO_HUP | SPA_IO_ERR, + false, on_remote_data, impl); + + return 0; + + error_close: + close(fd); + return -1; +} + +static int impl_disconnect(struct pw_protocol_connection *conn) +{ + struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this); + struct pw_remote *remote = impl->this.remote; + + impl->disconnecting = true; + + if (impl->source) + pw_loop_destroy_source(remote->core->main_loop, impl->source); + impl->source = NULL; + + if (impl->connection) + pw_connection_destroy(impl->connection); + impl->connection = NULL; + + if (impl->fd != -1) + close(impl->fd); + impl->fd = -1; + + return 0; +} + +static int impl_destroy(struct pw_protocol_connection *conn) +{ + struct connection *impl = SPA_CONTAINER_OF(conn, struct connection, this); + struct pw_remote *remote = conn->remote; + + pw_loop_destroy_source(remote->core->main_loop, impl->flush_event); + + spa_list_remove(&conn->link); + free(impl); + + return 0; +} + +static struct pw_protocol_connection * +impl_new_connection(struct pw_protocol *protocol, + struct pw_remote *remote, + struct pw_properties *properties) +{ + struct impl *impl = protocol->protocol_private; + struct connection *c; + struct pw_protocol_connection *this; + + if ((c = calloc(1, sizeof(struct connection))) == NULL) + return NULL; + + this = &c->this; + this->remote = remote; + + this->connect = impl_connect; + this->connect_fd = impl_connect_fd; + this->disconnect = impl_disconnect; + this->destroy = impl_destroy; + + c->flush_event = pw_loop_add_event(remote->core->main_loop, do_flush_event, c); + + spa_list_insert(impl->protocol->connection_list.prev, &c->this.link); + + return this; +} + +static struct pw_protocol_listener * +impl_add_listener(struct pw_protocol *protocol, + struct pw_core *core, + struct pw_properties *properties) +{ + struct impl *impl = protocol->protocol_private; + struct listener *l; + const char *name; + + if ((l = calloc(1, sizeof(struct listener))) == NULL) + return NULL; + + l->fd = -1; + l->fd_lock = -1; + + name = get_name(properties); + + if (!init_socket_name(l, name)) + goto error; + + if (!lock_socket(l)) + goto error; + + if (!add_socket(impl, l)) + goto error; + + spa_list_insert(impl->protocol->listener_list.prev, &l->this.link); + + impl->hooks.before = on_before_hook; + pw_loop_add_hooks(impl->core->main_loop, &impl->hooks); + + pw_log_info("protocol-native %p: Added listener", protocol); + + return &l->this; + + error: + destroy_listener(l); + return NULL; +} + static struct impl *pw_protocol_native_new(struct pw_core *core, struct pw_properties *properties) { struct impl *impl; - struct socket *s; - const char *name; impl = calloc(1, sizeof(struct impl)); - pw_log_debug("protocol-native %p: new", impl); impl->core = core; impl->properties = properties; impl->protocol = pw_protocol_native_init(); + impl->protocol->new_connection = impl_new_connection; + impl->protocol->add_listener = impl_add_listener; + impl->protocol->protocol_private = impl; + pw_log_debug("protocol-native %p: new %p", impl, impl->protocol); - name = NULL; - if (impl->properties) - name = pw_properties_get(impl->properties, "pipewire.core.name"); - if (name == NULL) - name = getenv("PIPEWIRE_CORE"); - if (name == NULL) - name = "pipewire-0"; - - s = create_socket(); - - spa_list_init(&impl->socket_list); spa_list_init(&impl->client_list); - if (!init_socket_name(s, name)) - goto error; - - if (!lock_socket(s)) - goto error; - - if (!add_socket(impl, s)) - goto error; - - impl->hooks.before = on_before_hook; - pw_loop_add_hooks(impl->core->main_loop->loop, &impl->hooks); + impl_add_listener(impl->protocol, core, properties); return impl; - - error: - destroy_socket(s); - free(impl); - return NULL; } #if 0 diff --git a/pipewire/client/connection.c b/pipewire/modules/module-protocol-native/connection.c similarity index 73% rename from pipewire/client/connection.c rename to pipewire/modules/module-protocol-native/connection.c index 94ebcac80..6cc5731ef 100644 --- a/pipewire/client/connection.c +++ b/pipewire/modules/module-protocol-native/connection.c @@ -27,9 +27,8 @@ #include -#include "pipewire.h" +#include #include "connection.h" -#include "log.h" /** \cond */ @@ -52,10 +51,14 @@ struct buffer { bool update; }; -struct pw_connection_impl { +struct impl { struct pw_connection this; struct buffer in, out; + + uint32_t dest_id; + uint8_t opcode; + struct spa_pod_builder builder; }; /** \endcond */ @@ -70,7 +73,7 @@ struct pw_connection_impl { */ int pw_connection_get_fd(struct pw_connection *conn, uint32_t index) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); if (index < 0 || index >= impl->in.n_fds) return -1; @@ -88,7 +91,7 @@ int pw_connection_get_fd(struct pw_connection *conn, uint32_t index) */ uint32_t pw_connection_add_fd(struct pw_connection *conn, int fd) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); uint32_t index, i; for (i = 0; i < impl->out.n_fds; i++) { @@ -186,10 +189,10 @@ static void clear_buffer(struct buffer *buf) */ struct pw_connection *pw_connection_new(int fd) { - struct pw_connection_impl *impl; + struct impl *impl; struct pw_connection *this; - impl = calloc(1, sizeof(struct pw_connection_impl)); + impl = calloc(1, sizeof(struct impl)); if (impl == NULL) return NULL; @@ -229,7 +232,7 @@ struct pw_connection *pw_connection_new(int fd) */ void pw_connection_destroy(struct pw_connection *conn) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); pw_log_debug("connection %p: destroy", conn); @@ -261,7 +264,7 @@ pw_connection_get_next(struct pw_connection *conn, void **dt, uint32_t *sz) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); size_t len, size; uint8_t *data; struct buffer *buf; @@ -326,20 +329,9 @@ pw_connection_get_next(struct pw_connection *conn, return true; } -/** Start writing \a size bytes - * - * \param conn the connection - * \param size the number of bytes to write - * \return memory to write into - * - * Makes sure that \a size bytes can be written to \a conn and - * returns a pointer to the memory to write into - * - * \memberof pw_connection - */ -void *pw_connection_begin_write(struct pw_connection *conn, uint32_t size) +static inline void *begin_write(struct pw_connection *conn, uint32_t size) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); uint32_t *p; struct buffer *buf = &impl->out; /* 4 for dest_id, 1 for opcode, 3 for size and size for payload */ @@ -347,28 +339,91 @@ void *pw_connection_begin_write(struct pw_connection *conn, uint32_t size) return p + 2; } -/** End writing to the connection - * - * \param conn the connection - * \param dest_id the destination id - * \param opcode the opcode - * \param size the total written size - * - * Finnish writing a message of \a size to \a conn and write the - * \a dest_id and \a opcode and final size to the connection - * - * \memberof pw_connection - */ -void -pw_connection_end_write(struct pw_connection *conn, uint32_t dest_id, uint8_t opcode, uint32_t size) +static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); - uint32_t *p; + struct impl *impl = SPA_CONTAINER_OF(b, struct impl, builder); + + if (ref == -1) + ref = b->offset; + + if (b->size <= b->offset) { + b->size = SPA_ROUND_UP_N(b->offset + size, 4096); + b->data = begin_write(&impl->this, b->size); + } + memcpy(b->data + ref, data, size); + + return ref; +} + +struct spa_pod_builder * +pw_connection_begin_write_resource(struct pw_connection *conn, + struct pw_resource *resource, + uint8_t opcode) +{ + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); + uint32_t diff, base, i, b; + struct pw_client *client = resource->client; + struct pw_core *core = client->core; + const char **types; + + base = client->n_types; + diff = spa_type_map_get_size(core->type.map) - base; + if (diff > 0) { + types = alloca(diff * sizeof(char *)); + for (i = 0, b = base; i < diff; i++, b++) + types[i] = spa_type_map_get_type(core->type.map, b); + + client->n_types += diff; + pw_core_notify_update_types(client->core_resource, base, diff, types); + } + + impl->dest_id = resource->id; + impl->opcode = opcode; + impl->builder = (struct spa_pod_builder) { NULL, 0, 0, NULL, write_pod }; + + return &impl->builder; +} + +struct spa_pod_builder * +pw_connection_begin_write_proxy(struct pw_connection *conn, + struct pw_proxy *proxy, + uint8_t opcode) +{ + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); + uint32_t diff, base, i, b; + const char **types; + struct pw_remote *remote = proxy->remote; + struct pw_core *core = remote->core; + + base = remote->n_types; + diff = spa_type_map_get_size(core->type.map) - base; + if (diff > 0) { + types = alloca(diff * sizeof(char *)); + for (i = 0, b = base; i < diff; i++, b++) + types[i] = spa_type_map_get_type(core->type.map, b); + + remote->n_types += diff; + pw_core_do_update_types(remote->core_proxy, base, diff, types); + } + + impl->dest_id = proxy->id; + impl->opcode = opcode; + impl->builder = (struct spa_pod_builder) { NULL, 0, 0, NULL, write_pod }; + + return &impl->builder; +} + +void +pw_connection_end_write(struct pw_connection *conn, + struct spa_pod_builder *builder) +{ + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); + uint32_t *p, size = builder->offset; struct buffer *buf = &impl->out; p = connection_ensure_size(conn, buf, 8 + size); - *p++ = dest_id; - *p++ = (opcode << 24) | (size & 0xffffff); + *p++ = impl->dest_id; + *p++ = (impl->opcode << 24) | (size & 0xffffff); buf->buffer_size += 8 + size; @@ -391,7 +446,7 @@ pw_connection_end_write(struct pw_connection *conn, uint32_t dest_id, uint8_t op */ bool pw_connection_flush(struct pw_connection *conn) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); ssize_t len; struct msghdr msg = { 0 }; struct iovec iov[1]; @@ -463,7 +518,7 @@ bool pw_connection_flush(struct pw_connection *conn) */ bool pw_connection_clear(struct pw_connection *conn) { - struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this); + struct impl *impl = SPA_CONTAINER_OF(conn, struct impl, this); clear_buffer(&impl->out); clear_buffer(&impl->in); diff --git a/pipewire/client/connection.h b/pipewire/modules/module-protocol-native/connection.h similarity index 87% rename from pipewire/client/connection.h rename to pipewire/modules/module-protocol-native/connection.h index f6f6ae4e4..1601a0b89 100644 --- a/pipewire/client/connection.h +++ b/pipewire/modules/module-protocol-native/connection.h @@ -61,12 +61,20 @@ pw_connection_get_next(struct pw_connection *conn, uint32_t *dest_id, void **data, uint32_t *size); -void * -pw_connection_begin_write(struct pw_connection *conn, uint32_t size); +struct spa_pod_builder * +pw_connection_begin_write_resource(struct pw_connection *conn, + struct pw_resource *resource, + uint8_t opcode); + +struct spa_pod_builder * +pw_connection_begin_write_proxy(struct pw_connection *conn, + struct pw_proxy *proxy, + uint8_t opcode); + void pw_connection_end_write(struct pw_connection *conn, - uint32_t dest_id, uint8_t opcode, uint32_t size); + struct spa_pod_builder *builder); bool pw_connection_flush(struct pw_connection *conn); diff --git a/pipewire/modules/module-protocol-native/protocol-native.c b/pipewire/modules/module-protocol-native/protocol-native.c index eaed5bd50..2cac84a7e 100644 --- a/pipewire/modules/module-protocol-native/protocol-native.c +++ b/pipewire/modules/module-protocol-native/protocol-native.c @@ -24,129 +24,66 @@ #include "pipewire/client/protocol.h" #include "pipewire/client/interfaces.h" -#include "pipewire/client/connection.h" #include "pipewire/server/resource.h" +#include "connection.h" + /** \cond */ -struct builder { - struct spa_pod_builder b; - struct pw_connection *connection; -}; typedef bool(*demarshal_func_t) (void *object, void *data, size_t size); /** \endcond */ -static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size) -{ - if (ref == -1) - ref = b->offset; - - if (b->size <= b->offset) { - b->size = SPA_ROUND_UP_N(b->offset + size, 4096); - b->data = pw_connection_begin_write(((struct builder *) b)->connection, b->size); - } - memcpy(b->data + ref, data, size); - return ref; -} - -static void core_update_map_client(struct pw_context *context) -{ - uint32_t diff, base, i; - const char **types; - - base = context->n_types; - diff = spa_type_map_get_size(context->type.map) - base; - if (diff == 0) - return; - - types = alloca(diff * sizeof(char *)); - for (i = 0; i < diff; i++, base++) - types[i] = spa_type_map_get_type(context->type.map, base); - - pw_core_do_update_types(context->core_proxy, context->n_types, diff, types); - context->n_types += diff; -} - -static void core_update_map_server(struct pw_client *client) -{ - uint32_t diff, base, i; - struct pw_core *core = client->core; - const char **types; - - base = client->n_types; - diff = spa_type_map_get_size(core->type.map) - base; - if (diff == 0) - return; - - types = alloca(diff * sizeof(char *)); - for (i = 0; i < diff; i++, base++) - types[i] = spa_type_map_get_type(core->type.map, base); - - pw_core_notify_update_types(client->core_resource, client->n_types, diff, types); - client->n_types += diff; -} - - static void core_marshal_client_update(void *object, const struct spa_dict *props) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; int i, n_items; - if (connection == NULL) - return; - - core_update_map_client(proxy->context); + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CLIENT_UPDATE); n_items = props ? props->n_items : 0; - spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, n_items, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, props->items[i].key, SPA_POD_TYPE_STRING, props->items[i].value, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CLIENT_UPDATE, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_sync(void *object, uint32_t seq) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_SYNC); - core_update_map_client(proxy->context); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq); - - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_SYNC, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_get_registry(void *object, uint32_t new_id) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_GET_REGISTRY); - core_update_map_client(proxy->context); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, new_id); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, new_id); - - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_GET_REGISTRY, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -155,31 +92,28 @@ core_marshal_create_node(void *object, const char *name, const struct spa_dict *props, uint32_t new_id) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - if (connection == NULL) - return; - - core_update_map_client(proxy->context); + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_NODE); n_items = props ? props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_STRING, factory_name, SPA_POD_TYPE_STRING, name, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, props->items[i].key, SPA_POD_TYPE_STRING, props->items[i].value, 0); } - spa_pod_builder_add(&b.b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_NODE, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -193,19 +127,16 @@ core_marshal_create_link(void *object, uint32_t new_id) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - if (connection == NULL) - return; - - core_update_map_client(proxy->context); + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_LINK); n_items = props ? props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, output_node_id, SPA_POD_TYPE_INT, output_port_id, @@ -215,39 +146,38 @@ core_marshal_create_link(void *object, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, props->items[i].key, SPA_POD_TYPE_STRING, props->items[i].value, 0); } - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_INT, new_id, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_CREATE_LINK, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_update_types_client(void *object, uint32_t first_id, uint32_t n_types, const char **types) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_UPDATE_TYPES); - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0); for (i = 0; i < n_types; i++) { - spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRING, types[i], 0); + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, types[i], 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_UPDATE_TYPES, b.b.offset); + pw_connection_end_write(connection, b); } static bool core_demarshal_info(void *object, void *data, size_t size) @@ -351,15 +281,15 @@ static void core_marshal_info(void *object, struct pw_core_info *info) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_INFO); n_items = info->props ? info->props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, info->id, SPA_POD_TYPE_LONG, info->change_mask, @@ -370,27 +300,27 @@ static void core_marshal_info(void *object, struct pw_core_info *info) SPA_POD_TYPE_INT, info->cookie, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, info->props->items[i].key, SPA_POD_TYPE_STRING, info->props->items[i].value, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_INFO, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_done(void *object, uint32_t seq) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_DONE); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, seq); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, seq); - pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_DONE, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_error(void *object, uint32_t id, int res, const char *error, ...) @@ -398,35 +328,35 @@ static void core_marshal_error(void *object, uint32_t id, int res, const char *e struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; char buffer[128]; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; va_list ap; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_ERROR); va_start(ap, error); vsnprintf(buffer, sizeof(buffer), error, ap); va_end(ap); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id, SPA_POD_TYPE_INT, res, SPA_POD_TYPE_STRING, buffer); - pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_ERROR, b.b.offset); + pw_connection_end_write(connection, b); } static void core_marshal_remove_id(void *object, uint32_t id) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_REMOVE_ID); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, id); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id); - pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_REMOVE_ID, b.b.offset); + pw_connection_end_write(connection, b); } static void @@ -434,20 +364,22 @@ core_marshal_update_types_server(void *object, uint32_t first_id, uint32_t n_typ { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i; - spa_pod_builder_add(&b.b, + b = pw_connection_begin_write_resource(connection, resource, PW_CORE_EVENT_UPDATE_TYPES); + + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0); for (i = 0; i < n_types; i++) { - spa_pod_builder_add(&b.b, SPA_POD_TYPE_STRING, types[i], 0); + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, types[i], 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_CORE_EVENT_UPDATE_TYPES, b.b.offset); + pw_connection_end_write(connection, b); } static bool core_demarshal_client_update(void *object, void *data, size_t size) @@ -594,32 +526,31 @@ static void registry_marshal_global(void *object, uint32_t id, const char *type, { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_REGISTRY_EVENT_GLOBAL); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id, SPA_POD_TYPE_STRING, type, SPA_POD_TYPE_INT, version); - pw_connection_end_write(connection, resource->id, PW_REGISTRY_EVENT_GLOBAL, b.b.offset); + pw_connection_end_write(connection, b); } static void registry_marshal_global_remove(void *object, uint32_t id) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_REGISTRY_EVENT_GLOBAL_REMOVE); - spa_pod_builder_struct(&b.b, &f, SPA_POD_TYPE_INT, id); + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id); - pw_connection_end_write(connection, resource->id, PW_REGISTRY_EVENT_GLOBAL_REMOVE, - b.b.offset); + pw_connection_end_write(connection, b); } static bool registry_demarshal_bind(void *object, void *data, size_t size) @@ -643,15 +574,15 @@ static void module_marshal_info(void *object, struct pw_module_info *info) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_MODULE_EVENT_INFO); n_items = info->props ? info->props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, info->id, SPA_POD_TYPE_LONG, info->change_mask, @@ -660,13 +591,13 @@ static void module_marshal_info(void *object, struct pw_module_info *info) SPA_POD_TYPE_STRING, info->args, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, info->props->items[i].key, SPA_POD_TYPE_STRING, info->props->items[i].value, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_MODULE_EVENT_INFO, b.b.offset); + pw_connection_end_write(connection, b); } static bool module_demarshal_info(void *object, void *data, size_t size) @@ -702,13 +633,13 @@ static void node_marshal_info(void *object, struct pw_node_info *info) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_NODE_EVENT_INFO); - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, info->id, SPA_POD_TYPE_LONG, info->change_mask, @@ -718,30 +649,30 @@ static void node_marshal_info(void *object, struct pw_node_info *info) SPA_POD_TYPE_INT, info->n_input_formats, 0); for (i = 0; i < info->n_input_formats; i++) - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, info->input_formats[i], 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, info->input_formats[i], 0); - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_INT, info->max_output_ports, SPA_POD_TYPE_INT, info->n_output_ports, SPA_POD_TYPE_INT, info->n_output_formats, 0); for (i = 0; i < info->n_output_formats; i++) - spa_pod_builder_add(&b.b, SPA_POD_TYPE_POD, info->output_formats[i], 0); + spa_pod_builder_add(b, SPA_POD_TYPE_POD, info->output_formats[i], 0); n_items = info->props ? info->props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_INT, info->state, SPA_POD_TYPE_STRING, info->error, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, info->props->items[i].key, SPA_POD_TYPE_STRING, info->props->items[i].value, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_NODE_EVENT_INFO, b.b.offset); + pw_connection_end_write(connection, b); } static bool node_demarshal_info(void *object, void *data, size_t size) @@ -753,7 +684,7 @@ static bool node_demarshal_info(void *object, void *data, size_t size) int i; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &info.id, SPA_POD_TYPE_LONG, &info.change_mask, @@ -801,27 +732,27 @@ static void client_marshal_info(void *object, struct pw_client_info *info) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; uint32_t i, n_items; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_CLIENT_EVENT_INFO); n_items = info->props ? info->props->n_items : 0; - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRUCT, &f, SPA_POD_TYPE_INT, info->id, SPA_POD_TYPE_LONG, info->change_mask, SPA_POD_TYPE_INT, n_items, 0); for (i = 0; i < n_items; i++) { - spa_pod_builder_add(&b.b, + spa_pod_builder_add(b, SPA_POD_TYPE_STRING, info->props->items[i].key, SPA_POD_TYPE_STRING, info->props->items[i].value, 0); } - spa_pod_builder_add(&b.b, -SPA_POD_TYPE_STRUCT, &f, 0); + spa_pod_builder_add(b, -SPA_POD_TYPE_STRUCT, &f, 0); - pw_connection_end_write(connection, resource->id, PW_CLIENT_EVENT_INFO, b.b.offset); + pw_connection_end_write(connection, b); } static bool client_demarshal_info(void *object, void *data, size_t size) @@ -855,12 +786,12 @@ static void link_marshal_info(void *object, struct pw_link_info *info) { struct pw_resource *resource = object; struct pw_connection *connection = resource->client->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct spa_pod_builder *b; struct spa_pod_frame f; - core_update_map_server(resource->client); + b = pw_connection_begin_write_resource(connection, resource, PW_LINK_EVENT_INFO); - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, info->id, SPA_POD_TYPE_LONG, info->change_mask, SPA_POD_TYPE_INT, info->output_node_id, @@ -869,7 +800,7 @@ static void link_marshal_info(void *object, struct pw_link_info *info) SPA_POD_TYPE_INT, info->input_port_id, SPA_POD_TYPE_POD, info->format); - pw_connection_end_write(connection, resource->id, PW_LINK_EVENT_INFO, b.b.offset); + pw_connection_end_write(connection, b); } static bool link_demarshal_info(void *object, void *data, size_t size) @@ -879,7 +810,7 @@ static bool link_demarshal_info(void *object, void *data, size_t size) struct pw_link_info info = { 0, }; if (!spa_pod_iter_struct(&it, data, size) || - !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->context->types) || + !pw_pod_remap_data(SPA_POD_TYPE_STRUCT, data, size, &proxy->remote->types) || !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &info.id, SPA_POD_TYPE_LONG, &info.change_mask, @@ -929,21 +860,18 @@ static bool registry_demarshal_global_remove(void *object, void *data, size_t si static void registry_marshal_bind(void *object, uint32_t id, uint32_t version, uint32_t new_id) { struct pw_proxy *proxy = object; - struct pw_connection *connection = proxy->context->protocol_private; - struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection }; + struct pw_connection *connection = proxy->remote->protocol_private; + struct spa_pod_builder *b; struct spa_pod_frame f; - if (connection == NULL) - return; + b = pw_connection_begin_write_proxy(connection, proxy, PW_REGISTRY_METHOD_BIND); - core_update_map_client(proxy->context); - - spa_pod_builder_struct(&b.b, &f, + spa_pod_builder_struct(b, &f, SPA_POD_TYPE_INT, id, SPA_POD_TYPE_INT, version, SPA_POD_TYPE_INT, new_id); - pw_connection_end_write(connection, proxy->id, PW_REGISTRY_METHOD_BIND, b.b.offset); + pw_connection_end_write(connection, b); } static const struct pw_core_methods pw_protocol_native_client_core_methods = { diff --git a/pipewire/modules/module-suspend-on-idle.c b/pipewire/modules/module-suspend-on-idle.c index 9b4e1077e..8a4844ae9 100644 --- a/pipewire/modules/module-suspend-on-idle.c +++ b/pipewire/modules/module-suspend-on-idle.c @@ -59,7 +59,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->loop, info->idle_timeout); + pw_loop_destroy_source(info->impl->core->main_loop, info->idle_timeout); info->idle_timeout = NULL; } } @@ -102,11 +102,11 @@ on_node_state_changed(struct pw_listener *listener, struct timespec value; pw_log_debug("module %p: node %p became idle", impl, node); - info->idle_timeout = pw_loop_add_timer(impl->core->main_loop->loop, + info->idle_timeout = pw_loop_add_timer(impl->core->main_loop, idle_timeout, info); value.tv_sec = 3; value.tv_nsec = 0; - pw_loop_update_timer(impl->core->main_loop->loop, + pw_loop_update_timer(impl->core->main_loop, info->idle_timeout, &value, NULL, false); } } diff --git a/pipewire/modules/spa/meson.build b/pipewire/modules/spa/meson.build index 27a062eb3..ee50aecb3 100644 --- a/pipewire/modules/spa/meson.build +++ b/pipewire/modules/spa/meson.build @@ -22,3 +22,13 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node', install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], ) + +pipewire_module_spa_node_factory = shared_library('pipewire-module-spa-node-factory', + [ 'module-node-factory.c', 'spa-node.c' ], + c_args : pipewire_module_spa_c_args, + include_directories : [configinc, spa_inc], + link_with : spalib, + install : true, + install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')), + dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep], +) diff --git a/pipewire/modules/spa/module-node-factory.c b/pipewire/modules/spa/module-node-factory.c new file mode 100644 index 000000000..2acdf7682 --- /dev/null +++ b/pipewire/modules/spa/module-node-factory.c @@ -0,0 +1,117 @@ +/* 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. + */ + +#include +#include +#include +#include + +#include "config.h" + +#include "pipewire/client/interfaces.h" +#include "pipewire/server/core.h" +#include "pipewire/server/module.h" +#include "spa-node.h" + +struct impl { + struct pw_node_factory this; + struct pw_properties *properties; +}; + +static struct pw_node *create_node(struct pw_node_factory *factory, + struct pw_resource *resource, + const char *name, + struct pw_properties *properties) +{ + struct pw_node *node; + const char *lib, *factory_name; + + if (properties == NULL) + goto no_properties; + + lib = pw_properties_get(properties, "spa.library.name"); + factory_name = pw_properties_get(properties, "spa.factory.name"); + + if(lib == NULL || factory_name == NULL) + goto no_properties; + + node = pw_spa_node_load(factory->core, + NULL, + lib, + factory_name, + name, + properties); + if (node == NULL) + goto no_mem; + + return node; + + no_properties: + pw_log_error("missing properties"); + if (resource) { + pw_core_notify_error(resource->client->core_resource, + resource->client->core_resource->id, + SPA_RESULT_INVALID_ARGUMENTS, "missing properties"); + } + return NULL; + no_mem: + pw_log_error("can't create node"); + if (resource) { + pw_core_notify_error(resource->client->core_resource, + resource->client->core_resource->id, + SPA_RESULT_NO_MEMORY, "no memory"); + } + return NULL; +} + +static struct impl *module_new(struct pw_core *core, struct pw_properties *properties) +{ + struct impl *impl; + + impl = calloc(1, sizeof(struct impl)); + pw_log_debug("module %p: new", impl); + + impl->properties = properties; + + impl->this.core = core; + impl->this.name = "spa-node-factory"; + pw_signal_init(&impl->this.destroy_signal); + impl->this.create_node = create_node; + + spa_list_insert(core->node_factory_list.prev, &impl->this.link); + + pw_core_add_global(core, NULL, core->type.node_factory, 0, impl, NULL, &impl->this.global); + + return impl; +} + +#if 0 +static void module_destroy(struct impl *impl) +{ + pw_log_debug("module %p: destroy", impl); + + free(impl); +} +#endif + +bool pipewire__module_init(struct pw_module *module, const char *args) +{ + module_new(module->core, NULL); + return true; +} diff --git a/pipewire/modules/spa/spa-node.c b/pipewire/modules/spa/spa-node.c index d03f6ac4f..a3aaf5c1a 100644 --- a/pipewire/modules/spa/spa-node.c +++ b/pipewire/modules/spa/spa-node.c @@ -270,12 +270,26 @@ node_impl_add_port(struct pw_node *node, return make_port(node, direction, port_id); } +static int node_impl_schedule_input(struct pw_node *node) +{ + struct impl *impl = node->user_data; + return spa_node_process_input(impl->node); +} + +static int node_impl_schedule_output(struct pw_node *node) +{ + struct impl *impl = node->user_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, }; static void pw_spa_node_destroy(void *object) @@ -347,16 +361,16 @@ on_node_reuse_buffer(struct spa_node *node, uint32_t port_id, uint32_t buffer_id { struct impl *impl = user_data; struct pw_node *this = impl->this; - struct spa_graph_port *p; + struct spa_graph_port *p, *pp; spa_list_for_each(p, &this->rt.node.ports[SPA_DIRECTION_INPUT], link) { if (p->port_id != port_id) continue; - if (p->peer && p->peer->node->methods->reuse_buffer) { - struct spa_graph_node *n = p->peer->node; - n->methods->reuse_buffer(p->peer, buffer_id, n->user_data); - } + pp = p->peer; + if (pp && pp->methods->reuse_buffer) + pp->methods->reuse_buffer(pp, buffer_id, pp->user_data); + break; } } @@ -403,8 +417,6 @@ pw_spa_node_new(struct pw_core *core, this->destroy = pw_spa_node_destroy; this->implementation = &node_impl; - this->rt.methods = spa_graph_scheduler_default; - this->rt.node.user_data = node; this->clock = clock; impl = this->user_data; diff --git a/pipewire/server/client.h b/pipewire/server/client.h index c429e4419..4f190a1b9 100644 --- a/pipewire/server/client.h +++ b/pipewire/server/client.h @@ -24,6 +24,10 @@ extern "C" { #endif +#ifndef __USE_GNU +#define __USE_GNU +#endif + #include #include diff --git a/pipewire/server/core.c b/pipewire/server/core.c index 0f030a860..68cf459c5 100644 --- a/pipewire/server/core.c +++ b/pipewire/server/core.c @@ -35,6 +35,7 @@ struct impl { struct pw_core this; struct spa_support support[4]; + struct pw_data_loop *data_loop; }; /** \endcond */ @@ -152,6 +153,7 @@ core_create_node(void *object, uint32_t new_id) { struct pw_resource *resource = object; + struct pw_resource *node_resource; struct pw_client *client = resource->client; struct pw_node_factory *factory; struct pw_properties *properties; @@ -160,15 +162,22 @@ core_create_node(void *object, if (factory == NULL) goto no_factory; + node_resource = pw_resource_new(client, + new_id, + factory->type, + 0); + if (node_resource == NULL) + goto no_resource; + if (props) { properties = pw_properties_new_dict(props); if (properties == NULL) - goto no_mem; + goto no_properties; } else properties = NULL; /* error will be posted */ - pw_node_factory_create_node(factory, client, name, properties, new_id); + pw_node_factory_create_node(factory, node_resource, name, properties); properties = NULL; done: @@ -180,8 +189,14 @@ core_create_node(void *object, resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name"); goto done; - no_mem: + no_resource: + pw_log_error("can't create resource"); + goto no_mem; + no_properties: pw_log_error("can't create properties"); + pw_resource_destroy(node_resource); + goto no_mem; + no_mem: pw_core_notify_error(client->core_resource, resource->id, SPA_RESULT_NO_MEMORY, "no memory"); goto done; @@ -271,7 +286,7 @@ core_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers * * \memberof pw_core */ -struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties *properties) +struct pw_core *pw_core_new(struct pw_loop *main_loop, struct pw_properties *properties) { struct impl *impl; struct pw_core *this; @@ -281,10 +296,11 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties return NULL; this = &impl->this; - this->data_loop = pw_data_loop_new(); - if (this->data_loop == NULL) + impl->data_loop = pw_data_loop_new(); + if (impl->data_loop == NULL) goto no_data_loop; + this->data_loop = impl->data_loop->loop; this->main_loop = main_loop; this->properties = properties; @@ -297,14 +313,15 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties 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->loop); - impl->support[2] = SPA_SUPPORT_INIT(SPA_TYPE_LOOP__MainLoop, this->main_loop->loop->loop); + 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->n_support = 4; - pw_data_loop_start(this->data_loop); + pw_data_loop_start(impl->data_loop); + spa_list_init(&this->remote_list); spa_list_init(&this->resource_list); spa_list_init(&this->registry_resource_list); spa_list_init(&this->global_list); @@ -312,6 +329,7 @@ struct pw_core *pw_core_new(struct pw_main_loop *main_loop, struct pw_properties 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); @@ -348,7 +366,7 @@ void pw_core_destroy(struct pw_core *core) pw_log_debug("core %p: destroy", core); pw_signal_emit(&core->destroy_signal, core); - pw_data_loop_destroy(core->data_loop); + pw_data_loop_destroy(impl->data_loop); pw_map_clear(&core->objects); @@ -497,6 +515,8 @@ 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); + spa_list_for_each(resource, &core->resource_list, link) { pw_core_notify_info(resource, &core->info); } diff --git a/pipewire/server/core.h b/pipewire/server/core.h index 01950ca9b..da975809a 100644 --- a/pipewire/server/core.h +++ b/pipewire/server/core.h @@ -148,6 +148,8 @@ 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 */ @@ -158,6 +160,7 @@ struct pw_core { struct pw_map objects; /**< map of known objects */ + 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 global_list; /**< list of globals */ @@ -166,8 +169,8 @@ struct pw_core { struct spa_list node_factory_list; /**< list of node factories */ struct spa_list link_list; /**< list of links */ - struct pw_main_loop *main_loop; /**< main loop for control */ - struct pw_data_loop *data_loop; /**< data loop for data passing */ + 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 */ @@ -189,7 +192,7 @@ struct pw_core { }; struct pw_core * -pw_core_new(struct pw_main_loop *main_loop, struct pw_properties *props); +pw_core_new(struct pw_loop *main_loop, struct pw_properties *props); void pw_core_destroy(struct pw_core *core); diff --git a/pipewire/server/link.c b/pipewire/server/link.c index 065e3978d..d598376d4 100644 --- a/pipewire/server/link.c +++ b/pipewire/server/link.c @@ -774,7 +774,7 @@ static void input_remove(struct pw_link *this, struct pw_port *port) pw_signal_remove(&impl->input_port_destroy); pw_signal_remove(&impl->input_async_complete); - pw_loop_invoke(port->node->data_loop->loop, + pw_loop_invoke(port->node->data_loop, do_remove_input, 1, 0, NULL, true, this); clear_port_buffers(this, this->input); @@ -797,7 +797,7 @@ static void output_remove(struct pw_link *this, struct pw_port *port) pw_signal_remove(&impl->output_port_destroy); pw_signal_remove(&impl->output_async_complete); - pw_loop_invoke(port->node->data_loop->loop, + pw_loop_invoke(port->node->data_loop, do_remove_output, 1, 0, NULL, true, this); clear_port_buffers(this, this->output); @@ -865,7 +865,7 @@ bool pw_link_activate(struct pw_link *this) impl->active = true; pw_log_debug("link %p: activate", this); - pw_loop_invoke(this->output->node->data_loop->loop, + pw_loop_invoke(this->output->node->data_loop, do_activate_link, SPA_ID_INVALID, 0, NULL, false, this); this->output->node->n_used_output_links++; @@ -896,7 +896,7 @@ bool pw_link_deactivate(struct pw_link *this) impl->active = false; pw_log_debug("link %p: deactivate", this); - pw_loop_invoke(this->output->node->data_loop->loop, + pw_loop_invoke(this->output->node->data_loop, do_deactivate_link, SPA_ID_INVALID, 0, NULL, true, this); input_node = this->input->node; @@ -1007,7 +1007,7 @@ struct pw_link *pw_link_new(struct pw_core *core, this = &impl->this; pw_log_debug("link %p: new", this); - impl->work = pw_work_queue_new(core->main_loop->loop); + impl->work = pw_work_queue_new(core->main_loop); this->core = core; this->properties = properties; @@ -1073,10 +1073,10 @@ struct pw_link *pw_link_new(struct pw_core *core, 0, &this->io); - pw_loop_invoke(output_node->data_loop->loop, + pw_loop_invoke(output_node->data_loop, do_add_link, SPA_ID_INVALID, sizeof(struct pw_port *), &output, false, this); - pw_loop_invoke(input_node->data_loop->loop, + pw_loop_invoke(input_node->data_loop, do_add_link, SPA_ID_INVALID, sizeof(struct pw_port *), &input, false, this); diff --git a/pipewire/server/link.h b/pipewire/server/link.h index f55d22580..254f674bf 100644 --- a/pipewire/server/link.h +++ b/pipewire/server/link.h @@ -27,6 +27,7 @@ extern "C" { #include #include +#include #include #include diff --git a/pipewire/server/meson.build b/pipewire/server/meson.build index 8fc7613ad..b0418eac5 100644 --- a/pipewire/server/meson.build +++ b/pipewire/server/meson.build @@ -9,8 +9,8 @@ pipewirecore_headers = [ 'node.h', 'node-factory.h', 'port.h', + 'remote.h', 'resource.h', -# 'spa-node.h', 'work-queue.h', ] @@ -25,8 +25,8 @@ pipewirecore_sources = [ 'node.c', 'node-factory.c', 'port.c', + 'remote.c', 'resource.c', -# 'spa-node.c', 'work-queue.c', ] diff --git a/pipewire/server/node-factory.h b/pipewire/server/node-factory.h index 452357523..bda87d855 100644 --- a/pipewire/server/node-factory.h +++ b/pipewire/server/node-factory.h @@ -42,16 +42,16 @@ struct pw_node_factory { struct pw_global *global; /**< global for this factory */ const char *name; /**< the factory name */ + uint32_t type; /**< type of the created nodes */ /** Emited when the factory is destroyed */ PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object)); /** The function to create a node from this factory */ struct pw_node *(*create_node) (struct pw_node_factory *factory, - struct pw_client *client, + struct pw_resource *resource, const char *name, - struct pw_properties *properties, - uint32_t new_id); + struct pw_properties *properties); }; #define pw_node_factory_create_node(f,...) (f)->create_node((f),__VA_ARGS__) diff --git a/pipewire/server/node.c b/pipewire/server/node.c index a99da3272..815145647 100644 --- a/pipewire/server/node.c +++ b/pipewire/server/node.c @@ -261,7 +261,7 @@ void pw_node_export(struct pw_node *this) this->owner, this->core->type.node, 0, this, node_bind_func, &this->global); - pw_loop_invoke(this->data_loop->loop, do_node_add, 1, 0, NULL, false, this); + pw_loop_invoke(this->data_loop, do_node_add, 1, 0, NULL, false, this); update_info(this); @@ -272,6 +272,26 @@ void pw_node_export(struct pw_node *this) pw_node_update_state(this, PW_NODE_STATE_SUSPENDED, NULL); } +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); +} + +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); +} + +static const struct spa_graph_node_methods graph_methods = { + SPA_VERSION_GRAPH_NODE_METHODS, + graph_impl_process_input, + graph_impl_process_output, +}; + struct pw_node *pw_node_new(struct pw_core *core, struct pw_resource *owner, const char *name, @@ -293,7 +313,7 @@ struct pw_node *pw_node_new(struct pw_core *core, if (user_data_size > 0) this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void); - impl->work = pw_work_queue_new(this->core->main_loop->loop); + impl->work = pw_work_queue_new(this->core->main_loop); this->info.name = strdup(name); this->properties = properties; @@ -324,9 +344,10 @@ struct pw_node *pw_node_new(struct pw_core *core, spa_list_init(&this->output_ports); pw_map_init(&this->output_port_map, 64, 64); - spa_graph_node_init(&this->rt.node, - &this->rt.methods, - this); + spa_graph_node_init(&this->rt.node); + spa_graph_node_set_methods(&this->rt.node, + &graph_methods, + this); return this; } @@ -361,7 +382,7 @@ void pw_node_destroy(struct pw_node *node) pw_log_debug("node %p: destroy", impl); pw_signal_emit(&node->destroy_signal, node); - pw_loop_invoke(node->data_loop->loop, do_node_remove, 1, 0, NULL, true, node); + pw_loop_invoke(node->data_loop, do_node_remove, 1, 0, NULL, true, node); if (impl->exported) { spa_list_remove(&node->link); diff --git a/pipewire/server/node.h b/pipewire/server/node.h index 4ba59634e..fe929be63 100644 --- a/pipewire/server/node.h +++ b/pipewire/server/node.h @@ -31,6 +31,7 @@ extern "C" { #include #include +#include #include #include @@ -57,6 +58,10 @@ struct pw_node_implementation { 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 @@ -132,10 +137,9 @@ struct pw_node { PW_SIGNAL(event, (struct pw_listener *listener, struct pw_node *node, struct spa_event *event)); - struct pw_data_loop *data_loop; /**< the data loop for this node */ + struct pw_loop *data_loop; /**< the data loop for this node */ struct { - struct spa_graph_node_methods methods; struct spa_graph_scheduler *sched; struct spa_graph_node node; } rt; diff --git a/pipewire/server/port.c b/pipewire/server/port.c index cdb555262..f81bb256a 100644 --- a/pipewire/server/port.c +++ b/pipewire/server/port.c @@ -74,15 +74,19 @@ static int schedule_tee_output(struct spa_graph_node *node, void *user_data) return SPA_RESULT_NEED_BUFFER; } +static const struct spa_graph_node_methods schedule_tee_node = { + SPA_VERSION_GRAPH_NODE_METHODS, + schedule_tee_input, + schedule_tee_output, +}; + static int schedule_tee_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data) { return SPA_RESULT_OK; } -static const struct spa_graph_node_methods schedule_tee = { - SPA_VERSION_GRAPH_NODE_METHODS, - schedule_tee_input, - schedule_tee_output, +static const struct spa_graph_port_methods schedule_tee_port = { + SPA_VERSION_GRAPH_PORT_METHODS, schedule_tee_reuse_buffer, }; @@ -114,15 +118,18 @@ static int schedule_mix_output(struct spa_graph_node *node, void *user_data) return SPA_RESULT_NEED_BUFFER; } +static const struct spa_graph_node_methods schedule_mix_node = { + SPA_VERSION_GRAPH_NODE_METHODS, + schedule_mix_input, + schedule_mix_output, +}; + static int schedule_mix_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data) { return SPA_RESULT_OK; } - -static const struct spa_graph_node_methods schedule_mix = { - SPA_VERSION_GRAPH_NODE_METHODS, - schedule_mix_input, - schedule_mix_output, +static const struct spa_graph_port_methods schedule_mix_port = { + SPA_VERSION_GRAPH_PORT_METHODS, schedule_mix_reuse_buffer, }; @@ -159,16 +166,22 @@ struct pw_port *pw_port_new(enum pw_direction direction, this->port_id, 0, &this->io); - spa_graph_node_init(&this->rt.mix_node, - this->direction == PW_DIRECTION_INPUT ? - &schedule_mix : - &schedule_tee, - this); + spa_graph_node_init(&this->rt.mix_node); + spa_graph_node_set_methods(&this->rt.mix_node, + this->direction == PW_DIRECTION_INPUT ? + &schedule_mix_node : + &schedule_tee_node, + this); spa_graph_port_init(&this->rt.mix_port, pw_direction_reverse(this->direction), 0, 0, &this->io); + spa_graph_port_set_methods(&this->rt.mix_port, + this->direction == PW_DIRECTION_INPUT ? + &schedule_mix_port : + &schedule_tee_port, + this); return this; } @@ -204,7 +217,7 @@ void pw_port_add(struct pw_port *port, struct pw_node *node) } port->rt.graph = node->rt.sched->graph; - pw_loop_invoke(node->data_loop->loop, do_add_port, SPA_ID_INVALID, 0, NULL, false, port); + pw_loop_invoke(node->data_loop, do_add_port, SPA_ID_INVALID, 0, NULL, false, port); port_update_state(port, PW_PORT_STATE_CONFIGURE); @@ -238,7 +251,7 @@ void pw_port_destroy(struct pw_port *port) pw_signal_emit(&port->destroy_signal, port); if (node) { - pw_loop_invoke(port->node->data_loop->loop, do_remove_port, SPA_ID_INVALID, 0, NULL, true, port); + pw_loop_invoke(port->node->data_loop, do_remove_port, SPA_ID_INVALID, 0, NULL, true, port); if (port->direction == PW_DIRECTION_INPUT) { pw_map_remove(&node->input_port_map, port->port_id); @@ -330,7 +343,7 @@ int pw_port_use_buffers(struct pw_port *port, struct spa_buffer **buffers, uint3 return SPA_RESULT_NO_FORMAT; if (port->state > PW_PORT_STATE_PAUSED) { - pw_loop_invoke(port->node->data_loop->loop, + pw_loop_invoke(port->node->data_loop, do_port_pause, 0, 0, NULL, true, port); port_update_state (port, PW_PORT_STATE_PAUSED); } @@ -362,7 +375,7 @@ int pw_port_alloc_buffers(struct pw_port *port, return SPA_RESULT_NO_FORMAT; if (port->state > PW_PORT_STATE_PAUSED) { - pw_loop_invoke(port->node->data_loop->loop, + pw_loop_invoke(port->node->data_loop, do_port_pause, 0, 0, NULL, true, port); port_update_state (port, PW_PORT_STATE_PAUSED); } diff --git a/pipewire/server/remote.c b/pipewire/server/remote.c new file mode 100644 index 000000000..dd5ba88dc --- /dev/null +++ b/pipewire/server/remote.c @@ -0,0 +1,289 @@ +/* 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. + */ + +#include +#include +#include +#include +#include + +#include "pipewire/client/pipewire.h" + +#include "pipewire/client/introspect.h" +#include "pipewire/client/interfaces.h" +#include "pipewire/client/connection.h" + +#include "pipewire/server/remote.h" +#include "pipewire/server/core.h" +#include "pipewire/server/module.h" + +#include + +/** \cond */ +struct remote { + struct pw_remote this; +}; +/** \endcond */ + +const char *pw_remote_state_as_string(enum pw_remote_state state) +{ + switch (state) { + case PW_REMOTE_STATE_ERROR: + return "error"; + case PW_REMOTE_STATE_UNCONNECTED: + return "unconnected"; + case PW_REMOTE_STATE_CONNECTING: + return "connecting"; + case PW_REMOTE_STATE_CONNECTED: + return "connected"; + } + return "invalid-state"; +} + +static void +remote_update_state(struct pw_remote *remote, enum pw_remote_state state, const char *fmt, ...) +{ + if (remote->state != state) { + if (remote->error) + free(remote->error); + + if (fmt) { + va_list varargs; + + va_start(varargs, fmt); + if (vasprintf(&remote->error, fmt, varargs) < 0) { + pw_log_debug("remote %p: error formating message: %m", remote); + remote->error = NULL; + } + va_end(varargs); + } else { + 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(state), remote->error); + + remote->state = state; + pw_signal_emit(&remote->state_changed, remote); + } +} + +static void core_event_info(void *object, struct pw_core_info *info) +{ + struct pw_proxy *proxy = object; + struct pw_remote *this = proxy->remote; + + pw_log_debug("got core info"); + this->info = pw_core_info_update(this->info, info); + pw_signal_emit(&this->info_changed, this); +} + +static void core_event_done(void *object, uint32_t seq) +{ + struct pw_proxy *proxy = object; + struct pw_remote *this = proxy->remote; + + pw_log_debug("core event done %d", seq); + if (seq == 0) + remote_update_state(this, PW_REMOTE_STATE_CONNECTED, NULL); + + pw_signal_emit(&this->sync_reply, this, seq); +} + +static void core_event_error(void *object, uint32_t id, int res, const char *error, ...) +{ + struct pw_proxy *proxy = object; + struct pw_remote *this = proxy->remote; + remote_update_state(this, PW_REMOTE_STATE_ERROR, error); +} + +static void core_event_remove_id(void *object, uint32_t id) +{ + struct pw_proxy *core_proxy = object; + struct pw_remote *this = core_proxy->remote; + struct pw_proxy *proxy; + + proxy = pw_map_lookup(&this->objects, id); + if (proxy) { + pw_log_debug("remote %p: object remove %u", this, id); + pw_proxy_destroy(proxy); + } +} + +static void +core_event_update_types(void *object, uint32_t first_id, uint32_t n_types, const char **types) +{ + struct pw_proxy *proxy = object; + struct pw_remote *this = proxy->remote; + int i; + + for (i = 0; i < n_types; i++, first_id++) { + uint32_t this_id = spa_type_map_get_id(this->core->type.map, types[i]); + if (!pw_map_insert_at(&this->types, first_id, PW_MAP_ID_TO_PTR(this_id))) + pw_log_error("can't add type for client"); + } +} + +static const struct pw_core_events core_events = { + &core_event_update_types, + &core_event_done, + &core_event_error, + &core_event_remove_id, + &core_event_info, +}; + +struct pw_remote *pw_remote_new(struct pw_core *core, + struct pw_properties *properties) +{ + struct remote *impl; + struct pw_remote *this; + + impl = calloc(1, sizeof(struct remote)); + if (impl == NULL) + return NULL; + + this = &impl->this; + pw_log_debug("remote %p: new", impl); + + this->core = core; + + if (properties == NULL) + properties = pw_properties_new(NULL, NULL); + if (properties == NULL) + goto no_mem; + + pw_fill_context_properties(properties); + this->properties = properties; + + this->state = PW_REMOTE_STATE_UNCONNECTED; + + pw_map_init(&this->objects, 64, 32); + pw_map_init(&this->types, 64, 32); + + 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_module_load(core, "libpipewire-module-protocol-native", NULL, NULL); + pw_module_load(core, "libpipewire-module-client-node", NULL, NULL); + this->protocol = pw_protocol_get(PW_TYPE_PROTOCOL__Native); + + this->conn = this->protocol->new_connection(this->protocol, this, properties); + + spa_list_insert(core->remote_list.prev, &this->link); + + return this; + + no_mem: + free(impl); + return NULL; +} + +void pw_remote_destroy(struct pw_remote *remote) +{ + struct remote *impl = SPA_CONTAINER_OF(remote, struct remote, this); + struct pw_proxy *proxy, *t2; + + pw_log_debug("remote %p: destroy", remote); + pw_signal_emit(&remote->destroy_signal, remote); + + if (remote->state != PW_REMOTE_STATE_UNCONNECTED) + pw_remote_disconnect(remote); + + remote->conn->destroy(remote->conn); + + spa_list_for_each_safe(proxy, t2, &remote->proxy_list, link) + pw_proxy_destroy(proxy); + + pw_map_clear(&remote->objects); + pw_map_clear(&remote->types); + + spa_list_remove(&remote->link); + + if (remote->info) + pw_core_info_free (remote->info); + + if (remote->properties) + pw_properties_free(remote->properties); + free(remote->error); + free(impl); +} + +static int do_connect(struct pw_remote *remote) +{ + remote->core_proxy = pw_proxy_new(remote, 0, remote->core->type.core, 0); + if (remote->core_proxy == NULL) + goto no_proxy; + + pw_proxy_set_implementation(remote->core_proxy, remote, PW_VERSION_CORE, + &core_events, NULL); + + pw_core_do_client_update(remote->core_proxy, &remote->properties->dict); + pw_core_do_sync(remote->core_proxy, 0); + + return 0; + + no_proxy: + remote->conn->disconnect(remote->conn); + remote_update_state(remote, PW_REMOTE_STATE_ERROR, "can't connect: no memory"); + return -1; +} + +int pw_remote_connect(struct pw_remote *remote) +{ + int res; + + remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL); + + if ((res = remote->conn->connect(remote->conn)) < 0) { + remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect failed"); + return res; + } + + return do_connect(remote); +} + +int pw_remote_connect_fd(struct pw_remote *remote, int fd) +{ + int res; + + remote_update_state(remote, PW_REMOTE_STATE_CONNECTING, NULL); + + if ((res = remote->conn->connect_fd(remote->conn, fd)) < 0) { + remote_update_state(remote, PW_REMOTE_STATE_ERROR, "connect_fd failed"); + return res; + } + + return do_connect(remote); +} + +void pw_remote_disconnect(struct pw_remote *remote) +{ + remote->conn->disconnect(remote->conn); + + if (remote->core_proxy) + pw_proxy_destroy(remote->core_proxy); + remote->core_proxy = NULL; + + remote_update_state(remote, PW_REMOTE_STATE_UNCONNECTED, NULL); +} diff --git a/pipewire/server/remote.h b/pipewire/server/remote.h new file mode 100644 index 000000000..5b2d9a9e5 --- /dev/null +++ b/pipewire/server/remote.h @@ -0,0 +1,181 @@ +/* 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_REMOTE_H__ +#define __PIPEWIRE_REMOTE_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \page page_remote_api Remote API + * + * \section sec_remote_api_overview Overview + * + * The remote API allows you to connect to a remote PipeWire and + * perform actions on the PipeWire graph. This includes + * + * \li introspecting the objects on the server + * \li Creating nodes + * \li Linking nodes on their ports + * \li providing media to the server for playback or consumption + * \li retrieving media from the server + * + * \section sec_remote_api_loop Event Loop Abstraction + * + * Most API is asynchronous and based around an event loop. Methods will + * start an operation which will cause a state change of the \ref pw_context + * object. Connect to the state_changed signal to be notified of these + * state changes. + * + * The most convenient way to deal with the asynchronous calls is probably + * with the thread loop (See \subpage page_thread_loop for more details). + * + * \subsection ssec_remote_api_proxy Proxy + * + * Proxies are local representations of remote resources. They + * allow communication between local and remote objects. + * + * The \ref pw_remote maintains a list of all proxies, including a core + * proxy that is used to get access to other proxy objects. + * + * See also \subpage page_proxy + * + * \section sec_remote_api_remote Remote + * + * \subsection ssec_remote_create Create + * + * To create a new remote use pw_remote_new(). You will + * need to pass a \ref pw_core implementation for event and data loop. + * + * A typical loop would be created with pw_thread_loop_new() but + * other implementation are possible. + * + * You will also need to pass properties for the remote. Use + * pw_fill_remote_properties() to get a default set of properties. + * + * After creating the remote, you can track the state of the remote + * by listening for the state_changed signal. + * + * \subsection ssec_remote_api_remote_connect Connecting + * + * A remote must be connected to a server before any operation can be + * issued. Calling pw_remote_connect() will initiate the connection + * procedure. + * + * When connecting, the remote will automatically create a core + * proxy to get access to the registry and types. + * + * \subsection ssec_remote_api_remote_disconnect Disconnect + * + * Use pw_remote_disconnect() to disconnect from the remote. + */ + +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 { + PW_REMOTE_STATE_ERROR = -1, /**< remote is in error */ + PW_REMOTE_STATE_UNCONNECTED = 0, /**< not connected */ + PW_REMOTE_STATE_CONNECTING = 1, /**< connecting to remote PipeWire */ + PW_REMOTE_STATE_CONNECTED = 2, /**< remote is connected and ready */ +}; + +/** 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_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_proxy objects */ + + struct pw_protocol *protocol; /**< the protocol in use */ + void *protocol_private; /**< private data for the protocol */ + 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)); +}; + +/** Create a new unconnected remote \memberof pw_remote + * \return a new unconnected remote */ +struct pw_remote * +pw_remote_new(struct pw_core *core, /**< a \ref pw_core */ + struct pw_properties *properties /**< optional properties, ownership of + * the properties is taken.*/ ); + +/** Destroy a remote \memberof pw_remote */ +void pw_remote_destroy(struct pw_remote *remote); + +/** Connect to a remote PipeWire \memberof pw_remote + * \return true on success. */ +int pw_remote_connect(struct pw_remote *remote); + +/** Connect to a remote PipeWire on the given socket \memberof pw_remote + * \param fd the connected socket to use + * \return true on success. */ +int pw_remote_connect_fd(struct pw_remote *remote, int fd); + +/** Disconnect from the remote PipeWire. \memberof pw_remote */ +void pw_remote_disconnect(struct pw_remote *remote); + +#ifdef __cplusplus +} +#endif + +#endif /* __PIPEWIRE_REMOTE_H__ */ diff --git a/pipewire/server/resource.c b/pipewire/server/resource.c index c10a3cb90..9c2ac6d51 100644 --- a/pipewire/server/resource.c +++ b/pipewire/server/resource.c @@ -20,6 +20,7 @@ #include #include "pipewire/client/interfaces.h" +#include "pipewire/client/protocol.h" #include "pipewire/server/resource.h" /** \cond */ diff --git a/pipewire/server/resource.h b/pipewire/server/resource.h index e15fbe8fc..d5b9a2883 100644 --- a/pipewire/server/resource.h +++ b/pipewire/server/resource.h @@ -30,6 +30,7 @@ extern "C" { #include #include +#include #include /** \page page_resource Resource diff --git a/pipewire/tools/meson.build b/pipewire/tools/meson.build index ca8e467f9..b6131d722 100644 --- a/pipewire/tools/meson.build +++ b/pipewire/tools/meson.build @@ -1,5 +1,5 @@ executable('pipewire-monitor', 'pipewire-monitor.c', install: true, - dependencies : [pipewire_dep], + dependencies : [pipewirecore_dep], ) diff --git a/pipewire/tools/pipewire-monitor.c b/pipewire/tools/pipewire-monitor.c index 501f536f6..673547762 100644 --- a/pipewire/tools/pipewire-monitor.c +++ b/pipewire/tools/pipewire-monitor.c @@ -26,10 +26,16 @@ struct data { bool running; struct pw_loop *loop; - struct pw_context *context; + struct pw_core *core; + struct pw_remote *remote; + struct pw_proxy *registry_proxy; + struct pw_listener on_info_changed; struct pw_listener on_state_changed; - struct pw_listener on_subscription; +}; + +struct proxy_data { + void *info; }; static void print_properties(struct spa_dict *props, char mark) @@ -45,24 +51,16 @@ static void print_properties(struct spa_dict *props, char mark) } } -struct dumpdata { - bool print_mark; - bool print_all; -}; +#define MARK_CHANGE(f) ((print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ') -#define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ') - -static void -dump_core_info(struct pw_context *c, int res, const struct pw_core_info *info, void *user_data) +static void on_info_changed(struct pw_listener *listener, struct pw_remote *remote) { - struct dumpdata *data = user_data; - - if (info == NULL) - return; + struct pw_core_info *info = remote->info; + bool print_all = true, print_mark = false; printf("\tid: %u\n", info->id); printf("\ttype: %s\n", PIPEWIRE_TYPE__Core); - if (data->print_all) { + if (print_all) { printf("%c\tuser-name: \"%s\"\n", MARK_CHANGE(0), info->user_name); printf("%c\thost-name: \"%s\"\n", MARK_CHANGE(1), info->host_name); printf("%c\tversion: \"%s\"\n", MARK_CHANGE(2), info->version); @@ -72,35 +70,59 @@ dump_core_info(struct pw_context *c, int res, const struct pw_core_info *info, v } } -static void -dump_client_info(struct pw_context *c, int res, const struct pw_client_info *info, void *user_data) +static void module_event_info(void *object, struct pw_module_info *info) { - struct dumpdata *data = user_data; + struct pw_proxy *proxy = object; + struct proxy_data *data = proxy->user_data; + bool print_all, print_mark; - if (info == NULL) - return; + print_all = true; + if (data->info == NULL) { + printf("added:\n"); + print_mark = false; + } + else { + printf("changed:\n"); + print_mark = true; + } + + info = data->info = pw_module_info_update(data->info, info); printf("\tid: %u\n", info->id); - printf("\ttype: %s\n", PIPEWIRE_TYPE__Client); - if (data->print_all) { - print_properties(info->props, MARK_CHANGE(0)); + printf("\ttype: %s\n", PIPEWIRE_TYPE__Module); + if (print_all) { + printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); + printf("%c\tfilename: \"%s\"\n", MARK_CHANGE(1), info->filename); + printf("%c\targs: \"%s\"\n", MARK_CHANGE(2), info->args); + print_properties(info->props, MARK_CHANGE(3)); } } -static void -dump_node_info(struct pw_context *c, int res, const struct pw_node_info *info, void *user_data) -{ - struct dumpdata *data = user_data; +static const struct pw_module_events module_events = { + &module_event_info, +}; - if (info == NULL) { - if (res != SPA_RESULT_ENUM_END) - printf("\tError introspecting node: %d\n", res); - return; +static void node_event_info(void *object, struct pw_node_info *info) +{ + struct pw_proxy *proxy = object; + struct proxy_data *data = proxy->user_data; + bool print_all, print_mark; + + print_all = true; + if (data->info == NULL) { + printf("added:\n"); + print_mark = false; } + else { + printf("changed:\n"); + print_mark = true; + } + + info = data->info = pw_node_info_update(data->info, info); printf("\tid: %u\n", info->id); printf("\ttype: %s\n", PIPEWIRE_TYPE__Node); - if (data->print_all) { + if (print_all) { int i; printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); @@ -123,41 +145,60 @@ dump_node_info(struct pw_context *c, int res, const struct pw_node_info *info, v } } -static void -dump_module_info(struct pw_context *c, int res, const struct pw_module_info *info, void *user_data) -{ - struct dumpdata *data = user_data; +static const struct pw_node_events node_events = { + &node_event_info +}; - if (info == NULL) { - if (res != SPA_RESULT_ENUM_END) - printf("\tError introspecting module: %d\n", res); - return; +static void client_event_info(void *object, struct pw_client_info *info) +{ + struct pw_proxy *proxy = object; + struct proxy_data *data = proxy->user_data; + bool print_all, print_mark; + + print_all = true; + if (data->info == NULL) { + printf("added:\n"); + print_mark = false; + } + else { + printf("changed:\n"); + print_mark = true; } + info = data->info = pw_client_info_update(data->info, info); + printf("\tid: %u\n", info->id); - printf("\ttype: %s\n", PIPEWIRE_TYPE__Module); - if (data->print_all) { - printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name); - printf("%c\tfilename: \"%s\"\n", MARK_CHANGE(1), info->filename); - printf("%c\targs: \"%s\"\n", MARK_CHANGE(2), info->args); - print_properties(info->props, MARK_CHANGE(3)); + printf("\ttype: %s\n", PIPEWIRE_TYPE__Client); + if (print_all) { + print_properties(info->props, MARK_CHANGE(0)); } } -static void -dump_link_info(struct pw_context *c, int res, const struct pw_link_info *info, void *user_data) -{ - struct dumpdata *data = user_data; +static const struct pw_client_events client_events = { + &client_event_info +}; - if (info == NULL) { - if (res != SPA_RESULT_ENUM_END) - printf("\tError introspecting link: %d\n", res); - return; +static void link_event_info(void *object, struct pw_link_info *info) +{ + struct pw_proxy *proxy = object; + struct proxy_data *data = proxy->user_data; + bool print_all, print_mark; + + print_all = true; + if (data->info == NULL) { + printf("added:\n"); + print_mark = false; } + else { + printf("changed:\n"); + print_mark = true; + } + + info = data->info = pw_link_info_update(data->info, info); printf("\tid: %u\n", info->id); printf("\ttype: %s\n", PIPEWIRE_TYPE__Link); - if (data->print_all) { + if (print_all) { printf("%c\toutput-node-id: %u\n", MARK_CHANGE(0), info->output_node_id); printf("%c\toutput-port-id: %u\n", MARK_CHANGE(1), info->output_port_id); printf("%c\tinput-node-id: %u\n", MARK_CHANGE(2), info->input_node_id); @@ -170,88 +211,136 @@ dump_link_info(struct pw_context *c, int res, const struct pw_link_info *info, v } } -static void -dump_object(struct pw_context *context, uint32_t type, uint32_t id, struct dumpdata *data) -{ - if (type == context->type.core) { - pw_context_get_core_info(context, dump_core_info, data); - } else if (type == context->type.node) { - pw_context_get_node_info_by_id(context, id, dump_node_info, data); - } else if (type == context->type.module) { - pw_context_get_module_info_by_id(context, id, dump_module_info, data); - } else if (type == context->type.client) { - pw_context_get_client_info_by_id(context, id, dump_client_info, data); - } else if (type == context->type.link) { - pw_context_get_link_info_by_id(context, id, dump_link_info, data); - } else { - printf("\tid: %u\n", id); - } - - -} +static const struct pw_link_events link_events = { + &link_event_info +}; static void -on_subscription(struct pw_listener *listener, - struct pw_context *context, - enum pw_subscription_event event, uint32_t type, uint32_t id) +destroy_proxy (void *data) { - struct dumpdata dd; + struct pw_proxy *proxy = data; + struct proxy_data *user_data = proxy->user_data; + struct pw_core *core = proxy->remote->core; - switch (event) { - case PW_SUBSCRIPTION_EVENT_NEW: - printf("added:\n"); - dd.print_mark = false; - dd.print_all = true; - dump_object(context, type, id, &dd); - break; + if (user_data->info == NULL) + return; - case PW_SUBSCRIPTION_EVENT_CHANGE: - printf("changed:\n"); - dd.print_mark = true; - dd.print_all = true; - dump_object(context, type, id, &dd); - break; - - case PW_SUBSCRIPTION_EVENT_REMOVE: - printf("removed:\n"); - dd.print_mark = false; - dd.print_all = false; - dump_object(context, type, id, &dd); - break; - } + 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); + } + user_data->info = NULL; } -static void on_state_changed(struct pw_listener *listener, struct pw_context *context) + +static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version) +{ + struct pw_proxy *registry_proxy = object; + struct data *data = registry_proxy->object; + struct pw_core *core = data->core; + struct pw_remote *remote = registry_proxy->remote; + struct pw_proxy *proxy = NULL; + uint32_t proxy_type, client_version; + const void *implementation; + + if (!strcmp(type, PIPEWIRE_TYPE__Node)) { + proxy_type = core->type.node; + implementation = &node_events; + client_version = PW_VERSION_NODE; + } else if (!strcmp(type, PIPEWIRE_TYPE__Module)) { + proxy_type = core->type.module; + implementation = &module_events; + client_version = PW_VERSION_MODULE; + } else if (!strcmp(type, PIPEWIRE_TYPE__Client)) { + proxy_type = core->type.client; + implementation = &client_events; + client_version = PW_VERSION_CLIENT; + } else if (!strcmp(type, PIPEWIRE_TYPE__Link)) { + proxy_type = core->type.link; + implementation = &link_events; + client_version = PW_VERSION_LINK; + } else + return; + + proxy = pw_proxy_new(remote, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data)); + if (proxy == NULL) + goto no_mem; + + pw_proxy_set_implementation(proxy, data, client_version, implementation, destroy_proxy); + + pw_registry_do_bind(registry_proxy, id, version, proxy->id); + + return; + + no_mem: + printf("failed to create proxy"); + return; +} + +static void registry_event_global_remove(void *object, uint32_t id) +{ + printf("removed:\n"); + printf("\tid: %u\n", id); +} + +static const struct pw_registry_events registry_events = { + registry_event_global, + registry_event_global_remove, +}; + +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); - switch (context->state) { + switch (remote->state) { case PW_CONTEXT_STATE_ERROR: - printf("context error: %s\n", context->error); + printf("remote error: %s\n", remote->error); data->running = false; break; + case PW_CONTEXT_STATE_CONNECTED: + printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); + + data->registry_proxy = pw_proxy_new(data->remote, + SPA_ID_INVALID, + data->core->type.registry, + 0); + pw_proxy_set_implementation(data->registry_proxy, data, PW_VERSION_REGISTRY, + ®istry_events, NULL); + + pw_core_do_get_registry(data->remote->core_proxy, + data->registry_proxy->id); + + break; + default: - printf("context state: \"%s\"\n", pw_context_state_as_string(context->state)); + printf("remote state: \"%s\"\n", pw_remote_state_as_string(remote->state)); break; } } int main(int argc, char *argv[]) { - struct data data; + struct data data = { 0 }; pw_init(&argc, &argv); data.loop = pw_loop_new(); data.running = true; - data.context = pw_context_new(data.loop, "pipewire-monitor", NULL); + data.core = pw_core_new(data.loop, NULL); + data.remote = pw_remote_new(data.core, NULL); - pw_signal_add(&data.context->state_changed, &data.on_state_changed, on_state_changed); + 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_signal_add(&data.context->subscription, &data.on_subscription, on_subscription); - - pw_context_connect(data.context, 0); + pw_remote_connect(data.remote); pw_loop_enter(data.loop); while (data.running) { @@ -259,7 +348,7 @@ int main(int argc, char *argv[]) } pw_loop_leave(data.loop); - pw_context_destroy(data.context); + pw_remote_destroy(data.remote); pw_loop_destroy(data.loop); return 0; diff --git a/spa/include/spa/graph-scheduler1.h b/spa/include/spa/graph-scheduler1.h index 7c3636d51..c619836bb 100644 --- a/spa/include/spa/graph-scheduler1.h +++ b/spa/include/spa/graph-scheduler1.h @@ -96,8 +96,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched switch (n->action) { case SPA_GRAPH_ACTION_IN: - n->state = n->methods->schedule_input(n, n->user_data); - debug("node %p scheduled input state %d\n", n, n->state); + n->state = n->methods->process_input(n, n->user_data); + debug("node %p processed input state %d\n", n, n->state); if (n == sched->node) break; n->action = SPA_GRAPH_ACTION_CHECK; @@ -105,8 +105,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched break; case SPA_GRAPH_ACTION_OUT: - n->state = n->methods->schedule_output(n, n->user_data); - debug("node %p scheduled output state %d\n", n, n->state); + n->state = n->methods->process_output(n, n->user_data); + debug("node %p processed output state %d\n", n, n->state); n->action = SPA_GRAPH_ACTION_CHECK; spa_list_insert(sched->ready.prev, &n->ready_link); break; diff --git a/spa/include/spa/graph-scheduler3.h b/spa/include/spa/graph-scheduler3.h index df97a032f..5ddaceca5 100644 --- a/spa/include/spa/graph-scheduler3.h +++ b/spa/include/spa/graph-scheduler3.h @@ -38,32 +38,36 @@ static inline void spa_graph_scheduler_init(struct spa_graph_scheduler *sched, sched->node = NULL; } -static inline int spa_graph_scheduler_input(struct spa_graph_node *node, void *user_data) +static inline int spa_graph_node_scheduler_input(struct spa_graph_node *node, void *user_data) { struct spa_node *n = node->user_data; return spa_node_process_input(n); } -static inline int spa_graph_scheduler_output(struct spa_graph_node *node, void *user_data) +static inline int spa_graph_node_scheduler_output(struct spa_graph_node *node, void *user_data) { struct spa_node *n = node->user_data; return spa_node_process_output(n); } -static inline int spa_graph_scheduler_reuse_buffer(struct spa_graph_port *port, - uint32_t buffer_id, void *user_data) + +static const struct spa_graph_node_methods spa_graph_node_scheduler_default = { + SPA_VERSION_GRAPH_NODE_METHODS, + spa_graph_node_scheduler_input, + spa_graph_node_scheduler_output, +}; + +static inline int spa_graph_port_scheduler_reuse_buffer(struct spa_graph_port *port, + uint32_t buffer_id, void *user_data) { printf("port %p reuse buffer %d\n", port, buffer_id); - struct spa_graph_node *node = port->node; - struct spa_node *n = node->user_data; - return spa_node_port_reuse_buffer(n, port->port_id, buffer_id); + struct spa_node *node = port->node->user_data; + return spa_node_port_reuse_buffer(node, port->port_id, buffer_id); } -static const struct spa_graph_node_methods spa_graph_scheduler_default = { - SPA_VERSION_GRAPH_NODE_METHODS, - spa_graph_scheduler_input, - spa_graph_scheduler_output, - spa_graph_scheduler_reuse_buffer, +static const struct spa_graph_port_methods spa_graph_port_scheduler_default = { + SPA_VERSION_GRAPH_PORT_METHODS, + spa_graph_port_scheduler_reuse_buffer, }; static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, struct spa_graph_node *node) @@ -92,8 +96,8 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s } spa_list_for_each_safe(n, t, &ready, ready_link) { - n->state = n->methods->schedule_output(n, n->user_data); - debug("peer %p scheduled out %d\n", n, n->state); + n->state = n->methods->process_output(n, n->user_data); + debug("peer %p processed out %d\n", n, n->state); if (n->state == SPA_RESULT_NEED_BUFFER) spa_graph_scheduler_pull(sched, n); else { @@ -109,8 +113,8 @@ static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, s debug("node %p %d %d\n", node, node->ready_in, node->required_in); if (node->required_in > 0 && node->ready_in == node->required_in) { - node->state = node->methods->schedule_input(node, node->user_data); - debug("node %p scheduled in %d\n", node, node->state); + node->state = node->methods->process_input(node, node->user_data); + debug("node %p processed in %d\n", node, node->state); if (node->state == SPA_RESULT_HAVE_BUFFER) { spa_list_for_each(p, &node->ports[SPA_DIRECTION_OUTPUT], link) { if (p->io->status == SPA_RESULT_HAVE_BUFFER) @@ -154,8 +158,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s } spa_list_for_each_safe(n, t, &ready, ready_link) { - n->state = n->methods->schedule_input(n, n->user_data); - debug("peer %p scheduled in %d\n", n, n->state); + n->state = n->methods->process_input(n, n->user_data); + debug("peer %p processed in %d\n", n, n->state); if (n->state == SPA_RESULT_HAVE_BUFFER) spa_graph_scheduler_push(sched, n); else { @@ -169,8 +173,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s n->ready_link.next = NULL; } - node->state = node->methods->schedule_output(node, node->user_data); - debug("node %p scheduled out %d\n", node, node->state); + node->state = node->methods->process_output(node, node->user_data); + debug("node %p processed out %d\n", node, node->state); if (node->state == SPA_RESULT_NEED_BUFFER) { node->ready_in = 0; spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) { diff --git a/spa/include/spa/graph.h b/spa/include/spa/graph.h index 58928fa8c..637c0d819 100644 --- a/spa/include/spa/graph.h +++ b/spa/include/spa/graph.h @@ -46,8 +46,14 @@ struct spa_graph { struct spa_graph_node_methods { uint32_t version; - int (*schedule_input) (struct spa_graph_node *node, void *user_data); - int (*schedule_output) (struct spa_graph_node *node, void *user_data); + int (*process_input) (struct spa_graph_node *node, void *user_data); + int (*process_output) (struct spa_graph_node *node, void *user_data); +}; + +#define SPA_VERSION_GRAPH_PORT_METHODS 0 +struct spa_graph_port_methods { + uint32_t version; + int (*reuse_buffer) (struct spa_graph_port *port, uint32_t buffer_id, void *user_data); }; @@ -62,11 +68,11 @@ struct spa_graph_node { #define SPA_GRAPH_ACTION_IN 1 #define SPA_GRAPH_ACTION_OUT 2 uint32_t action; - const struct spa_graph_node_methods *methods; - void *user_data; uint32_t max_in; uint32_t required_in; uint32_t ready_in; + const struct spa_graph_node_methods *methods; + void *user_data; }; struct spa_graph_port { @@ -77,6 +83,8 @@ struct spa_graph_port { uint32_t flags; struct spa_port_io *io; struct spa_graph_port *peer; + const struct spa_graph_port_methods *methods; + void *user_data; }; static inline void spa_graph_init(struct spa_graph *graph) @@ -85,19 +93,24 @@ static inline void spa_graph_init(struct spa_graph *graph) } static inline void -spa_graph_node_init(struct spa_graph_node *node, - const struct spa_graph_node_methods *methods, - void *user_data) +spa_graph_node_init(struct spa_graph_node *node) { spa_list_init(&node->ports[SPA_DIRECTION_INPUT]); spa_list_init(&node->ports[SPA_DIRECTION_OUTPUT]); node->flags = 0; - node->methods = methods; - node->user_data = user_data; node->max_in = node->required_in = node->ready_in = 0; debug("node %p init\n", node); } +static inline void +spa_graph_node_set_methods(struct spa_graph_node *node, + const struct spa_graph_node_methods *methods, + void *user_data) +{ + node->methods = methods; + node->user_data = user_data; +} + static inline void spa_graph_node_add(struct spa_graph *graph, struct spa_graph_node *node) @@ -123,6 +136,15 @@ spa_graph_port_init(struct spa_graph_port *port, port->io = io; } +static inline void +spa_graph_port_set_methods(struct spa_graph_port *port, + const struct spa_graph_port_methods *methods, + void *user_data) +{ + port->methods = methods; + port->user_data = user_data; +} + static inline void spa_graph_port_add(struct spa_graph_node *node, struct spa_graph_port *port) diff --git a/spa/tests/test-graph.c b/spa/tests/test-graph.c index 138d180e4..f2a9e699e 100644 --- a/spa/tests/test-graph.c +++ b/spa/tests/test-graph.c @@ -340,12 +340,14 @@ static int make_nodes(struct data *data, const char *device) spa_node_port_set_io(data->volume, SPA_DIRECTION_OUTPUT, 0, &data->volume_sink_io[0]); spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->volume_sink_io[0]); - spa_graph_node_init(&data->source_node, &spa_graph_scheduler_default, data->source); + spa_graph_node_init(&data->source_node); + spa_graph_node_set_methods(&data->source_node, &spa_graph_scheduler_default, data->source); spa_graph_node_add(&data->graph, &data->source_node); spa_graph_port_init(&data->source_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source_volume_io[0]); spa_graph_port_add(&data->source_node, &data->source_out); - spa_graph_node_init(&data->volume_node, &spa_graph_scheduler_default, data->volume); + spa_graph_node_init(&data->volume_node); + spa_graph_node_set_methods(&data->volume_node, &spa_graph_scheduler_default, data->volume); spa_graph_node_add(&data->graph, &data->volume_node); spa_graph_port_init(&data->volume_in, SPA_DIRECTION_INPUT, 0, 0, &data->source_volume_io[0]); spa_graph_port_add(&data->volume_node, &data->volume_in); @@ -355,7 +357,8 @@ static int make_nodes(struct data *data, const char *device) spa_graph_port_init(&data->volume_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->volume_sink_io[0]); spa_graph_port_add(&data->volume_node, &data->volume_out); - spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink); + spa_graph_node_init(&data->sink_node); + spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink); spa_graph_node_add(&data->graph, &data->sink_node); spa_graph_port_init(&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->volume_sink_io[0]); spa_graph_port_add(&data->sink_node, &data->sink_in); diff --git a/spa/tests/test-mixer.c b/spa/tests/test-mixer.c index 87f9186de..925b86711 100644 --- a/spa/tests/test-mixer.c +++ b/spa/tests/test-mixer.c @@ -418,17 +418,20 @@ static int make_nodes(struct data *data, const char *device) spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->mix_sink_io[0]); #ifdef USE_GRAPH - spa_graph_node_init(&data->source1_node, &spa_graph_scheduler_default, data->source1); + spa_graph_node_init(&data->source1_node); + spa_graph_node_set_methods(&data->source1_node, &spa_graph_scheduler_default, data->source1); spa_graph_port_init(&data->source1_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source1_mix_io[0]); spa_graph_port_add(&data->source1_node, &data->source1_out); spa_graph_node_add(&data->graph, &data->source1_node); - spa_graph_node_init(&data->source2_node, &spa_graph_scheduler_default, data->source2); + spa_graph_node_init(&data->source2_node); + spa_graph_node_set_methods(&data->source2_node, &spa_graph_scheduler_default, data->source2); spa_graph_port_init(&data->source2_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source2_mix_io[0]); spa_graph_port_add(&data->source2_node, &data->source2_out); spa_graph_node_add(&data->graph, &data->source2_node); - spa_graph_node_init(&data->mix_node, &spa_graph_scheduler_default, data->mix); + spa_graph_node_init(&data->mix_node); + spa_graph_node_set_methods(&data->mix_node, &spa_graph_scheduler_default, data->mix); spa_graph_port_init(&data->mix_in[0], SPA_DIRECTION_INPUT, data->mix_ports[0], 0, &data->source1_mix_io[0]); spa_graph_port_add(&data->mix_node, &data->mix_in[0]); @@ -443,7 +446,8 @@ static int make_nodes(struct data *data, const char *device) spa_graph_port_init(&data->mix_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->mix_sink_io[0]); spa_graph_port_add(&data->mix_node, &data->mix_out); - spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink); + spa_graph_node_init(&data->sink_node); + spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink); spa_graph_port_init(&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->mix_sink_io[0]); spa_graph_port_add(&data->sink_node, &data->sink_in); spa_graph_node_add(&data->graph, &data->sink_node); diff --git a/spa/tests/test-perf.c b/spa/tests/test-perf.c index 44f39f4f4..b7a4cdd1c 100644 --- a/spa/tests/test-perf.c +++ b/spa/tests/test-perf.c @@ -366,14 +366,16 @@ static int make_nodes(struct data *data) spa_node_port_set_io(data->source, SPA_DIRECTION_OUTPUT, 0, &data->source_sink_io[0]); spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->source_sink_io[0]); - spa_graph_node_init(&data->source_node, &spa_graph_scheduler_default, data->source); + spa_graph_node_init(&data->source_node); + spa_graph_node_set_methods(&data->source_node, &spa_graph_scheduler_default, data->source); spa_graph_node_add(&data->graph, &data->source_node); data->source_node.flags = (data->mode & MODE_ASYNC_PUSH) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0; spa_graph_port_init( &data->source_out, SPA_DIRECTION_OUTPUT, 0, 0, &data->source_sink_io[0]); spa_graph_port_add(&data->source_node, &data->source_out); - spa_graph_node_init(&data->sink_node, &spa_graph_scheduler_default, data->sink); + spa_graph_node_init(&data->sink_node); + spa_graph_node_set_methods(&data->sink_node, &spa_graph_scheduler_default, data->sink); spa_graph_node_add(&data->graph, &data->sink_node); data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;