mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									2ece95ea48
								
							
						
					
					
						commit
						847cef83b6
					
				
					 65 changed files with 2634 additions and 2713 deletions
				
			
		| 
						 | 
					@ -1,888 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <stdio.h>
 | 
					 | 
				
			||||||
#include <unistd.h>
 | 
					 | 
				
			||||||
#include <sys/socket.h>
 | 
					 | 
				
			||||||
#include <sys/un.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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 <spa/lib/debug.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** \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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,208 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/client/map.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/loop.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/properties.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/protocol.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/subscribe.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/proxy.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/type.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** \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__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,143 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2016 Axis Communications <dev-gstreamer@axis.com>
 | 
					 | 
				
			||||||
 * @author Linus Svensson <linus.svensson@axis.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <dlfcn.h>
 | 
					 | 
				
			||||||
#include <dirent.h>
 | 
					 | 
				
			||||||
#include <sys/stat.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,72 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2016 Axis Communications <dev-gstreamer@axis.com>
 | 
					 | 
				
			||||||
 * @author Linus Svensson <linus.svensson@axis.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <pipewire/client/context.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -21,7 +21,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire/client/pipewire.h"
 | 
					#include "pipewire/client/pipewire.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire/client/context.h"
 | 
					#include "pipewire/server/remote.h"
 | 
				
			||||||
