mirror of
				https://gitlab.freedesktop.org/pipewire/pipewire.git
				synced 2025-11-03 09:01:54 -05:00 
			
		
		
		
	context: move core implementation to impl-core.h
Move the core implementation to a separate file. Make a default core object in the context. Pass impl-core to server. We now tie the server to a core. Also keep track of the core that a client connected to. Fill the properties that we usually use to connect in the context and copy them when a connection is made. Use "internal" as the remote name to connect to the default internal core.
This commit is contained in:
		
							parent
							
								
									a1451fd820
								
							
						
					
					
						commit
						f724319e8a
					
				
					 16 changed files with 839 additions and 613 deletions
				
			
		| 
						 | 
					@ -301,11 +301,10 @@ static void on_start(void *data, uint32_t version)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct client_data *this = data;
 | 
						struct client_data *this = data;
 | 
				
			||||||
	struct pw_impl_client *client = this->client;
 | 
						struct pw_impl_client *client = this->client;
 | 
				
			||||||
	struct pw_context *context = client->context;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug("version %d", version);
 | 
						pw_log_debug("version %d", version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pw_global_bind(pw_context_get_global(context), client,
 | 
						if (pw_global_bind(pw_impl_core_get_global(client->core), client,
 | 
				
			||||||
			PW_PERM_RWX, version, 0) < 0)
 | 
								PW_PERM_RWX, version, 0) < 0)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -357,7 +356,7 @@ static struct client_data *client_new(struct server *s, int fd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_properties_setf(props, PW_KEY_MODULE_ID, "%d", d->module->global->id);
 | 
						pw_properties_setf(props, PW_KEY_MODULE_ID, "%d", d->module->global->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	client = pw_context_create_client(protocol->context,
 | 
						client = pw_context_create_client(s->this.core,
 | 
				
			||||||
			protocol, props, sizeof(struct client_data));
 | 
								protocol, props, sizeof(struct client_data));
 | 
				
			||||||
	if (client == NULL)
 | 
						if (client == NULL)
 | 
				
			||||||
		goto exit;
 | 
							goto exit;
 | 
				
			||||||
| 
						 | 
					@ -809,6 +808,7 @@ error:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pw_protocol_client *
 | 
					static struct pw_protocol_client *
 | 
				
			||||||
impl_new_client(struct pw_protocol *protocol,
 | 
					impl_new_client(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
							struct pw_core *core,
 | 
				
			||||||
		const struct pw_properties *properties)
 | 
							const struct pw_properties *properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct client *impl;
 | 
						struct client *impl;
 | 
				
			||||||
| 
						 | 
					@ -823,6 +823,7 @@ impl_new_client(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	this->protocol = protocol;
 | 
						this->protocol = protocol;
 | 
				
			||||||
 | 
						this->core = core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	impl->context = protocol->context;
 | 
						impl->context = protocol->context;
 | 
				
			||||||
	impl->connection = pw_protocol_native_connection_new(protocol->context, -1);
 | 
						impl->connection = pw_protocol_native_connection_new(protocol->context, -1);
 | 
				
			||||||
| 
						 | 
					@ -834,8 +835,8 @@ impl_new_client(struct pw_protocol *protocol,
 | 
				
			||||||
	if (properties) {
 | 
						if (properties) {
 | 
				
			||||||
		str = pw_properties_get(properties, PW_KEY_REMOTE_INTENTION);
 | 
							str = pw_properties_get(properties, PW_KEY_REMOTE_INTENTION);
 | 
				
			||||||
		if (str == NULL &&
 | 
							if (str == NULL &&
 | 
				
			||||||
		    (str = pw_properties_get(properties, PW_KEY_REMOTE_NAME)) != NULL &&
 | 
							   (str = pw_properties_get(properties, PW_KEY_REMOTE_NAME)) != NULL &&
 | 
				
			||||||
		    strcmp(str, impl->context->info.name) == 0)
 | 
							    strcmp(str, "internal") == 0)
 | 
				
			||||||
			str = "internal";
 | 
								str = "internal";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (str == NULL)
 | 
						if (str == NULL)
 | 
				
			||||||
| 
						 | 
					@ -933,6 +934,7 @@ get_name(const struct pw_properties *properties)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct server *
 | 
					static struct server *
 | 
				
			||||||
create_server(struct pw_protocol *protocol,
 | 
					create_server(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
							struct pw_impl_core *core,
 | 
				
			||||||
                const struct pw_properties *properties)
 | 
					                const struct pw_properties *properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_protocol_server *this;
 | 
						struct pw_protocol_server *this;
 | 
				
			||||||
| 
						 | 
					@ -946,6 +948,7 @@ create_server(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &s->this;
 | 
						this = &s->this;
 | 
				
			||||||
	this->protocol = protocol;
 | 
						this->protocol = protocol;
 | 
				
			||||||
 | 
						this->core = core;
 | 
				
			||||||
	spa_list_init(&this->client_list);
 | 
						spa_list_init(&this->client_list);
 | 
				
			||||||
	this->destroy = destroy_server;
 | 
						this->destroy = destroy_server;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -960,6 +963,7 @@ create_server(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct pw_protocol_server *
 | 
					static struct pw_protocol_server *
 | 
				
			||||||
impl_add_server(struct pw_protocol *protocol,
 | 
					impl_add_server(struct pw_protocol *protocol,
 | 
				
			||||||
 | 
							struct pw_impl_core *core,
 | 
				
			||||||
                const struct pw_properties *properties)
 | 
					                const struct pw_properties *properties)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_protocol_server *this;
 | 
						struct pw_protocol_server *this;
 | 
				
			||||||
| 
						 | 
					@ -967,7 +971,7 @@ impl_add_server(struct pw_protocol *protocol,
 | 
				
			||||||
	const char *name;
 | 
						const char *name;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((s = create_server(protocol, properties)) == NULL)
 | 
						if ((s = create_server(protocol, core, properties)) == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this = &s->this;
 | 
						this = &s->this;
 | 
				
			||||||
| 
						 | 
					@ -1083,9 +1087,9 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_context *context = pw_impl_module_get_context(module);
 | 
						struct pw_context *context = pw_impl_module_get_context(module);
 | 
				
			||||||
	struct pw_protocol *this;
 | 
						struct pw_protocol *this;
 | 
				
			||||||
	const char *val;
 | 
					 | 
				
			||||||
	struct protocol_data *d;
 | 
						struct protocol_data *d;
 | 
				
			||||||
	const struct pw_properties *props;
 | 
						const struct pw_properties *props;
 | 
				
			||||||
 | 
						const char *val;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (pw_context_find_protocol(context, PW_TYPE_INFO_PROTOCOL_Native) != NULL)
 | 
						if (pw_context_find_protocol(context, PW_TYPE_INFO_PROTOCOL_Native) != NULL)
 | 
				
			||||||
| 
						 | 
					@ -1109,15 +1113,14 @@ int pipewire__module_init(struct pw_impl_module *module, const char *args)
 | 
				
			||||||
	d->protocol = this;
 | 
						d->protocol = this;
 | 
				
			||||||
	d->module = module;
 | 
						d->module = module;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	d->local = create_server(this, props);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	props = pw_context_get_properties(context);
 | 
						props = pw_context_get_properties(context);
 | 
				
			||||||
 | 
						d->local = create_server(this, context->core, props);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	val = getenv("PIPEWIRE_DAEMON");
 | 
						val = getenv("PIPEWIRE_DAEMON");
 | 
				
			||||||
	if (val == NULL)
 | 
						if (val == NULL)
 | 
				
			||||||
		val = pw_properties_get(props, PW_KEY_CORE_DAEMON);
 | 
							val = pw_properties_get(props, PW_KEY_CORE_DAEMON);
 | 
				
			||||||
	if (val && pw_properties_parse_bool(val)) {
 | 
						if (val && pw_properties_parse_bool(val)) {
 | 
				
			||||||
		if (impl_add_server(this, props) == NULL) {
 | 
							if (impl_add_server(this, context->core, props) == NULL) {
 | 
				
			||||||
			res = -errno;
 | 
								res = -errno;
 | 
				
			||||||
			goto error_cleanup;
 | 
								goto error_cleanup;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,6 +39,8 @@
 | 
				
			||||||
#include <pipewire/impl.h>
 | 
					#include <pipewire/impl.h>
 | 
				
			||||||
#include <pipewire/private.h>
 | 
					#include <pipewire/private.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <extensions/protocol-native.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NAME "context"
 | 
					#define NAME "context"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \cond */
 | 
					/** \cond */
 | 
				
			||||||
| 
						 | 
					@ -58,399 +60,6 @@ struct factory_entry {
 | 
				
			||||||
	char *lib;
 | 
						char *lib;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** \endcond */
 | 
					 | 
				
			||||||
static void * registry_bind(void *object, uint32_t id,
 | 
					 | 
				
			||||||
		uint32_t type, uint32_t version, size_t user_data_size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_context *context = resource->context;
 | 
					 | 
				
			||||||
	struct pw_global *global;
 | 
					 | 
				
			||||||
	uint32_t permissions, new_id = user_data_size;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((global = pw_context_find_global(context, id)) == NULL)
 | 
					 | 
				
			||||||
		goto error_no_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	permissions = pw_global_get_permissions(global, client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!PW_PERM_IS_R(permissions))
 | 
					 | 
				
			||||||
		goto error_no_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (global->type != type)
 | 
					 | 
				
			||||||
		goto error_wrong_interface;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug("global %p: bind global id %d, iface %s/%d to %d", global, id,
 | 
					 | 
				
			||||||
		     spa_debug_type_find_name(pw_type_info(), type), version, new_id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (pw_global_bind(global, client, permissions, version, new_id) < 0)
 | 
					 | 
				
			||||||
		goto error_exit_clean;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error_no_id:
 | 
					 | 
				
			||||||
	pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id);
 | 
					 | 
				
			||||||
	pw_resource_errorf(resource, -ENOENT, "no such global %u", id);
 | 
					 | 
				
			||||||
	goto error_exit_clean;
 | 
					 | 
				
			||||||
error_wrong_interface:
 | 
					 | 
				
			||||||
	pw_log_debug("registry %p: global with id %u has no interface %u", resource, id, type);
 | 
					 | 
				
			||||||
	pw_resource_errorf(resource, -ENOENT, "no such interface %u", type);
 | 
					 | 
				
			||||||
	goto error_exit_clean;
 | 
					 | 
				
			||||||
error_exit_clean:
 | 
					 | 
				
			||||||
	/* unmark the new_id the map, the client does not yet know about the failed
 | 
					 | 
				
			||||||
	 * bind and will choose the next id, which we would refuse when we don't mark
 | 
					 | 
				
			||||||
	 * new_id as 'used and freed' */
 | 
					 | 
				
			||||||
	pw_map_insert_at(&client->objects, new_id, NULL);
 | 
					 | 
				
			||||||
	pw_core_resource_remove_id(client->core_resource, new_id);
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int registry_destroy(void *object, uint32_t id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_context *context = resource->context;
 | 
					 | 
				
			||||||
	struct pw_global *global;
 | 
					 | 
				
			||||||
	uint32_t permissions;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((global = pw_context_find_global(context, id)) == NULL)
 | 
					 | 
				
			||||||
		goto error_no_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	permissions = pw_global_get_permissions(global, client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!PW_PERM_IS_R(permissions))
 | 
					 | 
				
			||||||
		goto error_no_id;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!PW_PERM_IS_X(permissions))
 | 
					 | 
				
			||||||
		goto error_not_allowed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug("global %p: destroy global id %d", global, id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_global_destroy(global);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error_no_id:
 | 
					 | 
				
			||||||
	pw_log_debug("registry %p: no global with id %u to destroy", resource, id);
 | 
					 | 
				
			||||||
	res = -ENOENT;
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_not_allowed:
 | 
					 | 
				
			||||||
	pw_log_debug("registry %p: destroy of id %u not allowed", resource, id);
 | 
					 | 
				
			||||||
	res = -EPERM;
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_exit:
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct pw_registry_methods registry_methods = {
 | 
					 | 
				
			||||||
	PW_VERSION_REGISTRY_METHODS,
 | 
					 | 
				
			||||||
	.bind = registry_bind,
 | 
					 | 
				
			||||||
	.destroy = registry_destroy
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void destroy_registry_resource(void *object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	spa_list_remove(&resource->link);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct pw_resource_events resource_events = {
 | 
					 | 
				
			||||||
	PW_VERSION_RESOURCE_EVENTS,
 | 
					 | 
				
			||||||
	.destroy = destroy_registry_resource
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int destroy_resource(void *object, void *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (resource &&
 | 
					 | 
				
			||||||
	    resource != client->core_resource) {
 | 
					 | 
				
			||||||
		pw_resource_remove(resource);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int core_hello(void *object, uint32_t version)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_context *this = resource->context;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: hello %d from resource %p", this, version, resource);
 | 
					 | 
				
			||||||
	pw_map_for_each(&client->objects, destroy_resource, client);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->info.change_mask = PW_CORE_CHANGE_MASK_ALL;
 | 
					 | 
				
			||||||
	pw_core_resource_info(resource, &this->info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (version >= 3) {
 | 
					 | 
				
			||||||
		if ((res = pw_global_bind(client->global, client,
 | 
					 | 
				
			||||||
				PW_PERM_RWX, PW_VERSION_CLIENT, 1)) < 0)
 | 
					 | 
				
			||||||
			return res;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int core_sync(void *object, uint32_t id, int seq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	pw_log_trace(NAME" %p: sync %d for resource %d", resource->context, seq, id);
 | 
					 | 
				
			||||||
	pw_core_resource_done(resource, id, seq);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int core_pong(void *object, uint32_t id, int seq)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_resource *r;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: pong %d for resource %d", resource->context, seq, id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((r = pw_impl_client_find_resource(client, id)) == NULL)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_resource_emit_pong(r, seq);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int core_error(void *object, uint32_t id, int seq, int res, const char *message)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_resource *r;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: error %d for resource %d: %s", resource->context, res, id, message);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((r = pw_impl_client_find_resource(client, id)) == NULL)
 | 
					 | 
				
			||||||
		return -EINVAL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_resource_emit_error(r, seq, res, message);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static struct pw_registry * core_get_registry(void *object, uint32_t version, size_t user_data_size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_context *this = resource->context;
 | 
					 | 
				
			||||||
	struct pw_global *global;
 | 
					 | 
				
			||||||
	struct pw_resource *registry_resource;
 | 
					 | 
				
			||||||
	struct resource_data *data;
 | 
					 | 
				
			||||||
	uint32_t new_id = user_data_size;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	registry_resource = pw_resource_new(client,
 | 
					 | 
				
			||||||
					    new_id,
 | 
					 | 
				
			||||||
					    PW_PERM_RWX,
 | 
					 | 
				
			||||||
					    PW_TYPE_INTERFACE_Registry,
 | 
					 | 
				
			||||||
					    version,
 | 
					 | 
				
			||||||
					    sizeof(*data));
 | 
					 | 
				
			||||||
	if (registry_resource == NULL) {
 | 
					 | 
				
			||||||
		res = -errno;
 | 
					 | 
				
			||||||
		goto error_resource;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data = pw_resource_get_user_data(registry_resource);
 | 
					 | 
				
			||||||
	pw_resource_add_listener(registry_resource,
 | 
					 | 
				
			||||||
				&data->resource_listener,
 | 
					 | 
				
			||||||
				&resource_events,
 | 
					 | 
				
			||||||
				registry_resource);
 | 
					 | 
				
			||||||
	pw_resource_add_object_listener(registry_resource,
 | 
					 | 
				
			||||||
				&data->object_listener,
 | 
					 | 
				
			||||||
				®istry_methods,
 | 
					 | 
				
			||||||
				registry_resource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_list_append(&this->registry_resource_list, ®istry_resource->link);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_list_for_each(global, &this->global_list, link) {
 | 
					 | 
				
			||||||
		uint32_t permissions = pw_global_get_permissions(global, client);
 | 
					 | 
				
			||||||
		if (PW_PERM_IS_R(permissions)) {
 | 
					 | 
				
			||||||
			pw_registry_resource_global(registry_resource,
 | 
					 | 
				
			||||||
						    global->id,
 | 
					 | 
				
			||||||
						    permissions,
 | 
					 | 
				
			||||||
						    global->type,
 | 
					 | 
				
			||||||
						    global->version,
 | 
					 | 
				
			||||||
						    &global->properties->dict);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return (struct pw_registry *)registry_resource;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error_resource:
 | 
					 | 
				
			||||||
	pw_log_error(NAME" %p: can't create registry resource: %m", this);
 | 
					 | 
				
			||||||
	pw_core_resource_errorf(client->core_resource, new_id,
 | 
					 | 
				
			||||||
			client->recv_seq, res,
 | 
					 | 
				
			||||||
			"can't create registry resource: %s", spa_strerror(res));
 | 
					 | 
				
			||||||
	pw_map_insert_at(&client->objects, new_id, NULL);
 | 
					 | 
				
			||||||
	pw_core_resource_remove_id(client->core_resource, new_id);
 | 
					 | 
				
			||||||
	errno = -res;
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void *
 | 
					 | 
				
			||||||
core_create_object(void *object,
 | 
					 | 
				
			||||||
		   const char *factory_name,
 | 
					 | 
				
			||||||
		   uint32_t type,
 | 
					 | 
				
			||||||
		   uint32_t version,
 | 
					 | 
				
			||||||
		   const struct spa_dict *props,
 | 
					 | 
				
			||||||
		   size_t user_data_size)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_impl_factory *factory;
 | 
					 | 
				
			||||||
	void *obj;
 | 
					 | 
				
			||||||
	struct pw_properties *properties;
 | 
					 | 
				
			||||||
	struct pw_context *this = client->context;
 | 
					 | 
				
			||||||
	uint32_t new_id = user_data_size;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	factory = pw_context_find_factory(this, factory_name);
 | 
					 | 
				
			||||||
	if (factory == NULL || factory->global == NULL)
 | 
					 | 
				
			||||||
		goto error_no_factory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!PW_PERM_IS_R(pw_global_get_permissions(factory->global, client)))
 | 
					 | 
				
			||||||
		goto error_no_factory;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (factory->info.type != type)
 | 
					 | 
				
			||||||
		goto error_type;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (factory->info.version < version)
 | 
					 | 
				
			||||||
		goto error_version;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (props) {
 | 
					 | 
				
			||||||
		properties = pw_properties_new_dict(props);
 | 
					 | 
				
			||||||
		if (properties == NULL)
 | 
					 | 
				
			||||||
			goto error_properties;
 | 
					 | 
				
			||||||
	} else
 | 
					 | 
				
			||||||
		properties = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* error will be posted */
 | 
					 | 
				
			||||||
	obj = pw_impl_factory_create_object(factory, resource, type, version, properties, new_id);
 | 
					 | 
				
			||||||
	if (obj == NULL)
 | 
					 | 
				
			||||||
		goto error_create_failed;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error_no_factory:
 | 
					 | 
				
			||||||
	res = -ENOENT;
 | 
					 | 
				
			||||||
	pw_log_error(NAME" %p: can't find factory '%s'", this, factory_name);
 | 
					 | 
				
			||||||
	pw_resource_errorf(resource, res, "unknown factory name %s", factory_name);
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_version:
 | 
					 | 
				
			||||||
error_type:
 | 
					 | 
				
			||||||
	res = -EPROTO;
 | 
					 | 
				
			||||||
	pw_log_error(NAME" %p: invalid resource type/version", this);
 | 
					 | 
				
			||||||
	pw_resource_errorf(resource, res, "wrong resource type/version");
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_properties:
 | 
					 | 
				
			||||||
	res = -errno;
 | 
					 | 
				
			||||||
	pw_log_error(NAME" %p: can't create properties: %m", this);
 | 
					 | 
				
			||||||
	pw_resource_errorf(resource, res, "can't create properties: %s", spa_strerror(res));
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_create_failed:
 | 
					 | 
				
			||||||
	res = -errno;
 | 
					 | 
				
			||||||
	goto error_exit;
 | 
					 | 
				
			||||||
error_exit:
 | 
					 | 
				
			||||||
	pw_map_insert_at(&client->objects, new_id, NULL);
 | 
					 | 
				
			||||||
	pw_core_resource_remove_id(client->core_resource, new_id);
 | 
					 | 
				
			||||||
	errno = -res;
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int core_destroy(void *object, void *proxy)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = object;
 | 
					 | 
				
			||||||
	struct pw_impl_client *client = resource->client;
 | 
					 | 
				
			||||||
	struct pw_resource *r = proxy;
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: destroy resource %p from client %p", resource->context, r, client);
 | 
					 | 
				
			||||||
	pw_resource_destroy(r);
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct pw_core_methods core_methods = {
 | 
					 | 
				
			||||||
	PW_VERSION_CORE_METHODS,
 | 
					 | 
				
			||||||
	.hello = core_hello,
 | 
					 | 
				
			||||||
	.sync = core_sync,
 | 
					 | 
				
			||||||
	.pong = core_pong,
 | 
					 | 
				
			||||||
	.error = core_error,
 | 
					 | 
				
			||||||
	.get_registry = core_get_registry,
 | 
					 | 
				
			||||||
	.create_object = core_create_object,
 | 
					 | 
				
			||||||
	.destroy = core_destroy,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void core_unbind_func(void *data)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_resource *resource = data;
 | 
					 | 
				
			||||||
	if (resource->id == 0)
 | 
					 | 
				
			||||||
		resource->client->core_resource = NULL;
 | 
					 | 
				
			||||||
	spa_list_remove(&resource->link);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct pw_resource_events core_resource_events = {
 | 
					 | 
				
			||||||
	PW_VERSION_RESOURCE_EVENTS,
 | 
					 | 
				
			||||||
	.destroy = core_unbind_func,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					 | 
				
			||||||
global_bind(void *_data,
 | 
					 | 
				
			||||||
	    struct pw_impl_client *client,
 | 
					 | 
				
			||||||
	    uint32_t permissions,
 | 
					 | 
				
			||||||
	    uint32_t version,
 | 
					 | 
				
			||||||
	    uint32_t id)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_context *this = _data;
 | 
					 | 
				
			||||||
	struct pw_global *global = this->global;
 | 
					 | 
				
			||||||
	struct pw_resource *resource;
 | 
					 | 
				
			||||||
	struct resource_data *data;
 | 
					 | 
				
			||||||
	int res;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
 | 
					 | 
				
			||||||
	if (resource == NULL) {
 | 
					 | 
				
			||||||
		res = -errno;
 | 
					 | 
				
			||||||
		goto error;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	data = pw_resource_get_user_data(resource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_resource_add_listener(resource,
 | 
					 | 
				
			||||||
			&data->resource_listener,
 | 
					 | 
				
			||||||
			&core_resource_events,
 | 
					 | 
				
			||||||
			resource);
 | 
					 | 
				
			||||||
	pw_resource_add_object_listener(resource,
 | 
					 | 
				
			||||||
			&data->object_listener,
 | 
					 | 
				
			||||||
			&core_methods, resource);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_list_append(&global->resource_list, &resource->link);
 | 
					 | 
				
			||||||
	pw_resource_set_bound_id(resource, global->id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (resource->id == 0)
 | 
					 | 
				
			||||||
		client->core_resource = resource;
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
		pw_core_resource_info(resource, &this->info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: bound to %d", this, resource->id);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
error:
 | 
					 | 
				
			||||||
	pw_log_error(NAME" %p: can't create resource: %m", this);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void global_destroy(void *object)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	struct pw_context *context = object;
 | 
					 | 
				
			||||||
	spa_hook_remove(&context->global_listener);
 | 
					 | 
				
			||||||
	context->global = NULL;
 | 
					 | 
				
			||||||
	pw_context_destroy(context);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static const struct pw_global_events global_events = {
 | 
					 | 
				
			||||||
	PW_VERSION_GLOBAL_EVENTS,
 | 
					 | 
				
			||||||
	.destroy = global_destroy,
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int load_module_profile(struct pw_context *this, const char *profile)
 | 
					static int load_module_profile(struct pw_context *this, const char *profile)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	pw_log_debug(NAME" %p: module profile %s", this, profile);
 | 
						pw_log_debug(NAME" %p: module profile %s", this, profile);
 | 
				
			||||||
| 
						 | 
					@ -466,6 +75,41 @@ static int load_module_profile(struct pw_context *this, const char *profile)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void fill_properties(struct pw_context *context)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_properties *properties = context->properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_NAME))
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_NAME, pw_get_client_name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_BINARY))
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_PROCESS_BINARY, pw_get_prgname());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_LANGUAGE)) {
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_LANGUAGE, getenv("LANG"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_ID)) {
 | 
				
			||||||
 | 
							pw_properties_setf(properties, PW_KEY_APP_PROCESS_ID, "%zd", (size_t) getpid());
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_USER))
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_PROCESS_USER, pw_get_user_name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_HOST))
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_PROCESS_HOST, pw_get_host_name());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_SESSION_ID)) {
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_APP_PROCESS_SESSION_ID,
 | 
				
			||||||
 | 
									  getenv("XDG_SESSION_ID"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!pw_properties_get(properties, PW_KEY_WINDOW_X11_DISPLAY)) {
 | 
				
			||||||
 | 
							pw_properties_set(properties, PW_KEY_WINDOW_X11_DISPLAY,
 | 
				
			||||||
 | 
									  getenv("DISPLAY"));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						pw_properties_set(properties, PW_KEY_CORE_VERSION, context->core->info.version);
 | 
				
			||||||
 | 
						pw_properties_set(properties, PW_KEY_CORE_NAME, context->core->info.name);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Create a new context object
 | 
					/** Create a new context object
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * \param main_loop the main loop to use
 | 
					 * \param main_loop the main loop to use
 | 
				
			||||||
| 
						 | 
					@ -481,7 +125,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct impl *impl;
 | 
						struct impl *impl;
 | 
				
			||||||
	struct pw_context *this;
 | 
						struct pw_context *this;
 | 
				
			||||||
	const char *name, *lib, *str;
 | 
						const char *lib, *str;
 | 
				
			||||||
	void *dbus_iface = NULL;
 | 
						void *dbus_iface = NULL;
 | 
				
			||||||
	uint32_t n_support;
 | 
						uint32_t n_support;
 | 
				
			||||||
	struct pw_properties *pr;
 | 
						struct pw_properties *pr;
 | 
				
			||||||
| 
						 | 
					@ -560,6 +204,7 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
 | 
				
			||||||
	pw_array_init(&this->factory_lib, 32);
 | 
						pw_array_init(&this->factory_lib, 32);
 | 
				
			||||||
	pw_map_init(&this->globals, 128, 32);
 | 
						pw_map_init(&this->globals, 128, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_init(&this->core_impl_list);
 | 
				
			||||||
	spa_list_init(&this->protocol_list);
 | 
						spa_list_init(&this->protocol_list);
 | 
				
			||||||
	spa_list_init(&this->core_list);
 | 
						spa_list_init(&this->core_list);
 | 
				
			||||||
	spa_list_init(&this->registry_resource_list);
 | 
						spa_list_init(&this->registry_resource_list);
 | 
				
			||||||
| 
						 | 
					@ -576,48 +221,20 @@ struct pw_context *pw_context_new(struct pw_loop *main_loop,
 | 
				
			||||||
	spa_list_init(&this->driver_list);
 | 
						spa_list_init(&this->driver_list);
 | 
				
			||||||
	spa_hook_list_init(&this->listener_list);
 | 
						spa_hook_list_init(&this->listener_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((name = pw_properties_get(properties, PW_KEY_CORE_NAME)) == NULL) {
 | 
						this->core = pw_context_create_core(this, pw_properties_copy(properties), 0);
 | 
				
			||||||
		pw_properties_setf(properties,
 | 
						if (this->core == NULL) {
 | 
				
			||||||
				   PW_KEY_CORE_NAME, "pipewire-%s-%d",
 | 
							res = -errno;
 | 
				
			||||||
				   pw_get_user_name(), getpid());
 | 
							goto error_free_loop;
 | 
				
			||||||
		name = pw_properties_get(properties, PW_KEY_CORE_NAME);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						pw_impl_core_register(this->core, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fill_properties(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((res = pw_data_loop_start(this->data_loop_impl)) < 0)
 | 
						if ((res = pw_data_loop_start(this->data_loop_impl)) < 0)
 | 
				
			||||||
		goto error_free_loop;
 | 
							goto error_free_loop;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->info.change_mask = 0;
 | 
					 | 
				
			||||||
	this->info.user_name = pw_get_user_name();
 | 
					 | 
				
			||||||
	this->info.host_name = pw_get_host_name();
 | 
					 | 
				
			||||||
	this->info.version = pw_get_library_version();
 | 
					 | 
				
			||||||
	srandom(time(NULL));
 | 
					 | 
				
			||||||
	this->info.cookie = random();
 | 
					 | 
				
			||||||
	this->info.name = name;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	this->sc_pagesize = sysconf(_SC_PAGESIZE);
 | 
						this->sc_pagesize = sysconf(_SC_PAGESIZE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->global = pw_global_new(this,
 | 
					 | 
				
			||||||
				     PW_TYPE_INTERFACE_Core,
 | 
					 | 
				
			||||||
				     PW_VERSION_CORE,
 | 
					 | 
				
			||||||
				     pw_properties_new(
 | 
					 | 
				
			||||||
					     PW_KEY_USER_NAME, this->info.user_name,
 | 
					 | 
				
			||||||
					     PW_KEY_HOST_NAME, this->info.host_name,
 | 
					 | 
				
			||||||
					     PW_KEY_CORE_NAME, this->info.name,
 | 
					 | 
				
			||||||
					     PW_KEY_CORE_VERSION, this->info.version,
 | 
					 | 
				
			||||||
					     NULL),
 | 
					 | 
				
			||||||
				     global_bind,
 | 
					 | 
				
			||||||
				     this);
 | 
					 | 
				
			||||||
	if (this->global == NULL) {
 | 
					 | 
				
			||||||
		res = -errno;
 | 
					 | 
				
			||||||
		goto error_free_loop;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	this->info.id = this->global->id;
 | 
					 | 
				
			||||||
	pw_properties_setf(this->properties, PW_KEY_OBJECT_ID, "%d", this->info.id);
 | 
					 | 
				
			||||||
	this->info.props = &this->properties->dict;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_global_add_listener(this->global, &this->global_listener, &global_events, this);
 | 
					 | 
				
			||||||
	pw_global_register(this->global);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((str = pw_properties_get(properties, PW_KEY_CONTEXT_PROFILE_MODULES)) == NULL)
 | 
						if ((str = pw_properties_get(properties, PW_KEY_CONTEXT_PROFILE_MODULES)) == NULL)
 | 
				
			||||||
		str = "default";
 | 
							str = "default";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -655,12 +272,11 @@ void pw_context_destroy(struct pw_context *context)
 | 
				
			||||||
	struct pw_resource *resource;
 | 
						struct pw_resource *resource;
 | 
				
			||||||
	struct pw_impl_node *node;
 | 
						struct pw_impl_node *node;
 | 
				
			||||||
	struct factory_entry *entry;
 | 
						struct factory_entry *entry;
 | 
				
			||||||
 | 
						struct pw_impl_core *core_impl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug(NAME" %p: destroy", context);
 | 
						pw_log_debug(NAME" %p: destroy", context);
 | 
				
			||||||
	pw_context_emit_destroy(context);
 | 
						pw_context_emit_destroy(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_hook_remove(&context->global_listener);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_list_consume(core, &context->core_list, link)
 | 
						spa_list_consume(core, &context->core_list, link)
 | 
				
			||||||
		pw_core_disconnect(core);
 | 
							pw_core_disconnect(core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -679,6 +295,9 @@ void pw_context_destroy(struct pw_context *context)
 | 
				
			||||||
	spa_list_consume(global, &context->global_list, link)
 | 
						spa_list_consume(global, &context->global_list, link)
 | 
				
			||||||
		pw_global_destroy(global);
 | 
							pw_global_destroy(global);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_consume(core_impl, &context->core_impl_list, link)
 | 
				
			||||||
 | 
							pw_impl_core_destroy(core_impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_log_debug(NAME" %p: free", context);
 | 
						pw_log_debug(NAME" %p: free", context);
 | 
				
			||||||
	pw_context_emit_free(context);
 | 
						pw_context_emit_free(context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -708,18 +327,6 @@ void *pw_context_get_user_data(struct pw_context *context)
 | 
				
			||||||
	return context->user_data;
 | 
						return context->user_data;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
const struct pw_core_info *pw_context_get_info(struct pw_context *context)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return &context->info;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
struct pw_global *pw_context_get_global(struct pw_context *context)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return context->global;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
void pw_context_add_listener(struct pw_context *context,
 | 
					void pw_context_add_listener(struct pw_context *context,
 | 
				
			||||||
			  struct spa_hook *listener,
 | 
								  struct spa_hook *listener,
 | 
				
			||||||
| 
						 | 
					@ -760,27 +367,11 @@ const struct pw_properties *pw_context_get_properties(struct pw_context *context
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict)
 | 
					int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_resource *resource;
 | 
					 | 
				
			||||||
	int changed;
 | 
						int changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	changed = pw_properties_update(context->properties, dict);
 | 
						changed = pw_properties_update(context->properties, dict);
 | 
				
			||||||
	context->info.props = &context->properties->dict;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_log_debug(NAME" %p: updated %d properties", context, changed);
 | 
						pw_log_debug(NAME" %p: updated %d properties", context, changed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!changed)
 | 
					 | 
				
			||||||
		return 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	context->info.change_mask = PW_CORE_CHANGE_MASK_PROPS;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	pw_context_emit_info_changed(context, &context->info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (context->global)
 | 
					 | 
				
			||||||
		spa_list_for_each(resource, &context->global->resource_list, link)
 | 
					 | 
				
			||||||
			pw_core_resource_info(resource, &context->info);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	context->info.change_mask = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return changed;
 | 
						return changed;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -85,8 +85,6 @@ struct pw_context_events {
 | 
				
			||||||
	void (*destroy) (void *data);
 | 
						void (*destroy) (void *data);
 | 
				
			||||||
	/** The context is being freed */
 | 
						/** The context is being freed */
 | 
				
			||||||
	void (*free) (void *data);
 | 
						void (*free) (void *data);
 | 
				
			||||||
	/** The context info changed,  use \ref pw_context_get_info() to get the updated info */
 | 
					 | 
				
			||||||
	void (*info_changed) (void *data, const struct pw_core_info *info);
 | 
					 | 
				
			||||||
	/** a new client object is added */
 | 
						/** a new client object is added */
 | 
				
			||||||
	void (*check_access) (void *data, struct pw_impl_client *client);
 | 
						void (*check_access) (void *data, struct pw_impl_client *client);
 | 
				
			||||||
	/** a new global object was added */
 | 
						/** a new global object was added */
 | 
				
			||||||
| 
						 | 
					@ -112,12 +110,6 @@ void pw_context_add_listener(struct pw_context *context,
 | 
				
			||||||
			  const struct pw_context_events *events,
 | 
								  const struct pw_context_events *events,
 | 
				
			||||||
			  void *data);
 | 
								  void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Get the context info object */
 | 
					 | 
				
			||||||
const struct pw_core_info *pw_context_get_info(struct pw_context *context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Get the context global object */
 | 
					 | 
				
			||||||
struct pw_global *pw_context_get_global(struct pw_context *context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Get the context properties */
 | 
					/** Get the context properties */
 | 
				
			||||||
const struct pw_properties *pw_context_get_properties(struct pw_context *context);
 | 
					const struct pw_properties *pw_context_get_properties(struct pw_context *context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,7 +276,7 @@ static struct pw_core *core_new(struct pw_context *context,
 | 
				
			||||||
		struct pw_properties *properties, size_t user_data_size)
 | 
							struct pw_properties *properties, size_t user_data_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_core *p;
 | 
						struct pw_core *p;
 | 
				
			||||||
	struct pw_protocol *protocol = NULL;
 | 
						struct pw_protocol *protocol;
 | 
				
			||||||
	const char *protocol_name;
 | 
						const char *protocol_name;
 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -292,7 +292,7 @@ static struct pw_core *core_new(struct pw_context *context,
 | 
				
			||||||
	if (properties == NULL)
 | 
						if (properties == NULL)
 | 
				
			||||||
		goto error_properties;
 | 
							goto error_properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_fill_connect_properties(context, properties);
 | 
						pw_properties_add(properties, &context->properties->dict);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p->proxy.core = p;
 | 
						p->proxy.core = p;
 | 
				
			||||||
	p->context = context;
 | 
						p->context = context;
 | 
				
			||||||
| 
						 | 
					@ -307,25 +307,20 @@ static struct pw_core *core_new(struct pw_context *context,
 | 
				
			||||||
	spa_list_init(&p->stream_list);
 | 
						spa_list_init(&p->stream_list);
 | 
				
			||||||
	spa_list_init(&p->filter_list);
 | 
						spa_list_init(&p->filter_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL) {
 | 
						if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL &&
 | 
				
			||||||
		if ((protocol_name = pw_properties_get(context->properties, PW_KEY_PROTOCOL)) == NULL) {
 | 
						    (protocol_name = pw_properties_get(context->properties, PW_KEY_PROTOCOL)) == NULL)
 | 
				
			||||||
			protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
 | 
							protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (protocol == NULL)
 | 
						protocol = pw_context_find_protocol(context, protocol_name);
 | 
				
			||||||
		protocol = pw_context_find_protocol(context, protocol_name);
 | 
					 | 
				
			||||||
	if (protocol == NULL) {
 | 
						if (protocol == NULL) {
 | 
				
			||||||
		res = -ENOTSUP;
 | 
							res = -ENOTSUP;
 | 
				
			||||||
		goto error_protocol;
 | 
							goto error_protocol;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p->conn = pw_protocol_new_client(protocol, properties);
 | 
						p->conn = pw_protocol_new_client(protocol, p, properties);
 | 
				
			||||||
	if (p->conn == NULL)
 | 
						if (p->conn == NULL)
 | 
				
			||||||
		goto error_connection;
 | 
							goto error_connection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	p->conn->core = p;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((res = pw_proxy_init(&p->proxy, PW_TYPE_INTERFACE_Core, PW_VERSION_CORE)) < 0)
 | 
						if ((res = pw_proxy_init(&p->proxy, PW_TYPE_INTERFACE_Core, PW_VERSION_CORE)) < 0)
 | 
				
			||||||
		goto error_proxy;
 | 
							goto error_proxy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -423,15 +418,12 @@ struct pw_core *
 | 
				
			||||||
pw_context_connect_self(struct pw_context *context, struct pw_properties *properties,
 | 
					pw_context_connect_self(struct pw_context *context, struct pw_properties *properties,
 | 
				
			||||||
	      size_t user_data_size)
 | 
						      size_t user_data_size)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	const struct pw_core_info *info;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (properties == NULL)
 | 
						if (properties == NULL)
 | 
				
			||||||
                properties = pw_properties_new(NULL, NULL);
 | 
					                properties = pw_properties_new(NULL, NULL);
 | 
				
			||||||
	if (properties == NULL)
 | 
						if (properties == NULL)
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	info = pw_context_get_info(context);
 | 
						pw_properties_set(properties, PW_KEY_REMOTE_NAME, "internal");
 | 
				
			||||||
	pw_properties_set(properties, PW_KEY_REMOTE_NAME, info->name);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return pw_context_connect(context, properties, user_data_size);
 | 
						return pw_context_connect(context, properties, user_data_size);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -280,7 +280,7 @@ static const struct pw_context_events context_events = {
 | 
				
			||||||
 * \memberof pw_impl_client
 | 
					 * \memberof pw_impl_client
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
struct pw_impl_client *pw_context_create_client(struct pw_context *context,
 | 
					struct pw_impl_client *pw_context_create_client(struct pw_impl_core *core,
 | 
				
			||||||
				struct pw_protocol *protocol,
 | 
									struct pw_protocol *protocol,
 | 
				
			||||||
				struct pw_properties *properties,
 | 
									struct pw_properties *properties,
 | 
				
			||||||
				size_t user_data_size)
 | 
									size_t user_data_size)
 | 
				
			||||||
| 
						 | 
					@ -299,7 +299,8 @@ struct pw_impl_client *pw_context_create_client(struct pw_context *context,
 | 
				
			||||||
	this = &impl->this;
 | 
						this = &impl->this;
 | 
				
			||||||
	pw_log_debug(NAME" %p: new", this);
 | 
						pw_log_debug(NAME" %p: new", this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->context = context;
 | 
						this->context = core->context;
 | 
				
			||||||
 | 
						this->core = core;
 | 
				
			||||||
	this->protocol = protocol;
 | 
						this->protocol = protocol;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (properties == NULL)
 | 
						if (properties == NULL)
 | 
				
			||||||
| 
						 | 
					@ -336,11 +337,11 @@ struct pw_impl_client *pw_context_create_client(struct pw_context *context,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_map_init(&this->objects, 0, 32);
 | 
						pw_map_init(&this->objects, 0, 32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_add_listener(context, &impl->context_listener, &context_events, impl);
 | 
						pw_context_add_listener(this->context, &impl->context_listener, &context_events, impl);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	this->info.props = &this->properties->dict;
 | 
						this->info.props = &this->properties->dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_emit_check_access(context, this);
 | 
						pw_context_emit_check_access(this->context, this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return this;
 | 
						return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -427,7 +428,7 @@ error_existed:
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
struct pw_context *pw_impl_client_get_context(struct pw_impl_client *client)
 | 
					struct pw_context *pw_impl_client_get_context(struct pw_impl_client *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	return client->context;
 | 
						return client->core->context;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
| 
						 | 
					@ -569,7 +570,8 @@ SPA_EXPORT
 | 
				
			||||||
int pw_impl_client_update_permissions(struct pw_impl_client *client,
 | 
					int pw_impl_client_update_permissions(struct pw_impl_client *client,
 | 
				
			||||||
		uint32_t n_permissions, const struct pw_permission *permissions)
 | 
							uint32_t n_permissions, const struct pw_permission *permissions)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_context *context = client->context;
 | 
						struct pw_impl_core *core = client->core;
 | 
				
			||||||
 | 
						struct pw_context *context = core->context;
 | 
				
			||||||
	struct pw_permission *def;
 | 
						struct pw_permission *def;
 | 
				
			||||||
	uint32_t i;
 | 
						uint32_t i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -603,7 +605,7 @@ int pw_impl_client_update_permissions(struct pw_impl_client *client,
 | 
				
			||||||
		else  {
 | 
							else  {
 | 
				
			||||||
			struct pw_global *global;
 | 
								struct pw_global *global;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			global = pw_context_find_global(client->context, permissions[i].id);
 | 
								global = pw_context_find_global(context, permissions[i].id);
 | 
				
			||||||
			if (global == NULL || global->id != permissions[i].id) {
 | 
								if (global == NULL || global->id != permissions[i].id) {
 | 
				
			||||||
				pw_log_warn(NAME" %p: invalid global %d", client, permissions[i].id);
 | 
									pw_log_warn(NAME" %p: invalid global %d", client, permissions[i].id);
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -110,7 +110,7 @@ struct pw_impl_client_events {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Create a new client. This is mainly used by protocols. */
 | 
					/** Create a new client. This is mainly used by protocols. */
 | 
				
			||||||
struct pw_impl_client *
 | 
					struct pw_impl_client *
 | 
				
			||||||
pw_context_create_client(struct pw_context *context,			/**< the context object */
 | 
					pw_context_create_client(struct pw_impl_core *core,		/**< the core object */
 | 
				
			||||||
			struct pw_protocol *prototol,		/**< the client protocol */
 | 
								struct pw_protocol *prototol,		/**< the client protocol */
 | 
				
			||||||
			struct pw_properties *properties,	/**< client properties */
 | 
								struct pw_properties *properties,	/**< client properties */
 | 
				
			||||||
			size_t user_data_size			/**< extra user data size */);
 | 
								size_t user_data_size			/**< extra user data size */);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										624
									
								
								src/pipewire/impl-core.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										624
									
								
								src/pipewire/impl-core.c
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,624 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright © 2019 Wim Taymans
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
				
			||||||
 | 
					 * copy of this software and associated documentation files (the "Software"),
 | 
				
			||||||
 | 
					 * to deal in the Software without restriction, including without limitation
 | 
				
			||||||
 | 
					 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
				
			||||||
 | 
					 * and/or sell copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					 * Software is furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					 * paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					 * Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
				
			||||||
 | 
					 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
				
			||||||
 | 
					 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
				
			||||||
 | 
					 * DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <spa/debug/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "pipewire/impl.h"
 | 
				
			||||||
 | 
					#include "pipewire/private.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "extensions/protocol-native.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define NAME "impl-core"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct resource_data {
 | 
				
			||||||
 | 
						struct spa_hook resource_listener;
 | 
				
			||||||
 | 
						struct spa_hook object_listener;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void * registry_bind(void *object, uint32_t id,
 | 
				
			||||||
 | 
							uint32_t type, uint32_t version, size_t user_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_context *context = resource->context;
 | 
				
			||||||
 | 
						struct pw_global *global;
 | 
				
			||||||
 | 
						uint32_t permissions, new_id = user_data_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((global = pw_context_find_global(context, id)) == NULL)
 | 
				
			||||||
 | 
							goto error_no_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						permissions = pw_global_get_permissions(global, client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!PW_PERM_IS_R(permissions))
 | 
				
			||||||
 | 
							goto error_no_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (global->type != type)
 | 
				
			||||||
 | 
							goto error_wrong_interface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("global %p: bind global id %d, iface %s/%d to %d", global, id,
 | 
				
			||||||
 | 
							     spa_debug_type_find_name(pw_type_info(), type), version, new_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (pw_global_bind(global, client, permissions, version, new_id) < 0)
 | 
				
			||||||
 | 
							goto error_exit_clean;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_no_id:
 | 
				
			||||||
 | 
						pw_log_debug("registry %p: no global with id %u to bind to %u", resource, id, new_id);
 | 
				
			||||||
 | 
						pw_resource_errorf(resource, -ENOENT, "no such global %u", id);
 | 
				
			||||||
 | 
						goto error_exit_clean;
 | 
				
			||||||
 | 
					error_wrong_interface:
 | 
				
			||||||
 | 
						pw_log_debug("registry %p: global with id %u has no interface %u", resource, id, type);
 | 
				
			||||||
 | 
						pw_resource_errorf(resource, -ENOENT, "no such interface %u", type);
 | 
				
			||||||
 | 
						goto error_exit_clean;
 | 
				
			||||||
 | 
					error_exit_clean:
 | 
				
			||||||
 | 
						/* unmark the new_id the map, the client does not yet know about the failed
 | 
				
			||||||
 | 
						 * bind and will choose the next id, which we would refuse when we don't mark
 | 
				
			||||||
 | 
						 * new_id as 'used and freed' */
 | 
				
			||||||
 | 
						pw_map_insert_at(&client->objects, new_id, NULL);
 | 
				
			||||||
 | 
						pw_core_resource_remove_id(client->core_resource, new_id);
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int registry_destroy(void *object, uint32_t id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_context *context = resource->context;
 | 
				
			||||||
 | 
						struct pw_global *global;
 | 
				
			||||||
 | 
						uint32_t permissions;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((global = pw_context_find_global(context, id)) == NULL)
 | 
				
			||||||
 | 
							goto error_no_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						permissions = pw_global_get_permissions(global, client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!PW_PERM_IS_R(permissions))
 | 
				
			||||||
 | 
							goto error_no_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!PW_PERM_IS_X(permissions))
 | 
				
			||||||
 | 
							goto error_not_allowed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug("global %p: destroy global id %d", global, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_global_destroy(global);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_no_id:
 | 
				
			||||||
 | 
						pw_log_debug("registry %p: no global with id %u to destroy", resource, id);
 | 
				
			||||||
 | 
						res = -ENOENT;
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_not_allowed:
 | 
				
			||||||
 | 
						pw_log_debug("registry %p: destroy of id %u not allowed", resource, id);
 | 
				
			||||||
 | 
						res = -EPERM;
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_exit:
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_registry_methods registry_methods = {
 | 
				
			||||||
 | 
						PW_VERSION_REGISTRY_METHODS,
 | 
				
			||||||
 | 
						.bind = registry_bind,
 | 
				
			||||||
 | 
						.destroy = registry_destroy
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void destroy_registry_resource(void *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						spa_list_remove(&resource->link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_resource_events resource_events = {
 | 
				
			||||||
 | 
						PW_VERSION_RESOURCE_EVENTS,
 | 
				
			||||||
 | 
						.destroy = destroy_registry_resource
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int destroy_resource(void *object, void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (resource &&
 | 
				
			||||||
 | 
						    resource != client->core_resource) {
 | 
				
			||||||
 | 
							pw_resource_remove(resource);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int core_hello(void *object, uint32_t version)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_context *context = client->context;
 | 
				
			||||||
 | 
						struct pw_impl_core *this = client->core;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: hello %d from resource %p", context, version, resource);
 | 
				
			||||||
 | 
						pw_map_for_each(&client->objects, destroy_resource, client);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->info.change_mask = PW_CORE_CHANGE_MASK_ALL;
 | 
				
			||||||
 | 
						pw_core_resource_info(resource, &this->info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (version >= 3) {
 | 
				
			||||||
 | 
							if ((res = pw_global_bind(client->global, client,
 | 
				
			||||||
 | 
									PW_PERM_RWX, PW_VERSION_CLIENT, 1)) < 0)
 | 
				
			||||||
 | 
								return res;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int core_sync(void *object, uint32_t id, int seq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						pw_log_trace(NAME" %p: sync %d for resource %d", resource->context, seq, id);
 | 
				
			||||||
 | 
						pw_core_resource_done(resource, id, seq);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int core_pong(void *object, uint32_t id, int seq)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_resource *r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: pong %d for resource %d", resource->context, seq, id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((r = pw_impl_client_find_resource(client, id)) == NULL)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_resource_emit_pong(r, seq);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int core_error(void *object, uint32_t id, int seq, int res, const char *message)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_resource *r;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: error %d for resource %d: %s", resource->context, res, id, message);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((r = pw_impl_client_find_resource(client, id)) == NULL)
 | 
				
			||||||
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_resource_emit_error(r, seq, res, message);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct pw_registry * core_get_registry(void *object, uint32_t version, size_t user_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_context *context = client->context;
 | 
				
			||||||
 | 
						struct pw_global *global;
 | 
				
			||||||
 | 
						struct pw_resource *registry_resource;
 | 
				
			||||||
 | 
						struct resource_data *data;
 | 
				
			||||||
 | 
						uint32_t new_id = user_data_size;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						registry_resource = pw_resource_new(client,
 | 
				
			||||||
 | 
										    new_id,
 | 
				
			||||||
 | 
										    PW_PERM_RWX,
 | 
				
			||||||
 | 
										    PW_TYPE_INTERFACE_Registry,
 | 
				
			||||||
 | 
										    version,
 | 
				
			||||||
 | 
										    sizeof(*data));
 | 
				
			||||||
 | 
						if (registry_resource == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							goto error_resource;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = pw_resource_get_user_data(registry_resource);
 | 
				
			||||||
 | 
						pw_resource_add_listener(registry_resource,
 | 
				
			||||||
 | 
									&data->resource_listener,
 | 
				
			||||||
 | 
									&resource_events,
 | 
				
			||||||
 | 
									registry_resource);
 | 
				
			||||||
 | 
						pw_resource_add_object_listener(registry_resource,
 | 
				
			||||||
 | 
									&data->object_listener,
 | 
				
			||||||
 | 
									®istry_methods,
 | 
				
			||||||
 | 
									registry_resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_append(&context->registry_resource_list, ®istry_resource->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_for_each(global, &context->global_list, link) {
 | 
				
			||||||
 | 
							uint32_t permissions = pw_global_get_permissions(global, client);
 | 
				
			||||||
 | 
							if (PW_PERM_IS_R(permissions)) {
 | 
				
			||||||
 | 
								pw_registry_resource_global(registry_resource,
 | 
				
			||||||
 | 
											    global->id,
 | 
				
			||||||
 | 
											    permissions,
 | 
				
			||||||
 | 
											    global->type,
 | 
				
			||||||
 | 
											    global->version,
 | 
				
			||||||
 | 
											    &global->properties->dict);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return (struct pw_registry *)registry_resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_resource:
 | 
				
			||||||
 | 
						pw_log_error(NAME" %p: can't create registry resource: %m", context);
 | 
				
			||||||
 | 
						pw_core_resource_errorf(client->core_resource, new_id,
 | 
				
			||||||
 | 
								client->recv_seq, res,
 | 
				
			||||||
 | 
								"can't create registry resource: %s", spa_strerror(res));
 | 
				
			||||||
 | 
						pw_map_insert_at(&client->objects, new_id, NULL);
 | 
				
			||||||
 | 
						pw_core_resource_remove_id(client->core_resource, new_id);
 | 
				
			||||||
 | 
						errno = -res;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *
 | 
				
			||||||
 | 
					core_create_object(void *object,
 | 
				
			||||||
 | 
							   const char *factory_name,
 | 
				
			||||||
 | 
							   uint32_t type,
 | 
				
			||||||
 | 
							   uint32_t version,
 | 
				
			||||||
 | 
							   const struct spa_dict *props,
 | 
				
			||||||
 | 
							   size_t user_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_impl_factory *factory;
 | 
				
			||||||
 | 
						void *obj;
 | 
				
			||||||
 | 
						struct pw_properties *properties;
 | 
				
			||||||
 | 
						struct pw_context *context = client->context;
 | 
				
			||||||
 | 
						uint32_t new_id = user_data_size;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						factory = pw_context_find_factory(context, factory_name);
 | 
				
			||||||
 | 
						if (factory == NULL || factory->global == NULL)
 | 
				
			||||||
 | 
							goto error_no_factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!PW_PERM_IS_R(pw_global_get_permissions(factory->global, client)))
 | 
				
			||||||
 | 
							goto error_no_factory;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (factory->info.type != type)
 | 
				
			||||||
 | 
							goto error_type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (factory->info.version < version)
 | 
				
			||||||
 | 
							goto error_version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (props) {
 | 
				
			||||||
 | 
							properties = pw_properties_new_dict(props);
 | 
				
			||||||
 | 
							if (properties == NULL)
 | 
				
			||||||
 | 
								goto error_properties;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
 | 
							properties = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* error will be posted */
 | 
				
			||||||
 | 
						obj = pw_impl_factory_create_object(factory, resource, type, version, properties, new_id);
 | 
				
			||||||
 | 
						if (obj == NULL)
 | 
				
			||||||
 | 
							goto error_create_failed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_no_factory:
 | 
				
			||||||
 | 
						res = -ENOENT;
 | 
				
			||||||
 | 
						pw_log_error(NAME" %p: can't find factory '%s'", context, factory_name);
 | 
				
			||||||
 | 
						pw_resource_errorf(resource, res, "unknown factory name %s", factory_name);
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_version:
 | 
				
			||||||
 | 
					error_type:
 | 
				
			||||||
 | 
						res = -EPROTO;
 | 
				
			||||||
 | 
						pw_log_error(NAME" %p: invalid resource type/version", context);
 | 
				
			||||||
 | 
						pw_resource_errorf(resource, res, "wrong resource type/version");
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_properties:
 | 
				
			||||||
 | 
						res = -errno;
 | 
				
			||||||
 | 
						pw_log_error(NAME" %p: can't create properties: %m", context);
 | 
				
			||||||
 | 
						pw_resource_errorf(resource, res, "can't create properties: %s", spa_strerror(res));
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_create_failed:
 | 
				
			||||||
 | 
						res = -errno;
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					error_exit:
 | 
				
			||||||
 | 
						pw_map_insert_at(&client->objects, new_id, NULL);
 | 
				
			||||||
 | 
						pw_core_resource_remove_id(client->core_resource, new_id);
 | 
				
			||||||
 | 
						errno = -res;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int core_destroy(void *object, void *proxy)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = object;
 | 
				
			||||||
 | 
						struct pw_impl_client *client = resource->client;
 | 
				
			||||||
 | 
						struct pw_impl_core *this = client->core;
 | 
				
			||||||
 | 
						struct pw_resource *r = proxy;
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: destroy resource %p from client %p", this, r, client);
 | 
				
			||||||
 | 
						pw_resource_destroy(r);
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_core_methods core_methods = {
 | 
				
			||||||
 | 
						PW_VERSION_CORE_METHODS,
 | 
				
			||||||
 | 
						.hello = core_hello,
 | 
				
			||||||
 | 
						.sync = core_sync,
 | 
				
			||||||
 | 
						.pong = core_pong,
 | 
				
			||||||
 | 
						.error = core_error,
 | 
				
			||||||
 | 
						.get_registry = core_get_registry,
 | 
				
			||||||
 | 
						.create_object = core_create_object,
 | 
				
			||||||
 | 
						.destroy = core_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					struct pw_impl_core *pw_context_create_core(struct pw_context *context,
 | 
				
			||||||
 | 
									  struct pw_properties *properties,
 | 
				
			||||||
 | 
									  size_t user_data_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_impl_core *this;
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (properties == NULL)
 | 
				
			||||||
 | 
							properties = pw_properties_new(NULL, NULL);
 | 
				
			||||||
 | 
						if (properties == NULL)
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this = calloc(1, sizeof(*this) + user_data_size);
 | 
				
			||||||
 | 
						if (this == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							goto error_exit;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->context = context;
 | 
				
			||||||
 | 
						this->properties = properties;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((name = pw_properties_get(properties, PW_KEY_CORE_NAME)) == NULL) {
 | 
				
			||||||
 | 
							pw_properties_setf(properties,
 | 
				
			||||||
 | 
									   PW_KEY_CORE_NAME, "pipewire-%s-%d",
 | 
				
			||||||
 | 
									   pw_get_user_name(), getpid());
 | 
				
			||||||
 | 
							name = pw_properties_get(properties, PW_KEY_CORE_NAME);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						this->info.user_name = pw_get_user_name();
 | 
				
			||||||
 | 
						this->info.host_name = pw_get_host_name();
 | 
				
			||||||
 | 
						this->info.version = pw_get_library_version();
 | 
				
			||||||
 | 
						srandom(time(NULL));
 | 
				
			||||||
 | 
						this->info.cookie = random();
 | 
				
			||||||
 | 
						this->info.name = name;
 | 
				
			||||||
 | 
						spa_hook_list_init(&this->listener_list);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (user_data_size > 0)
 | 
				
			||||||
 | 
							this->user_data = SPA_MEMBER(this, sizeof(*this), void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: new %s", this, name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return this;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_exit:
 | 
				
			||||||
 | 
						if (properties)
 | 
				
			||||||
 | 
							pw_properties_free(properties);
 | 
				
			||||||
 | 
						errno = -res;
 | 
				
			||||||
 | 
						return NULL;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					struct pw_impl_core *pw_context_get_default_core(struct pw_context *context)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return context->core;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					void pw_impl_core_destroy(struct pw_impl_core *core)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: destroy", core);
 | 
				
			||||||
 | 
						pw_impl_core_emit_destroy(core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (core->registered)
 | 
				
			||||||
 | 
							spa_list_remove(&core->link);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (core->global) {
 | 
				
			||||||
 | 
							spa_hook_remove(&core->global_listener);
 | 
				
			||||||
 | 
							pw_global_destroy(core->global);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_impl_core_emit_free(core);
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: free", core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_properties_free(core->properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						free(core);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void core_unbind_func(void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource = data;
 | 
				
			||||||
 | 
						if (resource->id == 0)
 | 
				
			||||||
 | 
							resource->client->core_resource = NULL;
 | 
				
			||||||
 | 
						spa_list_remove(&resource->link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_resource_events core_resource_events = {
 | 
				
			||||||
 | 
						PW_VERSION_RESOURCE_EVENTS,
 | 
				
			||||||
 | 
						.destroy = core_unbind_func,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int
 | 
				
			||||||
 | 
					global_bind(void *_data,
 | 
				
			||||||
 | 
						    struct pw_impl_client *client,
 | 
				
			||||||
 | 
						    uint32_t permissions,
 | 
				
			||||||
 | 
						    uint32_t version,
 | 
				
			||||||
 | 
						    uint32_t id)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_impl_core *this = _data;
 | 
				
			||||||
 | 
						struct pw_global *global = this->global;
 | 
				
			||||||
 | 
						struct pw_resource *resource;
 | 
				
			||||||
 | 
						struct resource_data *data;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						resource = pw_resource_new(client, id, permissions, global->type, version, sizeof(*data));
 | 
				
			||||||
 | 
						if (resource == NULL) {
 | 
				
			||||||
 | 
							res = -errno;
 | 
				
			||||||
 | 
							goto error;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						data = pw_resource_get_user_data(resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_resource_add_listener(resource,
 | 
				
			||||||
 | 
								&data->resource_listener,
 | 
				
			||||||
 | 
								&core_resource_events,
 | 
				
			||||||
 | 
								resource);
 | 
				
			||||||
 | 
						pw_resource_add_object_listener(resource,
 | 
				
			||||||
 | 
								&data->object_listener,
 | 
				
			||||||
 | 
								&core_methods, resource);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_append(&global->resource_list, &resource->link);
 | 
				
			||||||
 | 
						pw_resource_set_bound_id(resource, global->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (resource->id == 0) {
 | 
				
			||||||
 | 
							client->core_resource = resource;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						else {
 | 
				
			||||||
 | 
							this->info.change_mask = PW_CORE_CHANGE_MASK_ALL;
 | 
				
			||||||
 | 
							pw_core_resource_info(resource, &this->info);
 | 
				
			||||||
 | 
							this->info.change_mask = 0;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: bound to %d", this, resource->id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error:
 | 
				
			||||||
 | 
						pw_log_error(NAME" %p: can't create resource: %m", this);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void global_destroy(void *object)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_impl_core *core = object;
 | 
				
			||||||
 | 
						spa_hook_remove(&core->global_listener);
 | 
				
			||||||
 | 
						core->global = NULL;
 | 
				
			||||||
 | 
						pw_impl_core_destroy(core);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const struct pw_global_events global_events = {
 | 
				
			||||||
 | 
						PW_VERSION_GLOBAL_EVENTS,
 | 
				
			||||||
 | 
						.destroy = global_destroy,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					const struct pw_properties *pw_impl_core_get_properties(struct pw_impl_core *core)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return core->properties;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					int pw_impl_core_update_properties(struct pw_impl_core *core, const struct spa_dict *dict)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_resource *resource;
 | 
				
			||||||
 | 
						int changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						changed = pw_properties_update(core->properties, dict);
 | 
				
			||||||
 | 
						core->info.props = &core->properties->dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_log_debug(NAME" %p: updated %d properties", core, changed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!changed)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core->info.change_mask |= PW_CORE_CHANGE_MASK_PROPS;
 | 
				
			||||||
 | 
						if (core->global)
 | 
				
			||||||
 | 
							spa_list_for_each(resource, &core->global->resource_list, link)
 | 
				
			||||||
 | 
								pw_core_resource_info(resource, &core->info);
 | 
				
			||||||
 | 
						core->info.change_mask = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return changed;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					int pw_impl_core_register(struct pw_impl_core *core,
 | 
				
			||||||
 | 
								 struct pw_properties *properties)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct pw_context *context = core->context;
 | 
				
			||||||
 | 
						int res;
 | 
				
			||||||
 | 
						const char *keys[] = {
 | 
				
			||||||
 | 
							PW_KEY_USER_NAME,
 | 
				
			||||||
 | 
							PW_KEY_HOST_NAME,
 | 
				
			||||||
 | 
							PW_KEY_CORE_NAME,
 | 
				
			||||||
 | 
							PW_KEY_CORE_VERSION,
 | 
				
			||||||
 | 
							NULL
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (core->registered)
 | 
				
			||||||
 | 
							goto error_existed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (properties == NULL)
 | 
				
			||||||
 | 
							properties = pw_properties_new(NULL, NULL);
 | 
				
			||||||
 | 
						if (properties == NULL)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_properties_update_keys(properties, &core->properties->dict, keys);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        core->global = pw_global_new(context,
 | 
				
			||||||
 | 
										PW_TYPE_INTERFACE_Core,
 | 
				
			||||||
 | 
										PW_VERSION_CORE,
 | 
				
			||||||
 | 
										properties,
 | 
				
			||||||
 | 
										global_bind,
 | 
				
			||||||
 | 
										core);
 | 
				
			||||||
 | 
						if (core->global == NULL)
 | 
				
			||||||
 | 
							return -errno;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						spa_list_append(&context->core_impl_list, &core->link);
 | 
				
			||||||
 | 
						core->registered = true;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						core->info.id = core->global->id;
 | 
				
			||||||
 | 
						pw_properties_setf(core->properties, PW_KEY_OBJECT_ID, "%d", core->info.id);
 | 
				
			||||||
 | 
						core->info.props = &core->properties->dict;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_impl_core_emit_initialized(core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						pw_global_add_listener(core->global, &core->global_listener, &global_events, core);
 | 
				
			||||||
 | 
						pw_global_register(core->global);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					error_existed:
 | 
				
			||||||
 | 
						res = -EEXIST;
 | 
				
			||||||
 | 
						goto error_exit;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					error_exit:
 | 
				
			||||||
 | 
						if (properties)
 | 
				
			||||||
 | 
							pw_properties_free(properties);
 | 
				
			||||||
 | 
						return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					void *pw_impl_core_get_user_data(struct pw_impl_core *core)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return core->user_data;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					struct pw_global *pw_impl_core_get_global(struct pw_impl_core *core)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return core->global;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SPA_EXPORT
 | 
				
			||||||
 | 
					void pw_impl_core_add_listener(struct pw_impl_core *core,
 | 
				
			||||||
 | 
								     struct spa_hook *listener,
 | 
				
			||||||
 | 
								     const struct pw_impl_core_events *events,
 | 
				
			||||||
 | 
								     void *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						spa_hook_list_append(&core->listener_list, listener, events, data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										94
									
								
								src/pipewire/impl-core.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/pipewire/impl-core.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,94 @@
 | 
				
			||||||
 | 
					/* PipeWire
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Copyright © 2018 Wim Taymans
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Permission is hereby granted, free of charge, to any person obtaining a
 | 
				
			||||||
 | 
					 * copy of this software and associated documentation files (the "Software"),
 | 
				
			||||||
 | 
					 * to deal in the Software without restriction, including without limitation
 | 
				
			||||||
 | 
					 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 | 
				
			||||||
 | 
					 * and/or sell copies of the Software, and to permit persons to whom the
 | 
				
			||||||
 | 
					 * Software is furnished to do so, subject to the following conditions:
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The above copyright notice and this permission notice (including the next
 | 
				
			||||||
 | 
					 * paragraph) shall be included in all copies or substantial portions of the
 | 
				
			||||||
 | 
					 * Software.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
				
			||||||
 | 
					 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
				
			||||||
 | 
					 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 | 
				
			||||||
 | 
					 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
				
			||||||
 | 
					 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 | 
				
			||||||
 | 
					 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 | 
				
			||||||
 | 
					 * DEALINGS IN THE SOFTWARE.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef PIPEWIRE_IMPL_CORE_H
 | 
				
			||||||
 | 
					#define PIPEWIRE_IMPL_CORE_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					extern "C" {
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** \class pw_impl_core
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * \brief PipeWire core interface.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * The core is used to make objects on demand.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct pw_impl_core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <pipewire/context.h>
 | 
				
			||||||
 | 
					#include <pipewire/global.h>
 | 
				
			||||||
 | 
					#include <pipewire/properties.h>
 | 
				
			||||||
 | 
					#include <pipewire/resource.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Factory events, listen to them with \ref pw_impl_core_add_listener */
 | 
				
			||||||
 | 
					struct pw_impl_core_events {
 | 
				
			||||||
 | 
					#define PW_VERSION_IMPL_CORE_EVENTS	0
 | 
				
			||||||
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/** the core is destroyed */
 | 
				
			||||||
 | 
					        void (*destroy) (void *data);
 | 
				
			||||||
 | 
						/** the core is freed */
 | 
				
			||||||
 | 
					        void (*free) (void *data);
 | 
				
			||||||
 | 
						/** the core is initialized */
 | 
				
			||||||
 | 
					        void (*initialized) (void *data);
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pw_impl_core *pw_context_create_core(struct pw_context *context,
 | 
				
			||||||
 | 
									  struct pw_properties *properties,
 | 
				
			||||||
 | 
									  size_t user_data_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* get the default core in a context */
 | 
				
			||||||
 | 
					struct pw_impl_core *pw_context_get_default_core(struct pw_context *context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Get the core properties */
 | 
				
			||||||
 | 
					const struct pw_properties *pw_impl_core_get_properties(struct pw_impl_core *core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Get the core information */
 | 
				
			||||||
 | 
					const struct pw_core_info *pw_impl_core_get_info(struct pw_impl_core *core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Update the core properties */
 | 
				
			||||||
 | 
					int pw_impl_core_update_properties(struct pw_impl_core *core, const struct spa_dict *dict);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int pw_impl_core_register(struct pw_impl_core *core,
 | 
				
			||||||
 | 
								struct pw_properties *properties);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pw_impl_core_destroy(struct pw_impl_core *core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void *pw_impl_core_get_user_data(struct pw_impl_core *core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Get the global of this core */
 | 
				
			||||||
 | 
					struct pw_global *pw_impl_core_get_global(struct pw_impl_core *core);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/** Add an event listener */
 | 
				
			||||||
 | 
					void pw_impl_core_add_listener(struct pw_impl_core *core,
 | 
				
			||||||
 | 
								     struct spa_hook *listener,
 | 
				
			||||||
 | 
								     const struct pw_impl_core_events *events,
 | 
				
			||||||
 | 
								     void *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef __cplusplus
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* PIPEWIRE_IMPL_CORE_H */
 | 
				
			||||||
| 
						 | 
					@ -38,6 +38,7 @@ struct pw_resource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <pipewire/pipewire.h>
 | 
					#include <pipewire/pipewire.h>
 | 
				
			||||||
#include <pipewire/control.h>
 | 
					#include <pipewire/control.h>
 | 
				
			||||||
 | 
					#include <pipewire/impl-core.h>
 | 
				
			||||||
#include <pipewire/impl-client.h>
 | 
					#include <pipewire/impl-client.h>
 | 
				
			||||||
#include <pipewire/impl-device.h>
 | 
					#include <pipewire/impl-device.h>
 | 
				
			||||||
#include <pipewire/impl-factory.h>
 | 
					#include <pipewire/impl-factory.h>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
pipewire_headers = [
 | 
					pipewire_headers = [
 | 
				
			||||||
  'array.h',
 | 
					  'array.h',
 | 
				
			||||||
  'buffers.h',
 | 
					  'buffers.h',
 | 
				
			||||||
 | 
					  'impl-core.h',
 | 
				
			||||||
  'impl-client.h',
 | 
					  'impl-client.h',
 | 
				
			||||||
  'client.h',
 | 
					  'client.h',
 | 
				
			||||||
  'context.h',
 | 
					  'context.h',
 | 
				
			||||||
| 
						 | 
					@ -42,6 +43,7 @@ pipewire_headers = [
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pipewire_sources = [
 | 
					pipewire_sources = [
 | 
				
			||||||
  'buffers.c',
 | 
					  'buffers.c',
 | 
				
			||||||
 | 
					  'impl-core.c',
 | 
				
			||||||
  'impl-client.c',
 | 
					  'impl-client.c',
 | 
				
			||||||
  'context.c',
 | 
					  'context.c',
 | 
				
			||||||
  'control.c',
 | 
					  'control.c',
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -496,63 +496,6 @@ const char *pw_get_client_name(void)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/** Fill connectremote properties
 | 
					 | 
				
			||||||
 * \param properties a \ref pw_properties
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Fill \a properties with a set of default properties for connecting to a PipeWire instance.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \memberof pw_pipewire
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
void pw_fill_connect_properties(struct pw_context *context, struct pw_properties *properties)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	const char *val;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_NAME))
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_NAME, pw_get_client_name());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_BINARY))
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_PROCESS_BINARY, pw_get_prgname());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_LANGUAGE)) {
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_LANGUAGE, getenv("LANG"));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_ID)) {
 | 
					 | 
				
			||||||
		pw_properties_setf(properties, PW_KEY_APP_PROCESS_ID, "%zd", (size_t) getpid());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_USER))
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_PROCESS_USER, pw_get_user_name());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_HOST))
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_PROCESS_HOST, pw_get_host_name());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_APP_PROCESS_SESSION_ID)) {
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_APP_PROCESS_SESSION_ID,
 | 
					 | 
				
			||||||
				  getenv("XDG_SESSION_ID"));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (!pw_properties_get(properties, PW_KEY_WINDOW_X11_DISPLAY)) {
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_WINDOW_X11_DISPLAY,
 | 
					 | 
				
			||||||
				  getenv("DISPLAY"));
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	pw_properties_set(properties, PW_KEY_CORE_VERSION, context->info.version);
 | 
					 | 
				
			||||||
	pw_properties_set(properties, PW_KEY_CORE_NAME, context->info.name);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if ((val = pw_properties_get(context->properties, PW_KEY_CORE_DAEMON)))
 | 
					 | 
				
			||||||
		pw_properties_set(properties, PW_KEY_CORE_DAEMON, val);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Fill stream properties
 | 
					 | 
				
			||||||
 * \param properties a \ref pw_properties
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * Fill \a properties with a set of default stream properties.
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * \memberof pw_pipewire
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
SPA_EXPORT
 | 
					 | 
				
			||||||
void pw_fill_stream_properties(struct pw_context *context, struct pw_properties *properties)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/** Reverse the direction \memberof pw_pipewire */
 | 
					/** Reverse the direction \memberof pw_pipewire */
 | 
				
			||||||
SPA_EXPORT
 | 
					SPA_EXPORT
 | 
				
			||||||
enum pw_direction pw_direction_reverse(enum pw_direction direction)
 | 
					enum pw_direction pw_direction_reverse(enum pw_direction direction)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -133,12 +133,6 @@ pw_get_host_name(void);
 | 
				
			||||||
const char *
 | 
					const char *
 | 
				
			||||||
pw_get_client_name(void);
 | 
					pw_get_client_name(void);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void
 | 
					 | 
				
			||||||
pw_fill_connect_properties(struct pw_context *context, struct pw_properties *properties);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void
 | 
					 | 
				
			||||||
pw_fill_stream_properties(struct pw_context *context, struct pw_properties *properties);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum pw_direction
 | 
					enum pw_direction
 | 
				
			||||||
pw_direction_reverse(enum pw_direction direction);
 | 
					pw_direction_reverse(enum pw_direction direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -95,10 +95,33 @@ struct protocol_compat_v2 {
 | 
				
			||||||
	struct pw_map types;
 | 
						struct pw_map types;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define pw_impl_core_emit(s,m,v,...) spa_hook_list_call(&s->listener_list, struct pw_impl_core_events, m, v, ##__VA_ARGS__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define pw_impl_core_emit_destroy(s)		pw_impl_core_emit(s, destroy, 0)
 | 
				
			||||||
 | 
					#define pw_impl_core_emit_free(s)		pw_impl_core_emit(s, free, 0)
 | 
				
			||||||
 | 
					#define pw_impl_core_emit_initialized(s)	pw_impl_core_emit(s, initialized, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct pw_impl_core {
 | 
				
			||||||
 | 
						struct pw_context *context;
 | 
				
			||||||
 | 
						struct spa_list link;			/**< link in context object core_impl list */
 | 
				
			||||||
 | 
						struct pw_global *global;		/**< global object created for this core */
 | 
				
			||||||
 | 
						struct spa_hook global_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pw_properties *properties;	/**< core properties */
 | 
				
			||||||
 | 
						struct pw_core_info info;		/**< core info */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_hook_list listener_list;
 | 
				
			||||||
 | 
						void *user_data;			/**< extra user data */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned int registered:1;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_impl_client {
 | 
					struct pw_impl_client {
 | 
				
			||||||
 | 
						struct pw_impl_core *core;		/**< core object */
 | 
				
			||||||
	struct pw_context *context;		/**< context object */
 | 
						struct pw_context *context;		/**< context object */
 | 
				
			||||||
	struct spa_list link;		/**< link in context object client list */
 | 
					
 | 
				
			||||||
	struct pw_global *global;	/**< global object created for this client */
 | 
						struct spa_list link;			/**< link in context object client list */
 | 
				
			||||||
 | 
						struct pw_global *global;		/**< global object created for this client */
 | 
				
			||||||
	struct spa_hook global_listener;
 | 
						struct spa_hook global_listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_permission_func_t permission_func;	/**< get permissions of an object */
 | 
						pw_permission_func_t permission_func;	/**< get permissions of an object */
 | 
				
			||||||
| 
						 | 
					@ -201,10 +224,7 @@ pw_core_resource_errorf(struct pw_resource *resource, uint32_t id, int seq,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct pw_context {
 | 
					struct pw_context {
 | 
				
			||||||
	struct pw_global *global;	/**< the global of the context */
 | 
						struct pw_impl_core *core;		/**< core object */
 | 
				
			||||||
	struct spa_hook global_listener;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	struct pw_core_info info;	/**< info about the core */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_properties *properties;	/**< properties of the context */
 | 
						struct pw_properties *properties;	/**< properties of the context */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -212,6 +232,7 @@ struct pw_context {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_map globals;			/**< map of globals */
 | 
						struct pw_map globals;			/**< map of globals */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct spa_list core_impl_list;		/**< list of core_imp */
 | 
				
			||||||
	struct spa_list protocol_list;		/**< list of protocols */
 | 
						struct spa_list protocol_list;		/**< list of protocols */
 | 
				
			||||||
	struct spa_list core_list;		/**< list of core connections */
 | 
						struct spa_list core_list;		/**< list of core connections */
 | 
				
			||||||
	struct spa_list registry_resource_list;	/**< list of registry resources */
 | 
						struct spa_list registry_resource_list;	/**< list of registry resources */
 | 
				
			||||||
| 
						 | 
					@ -675,7 +696,7 @@ struct pw_impl_link {
 | 
				
			||||||
struct pw_resource {
 | 
					struct pw_resource {
 | 
				
			||||||
	struct spa_interface impl;	/**< object implementation */
 | 
						struct spa_interface impl;	/**< object implementation */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_context *context;		/**< the context object */
 | 
						struct pw_context *context;	/**< the context object */
 | 
				
			||||||
	struct spa_list link;		/**< link in global resource_list */
 | 
						struct spa_list link;		/**< link in global resource_list */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_impl_client *client;	/**< owner client */
 | 
						struct pw_impl_client *client;	/**< owner client */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +66,8 @@ struct pw_protocol_server {
 | 
				
			||||||
	struct spa_list link;		/**< link in protocol server_list */
 | 
						struct spa_list link;		/**< link in protocol server_list */
 | 
				
			||||||
	struct pw_protocol *protocol;	/**< the owner protocol */
 | 
						struct pw_protocol *protocol;	/**< the owner protocol */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct pw_impl_core *core;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct spa_list client_list;	/**< list of clients of this protocol */
 | 
						struct spa_list client_list;	/**< list of clients of this protocol */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	void (*destroy) (struct pw_protocol_server *listen);
 | 
						void (*destroy) (struct pw_protocol_server *listen);
 | 
				
			||||||
| 
						 | 
					@ -91,8 +93,10 @@ struct pw_protocol_implementaton {
 | 
				
			||||||
	uint32_t version;
 | 
						uint32_t version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
 | 
						struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
 | 
				
			||||||
 | 
											   struct pw_core *core,
 | 
				
			||||||
						   const struct pw_properties *properties);
 | 
											   const struct pw_properties *properties);
 | 
				
			||||||
	struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
 | 
						struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
 | 
				
			||||||
 | 
											   struct pw_impl_core *core,
 | 
				
			||||||
						   const struct pw_properties *properties);
 | 
											   const struct pw_properties *properties);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,6 @@ static void test_abi(void)
 | 
				
			||||||
		uint32_t version;
 | 
							uint32_t version;
 | 
				
			||||||
		void (*destroy) (void *data);
 | 
							void (*destroy) (void *data);
 | 
				
			||||||
		void (*free) (void *data);
 | 
							void (*free) (void *data);
 | 
				
			||||||
		void (*info_changed) (void *data, const struct pw_core_info *info);
 | 
					 | 
				
			||||||
		void (*check_access) (void *data, struct pw_impl_client *client);
 | 
							void (*check_access) (void *data, struct pw_impl_client *client);
 | 
				
			||||||
		void (*global_added) (void *data, struct pw_global *global);
 | 
							void (*global_added) (void *data, struct pw_global *global);
 | 
				
			||||||
		void (*global_removed) (void *data, struct pw_global *global);
 | 
							void (*global_removed) (void *data, struct pw_global *global);
 | 
				
			||||||
| 
						 | 
					@ -46,7 +45,6 @@ static void test_abi(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	TEST_FUNC(ev, test, destroy);
 | 
						TEST_FUNC(ev, test, destroy);
 | 
				
			||||||
	TEST_FUNC(ev, test, free);
 | 
						TEST_FUNC(ev, test, free);
 | 
				
			||||||
	TEST_FUNC(ev, test, info_changed);
 | 
					 | 
				
			||||||
	TEST_FUNC(ev, test, check_access);
 | 
						TEST_FUNC(ev, test, check_access);
 | 
				
			||||||
	TEST_FUNC(ev, test, global_added);
 | 
						TEST_FUNC(ev, test, global_added);
 | 
				
			||||||
	TEST_FUNC(ev, test, global_removed);
 | 
						TEST_FUNC(ev, test, global_removed);
 | 
				
			||||||
| 
						 | 
					@ -63,10 +61,6 @@ static void context_free_error(void *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spa_assert_not_reached();
 | 
						spa_assert_not_reached();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
static void context_info_changed_error(void *data, const struct pw_core_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	spa_assert_not_reached();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
static void context_check_access_error(void *data, struct pw_impl_client *client)
 | 
					static void context_check_access_error(void *data, struct pw_impl_client *client)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	spa_assert_not_reached();
 | 
						spa_assert_not_reached();
 | 
				
			||||||
| 
						 | 
					@ -85,7 +79,6 @@ static const struct pw_context_events context_events_error =
 | 
				
			||||||
	PW_VERSION_CONTEXT_EVENTS,
 | 
						PW_VERSION_CONTEXT_EVENTS,
 | 
				
			||||||
	.destroy = context_destroy_error,
 | 
						.destroy = context_destroy_error,
 | 
				
			||||||
	.free = context_free_error,
 | 
						.free = context_free_error,
 | 
				
			||||||
	.info_changed = context_info_changed_error,
 | 
					 | 
				
			||||||
	.check_access = context_check_access_error,
 | 
						.check_access = context_check_access_error,
 | 
				
			||||||
	.global_added = context_global_added_error,
 | 
						.global_added = context_global_added_error,
 | 
				
			||||||
	.global_removed = context_global_removed_error,
 | 
						.global_removed = context_global_removed_error,
 | 
				
			||||||
| 
						 | 
					@ -123,7 +116,6 @@ static void test_create(void)
 | 
				
			||||||
	struct pw_context *context;
 | 
						struct pw_context *context;
 | 
				
			||||||
	struct spa_hook listener = { NULL, };
 | 
						struct spa_hook listener = { NULL, };
 | 
				
			||||||
	struct pw_context_events context_events = context_events_error;
 | 
						struct pw_context_events context_events = context_events_error;
 | 
				
			||||||
	struct pw_global *global;
 | 
					 | 
				
			||||||
	int res;
 | 
						int res;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	loop = pw_main_loop_new(NULL);
 | 
						loop = pw_main_loop_new(NULL);
 | 
				
			||||||
| 
						 | 
					@ -131,7 +123,7 @@ static void test_create(void)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	context = pw_context_new(pw_main_loop_get_loop(loop),
 | 
						context = pw_context_new(pw_main_loop_get_loop(loop),
 | 
				
			||||||
			pw_properties_new(
 | 
								pw_properties_new(
 | 
				
			||||||
				PW_KEY_CORE_PROFILE_MODULES, "none",
 | 
									PW_KEY_CONTEXT_PROFILE_MODULES, "none",
 | 
				
			||||||
				NULL), 12);
 | 
									NULL), 12);
 | 
				
			||||||
	spa_assert(context != NULL);
 | 
						spa_assert(context != NULL);
 | 
				
			||||||
	pw_context_add_listener(context, &listener, &context_events, context);
 | 
						pw_context_add_listener(context, &listener, &context_events, context);
 | 
				
			||||||
| 
						 | 
					@ -141,19 +133,6 @@ static void test_create(void)
 | 
				
			||||||
	/* check user data */
 | 
						/* check user data */
 | 
				
			||||||
	spa_assert(pw_context_get_user_data(context) != NULL);
 | 
						spa_assert(pw_context_get_user_data(context) != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check info */
 | 
					 | 
				
			||||||
	spa_assert(pw_context_get_info(context) != NULL);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* check global */
 | 
					 | 
				
			||||||
	global = pw_context_get_global(context);
 | 
					 | 
				
			||||||
	spa_assert(global != NULL);
 | 
					 | 
				
			||||||
	spa_assert(pw_context_find_global(context, 0) == global);
 | 
					 | 
				
			||||||
	spa_assert(pw_global_get_context(global) == context);
 | 
					 | 
				
			||||||
	spa_assert(pw_global_get_type(global) == PW_TYPE_INTERFACE_Core);
 | 
					 | 
				
			||||||
	spa_assert(pw_global_get_version(global) == PW_VERSION_CORE);
 | 
					 | 
				
			||||||
	spa_assert(pw_global_get_id(global) == 0);
 | 
					 | 
				
			||||||
	spa_assert(pw_global_get_object(global) == (void*)context);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/* iterate globals */
 | 
						/* iterate globals */
 | 
				
			||||||
	spa_assert(context_foreach_count == 0);
 | 
						spa_assert(context_foreach_count == 0);
 | 
				
			||||||
	res = pw_context_for_each_global(context, context_foreach, context);
 | 
						res = pw_context_for_each_global(context, context_foreach, context);
 | 
				
			||||||
| 
						 | 
					@ -178,15 +157,6 @@ static void test_create(void)
 | 
				
			||||||
	pw_main_loop_destroy(loop);
 | 
						pw_main_loop_destroy(loop);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int info_changed_count = 0;
 | 
					 | 
				
			||||||
static void context_info_changed_count(void *data, const struct pw_core_info *info)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	spa_assert(spa_dict_lookup(info->props, "foo") == NULL);
 | 
					 | 
				
			||||||
	spa_assert(!strcmp(spa_dict_lookup(info->props, "biz"), "buzz"));
 | 
					 | 
				
			||||||
	spa_assert(!strcmp(spa_dict_lookup(info->props, "buzz"), "frizz"));
 | 
					 | 
				
			||||||
	info_changed_count++;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void test_properties(void)
 | 
					static void test_properties(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct pw_main_loop *loop;
 | 
						struct pw_main_loop *loop;
 | 
				
			||||||
| 
						 | 
					@ -206,9 +176,6 @@ static void test_properties(void)
 | 
				
			||||||
	spa_assert(pw_context_get_user_data(context) == NULL);
 | 
						spa_assert(pw_context_get_user_data(context) == NULL);
 | 
				
			||||||
	pw_context_add_listener(context, &listener, &context_events, context);
 | 
						pw_context_add_listener(context, &listener, &context_events, context);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	context_events.info_changed = context_info_changed_count;
 | 
					 | 
				
			||||||
	spa_assert(info_changed_count == 0);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	props = pw_context_get_properties(context);
 | 
						props = pw_context_get_properties(context);
 | 
				
			||||||
	spa_assert(props != NULL);
 | 
						spa_assert(props != NULL);
 | 
				
			||||||
	spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar"));
 | 
						spa_assert(!strcmp(pw_properties_get(props, "foo"), "bar"));
 | 
				
			||||||
| 
						 | 
					@ -223,8 +190,6 @@ static void test_properties(void)
 | 
				
			||||||
	items[2] = SPA_DICT_ITEM_INIT("buzz", "frizz");
 | 
						items[2] = SPA_DICT_ITEM_INIT("buzz", "frizz");
 | 
				
			||||||
	pw_context_update_properties(context, &SPA_DICT_INIT(items, 3));
 | 
						pw_context_update_properties(context, &SPA_DICT_INIT(items, 3));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spa_assert(info_changed_count == 1);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	spa_assert(props == pw_context_get_properties(context));
 | 
						spa_assert(props == pw_context_get_properties(context));
 | 
				
			||||||
	spa_assert(pw_properties_get(props, "foo") == NULL);
 | 
						spa_assert(pw_properties_get(props, "foo") == NULL);
 | 
				
			||||||
	spa_assert(!strcmp(pw_properties_get(props, "biz"), "buzz"));
 | 
						spa_assert(!strcmp(pw_properties_get(props, "biz"), "buzz"));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1632,8 +1632,7 @@ int main(int argc, char *argv[])
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct data data = { 0 };
 | 
						struct data data = { 0 };
 | 
				
			||||||
	struct pw_loop *l;
 | 
						struct pw_loop *l;
 | 
				
			||||||
	const struct pw_core_info *info;
 | 
						char *error;
 | 
				
			||||||
	char *error, args[128];
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_init(&argc, &argv);
 | 
						pw_init(&argc, &argv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1646,16 +1645,15 @@ int main(int argc, char *argv[])
 | 
				
			||||||
	pw_map_init(&data.vars, 64, 16);
 | 
						pw_map_init(&data.vars, 64, 16);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	data.context = pw_context_new(l, pw_properties_new(PW_KEY_CORE_DAEMON, "1", NULL), 0);
 | 
						data.context = pw_context_new(l, pw_properties_new(PW_KEY_CORE_DAEMON, "1", NULL), 0);
 | 
				
			||||||
	info = pw_context_get_info(data.context);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_context_load_module(data.context, "libpipewire-module-link-factory", NULL, NULL);
 | 
						pw_context_load_module(data.context, "libpipewire-module-link-factory", NULL, NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_loop_add_io(l, STDIN_FILENO, SPA_IO_IN|SPA_IO_HUP, false, do_input, &data);
 | 
						pw_loop_add_io(l, STDIN_FILENO, SPA_IO_IN|SPA_IO_HUP, false, do_input, &data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fprintf(stdout, "Welcome to PipeWire \"%s\" version %s. Type 'help' for usage.\n", info->name, info->version);
 | 
						fprintf(stdout, "Welcome to PipeWire version %s. Type 'help' for usage.\n",
 | 
				
			||||||
 | 
								pw_get_library_version());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	snprintf(args, sizeof(args), "%s", info->name);
 | 
						do_connect(&data, "connect", "internal", &error);
 | 
				
			||||||
	do_connect(&data, "connect", args, &error);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pw_main_loop_run(data.loop);
 | 
						pw_main_loop_run(data.loop);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue