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:
Wim Taymans 2019-12-12 16:34:01 +01:00
parent a1451fd820
commit f724319e8a
16 changed files with 839 additions and 613 deletions

View file

@ -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;
}

View file

@ -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,
&registry_methods,
registry_resource);
spa_list_append(&this->registry_resource_list, &registry_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;
}

View file

@ -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);

View file

@ -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);
}

View file

@ -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;

View file

@ -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
View 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,
&registry_methods,
registry_resource);
spa_list_append(&context->registry_resource_list, &registry_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
View 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 */

View file

@ -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>

View file

@ -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',

View file

@ -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)

View file

@ -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);

View file

@ -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 */

View file

@ -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);
};

View file

@ -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"));

View file

@ -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);