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 pw_impl_client *client = this->client;
 | 
			
		||||
	struct pw_context *context = client->context;
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
		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);
 | 
			
		||||
 | 
			
		||||
	client = pw_context_create_client(protocol->context,
 | 
			
		||||
	client = pw_context_create_client(s->this.core,
 | 
			
		||||
			protocol, props, sizeof(struct client_data));
 | 
			
		||||
	if (client == NULL)
 | 
			
		||||
		goto exit;
 | 
			
		||||
| 
						 | 
				
			
			@ -809,6 +808,7 @@ error:
 | 
			
		|||
 | 
			
		||||
static struct pw_protocol_client *
 | 
			
		||||
impl_new_client(struct pw_protocol *protocol,
 | 
			
		||||
		struct pw_core *core,
 | 
			
		||||
		const struct pw_properties *properties)
 | 
			
		||||
{
 | 
			
		||||
	struct client *impl;
 | 
			
		||||
| 
						 | 
				
			
			@ -823,6 +823,7 @@ impl_new_client(struct pw_protocol *protocol,
 | 
			
		|||
 | 
			
		||||
	this = &impl->this;
 | 
			
		||||
	this->protocol = protocol;
 | 
			
		||||
	this->core = core;
 | 
			
		||||
 | 
			
		||||
	impl->context = protocol->context;
 | 
			
		||||
	impl->connection = pw_protocol_native_connection_new(protocol->context, -1);
 | 
			
		||||
| 
						 | 
				
			
			@ -835,7 +836,7 @@ impl_new_client(struct pw_protocol *protocol,
 | 
			
		|||
		str = pw_properties_get(properties, PW_KEY_REMOTE_INTENTION);
 | 
			
		||||
		if (str == NULL &&
 | 
			
		||||
		   (str = pw_properties_get(properties, PW_KEY_REMOTE_NAME)) != NULL &&
 | 
			
		||||
		    strcmp(str, impl->context->info.name) == 0)
 | 
			
		||||
		    strcmp(str, "internal") == 0)
 | 
			
		||||
			str = "internal";
 | 
			
		||||
	}
 | 
			
		||||
	if (str == NULL)
 | 
			
		||||
| 
						 | 
				
			
			@ -933,6 +934,7 @@ get_name(const struct pw_properties *properties)
 | 
			
		|||
 | 
			
		||||
static struct server *
 | 
			
		||||
create_server(struct pw_protocol *protocol,
 | 
			
		||||
		struct pw_impl_core *core,
 | 
			
		||||
                const struct pw_properties *properties)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_protocol_server *this;
 | 
			
		||||
| 
						 | 
				
			
			@ -946,6 +948,7 @@ create_server(struct pw_protocol *protocol,
 | 
			
		|||
 | 
			
		||||
	this = &s->this;
 | 
			
		||||
	this->protocol = protocol;
 | 
			
		||||
	this->core = core;
 | 
			
		||||
	spa_list_init(&this->client_list);
 | 
			
		||||
	this->destroy = destroy_server;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -960,6 +963,7 @@ create_server(struct pw_protocol *protocol,
 | 
			
		|||
 | 
			
		||||
static struct pw_protocol_server *
 | 
			
		||||
impl_add_server(struct pw_protocol *protocol,
 | 
			
		||||
		struct pw_impl_core *core,
 | 
			
		||||
                const struct pw_properties *properties)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_protocol_server *this;
 | 
			
		||||
| 
						 | 
				
			
			@ -967,7 +971,7 @@ impl_add_server(struct pw_protocol *protocol,
 | 
			
		|||
	const char *name;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	if ((s = create_server(protocol, properties)) == NULL)
 | 
			
		||||
	if ((s = create_server(protocol, core, properties)) == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	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_protocol *this;
 | 
			
		||||
	const char *val;
 | 
			
		||||
	struct protocol_data *d;
 | 
			
		||||
	const struct pw_properties *props;
 | 
			
		||||
	const char *val;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	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->module = module;
 | 
			
		||||
 | 
			
		||||
	d->local = create_server(this, props);
 | 
			
		||||
 | 
			
		||||
	props = pw_context_get_properties(context);
 | 
			
		||||
	d->local = create_server(this, context->core, props);
 | 
			
		||||
 | 
			
		||||
	val = getenv("PIPEWIRE_DAEMON");
 | 
			
		||||
	if (val == NULL)
 | 
			
		||||
		val = pw_properties_get(props, PW_KEY_CORE_DAEMON);
 | 
			
		||||
	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;
 | 
			
		||||
			goto error_cleanup;
 | 
			
		||||
		}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,6 +39,8 @@
 | 
			
		|||
#include <pipewire/impl.h>
 | 
			
		||||
#include <pipewire/private.h>
 | 
			
		||||
 | 
			
		||||
#include <extensions/protocol-native.h>
 | 
			
		||||
 | 
			
		||||
#define NAME "context"
 | 
			
		||||
 | 
			
		||||
/** \cond */
 | 
			
		||||
| 
						 | 
				
			
			@ -58,399 +60,6 @@ struct factory_entry {
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
 *
 | 
			
		||||
 * \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 pw_context *this;
 | 
			
		||||
	const char *name, *lib, *str;
 | 
			
		||||
	const char *lib, *str;
 | 
			
		||||
	void *dbus_iface = NULL;
 | 
			
		||||
	uint32_t n_support;
 | 
			
		||||
	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_map_init(&this->globals, 128, 32);
 | 
			
		||||
 | 
			
		||||
	spa_list_init(&this->core_impl_list);
 | 
			
		||||
	spa_list_init(&this->protocol_list);
 | 
			
		||||
	spa_list_init(&this->core_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_hook_list_init(&this->listener_list);
 | 
			
		||||
 | 
			
		||||
	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->core = pw_context_create_core(this, pw_properties_copy(properties), 0);
 | 
			
		||||
	if (this->core == NULL) {
 | 
			
		||||
		res = -errno;
 | 
			
		||||
		goto error_free_loop;
 | 
			
		||||
	}
 | 
			
		||||
	pw_impl_core_register(this->core, NULL);
 | 
			
		||||
 | 
			
		||||
	fill_properties(this);
 | 
			
		||||
 | 
			
		||||
	if ((res = pw_data_loop_start(this->data_loop_impl)) < 0)
 | 
			
		||||
		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->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)
 | 
			
		||||
		str = "default";
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -655,12 +272,11 @@ void pw_context_destroy(struct pw_context *context)
 | 
			
		|||
	struct pw_resource *resource;
 | 
			
		||||
	struct pw_impl_node *node;
 | 
			
		||||
	struct factory_entry *entry;
 | 
			
		||||
	struct pw_impl_core *core_impl;
 | 
			
		||||
 | 
			
		||||
	pw_log_debug(NAME" %p: destroy", context);
 | 
			
		||||
	pw_context_emit_destroy(context);
 | 
			
		||||
 | 
			
		||||
	spa_hook_remove(&context->global_listener);
 | 
			
		||||
 | 
			
		||||
	spa_list_consume(core, &context->core_list, link)
 | 
			
		||||
		pw_core_disconnect(core);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -679,6 +295,9 @@ void pw_context_destroy(struct pw_context *context)
 | 
			
		|||
	spa_list_consume(global, &context->global_list, link)
 | 
			
		||||
		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_context_emit_free(context);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -708,18 +327,6 @@ void *pw_context_get_user_data(struct pw_context *context)
 | 
			
		|||
	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
 | 
			
		||||
void pw_context_add_listener(struct pw_context *context,
 | 
			
		||||
			  struct spa_hook *listener,
 | 
			
		||||
| 
						 | 
				
			
			@ -760,27 +367,11 @@ const struct pw_properties *pw_context_get_properties(struct pw_context *context
 | 
			
		|||
SPA_EXPORT
 | 
			
		||||
int pw_context_update_properties(struct pw_context *context, const struct spa_dict *dict)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_resource *resource;
 | 
			
		||||
	int changed;
 | 
			
		||||
 | 
			
		||||
	changed = pw_properties_update(context->properties, dict);
 | 
			
		||||
	context->info.props = &context->properties->dict;
 | 
			
		||||
 | 
			
		||||
	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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -85,8 +85,6 @@ struct pw_context_events {
 | 
			
		|||
	void (*destroy) (void *data);
 | 
			
		||||
	/** The context is being freed */
 | 
			
		||||
	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 */
 | 
			
		||||
	void (*check_access) (void *data, struct pw_impl_client *client);
 | 
			
		||||
	/** 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,
 | 
			
		||||
			  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 */
 | 
			
		||||
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_core *p;
 | 
			
		||||
	struct pw_protocol *protocol = NULL;
 | 
			
		||||
	struct pw_protocol *protocol;
 | 
			
		||||
	const char *protocol_name;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -292,7 +292,7 @@ static struct pw_core *core_new(struct pw_context *context,
 | 
			
		|||
	if (properties == NULL)
 | 
			
		||||
		goto error_properties;
 | 
			
		||||
 | 
			
		||||
	pw_fill_connect_properties(context, properties);
 | 
			
		||||
	pw_properties_add(properties, &context->properties->dict);
 | 
			
		||||
 | 
			
		||||
	p->proxy.core = p;
 | 
			
		||||
	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->filter_list);
 | 
			
		||||
 | 
			
		||||
	if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL) {
 | 
			
		||||
		if ((protocol_name = pw_properties_get(context->properties, PW_KEY_PROTOCOL)) == NULL) {
 | 
			
		||||
	if ((protocol_name = pw_properties_get(properties, PW_KEY_PROTOCOL)) == NULL &&
 | 
			
		||||
	    (protocol_name = pw_properties_get(context->properties, PW_KEY_PROTOCOL)) == NULL)
 | 
			
		||||
		protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (protocol == NULL)
 | 
			
		||||
	protocol = pw_context_find_protocol(context, protocol_name);
 | 
			
		||||
	if (protocol == NULL) {
 | 
			
		||||
		res = -ENOTSUP;
 | 
			
		||||
		goto error_protocol;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	p->conn = pw_protocol_new_client(protocol, properties);
 | 
			
		||||
	p->conn = pw_protocol_new_client(protocol, p, properties);
 | 
			
		||||
	if (p->conn == NULL)
 | 
			
		||||
		goto error_connection;
 | 
			
		||||
 | 
			
		||||
	p->conn->core = p;
 | 
			
		||||
 | 
			
		||||
	if ((res = pw_proxy_init(&p->proxy, PW_TYPE_INTERFACE_Core, PW_VERSION_CORE)) < 0)
 | 
			
		||||
		goto error_proxy;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -423,15 +418,12 @@ struct pw_core *
 | 
			
		|||
pw_context_connect_self(struct pw_context *context, struct pw_properties *properties,
 | 
			
		||||
	      size_t user_data_size)
 | 
			
		||||
{
 | 
			
		||||
	const struct pw_core_info *info;
 | 
			
		||||
 | 
			
		||||
	if (properties == NULL)
 | 
			
		||||
                properties = pw_properties_new(NULL, NULL);
 | 
			
		||||
	if (properties == NULL)
 | 
			
		||||
		return NULL;
 | 
			
		||||
 | 
			
		||||
	info = pw_context_get_info(context);
 | 
			
		||||
	pw_properties_set(properties, PW_KEY_REMOTE_NAME, info->name);
 | 
			
		||||
	pw_properties_set(properties, PW_KEY_REMOTE_NAME, "internal");
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
 */
 | 
			
		||||
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_properties *properties,
 | 
			
		||||
				size_t user_data_size)
 | 
			
		||||
| 
						 | 
				
			
			@ -299,7 +299,8 @@ struct pw_impl_client *pw_context_create_client(struct pw_context *context,
 | 
			
		|||
	this = &impl->this;
 | 
			
		||||
	pw_log_debug(NAME" %p: new", this);
 | 
			
		||||
 | 
			
		||||
	this->context = context;
 | 
			
		||||
	this->context = core->context;
 | 
			
		||||
	this->core = core;
 | 
			
		||||
	this->protocol = protocol;
 | 
			
		||||
 | 
			
		||||
	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_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;
 | 
			
		||||
 | 
			
		||||
	pw_context_emit_check_access(context, this);
 | 
			
		||||
	pw_context_emit_check_access(this->context, this);
 | 
			
		||||
 | 
			
		||||
	return this;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -427,7 +428,7 @@ error_existed:
 | 
			
		|||
SPA_EXPORT
 | 
			
		||||
struct pw_context *pw_impl_client_get_context(struct pw_impl_client *client)
 | 
			
		||||
{
 | 
			
		||||
	return client->context;
 | 
			
		||||
	return client->core->context;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
| 
						 | 
				
			
			@ -569,7 +570,8 @@ SPA_EXPORT
 | 
			
		|||
int pw_impl_client_update_permissions(struct pw_impl_client *client,
 | 
			
		||||
		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;
 | 
			
		||||
	uint32_t i;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -603,7 +605,7 @@ int pw_impl_client_update_permissions(struct pw_impl_client *client,
 | 
			
		|||
		else  {
 | 
			
		||||
			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) {
 | 
			
		||||
				pw_log_warn(NAME" %p: invalid global %d", client, permissions[i].id);
 | 
			
		||||
				continue;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -110,7 +110,7 @@ struct pw_impl_client_events {
 | 
			
		|||
 | 
			
		||||
/** Create a new client. This is mainly used by protocols. */
 | 
			
		||||
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_properties *properties,	/**< client properties */
 | 
			
		||||
			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/control.h>
 | 
			
		||||
#include <pipewire/impl-core.h>
 | 
			
		||||
#include <pipewire/impl-client.h>
 | 
			
		||||
#include <pipewire/impl-device.h>
 | 
			
		||||
#include <pipewire/impl-factory.h>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
pipewire_headers = [
 | 
			
		||||
  'array.h',
 | 
			
		||||
  'buffers.h',
 | 
			
		||||
  'impl-core.h',
 | 
			
		||||
  'impl-client.h',
 | 
			
		||||
  'client.h',
 | 
			
		||||
  'context.h',
 | 
			
		||||
| 
						 | 
				
			
			@ -42,6 +43,7 @@ pipewire_headers = [
 | 
			
		|||
 | 
			
		||||
pipewire_sources = [
 | 
			
		||||
  'buffers.c',
 | 
			
		||||
  'impl-core.c',
 | 
			
		||||
  'impl-client.c',
 | 
			
		||||
  'context.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 */
 | 
			
		||||
SPA_EXPORT
 | 
			
		||||
enum pw_direction pw_direction_reverse(enum pw_direction direction)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,12 +133,6 @@ pw_get_host_name(void);
 | 
			
		|||
const char *
 | 
			
		||||
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
 | 
			
		||||
pw_direction_reverse(enum pw_direction direction);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -95,8 +95,31 @@ struct protocol_compat_v2 {
 | 
			
		|||
	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_core *core;		/**< core 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_hook global_listener;
 | 
			
		||||
| 
						 | 
				
			
			@ -201,10 +224,7 @@ pw_core_resource_errorf(struct pw_resource *resource, uint32_t id, int seq,
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
struct pw_context {
 | 
			
		||||
	struct pw_global *global;	/**< the global of the context */
 | 
			
		||||
	struct spa_hook global_listener;
 | 
			
		||||
 | 
			
		||||
	struct pw_core_info info;	/**< info about the core */
 | 
			
		||||
	struct pw_impl_core *core;		/**< core object */
 | 
			
		||||
 | 
			
		||||
	struct pw_properties *properties;	/**< properties of the context */
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -212,6 +232,7 @@ struct pw_context {
 | 
			
		|||
 | 
			
		||||
	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 core_list;		/**< list of core connections */
 | 
			
		||||
	struct spa_list registry_resource_list;	/**< list of registry resources */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -66,6 +66,8 @@ struct pw_protocol_server {
 | 
			
		|||
	struct spa_list link;		/**< link in protocol server_list */
 | 
			
		||||
	struct pw_protocol *protocol;	/**< the owner protocol */
 | 
			
		||||
 | 
			
		||||
	struct pw_impl_core *core;
 | 
			
		||||
 | 
			
		||||
	struct spa_list client_list;	/**< list of clients of this protocol */
 | 
			
		||||
 | 
			
		||||
	void (*destroy) (struct pw_protocol_server *listen);
 | 
			
		||||
| 
						 | 
				
			
			@ -91,8 +93,10 @@ struct pw_protocol_implementaton {
 | 
			
		|||
	uint32_t version;
 | 
			
		||||
 | 
			
		||||
	struct pw_protocol_client * (*new_client) (struct pw_protocol *protocol,
 | 
			
		||||
						   struct pw_core *core,
 | 
			
		||||
						   const struct pw_properties *properties);
 | 
			
		||||
	struct pw_protocol_server * (*add_server) (struct pw_protocol *protocol,
 | 
			
		||||
						   struct pw_impl_core *core,
 | 
			
		||||
						   const struct pw_properties *properties);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -38,7 +38,6 @@ static void test_abi(void)
 | 
			
		|||
		uint32_t version;
 | 
			
		||||
		void (*destroy) (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 (*global_added) (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, free);
 | 
			
		||||
	TEST_FUNC(ev, test, info_changed);
 | 
			
		||||
	TEST_FUNC(ev, test, check_access);
 | 
			
		||||
	TEST_FUNC(ev, test, global_added);
 | 
			
		||||
	TEST_FUNC(ev, test, global_removed);
 | 
			
		||||
| 
						 | 
				
			
			@ -63,10 +61,6 @@ static void context_free_error(void *data)
 | 
			
		|||
{
 | 
			
		||||
	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)
 | 
			
		||||
{
 | 
			
		||||
	spa_assert_not_reached();
 | 
			
		||||
| 
						 | 
				
			
			@ -85,7 +79,6 @@ static const struct pw_context_events context_events_error =
 | 
			
		|||
	PW_VERSION_CONTEXT_EVENTS,
 | 
			
		||||
	.destroy = context_destroy_error,
 | 
			
		||||
	.free = context_free_error,
 | 
			
		||||
	.info_changed = context_info_changed_error,
 | 
			
		||||
	.check_access = context_check_access_error,
 | 
			
		||||
	.global_added = context_global_added_error,
 | 
			
		||||
	.global_removed = context_global_removed_error,
 | 
			
		||||
| 
						 | 
				
			
			@ -123,7 +116,6 @@ static void test_create(void)
 | 
			
		|||
	struct pw_context *context;
 | 
			
		||||
	struct spa_hook listener = { NULL, };
 | 
			
		||||
	struct pw_context_events context_events = context_events_error;
 | 
			
		||||
	struct pw_global *global;
 | 
			
		||||
	int res;
 | 
			
		||||
 | 
			
		||||
	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),
 | 
			
		||||
			pw_properties_new(
 | 
			
		||||
				PW_KEY_CORE_PROFILE_MODULES, "none",
 | 
			
		||||
				PW_KEY_CONTEXT_PROFILE_MODULES, "none",
 | 
			
		||||
				NULL), 12);
 | 
			
		||||
	spa_assert(context != NULL);
 | 
			
		||||
	pw_context_add_listener(context, &listener, &context_events, context);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,19 +133,6 @@ static void test_create(void)
 | 
			
		|||
	/* check user data */
 | 
			
		||||
	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 */
 | 
			
		||||
	spa_assert(context_foreach_count == 0);
 | 
			
		||||
	res = pw_context_for_each_global(context, context_foreach, context);
 | 
			
		||||
| 
						 | 
				
			
			@ -178,15 +157,6 @@ static void test_create(void)
 | 
			
		|||
	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)
 | 
			
		||||
{
 | 
			
		||||
	struct pw_main_loop *loop;
 | 
			
		||||
| 
						 | 
				
			
			@ -206,9 +176,6 @@ static void test_properties(void)
 | 
			
		|||
	spa_assert(pw_context_get_user_data(context) == NULL);
 | 
			
		||||
	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);
 | 
			
		||||
	spa_assert(props != NULL);
 | 
			
		||||
	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");
 | 
			
		||||
	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(pw_properties_get(props, "foo") == NULL);
 | 
			
		||||
	spa_assert(!strcmp(pw_properties_get(props, "biz"), "buzz"));
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1632,8 +1632,7 @@ int main(int argc, char *argv[])
 | 
			
		|||
{
 | 
			
		||||
	struct data data = { 0 };
 | 
			
		||||
	struct pw_loop *l;
 | 
			
		||||
	const struct pw_core_info *info;
 | 
			
		||||
	char *error, args[128];
 | 
			
		||||
	char *error;
 | 
			
		||||
 | 
			
		||||
	pw_init(&argc, &argv);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1646,16 +1645,15 @@ int main(int argc, char *argv[])
 | 
			
		|||
	pw_map_init(&data.vars, 64, 16);
 | 
			
		||||
 | 
			
		||||
	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_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", args, &error);
 | 
			
		||||
	do_connect(&data, "connect", "internal", &error);
 | 
			
		||||
 | 
			
		||||
	pw_main_loop_run(data.loop);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue