mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-06 13:30:01 -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);
|
||||
|
|
@ -834,8 +835,8 @@ impl_new_client(struct pw_protocol *protocol,
|
|||
if (properties) {
|
||||
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)
|
||||
(str = pw_properties_get(properties, PW_KEY_REMOTE_NAME)) != NULL &&
|
||||
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) {
|
||||
protocol_name = PW_TYPE_INFO_PROTOCOL_Native;
|
||||
}
|
||||
}
|
||||
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);
|
||||
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,10 +95,33 @@ 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_list link; /**< link in context object client list */
|
||||
struct pw_global *global; /**< global object created for this client */
|
||||
struct spa_hook global_listener;
|
||||
|
||||
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_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 */
|
||||
|
|
@ -675,7 +696,7 @@ struct pw_impl_link {
|
|||
struct pw_resource {
|
||||
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 pw_impl_client *client; /**< owner client */
|
||||
|
|
|
|||
|
|
@ -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