#include "pipewire/client/subscribe.h"
 | 
					#include "pipewire/client/subscribe.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const char *pw_node_state_as_string(enum pw_node_state state)
 | 
					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,
 | 
					struct pw_core_info *pw_core_info_update(struct pw_core_info *info,
 | 
				
			||||||
					 const struct pw_core_info *update)
 | 
										 const struct pw_core_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t change_mask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (update == NULL)
 | 
						if (update == NULL)
 | 
				
			||||||
		return info;
 | 
							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));
 | 
							info = calloc(1, sizeof(struct pw_core_info));
 | 
				
			||||||
		if (info == NULL)
 | 
							if (info == NULL)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		change_mask = ~0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		change_mask = info->change_mask | update->change_mask;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info->id = update->id;
 | 
						info->id = update->id;
 | 
				
			||||||
	info->change_mask = change_mask;
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update->change_mask & (1 << 0)) {
 | 
						if (update->change_mask & (1 << 0)) {
 | 
				
			||||||
		if (info->user_name)
 | 
							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,
 | 
					struct pw_node_info *pw_node_info_update(struct pw_node_info *info,
 | 
				
			||||||
					 const struct pw_node_info *update)
 | 
										 const struct pw_node_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t change_mask;
 | 
					 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update == NULL)
 | 
						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));
 | 
							info = calloc(1, sizeof(struct pw_node_info));
 | 
				
			||||||
		if (info == NULL)
 | 
							if (info == NULL)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		change_mask = ~0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		change_mask = info->change_mask | update->change_mask;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info->id = update->id;
 | 
						info->id = update->id;
 | 
				
			||||||
	info->change_mask = change_mask;
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update->change_mask & (1 << 0)) {
 | 
						if (update->change_mask & (1 << 0)) {
 | 
				
			||||||
		if (info->name)
 | 
							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,
 | 
					struct pw_module_info *pw_module_info_update(struct pw_module_info *info,
 | 
				
			||||||
					     const struct pw_module_info *update)
 | 
										     const struct pw_module_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t change_mask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (update == NULL)
 | 
						if (update == NULL)
 | 
				
			||||||
		return info;
 | 
							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));
 | 
							info = calloc(1, sizeof(struct pw_module_info));
 | 
				
			||||||
		if (info == NULL)
 | 
							if (info == NULL)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		change_mask = ~0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		change_mask = info->change_mask | update->change_mask;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info->id = update->id;
 | 
						info->id = update->id;
 | 
				
			||||||
	info->change_mask = change_mask;
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update->change_mask & (1 << 0)) {
 | 
						if (update->change_mask & (1 << 0)) {
 | 
				
			||||||
		if (info->name)
 | 
							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,
 | 
					struct pw_client_info *pw_client_info_update(struct pw_client_info *info,
 | 
				
			||||||
					     const struct pw_client_info *update)
 | 
										     const struct pw_client_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t change_mask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (update == NULL)
 | 
						if (update == NULL)
 | 
				
			||||||
		return info;
 | 
							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));
 | 
							info = calloc(1, sizeof(struct pw_client_info));
 | 
				
			||||||
		if (info == NULL)
 | 
							if (info == NULL)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		change_mask = ~0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		change_mask = info->change_mask | update->change_mask;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info->id = update->id;
 | 
						info->id = update->id;
 | 
				
			||||||
	info->change_mask = change_mask;
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update->change_mask & (1 << 0)) {
 | 
						if (update->change_mask & (1 << 0)) {
 | 
				
			||||||
		if (info->props)
 | 
							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,
 | 
					struct pw_link_info *pw_link_info_update(struct pw_link_info *info,
 | 
				
			||||||
					 const struct pw_link_info *update)
 | 
										 const struct pw_link_info *update)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint64_t change_mask;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (update == NULL)
 | 
						if (update == NULL)
 | 
				
			||||||
		return info;
 | 
							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));
 | 
							info = calloc(1, sizeof(struct pw_link_info));
 | 
				
			||||||
		if (info == NULL)
 | 
							if (info == NULL)
 | 
				
			||||||
			return NULL;
 | 
								return NULL;
 | 
				
			||||||
		change_mask = ~0;
 | 
					 | 
				
			||||||
	} else {
 | 
					 | 
				
			||||||
		change_mask = info->change_mask | update->change_mask;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	info->id = update->id;
 | 
						info->id = update->id;
 | 
				
			||||||
	info->change_mask = change_mask;
 | 
						info->change_mask = update->change_mask;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (update->change_mask & (1 << 0))
 | 
						if (update->change_mask & (1 << 0))
 | 
				
			||||||
		info->output_node_id = update->output_node_id;
 | 
							info->output_node_id = update->output_node_id;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,6 @@
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_context;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <pipewire/client/context.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/properties.h>
 | 
					#include <pipewire/client/properties.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \enum pw_node_state The different node states \memberof pw_node */
 | 
					/** \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 */
 | 
					/** Free a \ref pw_core_info  \memberof pw_introspect */
 | 
				
			||||||
void pw_core_info_free(struct pw_core_info *info);
 | 
					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 */
 | 
					/** The module information. Extra information can be added in later versions \memberof pw_introspect */
 | 
				
			||||||
struct pw_module_info {
 | 
					struct pw_module_info {
 | 
				
			||||||
	uint32_t id;		/**< server side id of the module */
 | 
						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 */
 | 
					/** Free a \ref pw_module_info \memberof pw_introspect */
 | 
				
			||||||
void pw_module_info_free(struct pw_module_info *info);
 | 
					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 */
 | 
					/** The client information. Extra information can be added in later versions \memberof pw_introspect */
 | 
				
			||||||
struct pw_client_info {
 | 
					struct pw_client_info {
 | 
				
			||||||
	uint32_t id;		/**< server side id of the client */
 | 
						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);
 | 
					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 */
 | 
					/** The node information. Extra information can be added in later versions \memberof pw_introspect */
 | 
				
			||||||
struct pw_node_info {
 | 
					struct pw_node_info {
 | 
				
			||||||
	uint32_t id;				/**< server side id of the node */
 | 
						uint32_t id;				/**< server side id of the node */
 | 
				
			||||||
| 
						 | 
					@ -215,24 +158,6 @@ pw_node_info_update(struct pw_node_info *info,
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
pw_node_info_free(struct pw_node_info *info);
 | 
					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 */
 | 
					/** The link information. Extra information can be added in later versions \memberof pw_introspect */
 | 
				
			||||||
struct pw_link_info {
 | 
					struct pw_link_info {
 | 
				
			||||||
| 
						 | 
					@ -252,25 +177,6 @@ pw_link_info_update(struct pw_link_info *info,
 | 
				
			||||||
void
 | 
					void
 | 
				
			||||||
pw_link_info_free(struct pw_link_info *info);
 | 
					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
 | 
					#ifdef __cplusplus
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,5 @@
 | 
				
			||||||
pipewire_headers = [
 | 
					pipewire_headers = [
 | 
				
			||||||
  'array.h',
 | 
					  'array.h',
 | 
				
			||||||
  'connection.h',
 | 
					 | 
				
			||||||
  'context.h',
 | 
					 | 
				
			||||||
  'extension.h',
 | 
					 | 
				
			||||||
  'interfaces.h',
 | 
					  'interfaces.h',
 | 
				
			||||||
  'introspect.h',
 | 
					  'introspect.h',
 | 
				
			||||||
  'log.h',
 | 
					  'log.h',
 | 
				
			||||||
| 
						 | 
					@ -16,7 +13,6 @@ pipewire_headers = [
 | 
				
			||||||
  'rtkit.h',
 | 
					  'rtkit.h',
 | 
				
			||||||
  'sig.h',
 | 
					  'sig.h',
 | 
				
			||||||
  'stream.h',
 | 
					  'stream.h',
 | 
				
			||||||
  'subscribe.h',
 | 
					 | 
				
			||||||
  'thread-loop.h',
 | 
					  'thread-loop.h',
 | 
				
			||||||
  'transport.h',
 | 
					  'transport.h',
 | 
				
			||||||
  'type.h',
 | 
					  'type.h',
 | 
				
			||||||
| 
						 | 
					@ -24,9 +20,6 @@ pipewire_headers = [
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pipewire_sources = [
 | 
					pipewire_sources = [
 | 
				
			||||||
  'connection.c',
 | 
					 | 
				
			||||||
  'context.c',
 | 
					 | 
				
			||||||
  'extension.c',
 | 
					 | 
				
			||||||
  'introspect.c',
 | 
					  'introspect.c',
 | 
				
			||||||
  'log.c',
 | 
					  'log.c',
 | 
				
			||||||
  'loop.c',
 | 
					  'loop.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,6 +46,8 @@ struct pw_protocol *pw_protocol_get(const char *name)
 | 
				
			||||||
	protocol = calloc(1, sizeof(struct pw_protocol));
 | 
						protocol = calloc(1, sizeof(struct pw_protocol));
 | 
				
			||||||
	protocol->name = name;
 | 
						protocol->name = name;
 | 
				
			||||||
	spa_list_init(&protocol->iface_list);
 | 
						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);
 | 
						spa_list_insert(impl->protocol_list.prev, &protocol->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_info("Created protocol %s", name);
 | 
						pw_log_info("Created protocol %s", name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,9 +29,27 @@ extern "C" {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/subscribe.h>
 | 
					#include <pipewire/client/subscribe.h>
 | 
				
			||||||
#include <pipewire/client/type.h>
 | 
					#include <pipewire/client/type.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/properties.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define PW_TYPE_PROTOCOL__Native	PW_TYPE_PROTOCOL_BASE "Native"
 | 
					#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 pw_protocol_iface {
 | 
				
			||||||
	struct spa_list link;
 | 
						struct spa_list link;
 | 
				
			||||||
	const struct pw_interface *client_iface;
 | 
						const struct pw_interface *client_iface;
 | 
				
			||||||
| 
						 | 
					@ -42,6 +60,16 @@ struct pw_protocol {
 | 
				
			||||||
	struct spa_list link;
 | 
						struct spa_list link;
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	struct spa_list iface_list;
 | 
						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);
 | 
					struct pw_protocol *pw_protocol_get(const char *name);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -19,6 +19,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/log.h>
 | 
					#include <pipewire/client/log.h>
 | 
				
			||||||
#include <pipewire/client/proxy.h>
 | 
					#include <pipewire/client/proxy.h>
 | 
				
			||||||
 | 
					#include <pipewire/server/core.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
struct proxy {
 | 
					struct proxy {
 | 
				
			||||||
| 
						 | 
					@ -28,7 +29,7 @@ struct proxy {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Create a proxy object with a given id and type
 | 
					/** 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 id Id of the new object, SPA_ID_INVALID will choose a new id
 | 
				
			||||||
 * \param type Type of the proxy object
 | 
					 * \param type Type of the proxy object
 | 
				
			||||||
 * \return A newly allocated proxy object or NULL on failure
 | 
					 * \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
 | 
					 * 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.
 | 
					 * proxy object will have an id assigned from the client id space.
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \sa pw_context
 | 
					 * \sa pw_remote
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \memberof pw_proxy
 | 
					 * \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,
 | 
								      uint32_t id, uint32_t type,
 | 
				
			||||||
			      size_t user_data_size)
 | 
								      size_t user_data_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -52,14 +53,14 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context,
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	this->context = context;
 | 
						this->remote = remote;
 | 
				
			||||||
	this->type = type;
 | 
						this->type = type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_signal_init(&this->destroy_signal);
 | 
						pw_signal_init(&this->destroy_signal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (id == SPA_ID_INVALID) {
 | 
						if (id == SPA_ID_INVALID) {
 | 
				
			||||||
		id = pw_map_insert_new(&context->objects, this);
 | 
							id = pw_map_insert_new(&remote->objects, this);
 | 
				
			||||||
	} else if (!pw_map_insert_at(&context->objects, id, this))
 | 
						} else if (!pw_map_insert_at(&remote->objects, id, this))
 | 
				
			||||||
		goto in_use;
 | 
							goto in_use;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->id = id;
 | 
						this->id = id;
 | 
				
			||||||
| 
						 | 
					@ -67,18 +68,18 @@ struct pw_proxy *pw_proxy_new(struct pw_context *context,
 | 
				
			||||||
	if (user_data_size > 0)
 | 
						if (user_data_size > 0)
 | 
				
			||||||
		this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void);
 | 
							this->user_data = SPA_MEMBER(impl, sizeof(struct proxy), void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->iface = pw_protocol_get_interface(context->protocol,
 | 
						this->iface = pw_protocol_get_interface(remote->protocol,
 | 
				
			||||||
						spa_type_map_get_type(context->type.map, type),
 | 
											spa_type_map_get_type(remote->core->type.map, type),
 | 
				
			||||||
						false);
 | 
											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;
 | 
						return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      in_use:
 | 
					      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);
 | 
						free(impl);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -100,7 +101,7 @@ int pw_proxy_set_implementation(struct pw_proxy *proxy,
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \param proxy Proxy object to destroy
 | 
					 * \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
 | 
					 *       decides to destroy the server side object
 | 
				
			||||||
 * \memberof pw_proxy
 | 
					 * \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_log_debug("proxy %p: destroy %u", proxy, proxy->id);
 | 
				
			||||||
	pw_signal_emit(&proxy->destroy_signal, proxy);
 | 
						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);
 | 
						spa_list_remove(&proxy->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (proxy->destroy)
 | 
						if (proxy->destroy)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,10 +24,9 @@
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/connection.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/context.h>
 | 
					 | 
				
			||||||
#include <pipewire/client/type.h>
 | 
					#include <pipewire/client/type.h>
 | 
				
			||||||
#include <pipewire/client/utils.h>
 | 
					#include <pipewire/client/utils.h>
 | 
				
			||||||
 | 
					#include <pipewire/server/remote.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \page page_proxy Proxy
 | 
					/** \page page_proxy Proxy
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					@ -88,8 +87,8 @@ extern "C" {
 | 
				
			||||||
 * See \ref page_proxy
 | 
					 * See \ref page_proxy
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct pw_proxy {
 | 
					struct pw_proxy {
 | 
				
			||||||
	struct pw_context *context;	/**< the owner context of this proxy */
 | 
						struct pw_remote *remote;	/**< the owner remote of this proxy */
 | 
				
			||||||
	struct spa_list link;		/**< link in the context */
 | 
						struct spa_list link;		/**< link in the remote */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	uint32_t id;			/**< client side id */
 | 
						uint32_t id;			/**< client side id */
 | 
				
			||||||
	uint32_t type;			/**< object type id */
 | 
						uint32_t type;			/**< object type id */
 | 
				
			||||||
| 
						 | 
					@ -107,7 +106,7 @@ struct pw_proxy {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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 id,
 | 
				
			||||||
	     uint32_t type,
 | 
						     uint32_t type,
 | 
				
			||||||
	     size_t user_data_size);
 | 
						     size_t user_data_size);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,10 +30,10 @@
 | 
				
			||||||
#include "pipewire/client/interfaces.h"
 | 
					#include "pipewire/client/interfaces.h"
 | 
				
			||||||
#include "pipewire/client/array.h"
 | 
					#include "pipewire/client/array.h"
 | 
				
			||||||
#include "pipewire/client/connection.h"
 | 
					#include "pipewire/client/connection.h"
 | 
				
			||||||
#include "pipewire/client/context.h"
 | 
					 | 
				
			||||||
#include "pipewire/client/stream.h"
 | 
					#include "pipewire/client/stream.h"
 | 
				
			||||||
#include "pipewire/client/transport.h"
 | 
					#include "pipewire/client/transport.h"
 | 
				
			||||||
#include "pipewire/client/utils.h"
 | 
					#include "pipewire/client/utils.h"
 | 
				
			||||||
 | 
					#include "pipewire/client/stream.h"
 | 
				
			||||||
#include "pipewire/extensions/client-node.h"
 | 
					#include "pipewire/extensions/client-node.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
| 
						 | 
					@ -180,7 +180,7 @@ const char *pw_stream_state_as_string(enum pw_stream_state state)
 | 
				
			||||||
	return "invalid-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)
 | 
									const char *name, struct pw_properties *props)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct stream *impl;
 | 
						struct stream *impl;
 | 
				
			||||||
| 
						 | 
					@ -203,9 +203,9 @@ struct pw_stream *pw_stream_new(struct pw_context *context,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->properties = props;
 | 
						this->properties = props;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->context = context;
 | 
						this->remote = remote;
 | 
				
			||||||
	this->name = strdup(name);
 | 
						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->destroy_signal);
 | 
				
			||||||
	pw_signal_init(&this->state_changed);
 | 
						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;
 | 
						impl->pending_seq = SPA_ID_INVALID;
 | 
				
			||||||
	spa_list_init(&impl->free);
 | 
						spa_list_init(&impl->free);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_insert(&context->stream_list, &this->link);
 | 
						spa_list_insert(&remote->stream_list, &this->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return this;
 | 
						return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -238,11 +238,11 @@ static void unhandle_socket(struct pw_stream *stream)
 | 
				
			||||||
	struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
						struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (impl->rtsocket_source) {
 | 
						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;
 | 
							impl->rtsocket_source = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (impl->timeout_source) {
 | 
						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;
 | 
							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);
 | 
						struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_client_node_do_port_update(impl->node_proxy,
 | 
						pw_client_node_do_port_update(impl->node_proxy,
 | 
				
			||||||
				      impl->direction,
 | 
									      impl->direction,
 | 
				
			||||||
				      impl->port_id,
 | 
									      impl->port_id,
 | 
				
			||||||
| 
						 | 
					@ -367,7 +368,7 @@ static inline void send_need_input(struct pw_stream *stream)
 | 
				
			||||||
	uint64_t cmd = 1;
 | 
						uint64_t cmd = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_transport_add_event(impl->trans,
 | 
						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);
 | 
						write(impl->rtwritefd, &cmd, 8);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -378,7 +379,7 @@ static inline void send_have_output(struct pw_stream *stream)
 | 
				
			||||||
	uint64_t cmd = 1;
 | 
						uint64_t cmd = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_transport_add_event(impl->trans,
 | 
						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);
 | 
						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);
 | 
						struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_client_node_do_event(impl->node_proxy, (struct spa_event *)
 | 
						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.
 | 
														  event_node.
 | 
				
			||||||
									  RequestClockUpdate,
 | 
														  RequestClockUpdate,
 | 
				
			||||||
									  SPA_EVENT_NODE_REQUEST_CLOCK_UPDATE_TIME,
 | 
														  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)
 | 
					static void handle_rtnode_event(struct pw_stream *stream, struct spa_event *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
						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;
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < impl->trans->area->n_input_ports; 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;
 | 
								input->buffer_id = SPA_ID_INVALID;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		send_need_input(stream);
 | 
							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;
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (i = 0; i < impl->trans->area->n_output_ports; 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;
 | 
							impl->in_need_buffer = true;
 | 
				
			||||||
		pw_signal_emit(&stream->need_buffer, stream);
 | 
							pw_signal_emit(&stream->need_buffer, stream);
 | 
				
			||||||
		impl->in_need_buffer = false;
 | 
							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 *p =
 | 
				
			||||||
		    (struct pw_event_transport_reuse_buffer *) event;
 | 
							    (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->rtreadfd = rtreadfd;
 | 
				
			||||||
	impl->rtwritefd = rtwritefd;
 | 
						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,
 | 
										       impl->rtreadfd,
 | 
				
			||||||
					       SPA_IO_ERR | SPA_IO_HUP,
 | 
										       SPA_IO_ERR | SPA_IO_HUP,
 | 
				
			||||||
					       true, on_rtsocket_condition, stream);
 | 
										       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_sec = 0;
 | 
				
			||||||
	interval.tv_nsec = 100000000;
 | 
						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;
 | 
						return;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -563,26 +564,26 @@ static bool
 | 
				
			||||||
handle_node_command(struct pw_stream *stream, uint32_t seq, const struct spa_command *command)
 | 
					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 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);
 | 
							add_async_complete(stream, seq, SPA_RESULT_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (stream->state == PW_STREAM_STATE_STREAMING) {
 | 
							if (stream->state == PW_STREAM_STATE_STREAMING) {
 | 
				
			||||||
			pw_log_debug("stream %p: pause %d", stream, seq);
 | 
								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);
 | 
										  impl->rtsocket_source, SPA_IO_ERR | SPA_IO_HUP);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			stream_set_state(stream, PW_STREAM_STATE_PAUSED, NULL);
 | 
								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);
 | 
							add_async_complete(stream, seq, SPA_RESULT_OK);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (stream->state == PW_STREAM_STATE_PAUSED) {
 | 
							if (stream->state == PW_STREAM_STATE_PAUSED) {
 | 
				
			||||||
			pw_log_debug("stream %p: start %d %d", stream, seq, impl->direction);
 | 
								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,
 | 
										  impl->rtsocket_source,
 | 
				
			||||||
					  SPA_IO_IN | SPA_IO_ERR | SPA_IO_HUP);
 | 
										  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);
 | 
								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;
 | 
							struct spa_command_node_clock_update *cu = (__typeof__(cu)) command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (cu->body.flags.value & SPA_COMMAND_NODE_CLOCK_UPDATE_FLAG_LIVE) {
 | 
							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,
 | 
								    SPA_MEMBER(bid->buf_ptr, offset + sizeof(struct spa_chunk) * j,
 | 
				
			||||||
				       struct spa_chunk);
 | 
									       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));
 | 
									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->data = NULL;
 | 
				
			||||||
				d->fd = bmid->fd;
 | 
									d->fd = bmid->fd;
 | 
				
			||||||
				pw_log_debug(" data %d %u -> fd %d", j, bmid->id, 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->data = SPA_MEMBER(bid->buf_ptr, SPA_PTR_TO_INT(d->data), void);
 | 
				
			||||||
				d->fd = -1;
 | 
									d->fd = -1;
 | 
				
			||||||
				pw_log_debug(" data %d %u -> mem %p", j, bid->id, d->data);
 | 
									pw_log_debug(" data %d %u -> mem %p", j, bid->id, d->data);
 | 
				
			||||||
| 
						 | 
					@ -913,7 +914,7 @@ pw_stream_connect(struct pw_stream *stream,
 | 
				
			||||||
	if (flags & PW_STREAM_FLAG_AUTOCONNECT)
 | 
						if (flags & PW_STREAM_FLAG_AUTOCONNECT)
 | 
				
			||||||
		pw_properties_set(stream->properties, "pipewire.autoconnect", "1");
 | 
							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,
 | 
										SPA_ID_INVALID,
 | 
				
			||||||
					impl->type_client_node,
 | 
										impl->type_client_node,
 | 
				
			||||||
					0);
 | 
										0);
 | 
				
			||||||
| 
						 | 
					@ -927,7 +928,7 @@ pw_stream_connect(struct pw_stream *stream,
 | 
				
			||||||
	pw_signal_add(&impl->node_proxy->destroy_signal,
 | 
						pw_signal_add(&impl->node_proxy->destroy_signal,
 | 
				
			||||||
		      &impl->node_proxy_destroy, on_node_proxy_destroy);
 | 
							      &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",
 | 
				
			||||||
			       "client-node",
 | 
								       "client-node",
 | 
				
			||||||
			       &stream->properties->dict,
 | 
								       &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 stream *impl = SPA_CONTAINER_OF(stream, struct stream, this);
 | 
				
			||||||
	struct pw_event_transport_reuse_buffer rb = PW_EVENT_TRANSPORT_REUSE_BUFFER_INIT
 | 
						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;
 | 
						struct buffer_id *bid;
 | 
				
			||||||
	uint64_t cmd = 1;
 | 
						uint64_t cmd = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,7 +23,7 @@
 | 
				
			||||||
#include <spa/buffer.h>
 | 
					#include <spa/buffer.h>
 | 
				
			||||||
#include <spa/format.h>
 | 
					#include <spa/format.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/context.h>
 | 
					#include <pipewire/server/remote.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef __cplusplus
 | 
					#ifdef __cplusplus
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
| 
						 | 
					@ -204,8 +204,8 @@ struct pw_time {
 | 
				
			||||||
 * See also \ref page_streams and \ref page_client_api
 | 
					 * See also \ref page_streams and \ref page_client_api
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct pw_stream {
 | 
					struct pw_stream {
 | 
				
			||||||
	struct pw_context *context;	/**< the owner context */
 | 
						struct pw_remote *remote;	/**< the owner remote */
 | 
				
			||||||
	struct spa_list link;		/**< link in the context */
 | 
						struct spa_list link;		/**< link in the remote */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	char *name;				/**< the name of the stream */
 | 
						char *name;				/**< the name of the stream */
 | 
				
			||||||
	uint32_t node_id;			/**< node id for remote node, available from
 | 
						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
 | 
					/** Create a new unconneced \ref pw_stream \memberof pw_stream
 | 
				
			||||||
 * \return a newly allocated \ref pw_stream */
 | 
					 * \return a newly allocated \ref pw_stream */
 | 
				
			||||||
struct 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 */
 | 
						      const char *name,			/**< a stream name */
 | 
				
			||||||
	      struct pw_properties *props	/**< stream properties, ownership is taken */);
 | 
						      struct pw_properties *props	/**< stream properties, ownership is taken */);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,63 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <stdint.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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__ */
 | 
					 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,27 @@ extern "C" {
 | 
				
			||||||
#include <pipewire/client/map.h>
 | 
					#include <pipewire/client/map.h>
 | 
				
			||||||
#include <pipewire/client/transport.h>
 | 
					#include <pipewire/client/transport.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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
 | 
					/** \class pw_interface
 | 
				
			||||||
 * \brief The interface definition
 | 
					 * \brief The interface definition
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,7 +42,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	loop = pw_main_loop_new();
 | 
						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);
 | 
						pw_daemon_config_run_commands(config, core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										532
									
								
								pipewire/examples/local-v4l2.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										532
									
								
								pipewire/examples/local-v4l2.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,532 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <SDL2/SDL.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <spa/type-map.h>
 | 
				
			||||||
 | 
					#include <spa/format-utils.h>
 | 
				
			||||||
 | 
					#include <spa/video/format-utils.h>
 | 
				
			||||||
 | 
					#include <spa/format-builder.h>
 | 
				
			||||||
 | 
					#include <spa/props.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pipewire/client/pipewire.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/sig.h>
 | 
				
			||||||
 | 
					#include <pipewire/server/module.h>
 | 
				
			||||||
 | 
					#include <pipewire/server/node-factory.h>
 | 
				
			||||||
 | 
					#include <spa/lib/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,13 +1,18 @@
 | 
				
			||||||
executable('video-src',
 | 
					executable('video-src',
 | 
				
			||||||
  'video-src.c',
 | 
					  'video-src.c',
 | 
				
			||||||
  install: false,
 | 
					  install: false,
 | 
				
			||||||
  dependencies : [pipewire_dep],
 | 
					  dependencies : [pipewirecore_dep],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if sdl_dep.found()
 | 
					if sdl_dep.found()
 | 
				
			||||||
  executable('video-play',
 | 
					  executable('video-play',
 | 
				
			||||||
    'video-play.c',
 | 
					    'video-play.c',
 | 
				
			||||||
    install: false,
 | 
					    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
 | 
					endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -72,7 +72,8 @@ struct data {
 | 
				
			||||||
	struct pw_loop *loop;
 | 
						struct pw_loop *loop;
 | 
				
			||||||
	struct spa_source *timer;
 | 
						struct spa_source *timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_context *context;
 | 
						struct pw_core *core;
 | 
				
			||||||
 | 
						struct pw_remote *remote;
 | 
				
			||||||
	struct pw_listener on_state_changed;
 | 
						struct pw_listener on_state_changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_stream *stream;
 | 
						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 pw_stream *stream, struct spa_format *format)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed);
 | 
						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_builder b = { NULL };
 | 
				
			||||||
	struct spa_pod_frame f[2];
 | 
						struct spa_pod_frame f[2];
 | 
				
			||||||
	struct spa_param *params[2];
 | 
						struct spa_param *params[2];
 | 
				
			||||||
| 
						 | 
					@ -265,35 +267,35 @@ on_stream_format_changed(struct pw_listener *listener,
 | 
				
			||||||
	SDL_UnlockTexture(data->texture);
 | 
						SDL_UnlockTexture(data->texture);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_pod_builder_init(&b, data->params_buffer, sizeof(data->params_buffer));
 | 
						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,
 | 
						spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
 | 
							PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
 | 
				
			||||||
			data->stride * data->format.size.height),
 | 
								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),
 | 
								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,
 | 
								32,
 | 
				
			||||||
			2, 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));
 | 
								16));
 | 
				
			||||||
	params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
						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,
 | 
						spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
 | 
							PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
 | 
				
			||||||
			ctx->type.meta.Header),
 | 
								core->type.meta.Header),
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
 | 
							PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
 | 
				
			||||||
			sizeof(struct spa_meta_header)));
 | 
								sizeof(struct spa_meta_header)));
 | 
				
			||||||
	params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
						params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2);
 | 
						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);
 | 
						struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (context->state) {
 | 
						switch (remote->state) {
 | 
				
			||||||
	case PW_CONTEXT_STATE_ERROR:
 | 
						case PW_CONTEXT_STATE_ERROR:
 | 
				
			||||||
		printf("context error: %s\n", context->error);
 | 
							printf("remote error: %s\n", remote->error);
 | 
				
			||||||
		data->running = false;
 | 
							data->running = false;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -306,10 +308,10 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
 | 
				
			||||||
		SDL_RendererInfo info;
 | 
							SDL_RendererInfo info;
 | 
				
			||||||
		int i, c;
 | 
							int i, c;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("context state: \"%s\"\n",
 | 
							printf("remote state: \"%s\"\n",
 | 
				
			||||||
		       pw_context_state_as_string(context->state));
 | 
							       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);
 | 
							SDL_GetRendererInfo(data->renderer, &info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -364,7 +366,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	default:
 | 
						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;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -377,12 +379,13 @@ int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data.loop = pw_loop_new();
 | 
						data.loop = pw_loop_new();
 | 
				
			||||||
	data.running = true;
 | 
						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;
 | 
						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) {
 | 
						if (SDL_Init(SDL_INIT_VIDEO) < 0) {
 | 
				
			||||||
		printf("can't initialize SDL: %s\n", SDL_GetError());
 | 
							printf("can't initialize SDL: %s\n", SDL_GetError());
 | 
				
			||||||
| 
						 | 
					@ -395,9 +398,9 @@ int main(int argc, char *argv[])
 | 
				
			||||||
		return -1;
 | 
							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);
 | 
						pw_loop_enter(data.loop);
 | 
				
			||||||
	while (data.running) {
 | 
						while (data.running) {
 | 
				
			||||||
| 
						 | 
					@ -405,7 +408,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pw_loop_leave(data.loop);
 | 
						pw_loop_leave(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_destroy(data.context);
 | 
						pw_remote_destroy(data.remote);
 | 
				
			||||||
	pw_loop_destroy(data.loop);
 | 
						pw_loop_destroy(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -64,7 +64,8 @@ struct data {
 | 
				
			||||||
	struct pw_loop *loop;
 | 
						struct pw_loop *loop;
 | 
				
			||||||
	struct spa_source *timer;
 | 
						struct spa_source *timer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_context *context;
 | 
						struct pw_core *core;
 | 
				
			||||||
 | 
						struct pw_remote *remote;
 | 
				
			||||||
	struct pw_listener on_state_changed;
 | 
						struct pw_listener on_state_changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_stream *stream;
 | 
						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 pw_stream *stream, struct spa_format *format)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct data *data = SPA_CONTAINER_OF(listener, struct data, on_stream_format_changed);
 | 
						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_builder b = { NULL };
 | 
				
			||||||
	struct spa_pod_frame f[2];
 | 
						struct spa_pod_frame f[2];
 | 
				
			||||||
	struct spa_param *params[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);
 | 
						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_init(&b, data->params_buffer, sizeof(data->params_buffer));
 | 
				
			||||||
	spa_pod_builder_object(&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers,
 | 
						spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_buffers.Buffers,
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
 | 
							PROP(&f[1], core->type.param_alloc_buffers.size, SPA_POD_TYPE_INT,
 | 
				
			||||||
			data->stride * data->format.size.height),
 | 
								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),
 | 
								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,
 | 
								32,
 | 
				
			||||||
			2, 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));
 | 
								16));
 | 
				
			||||||
	params[0] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
						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,
 | 
						spa_pod_builder_object(&b, &f[0], 0, core->type.param_alloc_meta_enable.MetaEnable,
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
 | 
							PROP(&f[1], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID,
 | 
				
			||||||
			ctx->type.meta.Header),
 | 
								core->type.meta.Header),
 | 
				
			||||||
		PROP(&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
 | 
							PROP(&f[1], core->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT,
 | 
				
			||||||
			sizeof(struct spa_meta_header)));
 | 
								sizeof(struct spa_meta_header)));
 | 
				
			||||||
	params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
						params[1] = SPA_POD_BUILDER_DEREF(&b, f[0].ref, struct spa_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_stream_finish_format(stream, SPA_RESULT_OK, params, 2);
 | 
						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);
 | 
						struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (context->state) {
 | 
						switch (remote->state) {
 | 
				
			||||||
	case PW_CONTEXT_STATE_ERROR:
 | 
						case PW_REMOTE_STATE_ERROR:
 | 
				
			||||||
		printf("context error: %s\n", context->error);
 | 
							printf("remote error: %s\n", remote->error);
 | 
				
			||||||
		data->running = false;
 | 
							data->running = false;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_CONTEXT_STATE_CONNECTED:
 | 
						case PW_REMOTE_STATE_CONNECTED:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		const struct spa_format *formats[1];
 | 
							const struct spa_format *formats[1];
 | 
				
			||||||
		uint8_t buffer[1024];
 | 
							uint8_t buffer[1024];
 | 
				
			||||||
		struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
							struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
 | 
				
			||||||
		struct spa_pod_frame f[2];
 | 
							struct spa_pod_frame f[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("context state: \"%s\"\n",
 | 
							printf("remote state: \"%s\"\n",
 | 
				
			||||||
		       pw_context_state_as_string(context->state));
 | 
							       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,
 | 
							spa_pod_builder_format(&b, &f[0], data->type.format,
 | 
				
			||||||
			data->type.media_type.video,
 | 
								data->type.media_type.video,
 | 
				
			||||||
| 
						 | 
					@ -257,7 +259,7 @@ static void on_state_changed(struct pw_listener *listener, struct pw_context *co
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	default:
 | 
						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;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -270,15 +272,16 @@ int main(int argc, char *argv[])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data.loop = pw_loop_new();
 | 
						data.loop = pw_loop_new();
 | 
				
			||||||
	data.running = true;
 | 
						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);
 | 
						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);
 | 
						pw_loop_enter(data.loop);
 | 
				
			||||||
	while (data.running) {
 | 
						while (data.running) {
 | 
				
			||||||
| 
						 | 
					@ -286,7 +289,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pw_loop_leave(data.loop);
 | 
						pw_loop_leave(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_destroy(data.context);
 | 
						pw_remote_destroy(data.remote);
 | 
				
			||||||
	pw_loop_destroy(data.loop);
 | 
						pw_loop_destroy(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -207,7 +207,7 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info)
 | 
				
			||||||
    type = GST_PIPEWIRE_DEVICE_TYPE_SINK;
 | 
					    type = GST_PIPEWIRE_DEVICE_TYPE_SINK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (i = 0; i < info->n_input_formats; i++) {
 | 
					    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)
 | 
					      if (c1)
 | 
				
			||||||
        gst_caps_append (caps, 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) {
 | 
					  else if (info->max_output_ports > 0 && info->max_input_ports == 0) {
 | 
				
			||||||
    type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE;
 | 
					    type = GST_PIPEWIRE_DEVICE_TYPE_SOURCE;
 | 
				
			||||||
    for (i = 0; i < info->n_output_formats; i++) {
 | 
					    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)
 | 
					      if (c1)
 | 
				
			||||||
        gst_caps_append (caps, c1);
 | 
					        gst_caps_append (caps, c1);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -242,22 +242,6 @@ new_node (GstPipeWireDeviceProvider *self, const struct pw_node_info *info)
 | 
				
			||||||
                               props);
 | 
					                               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 *
 | 
					static GstPipeWireDevice *
 | 
				
			||||||
find_device (GstDeviceProvider *provider, uint32_t id)
 | 
					find_device (GstDeviceProvider *provider, uint32_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -279,66 +263,11 @@ find_device (GstDeviceProvider *provider, uint32_t id)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_context_subscription (struct pw_listener         *listener,
 | 
					get_core_info (struct pw_remote          *remote,
 | 
				
			||||||
                         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)
 | 
					               void                      *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstDeviceProvider *provider = user_data;
 | 
					  GstDeviceProvider *provider = user_data;
 | 
				
			||||||
 | 
					  struct pw_core_info *info = remote->info;
 | 
				
			||||||
  const gchar *value;
 | 
					  const gchar *value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (info == NULL || info->props == NULL)
 | 
					  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 *
 | 
					static GList *
 | 
				
			||||||
gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
 | 
					gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
 | 
					  GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
 | 
				
			||||||
  struct pw_loop *l = NULL;
 | 
					  struct pw_loop *l = NULL;
 | 
				
			||||||
  struct pw_context *c = NULL;
 | 
					  struct pw_core *c = NULL;
 | 
				
			||||||
  InfoData data;
 | 
					  struct pw_remote *r = NULL;
 | 
				
			||||||
 | 
					  struct pw_proxy *reg = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  GST_DEBUG_OBJECT (self, "starting probe");
 | 
					  GST_DEBUG_OBJECT (self, "starting probe");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(l = pw_loop_new ()))
 | 
					  if (!(l = pw_loop_new ()))
 | 
				
			||||||
    return NULL;
 | 
					    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;
 | 
					    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 (;;) {
 | 
					  for (;;) {
 | 
				
			||||||
    enum pw_context_state state;
 | 
					    enum pw_remote_state state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = c->state;
 | 
					    state = r->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state <= 0) {
 | 
					    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;
 | 
					      goto failed;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state == PW_CONTEXT_STATE_CONNECTED)
 | 
					    if (state == PW_REMOTE_STATE_CONNECTED)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Wait until something happens */
 | 
					    /* Wait until something happens */
 | 
				
			||||||
| 
						 | 
					@ -397,30 +404,31 @@ gst_pipewire_device_provider_probe (GstDeviceProvider * provider)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  GST_DEBUG_OBJECT (self, "connected");
 | 
					  GST_DEBUG_OBJECT (self, "connected");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_context_get_core_info (c,
 | 
					  get_core_info (r, self);
 | 
				
			||||||
                            get_core_info_cb,
 | 
					 | 
				
			||||||
                            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 (;;) {
 | 
					  for (;;) {
 | 
				
			||||||
    if (c->state <= 0)
 | 
					    if (r->state <= 0)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    if (data.end)
 | 
					    if (self->end)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    pw_loop_iterate (l, -1);
 | 
					    pw_loop_iterate (l, -1);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_context_disconnect (c);
 | 
					  pw_remote_disconnect (r);
 | 
				
			||||||
  pw_context_destroy (c);
 | 
					  pw_remote_destroy (r);
 | 
				
			||||||
 | 
					  pw_core_destroy (c);
 | 
				
			||||||
  pw_loop_destroy (l);
 | 
					  pw_loop_destroy (l);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return *data.devices;
 | 
					  return *self->devices;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
failed:
 | 
					failed:
 | 
				
			||||||
  pw_loop_destroy (l);
 | 
					  pw_loop_destroy (l);
 | 
				
			||||||
| 
						 | 
					@ -428,24 +436,24 @@ failed:
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_context_state_changed (struct pw_listener *listener,
 | 
					on_remote_state_changed (struct pw_listener *listener,
 | 
				
			||||||
                          struct pw_context  *context)
 | 
					                          struct pw_remote  *remote)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, ctx_state_changed);
 | 
					  GstPipeWireDeviceProvider *self = SPA_CONTAINER_OF (listener, GstPipeWireDeviceProvider, remote_state_changed);
 | 
				
			||||||
  enum pw_context_state state;
 | 
					  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) {
 | 
					  switch (state) {
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTING:
 | 
					    case PW_REMOTE_STATE_CONNECTING:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case PW_CONTEXT_STATE_UNCONNECTED:
 | 
					    case PW_REMOTE_STATE_UNCONNECTED:
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTED:
 | 
					    case PW_REMOTE_STATE_CONNECTED:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case PW_CONTEXT_STATE_ERROR:
 | 
					    case PW_REMOTE_STATE_ERROR:
 | 
				
			||||||
      GST_ERROR_OBJECT (self, "context error: %s", context->error);
 | 
					      GST_ERROR_OBJECT (self, "remote error: %s", remote->error);
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  pw_thread_loop_signal (self->main_loop, FALSE);
 | 
					  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");
 | 
					  GST_DEBUG_OBJECT (self, "starting provider");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  self->loop = pw_loop_new ();
 | 
					  self->loop = pw_loop_new ();
 | 
				
			||||||
 | 
					  self->list_only = FALSE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) {
 | 
					  if (!(self->main_loop = pw_thread_loop_new (self->loop, "pipewire-device-monitor"))) {
 | 
				
			||||||
    GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop");
 | 
					    GST_ERROR_OBJECT (self, "Could not create PipeWire mainloop");
 | 
				
			||||||
    goto failed_main_loop;
 | 
					    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) {
 | 
					  if (pw_thread_loop_start (self->main_loop) != SPA_RESULT_OK) {
 | 
				
			||||||
    GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop");
 | 
					    GST_ERROR_OBJECT (self, "Could not start PipeWire mainloop");
 | 
				
			||||||
    goto failed_start;
 | 
					    goto failed_start;
 | 
				
			||||||
| 
						 | 
					@ -472,49 +486,53 @@ gst_pipewire_device_provider_start (GstDeviceProvider * provider)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_thread_loop_lock (self->main_loop);
 | 
					  pw_thread_loop_lock (self->main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (!(self->context = pw_context_new (self->loop, self->client_name, NULL))) {
 | 
					  if (!(self->remote = pw_remote_new (self->core, NULL))) {
 | 
				
			||||||
    GST_ERROR_OBJECT (self, "Failed to create context");
 | 
					    GST_ERROR_OBJECT (self, "Failed to create remote");
 | 
				
			||||||
    goto failed_context;
 | 
					    goto failed_remote;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_signal_add (&self->context->state_changed,
 | 
					  pw_signal_add (&self->remote->state_changed,
 | 
				
			||||||
                    &self->ctx_state_changed,
 | 
					                 &self->remote_state_changed,
 | 
				
			||||||
                    on_context_state_changed);
 | 
					                 on_remote_state_changed);
 | 
				
			||||||
  pw_signal_add (&self->context->subscription,
 | 
					 | 
				
			||||||
                    &self->ctx_subscription,
 | 
					 | 
				
			||||||
                    on_context_subscription);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_context_connect (self->context, 0);
 | 
					  pw_remote_connect (self->remote);
 | 
				
			||||||
  for (;;) {
 | 
					  for (;;) {
 | 
				
			||||||
    enum pw_context_state state;
 | 
					    enum pw_remote_state state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    state = self->context->state;
 | 
					    state = self->remote->state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state <= 0) {
 | 
					    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;
 | 
					      goto not_running;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state == PW_CONTEXT_STATE_CONNECTED)
 | 
					    if (state == PW_REMOTE_STATE_CONNECTED)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Wait until something happens */
 | 
					    /* Wait until something happens */
 | 
				
			||||||
    pw_thread_loop_wait (self->main_loop);
 | 
					    pw_thread_loop_wait (self->main_loop);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  GST_DEBUG_OBJECT (self, "connected");
 | 
					  GST_DEBUG_OBJECT (self, "connected");
 | 
				
			||||||
  pw_context_get_core_info (self->context,
 | 
					  get_core_info (self->remote, self);
 | 
				
			||||||
                            get_core_info_cb,
 | 
					
 | 
				
			||||||
                            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);
 | 
					  pw_thread_loop_unlock (self->main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return TRUE;
 | 
					  return TRUE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
not_running:
 | 
					not_running:
 | 
				
			||||||
  pw_context_destroy (self->context);
 | 
					  pw_remote_destroy (self->remote);
 | 
				
			||||||
  self->context = NULL;
 | 
					  self->remote = NULL;
 | 
				
			||||||
failed_context:
 | 
					failed_remote:
 | 
				
			||||||
  pw_thread_loop_unlock (self->main_loop);
 | 
					  pw_thread_loop_unlock (self->main_loop);
 | 
				
			||||||
failed_start:
 | 
					failed_start:
 | 
				
			||||||
 | 
					  pw_core_destroy (self->core);
 | 
				
			||||||
 | 
					  self->core = NULL;
 | 
				
			||||||
 | 
					failed_core:
 | 
				
			||||||
  pw_thread_loop_destroy (self->main_loop);
 | 
					  pw_thread_loop_destroy (self->main_loop);
 | 
				
			||||||
  self->main_loop = NULL;
 | 
					  self->main_loop = NULL;
 | 
				
			||||||
failed_main_loop:
 | 
					failed_main_loop:
 | 
				
			||||||
| 
						 | 
					@ -528,10 +546,10 @@ gst_pipewire_device_provider_stop (GstDeviceProvider * provider)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
 | 
					  GstPipeWireDeviceProvider *self = GST_PIPEWIRE_DEVICE_PROVIDER (provider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (self->context) {
 | 
					  if (self->remote) {
 | 
				
			||||||
    pw_context_disconnect (self->context);
 | 
					    pw_remote_disconnect (self->remote);
 | 
				
			||||||
    pw_context_destroy (self->context);
 | 
					    pw_remote_destroy (self->remote);
 | 
				
			||||||
    self->context = NULL;
 | 
					    self->remote = NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (self->main_loop) {
 | 
					  if (self->main_loop) {
 | 
				
			||||||
    pw_thread_loop_destroy (self->main_loop);
 | 
					    pw_thread_loop_destroy (self->main_loop);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -84,9 +84,14 @@ struct _GstPipeWireDeviceProvider {
 | 
				
			||||||
  struct pw_loop *loop;
 | 
					  struct pw_loop *loop;
 | 
				
			||||||
  struct pw_thread_loop *main_loop;
 | 
					  struct pw_thread_loop *main_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct pw_context *context;
 | 
					  struct pw_core *core;
 | 
				
			||||||
  struct pw_listener ctx_state_changed;
 | 
					  struct pw_remote *remote;
 | 
				
			||||||
  struct pw_listener ctx_subscription;
 | 
					  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 {
 | 
					struct _GstPipeWireDeviceProviderClass {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -235,7 +235,8 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass)
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
pool_activated (GstPipeWirePool *pool, GstPipeWireSink *sink)
 | 
					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;
 | 
					  GstStructure *config;
 | 
				
			||||||
  GstCaps *caps;
 | 
					  GstCaps *caps;
 | 
				
			||||||
  guint size;
 | 
					  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);
 | 
					  gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  spa_pod_builder_init (&b, buffer, sizeof (buffer));
 | 
					  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)
 | 
					  if (size == 0)
 | 
				
			||||||
    spa_pod_builder_add (&b,
 | 
					    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
 | 
					  else
 | 
				
			||||||
    spa_pod_builder_add (&b,
 | 
					    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,
 | 
					  spa_pod_builder_add (&b,
 | 
				
			||||||
      PROP_MM (&f[1], ctx->type.param_alloc_buffers.stride,  SPA_POD_TYPE_INT, 0, 0, INT32_MAX),
 | 
					      PROP_MM (&f[1], core->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_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], ctx->type.param_alloc_buffers.align,   SPA_POD_TYPE_INT, 16),
 | 
					      PROP    (&f[1], core->type.param_alloc_buffers.align,   SPA_POD_TYPE_INT, 16),
 | 
				
			||||||
      0);
 | 
					      0);
 | 
				
			||||||
  spa_pod_builder_pop (&b, &f[0]);
 | 
					  spa_pod_builder_pop (&b, &f[0]);
 | 
				
			||||||
  port_params[0] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
 | 
					  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,
 | 
					  spa_pod_builder_object (&b, &f[0], 0, core->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], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header),
 | 
				
			||||||
      PROP    (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_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);
 | 
					  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,
 | 
					  spa_pod_builder_object (&b, &f[0], 0, core->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], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->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], core->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,
 | 
					      PROP    (&f[1], core->type.param_alloc_meta_enable.ringbufferSize,   SPA_POD_TYPE_INT,
 | 
				
			||||||
                                                                         size * SPA_MAX (4,
 | 
					                                                                         size * SPA_MAX (4,
 | 
				
			||||||
                                                                                SPA_MAX (min_buffers, max_buffers))),
 | 
					                                                                                SPA_MAX (min_buffers, max_buffers))),
 | 
				
			||||||
      PROP    (&f[1], ctx->type.param_alloc_meta_enable.ringbufferStride, SPA_POD_TYPE_INT, 0),
 | 
					      PROP    (&f[1], core->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], core->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.ringbufferAlign,  SPA_POD_TYPE_INT, 16));
 | 
				
			||||||
  port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
 | 
					  port_params[2] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_thread_loop_lock (sink->main_loop);
 | 
					  pw_thread_loop_lock (sink->main_loop);
 | 
				
			||||||
| 
						 | 
					@ -304,6 +305,7 @@ gst_pipewire_sink_init (GstPipeWireSink * sink)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  sink->loop = pw_loop_new ();
 | 
					  sink->loop = pw_loop_new ();
 | 
				
			||||||
  sink->main_loop = pw_thread_loop_new (sink->loop, "pipewire-sink-loop");
 | 
					  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);
 | 
					  GST_DEBUG ("loop %p %p", sink->loop, sink->main_loop);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -441,6 +443,7 @@ on_add_buffer (struct pw_listener *listener,
 | 
				
			||||||
  GstBuffer *buf;
 | 
					  GstBuffer *buf;
 | 
				
			||||||
  uint32_t i;
 | 
					  uint32_t i;
 | 
				
			||||||
  ProcessMemData data;
 | 
					  ProcessMemData data;
 | 
				
			||||||
 | 
					  struct pw_core *core = pwsink->remote->core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  GST_LOG_OBJECT (pwsink, "add buffer");
 | 
					  GST_LOG_OBJECT (pwsink, "add buffer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -454,20 +457,20 @@ on_add_buffer (struct pw_listener *listener,
 | 
				
			||||||
  data.sink = gst_object_ref (pwsink);
 | 
					  data.sink = gst_object_ref (pwsink);
 | 
				
			||||||
  data.id = id;
 | 
					  data.id = id;
 | 
				
			||||||
  data.buf = b;
 | 
					  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++) {
 | 
					  for (i = 0; i < b->n_datas; i++) {
 | 
				
			||||||
    struct spa_data *d = &b->datas[i];
 | 
					    struct spa_data *d = &b->datas[i];
 | 
				
			||||||
    GstMemory *gmem = NULL;
 | 
					    GstMemory *gmem = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (d->type == stream->context->type.data.MemFd ||
 | 
					    if (d->type == core->type.data.MemFd ||
 | 
				
			||||||
        d->type == stream->context->type.data.DmaBuf) {
 | 
					        d->type == core->type.data.DmaBuf) {
 | 
				
			||||||
      gmem = gst_fd_allocator_alloc (pwsink->allocator, dup (d->fd),
 | 
					      gmem = gst_fd_allocator_alloc (pwsink->allocator, dup (d->fd),
 | 
				
			||||||
                d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
 | 
					                d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
 | 
				
			||||||
      gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
 | 
					      gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
 | 
				
			||||||
      data.offset = d->mapoffset;
 | 
					      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,
 | 
					      gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset,
 | 
				
			||||||
                                     d->chunk->size, NULL, NULL);
 | 
					                                     d->chunk->size, NULL, NULL);
 | 
				
			||||||
      data.offset = 0;
 | 
					      data.offset = 0;
 | 
				
			||||||
| 
						 | 
					@ -623,7 +626,7 @@ gst_pipewire_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pwsink = GST_PIPEWIRE_SINK (bsink);
 | 
					  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);
 | 
					  pw_thread_loop_lock (pwsink->main_loop);
 | 
				
			||||||
  state = pwsink->stream->state;
 | 
					  state = pwsink->stream->state;
 | 
				
			||||||
| 
						 | 
					@ -755,7 +758,7 @@ gst_pipewire_sink_start (GstBaseSink * basesink)
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_thread_loop_lock (pwsink->main_loop);
 | 
					  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;
 | 
					  pwsink->pool->stream = pwsink->stream;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_signal_add (&pwsink->stream->state_changed, &pwsink->stream_state_changed, on_state_changed);
 | 
					  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
 | 
					static void
 | 
				
			||||||
on_ctx_state_changed (struct pw_listener *listener,
 | 
					on_remote_state_changed (struct pw_listener *listener,
 | 
				
			||||||
                      struct pw_context  *ctx)
 | 
					                      struct pw_remote  *remote)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, ctx_state_changed);
 | 
					  GstPipeWireSink *pwsink = SPA_CONTAINER_OF (listener, GstPipeWireSink, remote_state_changed);
 | 
				
			||||||
  enum pw_context_state state;
 | 
					  enum pw_remote_state state;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  state = ctx->state;
 | 
					  state = remote->state;
 | 
				
			||||||
  GST_DEBUG ("got context state %d", state);
 | 
					  GST_DEBUG ("got remote state %d", state);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  switch (state) {
 | 
					  switch (state) {
 | 
				
			||||||
    case PW_CONTEXT_STATE_UNCONNECTED:
 | 
					    case PW_REMOTE_STATE_UNCONNECTED:
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTING:
 | 
					    case PW_REMOTE_STATE_CONNECTING:
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTED:
 | 
					    case PW_REMOTE_STATE_CONNECTED:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case PW_CONTEXT_STATE_ERROR:
 | 
					    case PW_REMOTE_STATE_ERROR:
 | 
				
			||||||
      GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,
 | 
					      GST_ELEMENT_ERROR (pwsink, RESOURCE, FAILED,
 | 
				
			||||||
          ("context error: %s", ctx->error), (NULL));
 | 
					          ("remote error: %s", remote->error), (NULL));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  pw_thread_loop_signal (pwsink->main_loop, FALSE);
 | 
					  pw_thread_loop_signal (pwsink->main_loop, FALSE);
 | 
				
			||||||
| 
						 | 
					@ -818,19 +821,19 @@ gst_pipewire_sink_open (GstPipeWireSink * pwsink)
 | 
				
			||||||
    goto mainloop_error;
 | 
					    goto mainloop_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_thread_loop_lock (pwsink->main_loop);
 | 
					  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) {
 | 
					  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;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state == PW_CONTEXT_STATE_ERROR)
 | 
					    if (state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
      goto connect_error;
 | 
					      goto connect_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pw_thread_loop_wait (pwsink->main_loop);
 | 
					    pw_thread_loop_wait (pwsink->main_loop);
 | 
				
			||||||
| 
						 | 
					@ -860,16 +863,16 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink)
 | 
				
			||||||
  if (pwsink->stream) {
 | 
					  if (pwsink->stream) {
 | 
				
			||||||
    pw_stream_disconnect (pwsink->stream);
 | 
					    pw_stream_disconnect (pwsink->stream);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  if (pwsink->ctx) {
 | 
					  if (pwsink->remote) {
 | 
				
			||||||
    pw_context_disconnect (pwsink->ctx);
 | 
					    pw_remote_disconnect (pwsink->remote);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while (TRUE) {
 | 
					    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;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (state == PW_CONTEXT_STATE_ERROR)
 | 
					      if (state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      pw_thread_loop_wait (pwsink->main_loop);
 | 
					      pw_thread_loop_wait (pwsink->main_loop);
 | 
				
			||||||
| 
						 | 
					@ -884,9 +887,9 @@ gst_pipewire_sink_close (GstPipeWireSink * pwsink)
 | 
				
			||||||
    pwsink->stream = NULL;
 | 
					    pwsink->stream = NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (pwsink->ctx) {
 | 
					  if (pwsink->remote) {
 | 
				
			||||||
    pw_context_destroy (pwsink->ctx);
 | 
					    pw_remote_destroy (pwsink->remote);
 | 
				
			||||||
    pwsink->ctx = NULL;
 | 
					    pwsink->remote = NULL;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  return TRUE;
 | 
					  return TRUE;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,8 +80,9 @@ struct _GstPipeWireSink {
 | 
				
			||||||
  struct pw_loop *loop;
 | 
					  struct pw_loop *loop;
 | 
				
			||||||
  struct pw_thread_loop *main_loop;
 | 
					  struct pw_thread_loop *main_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct pw_context *ctx;
 | 
					  struct pw_core *core;
 | 
				
			||||||
  struct pw_listener ctx_state_changed;
 | 
					  struct pw_remote *remote;
 | 
				
			||||||
 | 
					  struct pw_listener remote_state_changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct pw_stream *stream;
 | 
					  struct pw_stream *stream;
 | 
				
			||||||
  struct pw_listener stream_state_changed;
 | 
					  struct pw_listener stream_state_changed;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -307,6 +307,7 @@ gst_pipewire_src_init (GstPipeWireSrc * src)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  src->loop = pw_loop_new ();
 | 
					  src->loop = pw_loop_new ();
 | 
				
			||||||
  src->main_loop = pw_thread_loop_new (src->loop, "pipewire-main-loop");
 | 
					  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);
 | 
					  GST_DEBUG ("loop %p, mainloop %p", src->loop, src->main_loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -359,7 +360,8 @@ on_add_buffer (struct pw_listener *listener,
 | 
				
			||||||
  GstBuffer *buf;
 | 
					  GstBuffer *buf;
 | 
				
			||||||
  uint32_t i;
 | 
					  uint32_t i;
 | 
				
			||||||
  ProcessMemData data;
 | 
					  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");
 | 
					  GST_LOG_OBJECT (pwsrc, "add buffer");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -374,19 +376,19 @@ on_add_buffer (struct pw_listener *listener,
 | 
				
			||||||
  data.src = gst_object_ref (pwsrc);
 | 
					  data.src = gst_object_ref (pwsrc);
 | 
				
			||||||
  data.id = id;
 | 
					  data.id = id;
 | 
				
			||||||
  data.buf = b;
 | 
					  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++) {
 | 
					  for (i = 0; i < b->n_datas; i++) {
 | 
				
			||||||
    struct spa_data *d = &b->datas[i];
 | 
					    struct spa_data *d = &b->datas[i];
 | 
				
			||||||
    GstMemory *gmem = NULL;
 | 
					    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),
 | 
					      gmem = gst_fd_allocator_alloc (pwsrc->fd_allocator, dup (d->fd),
 | 
				
			||||||
                d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
 | 
					                d->mapoffset + d->maxsize, GST_FD_MEMORY_FLAG_NONE);
 | 
				
			||||||
      gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
 | 
					      gst_memory_resize (gmem, d->chunk->offset + d->mapoffset, d->chunk->size);
 | 
				
			||||||
      data.offset = d->mapoffset;
 | 
					      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,
 | 
					      gmem = gst_memory_new_wrapped (0, d->data, d->maxsize, d->chunk->offset + d->mapoffset,
 | 
				
			||||||
                d->chunk->size, NULL, NULL);
 | 
					                d->chunk->size, NULL, NULL);
 | 
				
			||||||
      data.offset = 0;
 | 
					      data.offset = 0;
 | 
				
			||||||
| 
						 | 
					@ -543,7 +545,7 @@ gst_pipewire_src_stream_start (GstPipeWireSrc *pwsrc)
 | 
				
			||||||
    if (state == PW_STREAM_STATE_ERROR)
 | 
					    if (state == PW_STREAM_STATE_ERROR)
 | 
				
			||||||
      goto start_error;
 | 
					      goto start_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR)
 | 
					    if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
      goto start_error;
 | 
					      goto start_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pw_thread_loop_wait (pwsrc->main_loop);
 | 
					    pw_thread_loop_wait (pwsrc->main_loop);
 | 
				
			||||||
| 
						 | 
					@ -583,7 +585,7 @@ wait_negotiated (GstPipeWireSrc *this)
 | 
				
			||||||
    if (state == PW_STREAM_STATE_ERROR)
 | 
					    if (state == PW_STREAM_STATE_ERROR)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this->ctx->state == PW_CONTEXT_STATE_ERROR)
 | 
					    if (this->remote->state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (this->started)
 | 
					    if (this->started)
 | 
				
			||||||
| 
						 | 
					@ -634,7 +636,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
 | 
				
			||||||
  GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, caps);
 | 
					  GST_DEBUG_OBJECT (basesrc, "have common caps: %" GST_PTR_FORMAT, caps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* open a connection with these 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);
 | 
					  gst_caps_unref (caps);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /* first disconnect */
 | 
					  /* first disconnect */
 | 
				
			||||||
| 
						 | 
					@ -679,7 +681,7 @@ gst_pipewire_src_negotiate (GstBaseSrc * basesrc)
 | 
				
			||||||
    if (state == PW_STREAM_STATE_ERROR)
 | 
					    if (state == PW_STREAM_STATE_ERROR)
 | 
				
			||||||
      goto connect_error;
 | 
					      goto connect_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (pwsrc->ctx->state == PW_CONTEXT_STATE_ERROR)
 | 
					    if (pwsrc->remote->state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
      goto connect_error;
 | 
					      goto connect_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pw_thread_loop_wait (pwsrc->main_loop);
 | 
					    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);
 | 
					  GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, stream_format_changed);
 | 
				
			||||||
  GstCaps *caps;
 | 
					  GstCaps *caps;
 | 
				
			||||||
  gboolean res;
 | 
					  gboolean res;
 | 
				
			||||||
  struct pw_context *ctx = stream->context;
 | 
					  struct pw_remote *remote = stream->remote;
 | 
				
			||||||
 | 
					  struct pw_core *core = remote->core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if (format == NULL) {
 | 
					  if (format == NULL) {
 | 
				
			||||||
    GST_DEBUG_OBJECT (pwsrc, "clear format");
 | 
					    GST_DEBUG_OBJECT (pwsrc, "clear format");
 | 
				
			||||||
| 
						 | 
					@ -746,7 +749,7 @@ on_format_changed (struct pw_listener *listener,
 | 
				
			||||||
    return;
 | 
					    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);
 | 
					  GST_DEBUG_OBJECT (pwsrc, "we got format %" GST_PTR_FORMAT, caps);
 | 
				
			||||||
  res = gst_base_src_set_caps (GST_BASE_SRC (pwsrc), caps);
 | 
					  res = gst_base_src_set_caps (GST_BASE_SRC (pwsrc), caps);
 | 
				
			||||||
  gst_caps_unref (caps);
 | 
					  gst_caps_unref (caps);
 | 
				
			||||||
| 
						 | 
					@ -758,16 +761,16 @@ on_format_changed (struct pw_listener *listener,
 | 
				
			||||||
    struct spa_pod_frame f[2];
 | 
					    struct spa_pod_frame f[2];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    spa_pod_builder_init (&b, buffer, sizeof (buffer));
 | 
					    spa_pod_builder_init (&b, buffer, sizeof (buffer));
 | 
				
			||||||
    spa_pod_builder_object (&b, &f[0], 0, ctx->type.param_alloc_buffers.Buffers,
 | 
					    spa_pod_builder_object (&b, &f[0], 0, core->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], core->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], core->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_U_MM (&f[1], core->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));
 | 
					      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);
 | 
					    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,
 | 
					    spa_pod_builder_object (&b, &f[0], 0, core->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], core->type.param_alloc_meta_enable.type, SPA_POD_TYPE_ID, core->type.meta.Header),
 | 
				
			||||||
        PROP    (&f[1], ctx->type.param_alloc_meta_enable.size, SPA_POD_TYPE_INT, sizeof (struct spa_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);
 | 
					    params[1] = SPA_POD_BUILDER_DEREF (&b, f[0].ref, struct spa_param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    GST_DEBUG_OBJECT (pwsrc, "doing finish format");
 | 
					    GST_DEBUG_OBJECT (pwsrc, "doing finish format");
 | 
				
			||||||
| 
						 | 
					@ -969,22 +972,22 @@ gst_pipewire_src_stop (GstBaseSrc * basesrc)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
on_ctx_state_changed (struct pw_listener *listener,
 | 
					on_remote_state_changed (struct pw_listener *listener,
 | 
				
			||||||
                      struct pw_context  *ctx)
 | 
								 struct pw_remote  *remote)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
  GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, ctx_state_changed);
 | 
					  GstPipeWireSrc *pwsrc = SPA_CONTAINER_OF (listener, GstPipeWireSrc, remote_state_changed);
 | 
				
			||||||
  enum pw_context_state state = ctx->state;
 | 
					  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) {
 | 
					  switch (state) {
 | 
				
			||||||
    case PW_CONTEXT_STATE_UNCONNECTED:
 | 
					    case PW_REMOTE_STATE_UNCONNECTED:
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTING:
 | 
					    case PW_REMOTE_STATE_CONNECTING:
 | 
				
			||||||
    case PW_CONTEXT_STATE_CONNECTED:
 | 
					    case PW_REMOTE_STATE_CONNECTED:
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case PW_CONTEXT_STATE_ERROR:
 | 
					    case PW_REMOTE_STATE_ERROR:
 | 
				
			||||||
      GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
 | 
					      GST_ELEMENT_ERROR (pwsrc, RESOURCE, FAILED,
 | 
				
			||||||
          ("context error: %s", ctx->error), (NULL));
 | 
					          ("remote error: %s", remote->error), (NULL));
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  pw_thread_loop_signal (pwsrc->main_loop, FALSE);
 | 
					  pw_thread_loop_signal (pwsrc->main_loop, FALSE);
 | 
				
			||||||
| 
						 | 
					@ -1013,20 +1016,20 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc)
 | 
				
			||||||
    goto mainloop_failed;
 | 
					    goto mainloop_failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_thread_loop_lock (pwsrc->main_loop);
 | 
					  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) {
 | 
					  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));
 | 
					    GST_DEBUG ("waiting for CONNECTED, now %s", pw_remote_state_as_string (state));
 | 
				
			||||||
    if (state == PW_CONTEXT_STATE_CONNECTED)
 | 
					    if (state == PW_REMOTE_STATE_CONNECTED)
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (state == PW_CONTEXT_STATE_ERROR)
 | 
					    if (state == PW_REMOTE_STATE_ERROR)
 | 
				
			||||||
      goto connect_error;
 | 
					      goto connect_error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pw_thread_loop_wait (pwsrc->main_loop);
 | 
					    pw_thread_loop_wait (pwsrc->main_loop);
 | 
				
			||||||
| 
						 | 
					@ -1039,7 +1042,7 @@ gst_pipewire_src_open (GstPipeWireSrc * pwsrc)
 | 
				
			||||||
    props = NULL;
 | 
					    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->state_changed, &pwsrc->stream_state_changed, on_state_changed);
 | 
				
			||||||
  pw_signal_add (&pwsrc->stream->format_changed, &pwsrc->stream_format_changed, on_format_changed);
 | 
					  pw_signal_add (&pwsrc->stream->format_changed, &pwsrc->stream_format_changed, on_format_changed);
 | 
				
			||||||
| 
						 | 
					@ -1075,8 +1078,8 @@ gst_pipewire_src_close (GstPipeWireSrc * pwsrc)
 | 
				
			||||||
  pw_stream_destroy (pwsrc->stream);
 | 
					  pw_stream_destroy (pwsrc->stream);
 | 
				
			||||||
  pwsrc->stream = NULL;
 | 
					  pwsrc->stream = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  pw_context_destroy (pwsrc->ctx);
 | 
					  pw_remote_destroy (pwsrc->remote);
 | 
				
			||||||
  pwsrc->ctx = NULL;
 | 
					  pwsrc->remote = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  GST_OBJECT_LOCK (pwsrc);
 | 
					  GST_OBJECT_LOCK (pwsrc);
 | 
				
			||||||
  g_clear_object (&pwsrc->clock);
 | 
					  g_clear_object (&pwsrc->clock);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -67,8 +67,9 @@ struct _GstPipeWireSrc {
 | 
				
			||||||
  struct pw_loop *loop;
 | 
					  struct pw_loop *loop;
 | 
				
			||||||
  struct pw_thread_loop *main_loop;
 | 
					  struct pw_thread_loop *main_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct pw_context *ctx;
 | 
					  struct pw_core *core;
 | 
				
			||||||
  struct pw_listener ctx_state_changed;
 | 
					  struct pw_remote *remote;
 | 
				
			||||||
 | 
					  struct pw_listener remote_state_changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  struct pw_stream *stream;
 | 
					  struct pw_stream *stream;
 | 
				
			||||||
  struct pw_listener stream_state_changed;
 | 
					  struct pw_listener stream_state_changed;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,66 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <string.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <dlfcn.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -1,66 +0,0 @@
 | 
				
			||||||
/* PipeWire
 | 
					 | 
				
			||||||
 * Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * 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 <string.h>
 | 
					 | 
				
			||||||
#include <stdio.h>
 | 
					 | 
				
			||||||
#include <errno.h>
 | 
					 | 
				
			||||||
#include <dlfcn.h>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#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;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -37,8 +37,8 @@ pipewire_module_client_node = shared_library('pipewire-module-client-node',
 | 
				
			||||||
  [ 'module-client-node.c',
 | 
					  [ 'module-client-node.c',
 | 
				
			||||||
    'module-client-node/client-node.c',
 | 
					    'module-client-node/client-node.c',
 | 
				
			||||||
    'module-client-node/protocol-native.c',
 | 
					    'module-client-node/protocol-native.c',
 | 
				
			||||||
    'spa/spa-node.c',
 | 
					    'module-protocol-native/connection.c',
 | 
				
			||||||
    'extension-client-node.c', ],
 | 
					    'spa/spa-node.c', ],
 | 
				
			||||||
  c_args : pipewire_module_c_args,
 | 
					  c_args : pipewire_module_c_args,
 | 
				
			||||||
  include_directories : [configinc, spa_inc],
 | 
					  include_directories : [configinc, spa_inc],
 | 
				
			||||||
  link_with : spalib,
 | 
					  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',
 | 
					pipewire_module_protocol_native = shared_library('pipewire-module-protocol-native',
 | 
				
			||||||
  [ 'module-protocol-native.c',
 | 
					  [ 'module-protocol-native.c',
 | 
				
			||||||
    'module-protocol-native/protocol-native.c',
 | 
					    'module-protocol-native/protocol-native.c',
 | 
				
			||||||
    'extension-protocol-native.c' ],
 | 
					    'module-protocol-native/connection.c' ],
 | 
				
			||||||
  c_args : pipewire_module_c_args,
 | 
					  c_args : pipewire_module_c_args,
 | 
				
			||||||
  include_directories : [configinc, spa_inc],
 | 
					  include_directories : [configinc, spa_inc],
 | 
				
			||||||
  link_with : spalib,
 | 
					  link_with : spalib,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,14 +37,13 @@ struct impl {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pw_node *create_node(struct pw_node_factory *factory,
 | 
					static struct pw_node *create_node(struct pw_node_factory *factory,
 | 
				
			||||||
				   struct pw_client *client,
 | 
									   struct pw_resource *resource,
 | 
				
			||||||
				   const char *name,
 | 
									   const char *name,
 | 
				
			||||||
				   struct pw_properties *properties,
 | 
									   struct pw_properties *properties)
 | 
				
			||||||
				   uint32_t new_id)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_client_node *node;
 | 
						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)
 | 
						if (node == NULL)
 | 
				
			||||||
		goto no_mem;
 | 
							goto no_mem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,8 +51,8 @@ static struct pw_node *create_node(struct pw_node_factory *factory,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      no_mem:
 | 
					      no_mem:
 | 
				
			||||||
	pw_log_error("can't create node");
 | 
						pw_log_error("can't create node");
 | 
				
			||||||
	pw_core_notify_error(client->core_resource,
 | 
						pw_core_notify_error(resource->client->core_resource,
 | 
				
			||||||
			     client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory");
 | 
								     resource->client->core_resource->id, SPA_RESULT_NO_MEMORY, "no memory");
 | 
				
			||||||
	return NULL;
 | 
						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.core = core;
 | 
				
			||||||
	impl->this.name = "client-node";
 | 
						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);
 | 
					        pw_signal_init(&impl->this.destroy_signal);
 | 
				
			||||||
	impl->this.create_node = create_node;
 | 
						impl->this.create_node = create_node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1132,41 +1132,33 @@ static void on_node_free(struct pw_listener *listener, struct pw_node *node)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \memberof pw_client_node
 | 
					 * \memberof pw_client_node
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct pw_client_node *pw_client_node_new(struct pw_client *client,
 | 
					struct pw_client_node *pw_client_node_new(struct pw_resource *resource,
 | 
				
			||||||
					  uint32_t id,
 | 
					 | 
				
			||||||
					  const char *name,
 | 
										  const char *name,
 | 
				
			||||||
					  struct pw_properties *properties)
 | 
										  struct pw_properties *properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	struct pw_client_node *this;
 | 
						struct pw_client_node *this;
 | 
				
			||||||
 | 
						struct pw_core *core = resource->client->core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = calloc(1, sizeof(struct impl));
 | 
						impl = calloc(1, sizeof(struct impl));
 | 
				
			||||||
	if (impl == NULL)
 | 
						if (impl == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	this->client = client;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->core = client->core;
 | 
						impl->core = core;
 | 
				
			||||||
	impl->fds[0] = impl->fds[1] = -1;
 | 
						impl->fds[0] = impl->fds[1] = -1;
 | 
				
			||||||
	pw_log_debug("client-node %p: new", impl);
 | 
						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);
 | 
						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;
 | 
						impl->proxy.impl = impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->resource = pw_resource_new(client,
 | 
						this->resource = resource;
 | 
				
			||||||
					 id,
 | 
						this->node = pw_spa_node_new(core,
 | 
				
			||||||
					 impl->type_client_node,
 | 
					 | 
				
			||||||
					 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (this->resource == NULL)
 | 
					 | 
				
			||||||
		goto error_no_resource;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->node = pw_spa_node_new(client->core,
 | 
					 | 
				
			||||||
				     this->resource,
 | 
									     this->resource,
 | 
				
			||||||
				     name,
 | 
									     name,
 | 
				
			||||||
				     true,
 | 
									     true,
 | 
				
			||||||
| 
						 | 
					@ -1192,7 +1184,6 @@ struct pw_client_node *pw_client_node_new(struct pw_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      error_no_node:
 | 
					      error_no_node:
 | 
				
			||||||
	pw_resource_destroy(this->resource);
 | 
						pw_resource_destroy(this->resource);
 | 
				
			||||||
      error_no_resource:
 | 
					 | 
				
			||||||
	proxy_clear(&impl->proxy);
 | 
						proxy_clear(&impl->proxy);
 | 
				
			||||||
	free(impl);
 | 
						free(impl);
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -34,15 +34,13 @@ extern "C" {
 | 
				
			||||||
struct pw_client_node {
 | 
					struct pw_client_node {
 | 
				
			||||||
	struct pw_node *node;
 | 
						struct pw_node *node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_client *client;
 | 
					 | 
				
			||||||
	struct pw_resource *resource;
 | 
						struct pw_resource *resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client_node *node));
 | 
						PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_client_node *node));
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_client_node *
 | 
					struct pw_client_node *
 | 
				
			||||||
pw_client_node_new(struct pw_client *client,
 | 
					pw_client_node_new(struct pw_resource *resource,
 | 
				
			||||||
		   uint32_t id,
 | 
					 | 
				
			||||||
		   const char *name,
 | 
							   const char *name,
 | 
				
			||||||
		   struct pw_properties *properties);
 | 
							   struct pw_properties *properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,93 +24,35 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire/client/interfaces.h"
 | 
					#include "pipewire/client/interfaces.h"
 | 
				
			||||||
#include "pipewire/client/protocol.h"
 | 
					#include "pipewire/client/protocol.h"
 | 
				
			||||||
#include "pipewire/client/connection.h"
 | 
					 | 
				
			||||||
#include "pipewire/server/client.h"
 | 
					#include "pipewire/server/client.h"
 | 
				
			||||||
#include "pipewire/extensions/client-node.h"
 | 
					#include "pipewire/extensions/client-node.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pipewire/modules/module-protocol-native/connection.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
struct builder {
 | 
					 | 
				
			||||||
	struct spa_pod_builder b;
 | 
					 | 
				
			||||||
	struct pw_connection *connection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
 | 
					typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					/** \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
 | 
					static void
 | 
				
			||||||
client_node_marshal_done(void *object, int seq, int res)
 | 
					client_node_marshal_done(void *object, int seq, int res)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DONE);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
						spa_pod_builder_struct(b, &f,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_pod_builder_struct(&b.b, &f,
 | 
					 | 
				
			||||||
			       SPA_POD_TYPE_INT, seq,
 | 
								       SPA_POD_TYPE_INT, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, res);
 | 
								       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
 | 
					static void
 | 
				
			||||||
client_node_marshal_update(void *object,
 | 
					client_node_marshal_update(void *object,
 | 
				
			||||||
			   uint32_t change_mask,
 | 
								   uint32_t change_mask,
 | 
				
			||||||
| 
						 | 
					@ -118,21 +60,18 @@ client_node_marshal_update(void *object,
 | 
				
			||||||
			   uint32_t max_output_ports, const struct spa_props *props)
 | 
								   uint32_t max_output_ports, const struct spa_props *props)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_UPDATE);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
						spa_pod_builder_struct(b, &f,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_pod_builder_struct(&b.b, &f,
 | 
					 | 
				
			||||||
			       SPA_POD_TYPE_INT, change_mask,
 | 
								       SPA_POD_TYPE_INT, change_mask,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, max_input_ports,
 | 
								       SPA_POD_TYPE_INT, max_input_ports,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, max_output_ports, SPA_POD_TYPE_POD, props);
 | 
								       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
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -147,78 +86,68 @@ client_node_marshal_port_update(void *object,
 | 
				
			||||||
				const struct spa_param **params, const struct spa_port_info *info)
 | 
									const struct spa_param **params, const struct spa_port_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f[2];
 | 
						struct spa_pod_frame f[2];
 | 
				
			||||||
	int i;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_PORT_UPDATE);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
						spa_pod_builder_add(b,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_pod_builder_add(&b.b,
 | 
					 | 
				
			||||||
			    SPA_POD_TYPE_STRUCT, &f[0],
 | 
								    SPA_POD_TYPE_STRUCT, &f[0],
 | 
				
			||||||
			    SPA_POD_TYPE_INT, direction,
 | 
								    SPA_POD_TYPE_INT, direction,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, port_id,
 | 
								    SPA_POD_TYPE_INT, port_id,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, change_mask, SPA_POD_TYPE_INT, n_possible_formats, 0);
 | 
								    SPA_POD_TYPE_INT, change_mask, SPA_POD_TYPE_INT, n_possible_formats, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_possible_formats; i++)
 | 
						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++) {
 | 
						for (i = 0; i < n_params; i++) {
 | 
				
			||||||
		const struct spa_param *p = 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) {
 | 
						if (info) {
 | 
				
			||||||
		spa_pod_builder_add(&b.b,
 | 
							spa_pod_builder_add(b,
 | 
				
			||||||
				    SPA_POD_TYPE_STRUCT, &f[1],
 | 
									    SPA_POD_TYPE_STRUCT, &f[1],
 | 
				
			||||||
				    SPA_POD_TYPE_INT, info->flags, SPA_POD_TYPE_INT, info->rate, 0);
 | 
									    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 {
 | 
						} 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,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_node_marshal_event_method(void *object, struct spa_event *event)
 | 
					static void client_node_marshal_event_method(void *object, struct spa_event *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_EVENT);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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, b);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_EVENT, b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_node_marshal_destroy(void *object)
 | 
					static void client_node_marshal_destroy(void *object)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CLIENT_NODE_METHOD_DESTROY);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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, b);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_connection_end_write(connection, proxy->id, PW_CLIENT_NODE_METHOD_DESTROY, b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool client_node_demarshal_set_props(void *object, void *data, size_t size)
 | 
					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;
 | 
						const struct spa_event *event;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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))
 | 
						    !spa_pod_iter_get(&it, SPA_POD_TYPE_OBJECT, &event, 0))
 | 
				
			||||||
		return false;
 | 
							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;
 | 
						const struct spa_format *format = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &seq,
 | 
								      SPA_POD_TYPE_INT, &seq,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &direction,
 | 
								      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;
 | 
						const struct spa_param *param = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &seq,
 | 
								      SPA_POD_TYPE_INT, &seq,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &direction,
 | 
								      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 pw_proxy *proxy = object;
 | 
				
			||||||
	struct spa_pod_iter it;
 | 
						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;
 | 
						uint32_t direction, port_id, mem_id, type, memfd_idx, flags, offset, sz;
 | 
				
			||||||
	int memfd;
 | 
						int memfd;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &direction,
 | 
								      SPA_POD_TYPE_INT, &direction,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &port_id,
 | 
								      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;
 | 
						int i, j;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &seq,
 | 
								      SPA_POD_TYPE_INT, &seq,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &direction,
 | 
								      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;
 | 
						uint32_t seq;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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))
 | 
						    !spa_pod_iter_get(&it, SPA_POD_TYPE_INT, &seq, SPA_POD_TYPE_OBJECT, &command, 0))
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -449,7 +378,7 @@ static bool client_node_demarshal_port_command(void *object, void *data, size_t
 | 
				
			||||||
	uint32_t direction, port_id;
 | 
						uint32_t direction, port_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &direction,
 | 
								      SPA_POD_TYPE_INT, &direction,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &port_id,
 | 
								      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 pw_proxy *proxy = object;
 | 
				
			||||||
	struct spa_pod_iter it;
 | 
						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;
 | 
						uint32_t node_id, ridx, widx, memfd_idx, offset, sz;
 | 
				
			||||||
	int readfd, writefd, memfd;
 | 
						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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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_INT, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_POD, props);
 | 
								       SPA_POD_TYPE_POD, props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PROPS,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_node_marshal_event_event(void *object, const struct spa_event *event)
 | 
					static void client_node_marshal_event_event(void *object, const struct spa_event *event)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -531,17 +459,16 @@ client_node_marshal_add_port(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
 | 
								       SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_ADD_PORT,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -550,17 +477,16 @@ client_node_marshal_remove_port(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
 | 
								       SPA_POD_TYPE_INT, direction, SPA_POD_TYPE_INT, port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_REMOVE_PORT,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -573,20 +499,19 @@ client_node_marshal_set_format(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, direction,
 | 
								       SPA_POD_TYPE_INT, direction,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, port_id,
 | 
								       SPA_POD_TYPE_INT, port_id,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, flags,
 | 
								       SPA_POD_TYPE_INT, flags,
 | 
				
			||||||
			       SPA_POD_TYPE_POD, format);
 | 
								       SPA_POD_TYPE_POD, format);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_FORMAT,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -598,19 +523,18 @@ client_node_marshal_set_param(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, seq,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, direction,
 | 
								       SPA_POD_TYPE_INT, direction,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, port_id,
 | 
								       SPA_POD_TYPE_INT, port_id,
 | 
				
			||||||
			       SPA_POD_TYPE_POD, param);
 | 
								       SPA_POD_TYPE_POD, param);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_SET_PARAM,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -623,12 +547,12 @@ client_node_marshal_add_mem(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, direction,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, port_id,
 | 
								       SPA_POD_TYPE_INT, port_id,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, mem_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, flags,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size);
 | 
								       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
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -649,13 +573,13 @@ client_node_marshal_use_buffers(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, j;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, seq,
 | 
								    SPA_POD_TYPE_INT, seq,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, direction,
 | 
								    SPA_POD_TYPE_INT, direction,
 | 
				
			||||||
| 
						 | 
					@ -664,7 +588,7 @@ client_node_marshal_use_buffers(void *object,
 | 
				
			||||||
	for (i = 0; i < n_buffers; i++) {
 | 
						for (i = 0; i < n_buffers; i++) {
 | 
				
			||||||
		struct spa_buffer *buf = buffers[i].buffer;
 | 
							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].mem_id,
 | 
				
			||||||
				    SPA_POD_TYPE_INT, buffers[i].offset,
 | 
									    SPA_POD_TYPE_INT, buffers[i].offset,
 | 
				
			||||||
				    SPA_POD_TYPE_INT, buffers[i].size,
 | 
									    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++) {
 | 
							for (j = 0; j < buf->n_metas; j++) {
 | 
				
			||||||
			struct spa_meta *m = &buf->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_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++) {
 | 
							for (j = 0; j < buf->n_datas; j++) {
 | 
				
			||||||
			struct spa_data *d = &buf->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_ID, d->type,
 | 
				
			||||||
					    SPA_POD_TYPE_INT, SPA_PTR_TO_UINT32(d->data),
 | 
										    SPA_POD_TYPE_INT, SPA_PTR_TO_UINT32(d->data),
 | 
				
			||||||
					    SPA_POD_TYPE_INT, d->flags,
 | 
										    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_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,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -716,18 +638,17 @@ client_node_marshal_port_command(void *object,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, direction,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, port_id,
 | 
								       SPA_POD_TYPE_INT, port_id,
 | 
				
			||||||
			       SPA_POD_TYPE_POD, command);
 | 
								       SPA_POD_TYPE_POD, command);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_PORT_COMMAND,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void client_node_marshal_transport(void *object, uint32_t node_id, int readfd, int writefd,
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, node_id,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, pw_connection_add_fd(connection, readfd),
 | 
								       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, writefd),
 | 
				
			||||||
			       SPA_POD_TYPE_INT, pw_connection_add_fd(connection, memfd),
 | 
								       SPA_POD_TYPE_INT, pw_connection_add_fd(connection, memfd),
 | 
				
			||||||
			       SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size);
 | 
								       SPA_POD_TYPE_INT, offset, SPA_POD_TYPE_INT, size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_end_write(connection, resource->id, PW_CLIENT_NODE_EVENT_TRANSPORT,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -484,14 +484,14 @@ static void dispatch_cb(struct spa_loop_utils *utils, struct spa_source *source,
 | 
				
			||||||
	struct impl *impl = userdata;
 | 
						struct impl *impl = userdata;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (dbus_connection_dispatch(impl->bus) == DBUS_DISPATCH_COMPLETE)
 | 
						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)
 | 
					static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *userdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = 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);
 | 
								    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
 | 
						/* we dup because dbus tends to add the same fd multiple times and our epoll
 | 
				
			||||||
	 * implementation does not like that */
 | 
						 * 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)),
 | 
									dup(dbus_watch_get_unix_fd(watch)),
 | 
				
			||||||
				dbus_to_io(watch), true, handle_io_event, 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;
 | 
						struct spa_source *source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((source = dbus_watch_get_data(watch)))
 | 
						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)
 | 
					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);
 | 
						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
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -606,14 +606,14 @@ static dbus_bool_t add_timeout(DBusTimeout *timeout, void *userdata)
 | 
				
			||||||
	if (!dbus_timeout_get_enabled(timeout))
 | 
						if (!dbus_timeout_get_enabled(timeout))
 | 
				
			||||||
		return FALSE;
 | 
							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);
 | 
						dbus_timeout_set_data(timeout, source, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
 | 
						t = dbus_timeout_get_interval(timeout) * SPA_NSEC_PER_MSEC;
 | 
				
			||||||
	ts.tv_sec = t / SPA_NSEC_PER_SEC;
 | 
						ts.tv_sec = t / SPA_NSEC_PER_SEC;
 | 
				
			||||||
	ts.tv_nsec = 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;
 | 
						return TRUE;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -623,7 +623,7 @@ static void remove_timeout(DBusTimeout *timeout, void *userdata)
 | 
				
			||||||
	struct spa_source *source;
 | 
						struct spa_source *source;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((source = dbus_timeout_get_data(timeout)))
 | 
						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)
 | 
					static void toggle_timeout(DBusTimeout *timeout, void *userdata)
 | 
				
			||||||
| 
						 | 
					@ -642,14 +642,14 @@ static void toggle_timeout(DBusTimeout *timeout, void *userdata)
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		tsp = NULL;
 | 
							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)
 | 
					static void wakeup_main(void *userdata)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl = 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)
 | 
					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)
 | 
						if (impl->bus == NULL)
 | 
				
			||||||
		goto error;
 | 
							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_exit_on_disconnect(impl->bus, false);
 | 
				
			||||||
	dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL);
 | 
						dbus_connection_set_dispatch_status_function(impl->bus, dispatch_status, impl, NULL);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,7 +106,7 @@ static void client_destroy(void *data)
 | 
				
			||||||
	struct pw_client *client = data;
 | 
						struct pw_client *client = data;
 | 
				
			||||||
	struct client *this = client->user_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);
 | 
						spa_list_remove(&this->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	close(this->fd);
 | 
						close(this->fd);
 | 
				
			||||||
| 
						 | 
					@ -407,7 +407,7 @@ on_busy_changed(struct pw_listener *listener,
 | 
				
			||||||
	if (!client->busy)
 | 
						if (!client->busy)
 | 
				
			||||||
		mask |= SPA_IO_IN;
 | 
							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)
 | 
						if (!client->busy)
 | 
				
			||||||
		process_messages(c);
 | 
							process_messages(c);
 | 
				
			||||||
| 
						 | 
					@ -453,7 +453,7 @@ static struct client *client_new(struct impl *impl, int fd)
 | 
				
			||||||
	this = client->user_data;
 | 
						this = client->user_data;
 | 
				
			||||||
	this->impl = impl;
 | 
						this->impl = impl;
 | 
				
			||||||
	this->fd = fd;
 | 
						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,
 | 
									      this->fd,
 | 
				
			||||||
				      SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
 | 
									      SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
 | 
				
			||||||
	if (this->source == NULL)
 | 
						if (this->source == NULL)
 | 
				
			||||||
| 
						 | 
					@ -622,7 +622,7 @@ socket_data(struct spa_loop_utils *utils,
 | 
				
			||||||
		return;
 | 
							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);
 | 
								  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;
 | 
							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);
 | 
						s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl);
 | 
				
			||||||
	if (s->source == NULL)
 | 
						if (s->source == NULL)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -29,6 +29,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "config.h"
 | 
					#include "config.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pipewire/client/connection.h"
 | 
				
			||||||
#include "pipewire/client/pipewire.h"
 | 
					#include "pipewire/client/pipewire.h"
 | 
				
			||||||
#include "pipewire/client/log.h"
 | 
					#include "pipewire/client/log.h"
 | 
				
			||||||
#include "pipewire/client/interfaces.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);
 | 
					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;
 | 
				
			||||||
	int fd_lock;
 | 
						int fd_lock;
 | 
				
			||||||
	struct sockaddr_un addr;
 | 
						struct sockaddr_un addr;
 | 
				
			||||||
| 
						 | 
					@ -62,8 +78,6 @@ struct socket {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_loop *loop;
 | 
						struct pw_loop *loop;
 | 
				
			||||||
	struct spa_source *source;
 | 
						struct spa_source *source;
 | 
				
			||||||
	char *core_name;
 | 
					 | 
				
			||||||
	struct spa_list link;
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct impl {
 | 
					struct impl {
 | 
				
			||||||
| 
						 | 
					@ -73,7 +87,6 @@ struct impl {
 | 
				
			||||||
	struct pw_protocol *protocol;
 | 
						struct pw_protocol *protocol;
 | 
				
			||||||
	struct pw_properties *properties;
 | 
						struct pw_properties *properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_list socket_list;
 | 
					 | 
				
			||||||
	struct spa_list client_list;
 | 
						struct spa_list client_list;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_loop_control_hooks hooks;
 | 
						struct spa_loop_control_hooks hooks;
 | 
				
			||||||
| 
						 | 
					@ -94,7 +107,7 @@ static void client_destroy(void *data)
 | 
				
			||||||
	struct pw_client *client = data;
 | 
						struct pw_client *client = data;
 | 
				
			||||||
	struct native_client *this = client->user_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);
 | 
						spa_list_remove(&this->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_connection_destroy(this->connection);
 | 
						pw_connection_destroy(this->connection);
 | 
				
			||||||
| 
						 | 
					@ -153,7 +166,7 @@ on_busy_changed(struct pw_listener *listener,
 | 
				
			||||||
	if (!client->busy)
 | 
						if (!client->busy)
 | 
				
			||||||
		mask |= SPA_IO_IN;
 | 
							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)
 | 
						if (!client->busy)
 | 
				
			||||||
		process_messages(c);
 | 
							process_messages(c);
 | 
				
			||||||
| 
						 | 
					@ -209,7 +222,7 @@ static struct native_client *client_new(struct impl *impl, int fd)
 | 
				
			||||||
	this = client->user_data;
 | 
						this = client->user_data;
 | 
				
			||||||
	this->impl = impl;
 | 
						this->impl = impl;
 | 
				
			||||||
	this->fd = fd;
 | 
						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,
 | 
									      this->fd,
 | 
				
			||||||
				      SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
 | 
									      SPA_IO_ERR | SPA_IO_HUP, false, connection_data, this);
 | 
				
			||||||
	if (this->source == NULL)
 | 
						if (this->source == NULL)
 | 
				
			||||||
| 
						 | 
					@ -233,41 +246,29 @@ static struct native_client *client_new(struct impl *impl, int fd)
 | 
				
			||||||
	return this;
 | 
						return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      no_connection:
 | 
					      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:
 | 
					      no_source:
 | 
				
			||||||
	free(this);
 | 
						free(this);
 | 
				
			||||||
      no_client:
 | 
					      no_client:
 | 
				
			||||||
	return NULL;
 | 
						return NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct socket *create_socket(void)
 | 
					static void destroy_listener(struct listener *l)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct socket *s;
 | 
						if (l->source)
 | 
				
			||||||
 | 
							pw_loop_destroy_source(l->loop, l->source);
 | 
				
			||||||
	if ((s = calloc(1, sizeof(struct socket))) == NULL)
 | 
						if (l->addr.sun_path[0])
 | 
				
			||||||
		return NULL;
 | 
							unlink(l->addr.sun_path);
 | 
				
			||||||
 | 
						if (l->fd >= 0)
 | 
				
			||||||
	s->fd = -1;
 | 
							close(l->fd);
 | 
				
			||||||
	s->fd_lock = -1;
 | 
						if (l->lock_addr[0])
 | 
				
			||||||
	return s;
 | 
							unlink(l->lock_addr);
 | 
				
			||||||
 | 
						if (l->fd_lock >= 0)
 | 
				
			||||||
 | 
							close(l->fd_lock);
 | 
				
			||||||
 | 
						free(l);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void destroy_socket(struct socket *s)
 | 
					static bool init_socket_name(struct listener *l, const char *name)
 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int name_size;
 | 
						int name_size;
 | 
				
			||||||
	const char *runtime_dir;
 | 
						const char *runtime_dir;
 | 
				
			||||||
| 
						 | 
					@ -277,57 +278,55 @@ static bool init_socket_name(struct socket *s, const char *name)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->addr.sun_family = AF_LOCAL;
 | 
						l->addr.sun_family = AF_LOCAL;
 | 
				
			||||||
	name_size = snprintf(s->addr.sun_path, sizeof(s->addr.sun_path),
 | 
						name_size = snprintf(l->addr.sun_path, sizeof(l->addr.sun_path),
 | 
				
			||||||
			     "%s/%s", runtime_dir, name) + 1;
 | 
								     "%s/%s", runtime_dir, name) + 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->core_name = (s->addr.sun_path + name_size - 1) - strlen(name);
 | 
						if (name_size > (int) sizeof(l->addr.sun_path)) {
 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (name_size > (int) sizeof(s->addr.sun_path)) {
 | 
					 | 
				
			||||||
		pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
 | 
							pw_log_error("socket path \"%s/%s\" plus null terminator exceeds 108 bytes",
 | 
				
			||||||
			     runtime_dir, name);
 | 
								     runtime_dir, name);
 | 
				
			||||||
		*s->addr.sun_path = 0;
 | 
							*l->addr.sun_path = 0;
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool lock_socket(struct socket *s)
 | 
					static bool lock_socket(struct listener *l)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct stat socket_stat;
 | 
						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));
 | 
								  (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (s->fd_lock < 0) {
 | 
						if (l->fd_lock < 0) {
 | 
				
			||||||
		pw_log_error("unable to open lockfile %s check permissions", s->lock_addr);
 | 
							pw_log_error("unable to open lockfile %s check permissions", l->lock_addr);
 | 
				
			||||||
		goto err;
 | 
							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",
 | 
							pw_log_error("unable to lock lockfile %s, maybe another daemon is running",
 | 
				
			||||||
			     s->lock_addr);
 | 
								     l->lock_addr);
 | 
				
			||||||
		goto err_fd;
 | 
							goto err_fd;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (stat(s->addr.sun_path, &socket_stat) < 0) {
 | 
						if (stat(l->addr.sun_path, &socket_stat) < 0) {
 | 
				
			||||||
		if (errno != ENOENT) {
 | 
							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;
 | 
								goto err_fd;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	} else if (socket_stat.st_mode & S_IWUSR || socket_stat.st_mode & S_IWGRP) {
 | 
						} 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;
 | 
						return true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      err_fd:
 | 
					      err_fd:
 | 
				
			||||||
	close(s->fd_lock);
 | 
						close(l->fd_lock);
 | 
				
			||||||
	s->fd_lock = -1;
 | 
						l->fd_lock = -1;
 | 
				
			||||||
      err:
 | 
					      err:
 | 
				
			||||||
	*s->lock_addr = 0;
 | 
						*l->lock_addr = 0;
 | 
				
			||||||
	*s->addr.sun_path = 0;
 | 
						*l->addr.sun_path = 0;
 | 
				
			||||||
	return false;
 | 
						return false;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -355,83 +354,309 @@ socket_data(struct spa_loop_utils *utils,
 | 
				
			||||||
		return;
 | 
							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);
 | 
								  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;
 | 
						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;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size = offsetof(struct sockaddr_un, sun_path) +strlen(s->addr.sun_path);
 | 
						size = offsetof(struct sockaddr_un, sun_path) + strlen(l->addr.sun_path);
 | 
				
			||||||
	if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
 | 
						if (bind(l->fd, (struct sockaddr *) &l->addr, size) < 0) {
 | 
				
			||||||
		pw_log_error("bind() failed with error: %m");
 | 
							pw_log_error("bind() failed with error: %m");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (listen(s->fd, 128) < 0) {
 | 
						if (listen(l->fd, 128) < 0) {
 | 
				
			||||||
		pw_log_error("listen() failed with error: %m");
 | 
							pw_log_error("listen() failed with error: %m");
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	s->loop = impl->core->main_loop->loop;
 | 
						l->loop = impl->core->main_loop;
 | 
				
			||||||
	s->source = pw_loop_add_io(s->loop, s->fd, SPA_IO_IN, false, socket_data, impl);
 | 
						l->source = pw_loop_add_io(l->loop, l->fd, SPA_IO_IN, false, socket_data, impl);
 | 
				
			||||||
	if (s->source == NULL)
 | 
						if (l->source == NULL)
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_list_insert(impl->socket_list.prev, &s->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return true;
 | 
						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)
 | 
					static struct impl *pw_protocol_native_new(struct pw_core *core, struct pw_properties *properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	struct socket *s;
 | 
					 | 
				
			||||||
	const char *name;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = calloc(1, sizeof(struct impl));
 | 
						impl = calloc(1, sizeof(struct impl));
 | 
				
			||||||
	pw_log_debug("protocol-native %p: new", impl);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->core = core;
 | 
						impl->core = core;
 | 
				
			||||||
	impl->properties = properties;
 | 
						impl->properties = properties;
 | 
				
			||||||
	impl->protocol = pw_protocol_native_init();
 | 
						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);
 | 
						spa_list_init(&impl->client_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!init_socket_name(s, name))
 | 
						impl_add_listener(impl->protocol, core, properties);
 | 
				
			||||||
		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);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return impl;
 | 
						return impl;
 | 
				
			||||||
 | 
					 | 
				
			||||||
      error:
 | 
					 | 
				
			||||||
	destroy_socket(s);
 | 
					 | 
				
			||||||
	free(impl);
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if 0
 | 
					#if 0
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,9 +27,8 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <spa/lib/debug.h>
 | 
					#include <spa/lib/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire.h"
 | 
					#include <pipewire/client/pipewire.h>
 | 
				
			||||||
#include "connection.h"
 | 
					#include "connection.h"
 | 
				
			||||||
#include "log.h"
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,10 +51,14 @@ struct buffer {
 | 
				
			||||||
	bool update;
 | 
						bool update;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_connection_impl {
 | 
					struct impl {
 | 
				
			||||||
	struct pw_connection this;
 | 
						struct pw_connection this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct buffer in, out;
 | 
						struct buffer in, out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						uint32_t dest_id;
 | 
				
			||||||
 | 
						uint8_t opcode;
 | 
				
			||||||
 | 
						struct spa_pod_builder builder;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					/** \endcond */
 | 
				
			||||||
| 
						 | 
					@ -70,7 +73,7 @@ struct pw_connection_impl {
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int pw_connection_get_fd(struct pw_connection *conn, uint32_t index)
 | 
					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)
 | 
						if (index < 0 || index >= impl->in.n_fds)
 | 
				
			||||||
		return -1;
 | 
							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)
 | 
					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;
 | 
						uint32_t index, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < impl->out.n_fds; 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 *pw_connection_new(int fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_connection_impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	struct pw_connection *this;
 | 
						struct pw_connection *this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = calloc(1, sizeof(struct pw_connection_impl));
 | 
						impl = calloc(1, sizeof(struct impl));
 | 
				
			||||||
	if (impl == NULL)
 | 
						if (impl == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -229,7 +232,7 @@ struct pw_connection *pw_connection_new(int fd)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
void pw_connection_destroy(struct pw_connection *conn)
 | 
					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);
 | 
						pw_log_debug("connection %p: destroy", conn);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,7 +264,7 @@ pw_connection_get_next(struct pw_connection *conn,
 | 
				
			||||||
		       void **dt,
 | 
							       void **dt,
 | 
				
			||||||
		       uint32_t *sz)
 | 
							       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;
 | 
						size_t len, size;
 | 
				
			||||||
	uint8_t *data;
 | 
						uint8_t *data;
 | 
				
			||||||
	struct buffer *buf;
 | 
						struct buffer *buf;
 | 
				
			||||||
| 
						 | 
					@ -326,20 +329,9 @@ pw_connection_get_next(struct pw_connection *conn,
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Start writing \a size bytes
 | 
					static inline void *begin_write(struct pw_connection *conn, uint32_t size)
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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;
 | 
						uint32_t *p;
 | 
				
			||||||
	struct buffer *buf = &impl->out;
 | 
						struct buffer *buf = &impl->out;
 | 
				
			||||||
	/* 4 for dest_id, 1 for opcode, 3 for size and size for payload */
 | 
						/* 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;
 | 
						return p + 2;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** End writing to the connection
 | 
					static uint32_t write_pod(struct spa_pod_builder *b, uint32_t ref, const void *data, uint32_t size)
 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \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)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_connection_impl *impl = SPA_CONTAINER_OF(conn, struct pw_connection_impl, this);
 | 
						struct impl *impl = SPA_CONTAINER_OF(b, struct impl, builder);
 | 
				
			||||||
	uint32_t *p;
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
						struct buffer *buf = &impl->out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p = connection_ensure_size(conn, buf, 8 + size);
 | 
						p = connection_ensure_size(conn, buf, 8 + size);
 | 
				
			||||||
	*p++ = dest_id;
 | 
						*p++ = impl->dest_id;
 | 
				
			||||||
	*p++ = (opcode << 24) | (size & 0xffffff);
 | 
						*p++ = (impl->opcode << 24) | (size & 0xffffff);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	buf->buffer_size += 8 + size;
 | 
						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)
 | 
					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;
 | 
						ssize_t len;
 | 
				
			||||||
	struct msghdr msg = { 0 };
 | 
						struct msghdr msg = { 0 };
 | 
				
			||||||
	struct iovec iov[1];
 | 
						struct iovec iov[1];
 | 
				
			||||||
| 
						 | 
					@ -463,7 +518,7 @@ bool pw_connection_flush(struct pw_connection *conn)
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
bool pw_connection_clear(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->out);
 | 
				
			||||||
	clear_buffer(&impl->in);
 | 
						clear_buffer(&impl->in);
 | 
				
			||||||
| 
						 | 
					@ -61,12 +61,20 @@ pw_connection_get_next(struct pw_connection *conn,
 | 
				
			||||||
		       uint32_t *dest_id,
 | 
							       uint32_t *dest_id,
 | 
				
			||||||
		       void **data, uint32_t *size);
 | 
							       void **data, uint32_t *size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void *
 | 
					struct spa_pod_builder *
 | 
				
			||||||
pw_connection_begin_write(struct pw_connection *conn, uint32_t size);
 | 
					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
 | 
					void
 | 
				
			||||||
pw_connection_end_write(struct pw_connection *conn,
 | 
					pw_connection_end_write(struct pw_connection *conn,
 | 
				
			||||||
			uint32_t dest_id, uint8_t opcode, uint32_t size);
 | 
								struct spa_pod_builder *builder);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool
 | 
					bool
 | 
				
			||||||
pw_connection_flush(struct pw_connection *conn);
 | 
					pw_connection_flush(struct pw_connection *conn);
 | 
				
			||||||
| 
						 | 
					@ -24,129 +24,66 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire/client/protocol.h"
 | 
					#include "pipewire/client/protocol.h"
 | 
				
			||||||
#include "pipewire/client/interfaces.h"
 | 
					#include "pipewire/client/interfaces.h"
 | 
				
			||||||
#include "pipewire/client/connection.h"
 | 
					 | 
				
			||||||
#include "pipewire/server/resource.h"
 | 
					#include "pipewire/server/resource.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "connection.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
struct builder {
 | 
					 | 
				
			||||||
	struct spa_pod_builder b;
 | 
					 | 
				
			||||||
	struct pw_connection *connection;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
 | 
					typedef bool(*demarshal_func_t) (void *object, void *data, size_t size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					/** \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)
 | 
					static void core_marshal_client_update(void *object, const struct spa_dict *props)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	int i, n_items;
 | 
						int i, n_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CLIENT_UPDATE);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n_items = props ? props->n_items : 0;
 | 
						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++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, props->items[i].value, 0);
 | 
									    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)
 | 
					static void core_marshal_sync(void *object, uint32_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_SYNC);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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, b);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_SYNC, b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void core_marshal_get_registry(void *object, uint32_t new_id)
 | 
					static void core_marshal_get_registry(void *object, uint32_t new_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_GET_REGISTRY);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	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, b);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_connection_end_write(connection, proxy->id, PW_CORE_METHOD_GET_REGISTRY, b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -155,31 +92,28 @@ core_marshal_create_node(void *object,
 | 
				
			||||||
			 const char *name, const struct spa_dict *props, uint32_t new_id)
 | 
								 const char *name, const struct spa_dict *props, uint32_t new_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						uint32_t i, n_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_NODE);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n_items = props ? props->n_items : 0;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_STRING, factory_name,
 | 
								    SPA_POD_TYPE_STRING, factory_name,
 | 
				
			||||||
			    SPA_POD_TYPE_STRING, name, SPA_POD_TYPE_INT, n_items, 0);
 | 
								    SPA_POD_TYPE_STRING, name, SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, props->items[i].value, 0);
 | 
									    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
 | 
					static void
 | 
				
			||||||
| 
						 | 
					@ -193,19 +127,16 @@ core_marshal_create_link(void *object,
 | 
				
			||||||
			 uint32_t new_id)
 | 
								 uint32_t new_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						uint32_t i, n_items;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_CREATE_LINK);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	n_items = props ? props->n_items : 0;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, output_node_id,
 | 
								    SPA_POD_TYPE_INT, output_node_id,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, output_port_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);
 | 
								    SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, props->items[i].value, 0);
 | 
									    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_INT, new_id,
 | 
				
			||||||
			    -SPA_POD_TYPE_STRUCT, &f, 0);
 | 
								    -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
 | 
					static void
 | 
				
			||||||
core_marshal_update_types_client(void *object, uint32_t first_id, uint32_t n_types, const char **types)
 | 
					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_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i;
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_CORE_METHOD_UPDATE_TYPES);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_pod_builder_add(&b.b,
 | 
						spa_pod_builder_add(b,
 | 
				
			||||||
			    SPA_POD_TYPE_STRUCT, &f,
 | 
								    SPA_POD_TYPE_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
 | 
								    SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_types; i++) {
 | 
						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)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						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;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->id,
 | 
								    SPA_POD_TYPE_INT, info->id,
 | 
				
			||||||
			    SPA_POD_TYPE_LONG, info->change_mask,
 | 
								    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);
 | 
								    SPA_POD_TYPE_INT, info->cookie, SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
 | 
									    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)
 | 
					static void core_marshal_done(void *object, uint32_t seq)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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, ...)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						struct pw_connection *connection = resource->client->protocol_private;
 | 
				
			||||||
	char buffer[128];
 | 
						char buffer[128];
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	va_list ap;
 | 
						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);
 | 
						va_start(ap, error);
 | 
				
			||||||
	vsnprintf(buffer, sizeof(buffer), error, ap);
 | 
						vsnprintf(buffer, sizeof(buffer), error, ap);
 | 
				
			||||||
	va_end(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, id,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, res, SPA_POD_TYPE_STRING, buffer);
 | 
								       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)
 | 
					static void core_marshal_remove_id(void *object, uint32_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
 | 
								    SPA_POD_TYPE_INT, first_id, SPA_POD_TYPE_INT, n_types, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_types; i++) {
 | 
						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)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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_INT, id,
 | 
				
			||||||
			       SPA_POD_TYPE_STRING, type,
 | 
								       SPA_POD_TYPE_STRING, type,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, version);
 | 
								       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)
 | 
					static void registry_marshal_global_remove(void *object, uint32_t id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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,
 | 
						pw_connection_end_write(connection, b);
 | 
				
			||||||
				b.b.offset);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool registry_demarshal_bind(void *object, void *data, size_t size)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						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;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->id,
 | 
								    SPA_POD_TYPE_INT, info->id,
 | 
				
			||||||
			    SPA_POD_TYPE_LONG, info->change_mask,
 | 
								    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);
 | 
								    SPA_POD_TYPE_STRING, info->args, SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
 | 
									    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)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->id,
 | 
								    SPA_POD_TYPE_INT, info->id,
 | 
				
			||||||
			    SPA_POD_TYPE_LONG, info->change_mask,
 | 
								    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);
 | 
								    SPA_POD_TYPE_INT, info->n_input_formats, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < info->n_input_formats; i++)
 | 
						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->max_output_ports,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->n_output_ports,
 | 
								    SPA_POD_TYPE_INT, info->n_output_ports,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->n_output_formats, 0);
 | 
								    SPA_POD_TYPE_INT, info->n_output_formats, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < info->n_output_formats; i++)
 | 
						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;
 | 
						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_INT, info->state,
 | 
				
			||||||
			    SPA_POD_TYPE_STRING, info->error, SPA_POD_TYPE_INT, n_items, 0);
 | 
								    SPA_POD_TYPE_STRING, info->error, SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
 | 
									    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)
 | 
					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;
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &info.id,
 | 
								      SPA_POD_TYPE_INT, &info.id,
 | 
				
			||||||
			      SPA_POD_TYPE_LONG, &info.change_mask,
 | 
								      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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
	uint32_t i, n_items;
 | 
						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;
 | 
						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_STRUCT, &f,
 | 
				
			||||||
			    SPA_POD_TYPE_INT, info->id,
 | 
								    SPA_POD_TYPE_INT, info->id,
 | 
				
			||||||
			    SPA_POD_TYPE_LONG, info->change_mask, SPA_POD_TYPE_INT, n_items, 0);
 | 
								    SPA_POD_TYPE_LONG, info->change_mask, SPA_POD_TYPE_INT, n_items, 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < n_items; i++) {
 | 
						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].key,
 | 
				
			||||||
				    SPA_POD_TYPE_STRING, info->props->items[i].value, 0);
 | 
									    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)
 | 
					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_resource *resource = object;
 | 
				
			||||||
	struct pw_connection *connection = resource->client->protocol_private;
 | 
						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;
 | 
						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_INT, info->id,
 | 
				
			||||||
			       SPA_POD_TYPE_LONG, info->change_mask,
 | 
								       SPA_POD_TYPE_LONG, info->change_mask,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, info->output_node_id,
 | 
								       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_INT, info->input_port_id,
 | 
				
			||||||
			       SPA_POD_TYPE_POD, info->format);
 | 
								       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)
 | 
					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, };
 | 
						struct pw_link_info info = { 0, };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!spa_pod_iter_struct(&it, data, size) ||
 | 
						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_iter_get(&it,
 | 
				
			||||||
			      SPA_POD_TYPE_INT, &info.id,
 | 
								      SPA_POD_TYPE_INT, &info.id,
 | 
				
			||||||
			      SPA_POD_TYPE_LONG, &info.change_mask,
 | 
								      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)
 | 
					static void registry_marshal_bind(void *object, uint32_t id, uint32_t version, uint32_t new_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_proxy *proxy = object;
 | 
						struct pw_proxy *proxy = object;
 | 
				
			||||||
	struct pw_connection *connection = proxy->context->protocol_private;
 | 
						struct pw_connection *connection = proxy->remote->protocol_private;
 | 
				
			||||||
	struct builder b = { {NULL, 0, 0, NULL, write_pod}, connection };
 | 
						struct spa_pod_builder *b;
 | 
				
			||||||
	struct spa_pod_frame f;
 | 
						struct spa_pod_frame f;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (connection == NULL)
 | 
						b = pw_connection_begin_write_proxy(connection, proxy, PW_REGISTRY_METHOD_BIND);
 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	core_update_map_client(proxy->context);
 | 
						spa_pod_builder_struct(b, &f,
 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_pod_builder_struct(&b.b, &f,
 | 
					 | 
				
			||||||
			       SPA_POD_TYPE_INT, id,
 | 
								       SPA_POD_TYPE_INT, id,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, version,
 | 
								       SPA_POD_TYPE_INT, version,
 | 
				
			||||||
			       SPA_POD_TYPE_INT, new_id);
 | 
								       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 = {
 | 
					static const struct pw_core_methods pw_protocol_native_client_core_methods = {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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)
 | 
					static void remove_idle_timeout(struct node_info *info)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (info->idle_timeout) {
 | 
						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;
 | 
							info->idle_timeout = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -102,11 +102,11 @@ on_node_state_changed(struct pw_listener *listener,
 | 
				
			||||||
		struct timespec value;
 | 
							struct timespec value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		pw_log_debug("module %p: node %p became idle", impl, node);
 | 
							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);
 | 
											       idle_timeout, info);
 | 
				
			||||||
		value.tv_sec = 3;
 | 
							value.tv_sec = 3;
 | 
				
			||||||
		value.tv_nsec = 0;
 | 
							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);
 | 
									     info->idle_timeout, &value, NULL, false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,3 +22,13 @@ pipewire_module_spa_node = shared_library('pipewire-module-spa-node',
 | 
				
			||||||
  install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')),
 | 
					  install_dir : '@0@/pipewire-0.1'.format(get_option('libdir')),
 | 
				
			||||||
  dependencies : [mathlib, dl_lib, pipewire_dep, pipewirecore_dep],
 | 
					  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],
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										117
									
								
								pipewire/modules/spa/module-node-factory.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								pipewire/modules/spa/module-node-factory.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,117 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 * Copyright (C) 2017 Wim Taymans <wim.taymans@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <string.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <dlfcn.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -270,12 +270,26 @@ node_impl_add_port(struct pw_node *node,
 | 
				
			||||||
	return make_port(node, direction, port_id);
 | 
						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 = {
 | 
					static const struct pw_node_implementation node_impl = {
 | 
				
			||||||
	PW_VERSION_NODE_IMPLEMENTATION,
 | 
						PW_VERSION_NODE_IMPLEMENTATION,
 | 
				
			||||||
	node_impl_get_props,
 | 
						node_impl_get_props,
 | 
				
			||||||
	node_impl_set_props,
 | 
						node_impl_set_props,
 | 
				
			||||||
	node_impl_send_command,
 | 
						node_impl_send_command,
 | 
				
			||||||
	node_impl_add_port,
 | 
						node_impl_add_port,
 | 
				
			||||||
 | 
						node_impl_schedule_input,
 | 
				
			||||||
 | 
						node_impl_schedule_output,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pw_spa_node_destroy(void *object)
 | 
					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 impl *impl = user_data;
 | 
				
			||||||
        struct pw_node *this = impl->this;
 | 
					        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) {
 | 
					        spa_list_for_each(p, &this->rt.node.ports[SPA_DIRECTION_INPUT], link) {
 | 
				
			||||||
		if (p->port_id != port_id)
 | 
							if (p->port_id != port_id)
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (p->peer && p->peer->node->methods->reuse_buffer) {
 | 
							pp = p->peer;
 | 
				
			||||||
			struct spa_graph_node *n = p->peer->node;
 | 
							if (pp && pp->methods->reuse_buffer)
 | 
				
			||||||
			n->methods->reuse_buffer(p->peer, buffer_id, n->user_data);
 | 
								pp->methods->reuse_buffer(pp, buffer_id, pp->user_data);
 | 
				
			||||||
		}
 | 
					
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -403,8 +417,6 @@ pw_spa_node_new(struct pw_core *core,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->destroy = pw_spa_node_destroy;
 | 
						this->destroy = pw_spa_node_destroy;
 | 
				
			||||||
	this->implementation = &node_impl;
 | 
						this->implementation = &node_impl;
 | 
				
			||||||
	this->rt.methods = spa_graph_scheduler_default;
 | 
					 | 
				
			||||||
	this->rt.node.user_data = node;
 | 
					 | 
				
			||||||
	this->clock = clock;
 | 
						this->clock = clock;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl = this->user_data;
 | 
						impl = this->user_data;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,6 +24,10 @@
 | 
				
			||||||
extern "C" {
 | 
					extern "C" {
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __USE_GNU
 | 
				
			||||||
 | 
					#define __USE_GNU
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <sys/socket.h>
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/introspect.h>
 | 
					#include <pipewire/client/introspect.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -35,6 +35,7 @@ struct impl {
 | 
				
			||||||
	struct pw_core this;
 | 
						struct pw_core this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_support support[4];
 | 
						struct spa_support support[4];
 | 
				
			||||||
 | 
						struct pw_data_loop *data_loop;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					/** \endcond */
 | 
				
			||||||
| 
						 | 
					@ -152,6 +153,7 @@ core_create_node(void *object,
 | 
				
			||||||
		 uint32_t new_id)
 | 
							 uint32_t new_id)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_resource *node_resource;
 | 
				
			||||||
	struct pw_client *client = resource->client;
 | 
						struct pw_client *client = resource->client;
 | 
				
			||||||
	struct pw_node_factory *factory;
 | 
						struct pw_node_factory *factory;
 | 
				
			||||||
	struct pw_properties *properties;
 | 
						struct pw_properties *properties;
 | 
				
			||||||
| 
						 | 
					@ -160,15 +162,22 @@ core_create_node(void *object,
 | 
				
			||||||
	if (factory == NULL)
 | 
						if (factory == NULL)
 | 
				
			||||||
		goto no_factory;
 | 
							goto no_factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						node_resource = pw_resource_new(client,
 | 
				
			||||||
 | 
										new_id,
 | 
				
			||||||
 | 
										factory->type,
 | 
				
			||||||
 | 
										0);
 | 
				
			||||||
 | 
						if (node_resource == NULL)
 | 
				
			||||||
 | 
							goto no_resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (props) {
 | 
						if (props) {
 | 
				
			||||||
		properties = pw_properties_new_dict(props);
 | 
							properties = pw_properties_new_dict(props);
 | 
				
			||||||
		if (properties == NULL)
 | 
							if (properties == NULL)
 | 
				
			||||||
			goto no_mem;
 | 
								goto no_properties;
 | 
				
			||||||
	} else
 | 
						} else
 | 
				
			||||||
		properties = NULL;
 | 
							properties = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* error will be posted */
 | 
						/* 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;
 | 
						properties = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      done:
 | 
					      done:
 | 
				
			||||||
| 
						 | 
					@ -180,8 +189,14 @@ core_create_node(void *object,
 | 
				
			||||||
			     resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name");
 | 
								     resource->id, SPA_RESULT_INVALID_ARGUMENTS, "unknown factory name");
 | 
				
			||||||
	goto done;
 | 
						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_log_error("can't create properties");
 | 
				
			||||||
 | 
						pw_resource_destroy(node_resource);
 | 
				
			||||||
 | 
						goto no_mem;
 | 
				
			||||||
 | 
					      no_mem:
 | 
				
			||||||
	pw_core_notify_error(client->core_resource,
 | 
						pw_core_notify_error(client->core_resource,
 | 
				
			||||||
			     resource->id, SPA_RESULT_NO_MEMORY, "no memory");
 | 
								     resource->id, SPA_RESULT_NO_MEMORY, "no memory");
 | 
				
			||||||
	goto done;
 | 
						goto done;
 | 
				
			||||||
| 
						 | 
					@ -271,7 +286,7 @@ core_bind_func(struct pw_global *global, struct pw_client *client, uint32_t vers
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \memberof pw_core
 | 
					 * \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 impl *impl;
 | 
				
			||||||
	struct pw_core *this;
 | 
						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;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	this->data_loop = pw_data_loop_new();
 | 
						impl->data_loop = pw_data_loop_new();
 | 
				
			||||||
	if (this->data_loop == NULL)
 | 
						if (impl->data_loop == NULL)
 | 
				
			||||||
		goto no_data_loop;
 | 
							goto no_data_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->data_loop = impl->data_loop->loop;
 | 
				
			||||||
	this->main_loop = main_loop;
 | 
						this->main_loop = main_loop;
 | 
				
			||||||
	this->properties = properties;
 | 
						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);
 | 
						spa_debug_set_type_map(this->type.map);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->support[0] = SPA_SUPPORT_INIT(SPA_TYPE__TypeMap, 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[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->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());
 | 
						impl->support[3] = SPA_SUPPORT_INIT(SPA_TYPE__Log, pw_log_get());
 | 
				
			||||||
	this->support = impl->support;
 | 
						this->support = impl->support;
 | 
				
			||||||
	this->n_support = 4;
 | 
						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->resource_list);
 | 
				
			||||||
	spa_list_init(&this->registry_resource_list);
 | 
						spa_list_init(&this->registry_resource_list);
 | 
				
			||||||
	spa_list_init(&this->global_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_list);
 | 
				
			||||||
	spa_list_init(&this->node_factory_list);
 | 
						spa_list_init(&this->node_factory_list);
 | 
				
			||||||
	spa_list_init(&this->link_list);
 | 
						spa_list_init(&this->link_list);
 | 
				
			||||||
 | 
						pw_signal_init(&this->info_changed);
 | 
				
			||||||
	pw_signal_init(&this->destroy_signal);
 | 
						pw_signal_init(&this->destroy_signal);
 | 
				
			||||||
	pw_signal_init(&this->global_added);
 | 
						pw_signal_init(&this->global_added);
 | 
				
			||||||
	pw_signal_init(&this->global_removed);
 | 
						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_log_debug("core %p: destroy", core);
 | 
				
			||||||
	pw_signal_emit(&core->destroy_signal, 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);
 | 
						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.change_mask = PW_CORE_CHANGE_MASK_PROPS;
 | 
				
			||||||
	core->info.props = core->properties ? &core->properties->dict : NULL;
 | 
						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) {
 | 
						spa_list_for_each(resource, &core->resource_list, link) {
 | 
				
			||||||
		pw_core_notify_info(resource, &core->info);
 | 
							pw_core_notify_info(resource, &core->info);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -148,6 +148,8 @@ struct pw_core {
 | 
				
			||||||
	struct pw_global *global;	/**< the global of the core */
 | 
						struct pw_global *global;	/**< the global of the core */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_core_info info;	/**< info about the core */
 | 
						struct pw_core_info info;	/**< info about the core */
 | 
				
			||||||
 | 
						/** Emited when the core info is updated */
 | 
				
			||||||
 | 
						PW_SIGNAL(info_changed, (struct pw_listener *listener, struct pw_core *core));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_properties *properties;	/**< properties of the core */
 | 
						struct pw_properties *properties;	/**< properties of the core */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -158,6 +160,7 @@ struct pw_core {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_map objects;		/**< map of known objects */
 | 
						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 resource_list;		/**< list of core resources */
 | 
				
			||||||
	struct spa_list registry_resource_list;	/**< list of registry resources */
 | 
						struct spa_list registry_resource_list;	/**< list of registry resources */
 | 
				
			||||||
	struct spa_list global_list;		/**< list of globals */
 | 
						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 node_factory_list;	/**< list of node factories */
 | 
				
			||||||
	struct spa_list link_list;		/**< list of links */
 | 
						struct spa_list link_list;		/**< list of links */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_main_loop *main_loop;	/**< main loop for control */
 | 
						struct pw_loop *main_loop;	/**< main loop for control */
 | 
				
			||||||
	struct pw_data_loop *data_loop;	/**< data loop for data passing */
 | 
						struct pw_loop *data_loop;	/**< data loop for data passing */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_support *support;	/**< support for spa plugins */
 | 
						struct spa_support *support;	/**< support for spa plugins */
 | 
				
			||||||
	uint32_t n_support;		/**< number of support items */
 | 
						uint32_t n_support;		/**< number of support items */
 | 
				
			||||||
| 
						 | 
					@ -189,7 +192,7 @@ struct pw_core {
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
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
 | 
					void
 | 
				
			||||||
pw_core_destroy(struct pw_core *core);
 | 
					pw_core_destroy(struct pw_core *core);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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_port_destroy);
 | 
				
			||||||
	pw_signal_remove(&impl->input_async_complete);
 | 
						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);
 | 
							       do_remove_input, 1, 0, NULL, true, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clear_port_buffers(this, this->input);
 | 
						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_port_destroy);
 | 
				
			||||||
	pw_signal_remove(&impl->output_async_complete);
 | 
						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);
 | 
							       do_remove_output, 1, 0, NULL, true, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	clear_port_buffers(this, this->output);
 | 
						clear_port_buffers(this, this->output);
 | 
				
			||||||
| 
						 | 
					@ -865,7 +865,7 @@ bool pw_link_activate(struct pw_link *this)
 | 
				
			||||||
	impl->active = true;
 | 
						impl->active = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("link %p: activate", this);
 | 
						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);
 | 
							       do_activate_link, SPA_ID_INVALID, 0, NULL, false, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->output->node->n_used_output_links++;
 | 
						this->output->node->n_used_output_links++;
 | 
				
			||||||
| 
						 | 
					@ -896,7 +896,7 @@ bool pw_link_deactivate(struct pw_link *this)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->active = false;
 | 
						impl->active = false;
 | 
				
			||||||
	pw_log_debug("link %p: deactivate", this);
 | 
						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);
 | 
							       do_deactivate_link, SPA_ID_INVALID, 0, NULL, true, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	input_node = this->input->node;
 | 
						input_node = this->input->node;
 | 
				
			||||||
| 
						 | 
					@ -1007,7 +1007,7 @@ struct pw_link *pw_link_new(struct pw_core *core,
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	pw_log_debug("link %p: new", 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->core = core;
 | 
				
			||||||
	this->properties = properties;
 | 
						this->properties = properties;
 | 
				
			||||||
| 
						 | 
					@ -1073,10 +1073,10 @@ struct pw_link *pw_link_new(struct pw_core *core,
 | 
				
			||||||
			    0,
 | 
								    0,
 | 
				
			||||||
			    &this->io);
 | 
								    &this->io);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_loop_invoke(output_node->data_loop->loop,
 | 
						pw_loop_invoke(output_node->data_loop,
 | 
				
			||||||
		       do_add_link,
 | 
							       do_add_link,
 | 
				
			||||||
		       SPA_ID_INVALID, sizeof(struct pw_port *), &output, false, this);
 | 
							       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,
 | 
							       do_add_link,
 | 
				
			||||||
		       SPA_ID_INVALID, sizeof(struct pw_port *), &input, false, this);
 | 
							       SPA_ID_INVALID, sizeof(struct pw_port *), &input, false, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,6 +27,7 @@ extern "C" {
 | 
				
			||||||
#include <spa/ringbuffer.h>
 | 
					#include <spa/ringbuffer.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/mem.h>
 | 
					#include <pipewire/client/mem.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/introspect.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/server/core.h>
 | 
					#include <pipewire/server/core.h>
 | 
				
			||||||
#include <pipewire/server/port.h>
 | 
					#include <pipewire/server/port.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,8 +9,8 @@ pipewirecore_headers = [
 | 
				
			||||||
  'node.h',
 | 
					  'node.h',
 | 
				
			||||||
  'node-factory.h',
 | 
					  'node-factory.h',
 | 
				
			||||||
  'port.h',
 | 
					  'port.h',
 | 
				
			||||||
 | 
					  'remote.h',
 | 
				
			||||||
  'resource.h',
 | 
					  'resource.h',
 | 
				
			||||||
#  'spa-node.h',
 | 
					 | 
				
			||||||
  'work-queue.h',
 | 
					  'work-queue.h',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,8 +25,8 @@ pipewirecore_sources = [
 | 
				
			||||||
  'node.c',
 | 
					  'node.c',
 | 
				
			||||||
  'node-factory.c',
 | 
					  'node-factory.c',
 | 
				
			||||||
  'port.c',
 | 
					  'port.c',
 | 
				
			||||||
 | 
					  'remote.c',
 | 
				
			||||||
  'resource.c',
 | 
					  'resource.c',
 | 
				
			||||||
#  'spa-node.c',
 | 
					 | 
				
			||||||
  'work-queue.c',
 | 
					  'work-queue.c',
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -42,16 +42,16 @@ struct pw_node_factory {
 | 
				
			||||||
	struct pw_global *global;	/**< global for this factory */
 | 
						struct pw_global *global;	/**< global for this factory */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	const char *name;		/**< the factory name */
 | 
						const char *name;		/**< the factory name */
 | 
				
			||||||
 | 
						uint32_t type;			/**< type of the created nodes */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** Emited when the factory is destroyed */
 | 
						/** Emited when the factory is destroyed */
 | 
				
			||||||
	PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object));
 | 
						PW_SIGNAL(destroy_signal, (struct pw_listener *listener, struct pw_node_factory *object));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/** The function to create a node from this factory */
 | 
						/** The function to create a node from this factory */
 | 
				
			||||||
	struct pw_node *(*create_node) (struct pw_node_factory *factory,
 | 
						struct pw_node *(*create_node) (struct pw_node_factory *factory,
 | 
				
			||||||
					struct pw_client *client,
 | 
										struct pw_resource *resource,
 | 
				
			||||||
					const char *name,
 | 
										const char *name,
 | 
				
			||||||
					struct pw_properties *properties,
 | 
										struct pw_properties *properties);
 | 
				
			||||||
					uint32_t new_id);
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define pw_node_factory_create_node(f,...)	(f)->create_node((f),__VA_ARGS__)
 | 
					#define pw_node_factory_create_node(f,...)	(f)->create_node((f),__VA_ARGS__)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -261,7 +261,7 @@ void pw_node_export(struct pw_node *this)
 | 
				
			||||||
			   this->owner,
 | 
								   this->owner,
 | 
				
			||||||
			   this->core->type.node, 0, this, node_bind_func, &this->global);
 | 
								   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);
 | 
						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);
 | 
						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_node *pw_node_new(struct pw_core *core,
 | 
				
			||||||
			    struct pw_resource *owner,
 | 
								    struct pw_resource *owner,
 | 
				
			||||||
			    const char *name,
 | 
								    const char *name,
 | 
				
			||||||
| 
						 | 
					@ -293,7 +313,7 @@ struct pw_node *pw_node_new(struct pw_core *core,
 | 
				
			||||||
	if (user_data_size > 0)
 | 
						if (user_data_size > 0)
 | 
				
			||||||
                this->user_data = SPA_MEMBER(impl, sizeof(struct impl), void);
 | 
					                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->info.name = strdup(name);
 | 
				
			||||||
	this->properties = properties;
 | 
						this->properties = properties;
 | 
				
			||||||
| 
						 | 
					@ -324,8 +344,9 @@ struct pw_node *pw_node_new(struct pw_core *core,
 | 
				
			||||||
	spa_list_init(&this->output_ports);
 | 
						spa_list_init(&this->output_ports);
 | 
				
			||||||
	pw_map_init(&this->output_port_map, 64, 64);
 | 
						pw_map_init(&this->output_port_map, 64, 64);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_graph_node_init(&this->rt.node,
 | 
						spa_graph_node_init(&this->rt.node);
 | 
				
			||||||
			    &this->rt.methods,
 | 
						spa_graph_node_set_methods(&this->rt.node,
 | 
				
			||||||
 | 
									   &graph_methods,
 | 
				
			||||||
				   this);
 | 
									   this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return this;
 | 
						return this;
 | 
				
			||||||
| 
						 | 
					@ -361,7 +382,7 @@ void pw_node_destroy(struct pw_node *node)
 | 
				
			||||||
	pw_log_debug("node %p: destroy", impl);
 | 
						pw_log_debug("node %p: destroy", impl);
 | 
				
			||||||
	pw_signal_emit(&node->destroy_signal, node);
 | 
						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) {
 | 
						if (impl->exported) {
 | 
				
			||||||
		spa_list_remove(&node->link);
 | 
							spa_list_remove(&node->link);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,6 +31,7 @@ extern "C" {
 | 
				
			||||||
#include <spa/node.h>
 | 
					#include <spa/node.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/mem.h>
 | 
					#include <pipewire/client/mem.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/introspect.h>
 | 
				
			||||||
#include <pipewire/client/transport.h>
 | 
					#include <pipewire/client/transport.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/server/core.h>
 | 
					#include <pipewire/server/core.h>
 | 
				
			||||||
| 
						 | 
					@ -57,6 +58,10 @@ struct pw_node_implementation {
 | 
				
			||||||
	struct pw_port* (*add_port) (struct pw_node *node,
 | 
						struct pw_port* (*add_port) (struct pw_node *node,
 | 
				
			||||||
				     enum pw_direction direction,
 | 
									     enum pw_direction direction,
 | 
				
			||||||
				     uint32_t port_id);
 | 
									     uint32_t port_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int (*process_input) (struct pw_node *node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        int (*process_output) (struct pw_node *node);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \page page_node Node
 | 
					/** \page page_node Node
 | 
				
			||||||
| 
						 | 
					@ -132,10 +137,9 @@ struct pw_node {
 | 
				
			||||||
	PW_SIGNAL(event, (struct pw_listener *listener,
 | 
						PW_SIGNAL(event, (struct pw_listener *listener,
 | 
				
			||||||
			  struct pw_node *node, struct spa_event *event));
 | 
								  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 {
 | 
				
			||||||
		struct spa_graph_node_methods methods;
 | 
					 | 
				
			||||||
		struct spa_graph_scheduler *sched;
 | 
							struct spa_graph_scheduler *sched;
 | 
				
			||||||
		struct spa_graph_node node;
 | 
							struct spa_graph_node node;
 | 
				
			||||||
	} rt;
 | 
						} rt;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -74,15 +74,19 @@ static int schedule_tee_output(struct spa_graph_node *node, void *user_data)
 | 
				
			||||||
	return SPA_RESULT_NEED_BUFFER;
 | 
						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)
 | 
					static int schedule_tee_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return SPA_RESULT_OK;
 | 
						return SPA_RESULT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_graph_node_methods schedule_tee = {
 | 
					static const struct spa_graph_port_methods schedule_tee_port = {
 | 
				
			||||||
	SPA_VERSION_GRAPH_NODE_METHODS,
 | 
						SPA_VERSION_GRAPH_PORT_METHODS,
 | 
				
			||||||
	schedule_tee_input,
 | 
					 | 
				
			||||||
	schedule_tee_output,
 | 
					 | 
				
			||||||
	schedule_tee_reuse_buffer,
 | 
						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;
 | 
						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)
 | 
					static int schedule_mix_reuse_buffer(struct spa_graph_port *port, uint32_t buffer_id, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return SPA_RESULT_OK;
 | 
						return SPA_RESULT_OK;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					static const struct spa_graph_port_methods schedule_mix_port = {
 | 
				
			||||||
static const struct spa_graph_node_methods schedule_mix = {
 | 
						SPA_VERSION_GRAPH_PORT_METHODS,
 | 
				
			||||||
	SPA_VERSION_GRAPH_NODE_METHODS,
 | 
					 | 
				
			||||||
	schedule_mix_input,
 | 
					 | 
				
			||||||
	schedule_mix_output,
 | 
					 | 
				
			||||||
	schedule_mix_reuse_buffer,
 | 
						schedule_mix_reuse_buffer,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -159,16 +166,22 @@ struct pw_port *pw_port_new(enum pw_direction direction,
 | 
				
			||||||
			    this->port_id,
 | 
								    this->port_id,
 | 
				
			||||||
			    0,
 | 
								    0,
 | 
				
			||||||
			    &this->io);
 | 
								    &this->io);
 | 
				
			||||||
	spa_graph_node_init(&this->rt.mix_node,
 | 
						spa_graph_node_init(&this->rt.mix_node);
 | 
				
			||||||
 | 
						spa_graph_node_set_methods(&this->rt.mix_node,
 | 
				
			||||||
				   this->direction == PW_DIRECTION_INPUT ?
 | 
									   this->direction == PW_DIRECTION_INPUT ?
 | 
				
			||||||
				&schedule_mix :
 | 
										&schedule_mix_node :
 | 
				
			||||||
				&schedule_tee,
 | 
										&schedule_tee_node,
 | 
				
			||||||
				   this);
 | 
									   this);
 | 
				
			||||||
	spa_graph_port_init(&this->rt.mix_port,
 | 
						spa_graph_port_init(&this->rt.mix_port,
 | 
				
			||||||
			    pw_direction_reverse(this->direction),
 | 
								    pw_direction_reverse(this->direction),
 | 
				
			||||||
			    0,
 | 
								    0,
 | 
				
			||||||
			    0,
 | 
								    0,
 | 
				
			||||||
			    &this->io);
 | 
								    &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;
 | 
						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;
 | 
						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);
 | 
						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);
 | 
						pw_signal_emit(&port->destroy_signal, port);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (node) {
 | 
						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) {
 | 
							if (port->direction == PW_DIRECTION_INPUT) {
 | 
				
			||||||
			pw_map_remove(&node->input_port_map, port->port_id);
 | 
								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;
 | 
							return SPA_RESULT_NO_FORMAT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->state > PW_PORT_STATE_PAUSED) {
 | 
						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);
 | 
								       do_port_pause, 0, 0, NULL, true, port);
 | 
				
			||||||
		port_update_state (port, PW_PORT_STATE_PAUSED);
 | 
							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;
 | 
							return SPA_RESULT_NO_FORMAT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (port->state > PW_PORT_STATE_PAUSED) {
 | 
						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);
 | 
								       do_port_pause, 0, 0, NULL, true, port);
 | 
				
			||||||
		port_update_state (port, PW_PORT_STATE_PAUSED);
 | 
							port_update_state (port, PW_PORT_STATE_PAUSED);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										289
									
								
								pipewire/server/remote.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										289
									
								
								pipewire/server/remote.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,289 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <stdio.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <sys/socket.h>
 | 
				
			||||||
 | 
					#include <sys/un.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#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 <spa/lib/debug.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										181
									
								
								pipewire/server/remote.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								pipewire/server/remote.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,181 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Wim Taymans <wim.taymans@gmail.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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 <pipewire/client/map.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/loop.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/properties.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/protocol.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/proxy.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/type.h>
 | 
				
			||||||
 | 
					#include <pipewire/server/core.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \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__ */
 | 
				
			||||||
| 
						 | 
					@ -20,6 +20,7 @@
 | 
				
			||||||
#include <string.h>
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "pipewire/client/interfaces.h"
 | 
					#include "pipewire/client/interfaces.h"
 | 
				
			||||||
 | 
					#include "pipewire/client/protocol.h"
 | 
				
			||||||
#include "pipewire/server/resource.h"
 | 
					#include "pipewire/server/resource.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,6 +30,7 @@ extern "C" {
 | 
				
			||||||
#include <spa/list.h>
 | 
					#include <spa/list.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/client/sig.h>
 | 
					#include <pipewire/client/sig.h>
 | 
				
			||||||
 | 
					#include <pipewire/client/utils.h>
 | 
				
			||||||
#include <pipewire/server/core.h>
 | 
					#include <pipewire/server/core.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \page page_resource Resource
 | 
					/** \page page_resource Resource
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,5 @@
 | 
				
			||||||
executable('pipewire-monitor',
 | 
					executable('pipewire-monitor',
 | 
				
			||||||
  'pipewire-monitor.c',
 | 
					  'pipewire-monitor.c',
 | 
				
			||||||
  install: true,
 | 
					  install: true,
 | 
				
			||||||
  dependencies : [pipewire_dep],
 | 
					  dependencies : [pipewirecore_dep],
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,10 +26,16 @@
 | 
				
			||||||
struct data {
 | 
					struct data {
 | 
				
			||||||
	bool running;
 | 
						bool running;
 | 
				
			||||||
	struct pw_loop *loop;
 | 
						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_state_changed;
 | 
				
			||||||
	struct pw_listener on_subscription;
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct proxy_data {
 | 
				
			||||||
 | 
						void *info;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void print_properties(struct spa_dict *props, char mark)
 | 
					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 {
 | 
					#define MARK_CHANGE(f) ((print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
 | 
				
			||||||
	bool print_mark;
 | 
					 | 
				
			||||||
	bool print_all;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define MARK_CHANGE(f) ((data->print_mark && ((info)->change_mask & (1 << (f)))) ? '*' : ' ')
 | 
					static void on_info_changed(struct pw_listener *listener, struct pw_remote *remote)
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void
 | 
					 | 
				
			||||||
dump_core_info(struct pw_context *c, int res, const struct pw_core_info *info, void *user_data)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dumpdata *data = user_data;
 | 
						struct pw_core_info *info = remote->info;
 | 
				
			||||||
 | 
						bool print_all = true, print_mark = false;
 | 
				
			||||||
	if (info == NULL)
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printf("\tid: %u\n", info->id);
 | 
						printf("\tid: %u\n", info->id);
 | 
				
			||||||
	printf("\ttype: %s\n", PIPEWIRE_TYPE__Core);
 | 
						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\tuser-name: \"%s\"\n", MARK_CHANGE(0), info->user_name);
 | 
				
			||||||
		printf("%c\thost-name: \"%s\"\n", MARK_CHANGE(1), info->host_name);
 | 
							printf("%c\thost-name: \"%s\"\n", MARK_CHANGE(1), info->host_name);
 | 
				
			||||||
		printf("%c\tversion: \"%s\"\n", MARK_CHANGE(2), info->version);
 | 
							printf("%c\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
 | 
					static void module_event_info(void *object, struct pw_module_info *info)
 | 
				
			||||||
dump_client_info(struct pw_context *c, int res, const struct pw_client_info *info, void *user_data)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	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)
 | 
						print_all = true;
 | 
				
			||||||
		return;
 | 
					        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("\tid: %u\n", info->id);
 | 
				
			||||||
	printf("\ttype: %s\n", PIPEWIRE_TYPE__Client);
 | 
						printf("\ttype: %s\n", PIPEWIRE_TYPE__Module);
 | 
				
			||||||
	if (data->print_all) {
 | 
						if (print_all) {
 | 
				
			||||||
		print_properties(info->props, MARK_CHANGE(0));
 | 
							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
 | 
					static const struct pw_module_events module_events = {
 | 
				
			||||||
dump_node_info(struct pw_context *c, int res, const struct pw_node_info *info, void *user_data)
 | 
					        &module_event_info,
 | 
				
			||||||
{
 | 
					};
 | 
				
			||||||
	struct dumpdata *data = user_data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info == NULL) {
 | 
					static void node_event_info(void *object, struct pw_node_info *info)
 | 
				
			||||||
		if (res != SPA_RESULT_ENUM_END)
 | 
					{
 | 
				
			||||||
			printf("\tError introspecting node: %d\n", res);
 | 
					        struct pw_proxy *proxy = object;
 | 
				
			||||||
		return;
 | 
					        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("\tid: %u\n", info->id);
 | 
				
			||||||
	printf("\ttype: %s\n", PIPEWIRE_TYPE__Node);
 | 
						printf("\ttype: %s\n", PIPEWIRE_TYPE__Node);
 | 
				
			||||||
	if (data->print_all) {
 | 
						if (print_all) {
 | 
				
			||||||
		int i;
 | 
							int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
 | 
							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
 | 
					static const struct pw_node_events node_events = {
 | 
				
			||||||
dump_module_info(struct pw_context *c, int res, const struct pw_module_info *info, void *user_data)
 | 
					        &node_event_info
 | 
				
			||||||
{
 | 
					};
 | 
				
			||||||
	struct dumpdata *data = user_data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info == NULL) {
 | 
					static void client_event_info(void *object, struct pw_client_info *info)
 | 
				
			||||||
		if (res != SPA_RESULT_ENUM_END)
 | 
					{
 | 
				
			||||||
			printf("\tError introspecting module: %d\n", res);
 | 
					        struct pw_proxy *proxy = object;
 | 
				
			||||||
		return;
 | 
					        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("\tid: %u\n", info->id);
 | 
				
			||||||
	printf("\ttype: %s\n", PIPEWIRE_TYPE__Module);
 | 
						printf("\ttype: %s\n", PIPEWIRE_TYPE__Client);
 | 
				
			||||||
	if (data->print_all) {
 | 
						if (print_all) {
 | 
				
			||||||
		printf("%c\tname: \"%s\"\n", MARK_CHANGE(0), info->name);
 | 
							print_properties(info->props, MARK_CHANGE(0));
 | 
				
			||||||
		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
 | 
					static const struct pw_client_events client_events = {
 | 
				
			||||||
dump_link_info(struct pw_context *c, int res, const struct pw_link_info *info, void *user_data)
 | 
					        &client_event_info
 | 
				
			||||||
{
 | 
					};
 | 
				
			||||||
	struct dumpdata *data = user_data;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (info == NULL) {
 | 
					static void link_event_info(void *object, struct pw_link_info *info)
 | 
				
			||||||
		if (res != SPA_RESULT_ENUM_END)
 | 
					{
 | 
				
			||||||
			printf("\tError introspecting link: %d\n", res);
 | 
					        struct pw_proxy *proxy = object;
 | 
				
			||||||
		return;
 | 
					        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("\tid: %u\n", info->id);
 | 
				
			||||||
	printf("\ttype: %s\n", PIPEWIRE_TYPE__Link);
 | 
						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-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\toutput-port-id: %u\n", MARK_CHANGE(1), info->output_port_id);
 | 
				
			||||||
		printf("%c\tinput-node-id: %u\n", MARK_CHANGE(2), info->input_node_id);
 | 
							printf("%c\tinput-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 const struct pw_link_events link_events = {
 | 
				
			||||||
 | 
					        &link_event_info
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void
 | 
					static void
 | 
				
			||||||
dump_object(struct pw_context *context, uint32_t type, uint32_t id, struct dumpdata *data)
 | 
					destroy_proxy (void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (type == context->type.core) {
 | 
					        struct pw_proxy *proxy = data;
 | 
				
			||||||
		pw_context_get_core_info(context, dump_core_info, data);
 | 
					        struct proxy_data *user_data = proxy->user_data;
 | 
				
			||||||
	} else if (type == context->type.node) {
 | 
						struct pw_core *core = proxy->remote->core;
 | 
				
			||||||
		pw_context_get_node_info_by_id(context, id, dump_node_info, data);
 | 
					
 | 
				
			||||||
	} else if (type == context->type.module) {
 | 
					        if (user_data->info == NULL)
 | 
				
			||||||
		pw_context_get_module_info_by_id(context, id, dump_module_info, data);
 | 
					                return;
 | 
				
			||||||
	} else if (type == context->type.client) {
 | 
					
 | 
				
			||||||
		pw_context_get_client_info_by_id(context, id, dump_client_info, data);
 | 
					        if (proxy->type == core->type.core) {
 | 
				
			||||||
	} else if (type == context->type.link) {
 | 
					                pw_core_info_free (user_data->info);
 | 
				
			||||||
		pw_context_get_link_info_by_id(context, id, dump_link_info, data);
 | 
					        } else if (proxy->type == core->type.node) {
 | 
				
			||||||
	} else {
 | 
					                pw_node_info_free (user_data->info);
 | 
				
			||||||
		printf("\tid: %u\n", id);
 | 
					        } 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_subscription(struct pw_listener *listener,
 | 
					static void registry_event_global(void *object, uint32_t id, const char *type, uint32_t version)
 | 
				
			||||||
		struct pw_context *context,
 | 
					 | 
				
			||||||
		enum pw_subscription_event event, uint32_t type, uint32_t id)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct dumpdata dd;
 | 
					        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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (event) {
 | 
					        if (!strcmp(type, PIPEWIRE_TYPE__Node)) {
 | 
				
			||||||
	case PW_SUBSCRIPTION_EVENT_NEW:
 | 
					                proxy_type = core->type.node;
 | 
				
			||||||
		printf("added:\n");
 | 
					                implementation = &node_events;
 | 
				
			||||||
		dd.print_mark = false;
 | 
					                client_version = PW_VERSION_NODE;
 | 
				
			||||||
		dd.print_all = true;
 | 
					        } else if (!strcmp(type, PIPEWIRE_TYPE__Module)) {
 | 
				
			||||||
		dump_object(context, type, id, &dd);
 | 
					                proxy_type = core->type.module;
 | 
				
			||||||
		break;
 | 
					                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;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_SUBSCRIPTION_EVENT_CHANGE:
 | 
					        proxy = pw_proxy_new(remote, SPA_ID_INVALID, proxy_type, sizeof(struct proxy_data));
 | 
				
			||||||
		printf("changed:\n");
 | 
					        if (proxy == NULL)
 | 
				
			||||||
		dd.print_mark = true;
 | 
					                goto no_mem;
 | 
				
			||||||
		dd.print_all = true;
 | 
					 | 
				
			||||||
		dump_object(context, type, id, &dd);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case PW_SUBSCRIPTION_EVENT_REMOVE:
 | 
					        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("removed:\n");
 | 
				
			||||||
		dd.print_mark = false;
 | 
						printf("\tid: %u\n", id);
 | 
				
			||||||
		dd.print_all = false;
 | 
					 | 
				
			||||||
		dump_object(context, type, id, &dd);
 | 
					 | 
				
			||||||
		break;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void on_state_changed(struct pw_listener *listener, struct pw_context *context)
 | 
					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);
 | 
						struct data *data = SPA_CONTAINER_OF(listener, struct data, on_state_changed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (context->state) {
 | 
						switch (remote->state) {
 | 
				
			||||||
	case PW_CONTEXT_STATE_ERROR:
 | 
						case PW_CONTEXT_STATE_ERROR:
 | 
				
			||||||
		printf("context error: %s\n", context->error);
 | 
							printf("remote error: %s\n", remote->error);
 | 
				
			||||||
		data->running = false;
 | 
							data->running = false;
 | 
				
			||||||
		break;
 | 
							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:
 | 
						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;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int main(int argc, char *argv[])
 | 
					int main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct data data;
 | 
						struct data data = { 0 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_init(&argc, &argv);
 | 
						pw_init(&argc, &argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data.loop = pw_loop_new();
 | 
						data.loop = pw_loop_new();
 | 
				
			||||||
	data.running = true;
 | 
						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_remote_connect(data.remote);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_context_connect(data.context, 0);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_loop_enter(data.loop);
 | 
						pw_loop_enter(data.loop);
 | 
				
			||||||
	while (data.running) {
 | 
						while (data.running) {
 | 
				
			||||||
| 
						 | 
					@ -259,7 +348,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	pw_loop_leave(data.loop);
 | 
						pw_loop_leave(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_destroy(data.context);
 | 
						pw_remote_destroy(data.remote);
 | 
				
			||||||
	pw_loop_destroy(data.loop);
 | 
						pw_loop_destroy(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -96,8 +96,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		switch (n->action) {
 | 
							switch (n->action) {
 | 
				
			||||||
		case SPA_GRAPH_ACTION_IN:
 | 
							case SPA_GRAPH_ACTION_IN:
 | 
				
			||||||
			n->state = n->methods->schedule_input(n, n->user_data);
 | 
								n->state = n->methods->process_input(n, n->user_data);
 | 
				
			||||||
			debug("node %p scheduled input state %d\n", n, n->state);
 | 
								debug("node %p processed input state %d\n", n, n->state);
 | 
				
			||||||
			if (n == sched->node)
 | 
								if (n == sched->node)
 | 
				
			||||||
				break;
 | 
									break;
 | 
				
			||||||
			n->action = SPA_GRAPH_ACTION_CHECK;
 | 
								n->action = SPA_GRAPH_ACTION_CHECK;
 | 
				
			||||||
| 
						 | 
					@ -105,8 +105,8 @@ static inline bool spa_graph_scheduler_iterate(struct spa_graph_scheduler *sched
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		case SPA_GRAPH_ACTION_OUT:
 | 
							case SPA_GRAPH_ACTION_OUT:
 | 
				
			||||||
			n->state = n->methods->schedule_output(n, n->user_data);
 | 
								n->state = n->methods->process_output(n, n->user_data);
 | 
				
			||||||
			debug("node %p scheduled output state %d\n", n, n->state);
 | 
								debug("node %p processed output state %d\n", n, n->state);
 | 
				
			||||||
			n->action = SPA_GRAPH_ACTION_CHECK;
 | 
								n->action = SPA_GRAPH_ACTION_CHECK;
 | 
				
			||||||
			spa_list_insert(sched->ready.prev, &n->ready_link);
 | 
								spa_list_insert(sched->ready.prev, &n->ready_link);
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,32 +38,36 @@ static inline void spa_graph_scheduler_init(struct spa_graph_scheduler *sched,
 | 
				
			||||||
	sched->node = NULL;
 | 
						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;
 | 
						struct spa_node *n = node->user_data;
 | 
				
			||||||
	return spa_node_process_input(n);
 | 
						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;
 | 
						struct spa_node *n = node->user_data;
 | 
				
			||||||
	return spa_node_process_output(n);
 | 
						return spa_node_process_output(n);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline int spa_graph_scheduler_reuse_buffer(struct spa_graph_port *port,
 | 
					
 | 
				
			||||||
 | 
					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)
 | 
												uint32_t buffer_id, void *user_data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	printf("port %p reuse buffer %d\n", port, buffer_id);
 | 
						printf("port %p reuse buffer %d\n", port, buffer_id);
 | 
				
			||||||
	struct spa_graph_node *node = port->node;
 | 
						struct spa_node *node = port->node->user_data;
 | 
				
			||||||
	struct spa_node *n = node->user_data;
 | 
						return spa_node_port_reuse_buffer(node, port->port_id, buffer_id);
 | 
				
			||||||
	return spa_node_port_reuse_buffer(n, port->port_id, buffer_id);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct spa_graph_node_methods spa_graph_scheduler_default = {
 | 
					static const struct spa_graph_port_methods spa_graph_port_scheduler_default = {
 | 
				
			||||||
	SPA_VERSION_GRAPH_NODE_METHODS,
 | 
						SPA_VERSION_GRAPH_PORT_METHODS,
 | 
				
			||||||
	spa_graph_scheduler_input,
 | 
						spa_graph_port_scheduler_reuse_buffer,
 | 
				
			||||||
	spa_graph_scheduler_output,
 | 
					 | 
				
			||||||
	spa_graph_scheduler_reuse_buffer,
 | 
					 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static inline void spa_graph_scheduler_pull(struct spa_graph_scheduler *sched, struct spa_graph_node *node)
 | 
					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) {
 | 
						spa_list_for_each_safe(n, t, &ready, ready_link) {
 | 
				
			||||||
		n->state = n->methods->schedule_output(n, n->user_data);
 | 
							n->state = n->methods->process_output(n, n->user_data);
 | 
				
			||||||
		debug("peer %p scheduled out %d\n", n, n->state);
 | 
							debug("peer %p processed out %d\n", n, n->state);
 | 
				
			||||||
		if (n->state == SPA_RESULT_NEED_BUFFER)
 | 
							if (n->state == SPA_RESULT_NEED_BUFFER)
 | 
				
			||||||
			spa_graph_scheduler_pull(sched, n);
 | 
								spa_graph_scheduler_pull(sched, n);
 | 
				
			||||||
		else {
 | 
							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);
 | 
						debug("node %p %d %d\n", node, node->ready_in, node->required_in);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (node->required_in > 0 && 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);
 | 
							node->state = node->methods->process_input(node, node->user_data);
 | 
				
			||||||
		debug("node %p scheduled in %d\n", node, node->state);
 | 
							debug("node %p processed in %d\n", node, node->state);
 | 
				
			||||||
		if (node->state == SPA_RESULT_HAVE_BUFFER) {
 | 
							if (node->state == SPA_RESULT_HAVE_BUFFER) {
 | 
				
			||||||
			spa_list_for_each(p, &node->ports[SPA_DIRECTION_OUTPUT], link) {
 | 
								spa_list_for_each(p, &node->ports[SPA_DIRECTION_OUTPUT], link) {
 | 
				
			||||||
				if (p->io->status == SPA_RESULT_HAVE_BUFFER)
 | 
									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) {
 | 
						spa_list_for_each_safe(n, t, &ready, ready_link) {
 | 
				
			||||||
		n->state = n->methods->schedule_input(n, n->user_data);
 | 
							n->state = n->methods->process_input(n, n->user_data);
 | 
				
			||||||
		debug("peer %p scheduled in %d\n", n, n->state);
 | 
							debug("peer %p processed in %d\n", n, n->state);
 | 
				
			||||||
		if (n->state == SPA_RESULT_HAVE_BUFFER)
 | 
							if (n->state == SPA_RESULT_HAVE_BUFFER)
 | 
				
			||||||
			spa_graph_scheduler_push(sched, n);
 | 
								spa_graph_scheduler_push(sched, n);
 | 
				
			||||||
		else {
 | 
							else {
 | 
				
			||||||
| 
						 | 
					@ -169,8 +173,8 @@ static inline void spa_graph_scheduler_push(struct spa_graph_scheduler *sched, s
 | 
				
			||||||
		n->ready_link.next = NULL;
 | 
							n->ready_link.next = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	node->state = node->methods->schedule_output(node, node->user_data);
 | 
						node->state = node->methods->process_output(node, node->user_data);
 | 
				
			||||||
	debug("node %p scheduled out %d\n", node, node->state);
 | 
						debug("node %p processed out %d\n", node, node->state);
 | 
				
			||||||
	if (node->state == SPA_RESULT_NEED_BUFFER) {
 | 
						if (node->state == SPA_RESULT_NEED_BUFFER) {
 | 
				
			||||||
		node->ready_in = 0;
 | 
							node->ready_in = 0;
 | 
				
			||||||
		spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) {
 | 
							spa_list_for_each(p, &node->ports[SPA_DIRECTION_INPUT], link) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -46,8 +46,14 @@ struct spa_graph {
 | 
				
			||||||
struct spa_graph_node_methods {
 | 
					struct spa_graph_node_methods {
 | 
				
			||||||
	uint32_t version;
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int (*schedule_input) (struct spa_graph_node *node, void *user_data);
 | 
						int (*process_input) (struct spa_graph_node *node, void *user_data);
 | 
				
			||||||
	int (*schedule_output) (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);
 | 
						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_IN      1
 | 
				
			||||||
#define SPA_GRAPH_ACTION_OUT     2
 | 
					#define SPA_GRAPH_ACTION_OUT     2
 | 
				
			||||||
	uint32_t action;
 | 
						uint32_t action;
 | 
				
			||||||
	const struct spa_graph_node_methods *methods;
 | 
					 | 
				
			||||||
	void *user_data;
 | 
					 | 
				
			||||||
	uint32_t max_in;
 | 
						uint32_t max_in;
 | 
				
			||||||
	uint32_t required_in;
 | 
						uint32_t required_in;
 | 
				
			||||||
	uint32_t ready_in;
 | 
						uint32_t ready_in;
 | 
				
			||||||
 | 
						const struct spa_graph_node_methods *methods;
 | 
				
			||||||
 | 
						void *user_data;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct spa_graph_port {
 | 
					struct spa_graph_port {
 | 
				
			||||||
| 
						 | 
					@ -77,6 +83,8 @@ struct spa_graph_port {
 | 
				
			||||||
	uint32_t flags;
 | 
						uint32_t flags;
 | 
				
			||||||
	struct spa_port_io *io;
 | 
						struct spa_port_io *io;
 | 
				
			||||||
	struct spa_graph_port *peer;
 | 
						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)
 | 
					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
 | 
					static inline void
 | 
				
			||||||
spa_graph_node_init(struct spa_graph_node *node,
 | 
					spa_graph_node_init(struct spa_graph_node *node)
 | 
				
			||||||
		    const struct spa_graph_node_methods *methods,
 | 
					 | 
				
			||||||
		    void *user_data)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spa_list_init(&node->ports[SPA_DIRECTION_INPUT]);
 | 
						spa_list_init(&node->ports[SPA_DIRECTION_INPUT]);
 | 
				
			||||||
	spa_list_init(&node->ports[SPA_DIRECTION_OUTPUT]);
 | 
						spa_list_init(&node->ports[SPA_DIRECTION_OUTPUT]);
 | 
				
			||||||
	node->flags = 0;
 | 
						node->flags = 0;
 | 
				
			||||||
	node->methods = methods;
 | 
					 | 
				
			||||||
	node->user_data = user_data;
 | 
					 | 
				
			||||||
	node->max_in = node->required_in = node->ready_in = 0;
 | 
						node->max_in = node->required_in = node->ready_in = 0;
 | 
				
			||||||
	debug("node %p init\n", node);
 | 
						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
 | 
					static inline void
 | 
				
			||||||
spa_graph_node_add(struct spa_graph *graph,
 | 
					spa_graph_node_add(struct spa_graph *graph,
 | 
				
			||||||
		   struct spa_graph_node *node)
 | 
							   struct spa_graph_node *node)
 | 
				
			||||||
| 
						 | 
					@ -123,6 +136,15 @@ spa_graph_port_init(struct spa_graph_port *port,
 | 
				
			||||||
	port->io = io;
 | 
						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
 | 
					static inline void
 | 
				
			||||||
spa_graph_port_add(struct spa_graph_node *node,
 | 
					spa_graph_port_add(struct spa_graph_node *node,
 | 
				
			||||||
		   struct spa_graph_port *port)
 | 
							   struct spa_graph_port *port)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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->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_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_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_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_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_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_init(&data->volume_in, SPA_DIRECTION_INPUT, 0, 0, &data->source_volume_io[0]);
 | 
				
			||||||
	spa_graph_port_add(&data->volume_node, &data->volume_in);
 | 
						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_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_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_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_init(&data->sink_in, SPA_DIRECTION_INPUT, 0, 0, &data->volume_sink_io[0]);
 | 
				
			||||||
	spa_graph_port_add(&data->sink_node, &data->sink_in);
 | 
						spa_graph_port_add(&data->sink_node, &data->sink_in);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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]);
 | 
						spa_node_port_set_io(data->sink, SPA_DIRECTION_INPUT, 0, &data->mix_sink_io[0]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef USE_GRAPH
 | 
					#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_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_port_add(&data->source1_node, &data->source1_out);
 | 
				
			||||||
	spa_graph_node_add(&data->graph, &data->source1_node);
 | 
						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_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_port_add(&data->source2_node, &data->source2_out);
 | 
				
			||||||
	spa_graph_node_add(&data->graph, &data->source2_node);
 | 
						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,
 | 
						spa_graph_port_init(&data->mix_in[0], SPA_DIRECTION_INPUT,
 | 
				
			||||||
			    data->mix_ports[0], 0, &data->source1_mix_io[0]);
 | 
								    data->mix_ports[0], 0, &data->source1_mix_io[0]);
 | 
				
			||||||
	spa_graph_port_add(&data->mix_node, &data->mix_in[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_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_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_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_port_add(&data->sink_node, &data->sink_in);
 | 
				
			||||||
	spa_graph_node_add(&data->graph, &data->sink_node);
 | 
						spa_graph_node_add(&data->graph, &data->sink_node);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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->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_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);
 | 
						spa_graph_node_add(&data->graph, &data->source_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->source_node.flags = (data->mode & MODE_ASYNC_PUSH) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
 | 
						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_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_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);
 | 
						spa_graph_node_add(&data->graph, &data->sink_node);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
 | 
						data->sink_node.flags = (data->mode & MODE_ASYNC_PULL) ? SPA_GRAPH_NODE_FLAG_ASYNC : 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue