modules: use the registry from WpRemotePipewire

This commit is contained in:
Julian Bouzas 2019-06-20 12:55:46 -04:00
parent d84217c1e9
commit d2b8337045
3 changed files with 150 additions and 284 deletions

View file

@ -26,12 +26,7 @@ gpointer simple_endpoint_link_factory (WpFactory * factory, GType type,
struct module_data
{
WpModule *module;
/* Registry */
struct pw_registry_proxy *registry_proxy;
struct spa_hook registry_listener;
/* Client nodes info */
WpRemotePipewire *remote_pipewire;
GHashTable *client_nodes_info;
};
@ -39,7 +34,7 @@ struct endpoint_info
{
gchar *name;
gchar *media_class;
const struct pw_proxy *proxy;
struct pw_proxy *proxy;
};
struct proxy_info
@ -143,8 +138,8 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer d)
{
struct proxy_info *pi = d;
const struct module_data *data = pi->data;
struct endpoint_info *ei = NULL;
WpProxyPort *proxy_port = NULL;
struct pw_proxy *proxy = NULL;
/* Get the proxy port */
proxy_port = wp_proxy_port_new_finish(initable, res, NULL);
@ -155,19 +150,21 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer d)
pi->proxy_port = proxy_port;
/* Get the node proxy */
proxy = pw_registry_proxy_bind (data->registry_proxy, pi->node_id,
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
if (!proxy)
ei = g_hash_table_lookup(data->client_nodes_info,
GINT_TO_POINTER(pi->node_id));
if (!ei)
return;
/* Create the proxy node asynchronically */
wp_proxy_node_new(pi->node_id, proxy, proxy_node_created, pi);
wp_proxy_node_new(pi->node_id, ei->proxy, proxy_node_created, pi);
}
static void
handle_node (struct module_data *data, uint32_t id, uint32_t parent_id,
const struct spa_dict * props)
handle_node (WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
gpointer d)
{
struct module_data *data = d;
const struct spa_dict *props = p;
struct endpoint_info *ei = NULL;
const gchar *name;
const gchar *media_class;
@ -198,9 +195,10 @@ handle_node (struct module_data *data, uint32_t id, uint32_t parent_id,
g_debug ("found stream node: id:%u ; name:%s ; media_class:%s", id, name,
media_class);
/* Get the proxy */
proxy = pw_registry_proxy_bind (data->registry_proxy, id,
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
/* Bind the proxy */
proxy = wp_remote_pipewire_proxy_bind(rp, id, PW_TYPE_INTERFACE_Node);
if (!proxy)
return;
/* TODO: Assume all clients have this format for now */
format.format = SPA_AUDIO_FORMAT_F32P;
@ -230,9 +228,10 @@ handle_node (struct module_data *data, uint32_t id, uint32_t parent_id,
}
static void
handle_port(struct module_data *data, uint32_t id, uint32_t parent_id,
const struct spa_dict *props)
handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
gpointer d)
{
struct module_data *data = d;
struct proxy_info *pi = NULL;
struct pw_proxy *proxy = NULL;
@ -241,9 +240,8 @@ handle_port(struct module_data *data, uint32_t id, uint32_t parent_id,
GINT_TO_POINTER (parent_id)))
return;
/* Get the port proxy */
proxy = pw_registry_proxy_bind (data->registry_proxy, id,
PW_TYPE_INTERFACE_Port, PW_VERSION_PORT, 0);
/* Bind the proxy */
proxy = wp_remote_pipewire_proxy_bind (rp, id, PW_TYPE_INTERFACE_Port);
if (!proxy)
return;
@ -257,55 +255,18 @@ handle_port(struct module_data *data, uint32_t id, uint32_t parent_id,
wp_proxy_port_new(id, proxy, proxy_port_created, pi);
}
static void
registry_global(void *d, uint32_t id, uint32_t parent_id,
uint32_t permissions, uint32_t type, uint32_t version,
const struct spa_dict *props)
{
struct module_data *data = d;
switch (type) {
case PW_TYPE_INTERFACE_Node:
handle_node(data, id, parent_id, props);
break;
case PW_TYPE_INTERFACE_Port:
handle_port(data, id, parent_id, props);
break;
default:
break;
}
}
static const struct pw_registry_proxy_events registry_events = {
PW_VERSION_REGISTRY_PROXY_EVENTS,
.global = registry_global,
};
static void
on_remote_connected (WpRemote *remote, WpRemoteState state,
struct module_data *data)
{
struct pw_core_proxy *core_proxy;
struct pw_remote *pw_remote;
g_object_get (remote, "pw-remote", &pw_remote, NULL);
core_proxy = pw_remote_get_core_proxy (pw_remote);
data->registry_proxy = pw_core_proxy_get_registry (core_proxy,
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
pw_registry_proxy_add_listener(data->registry_proxy,
&data->registry_listener, &registry_events, data);
}
static void
module_destroy (gpointer d)
{
struct module_data *data = d;
/* Set to NULL module and remote pipewire as we don't own the reference */
data->module = NULL;
data->remote_pipewire = NULL;
/* Destroy the hash table */
g_hash_table_unref (data->client_nodes_info);
data->client_nodes_info = NULL;
/* Clean up */
g_slice_free (struct module_data, data);
@ -315,12 +276,13 @@ void
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
struct module_data *data;
WpRemote *remote;
WpRemotePipewire *rp;
struct pw_core *pw_core;
struct pw_remote *pw_remote;
remote = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
if (!remote) {
/* Make sure the remote pipewire is valid */
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
if (!rp) {
g_critical ("module-pipewire cannot be loaded without a registered "
"WpRemotePipewire object");
return;
@ -329,20 +291,22 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
/* Create the module data */
data = g_slice_new0 (struct module_data);
data->module = module;
data->remote_pipewire = rp;
data->client_nodes_info = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, endpoint_info_destroy);
/* Set the module destroy callback */
wp_module_set_destroy_callback (module, module_destroy, data);
g_signal_connect (remote, "state-changed::connected",
(GCallback) on_remote_connected, data);
/* Register the global addded callbacks */
g_signal_connect(rp, "global-added::node", (GCallback)handle_node, data);
g_signal_connect(rp, "global-added::port", (GCallback)handle_port, data);
g_object_get (remote,
"pw-core", &pw_core,
"pw-remote", &pw_remote,
NULL);
/* Init remoted endpoint */
g_object_get (rp, "pw-core", &pw_core, "pw-remote", &pw_remote, NULL);
remote_endpoint_init (core, pw_core, pw_remote);
/* Register simple-endpoint and simple-endpoint-link */
wp_factory_new (core, "pipewire-simple-endpoint", simple_endpoint_factory);
wp_factory_new (core, "pipewire-simple-endpoint-link",
simple_endpoint_link_factory);

View file

@ -18,15 +18,7 @@
struct impl
{
WpModule *module;
/* Remote */
struct spa_hook remote_listener;
/* Registry */
struct pw_registry_proxy *registry_proxy;
struct spa_hook registry_listener;
/* The alsa node proxies */
WpRemotePipewire *remote_pipewire;
GHashTable *alsa_nodes_info;
};
@ -89,8 +81,8 @@ proxy_node_created(GObject *initable, GAsyncResult *res, gpointer data)
g_autoptr(WpProxyNode) proxy_node = NULL;
struct endpoint_info *ei = NULL;
GVariantBuilder b;
g_autoptr(GVariant) endpoint_props = NULL;
g_autoptr(WpEndpoint) endpoint = NULL;
g_autoptr (GVariant) endpoint_props = NULL;
g_autoptr (WpEndpoint) endpoint = NULL;
/* Get the proxy */
proxy_node = wp_proxy_node_new_finish(initable, res, NULL);
@ -147,8 +139,8 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data)
pi->proxy_port = proxy_port;
/* Get the node proxy */
proxy = pw_registry_proxy_bind (impl->registry_proxy, pi->node_id,
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
proxy = wp_remote_pipewire_proxy_bind (impl->remote_pipewire, pi->node_id,
PW_TYPE_INTERFACE_Node);
if (!proxy)
return;
@ -157,17 +149,16 @@ proxy_port_created(GObject *initable, GAsyncResult *res, gpointer data)
}
static void
handle_node(struct impl *impl, uint32_t id, uint32_t parent_id,
const struct spa_dict *props)
handle_node(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
gpointer d)
{
struct impl *impl = d;
const struct spa_dict *props = p;
const gchar *media_class = NULL, *name = NULL;
struct endpoint_info *ei = NULL;
/* Make sure the node has properties */
if (!props) {
g_warning("node has no properties, skipping...");
return;
}
g_return_if_fail(props);
/* Get the name and media_class */
name = spa_dict_lookup(props, "node.name");
@ -189,9 +180,10 @@ handle_node(struct impl *impl, uint32_t id, uint32_t parent_id,
}
static void
handle_port(struct impl *impl, uint32_t id, uint32_t parent_id,
const struct spa_dict *props)
handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
gpointer d)
{
struct impl *impl = d;
struct proxy_info *pi = NULL;
struct pw_proxy *proxy = NULL;
@ -199,13 +191,8 @@ handle_port(struct impl *impl, uint32_t id, uint32_t parent_id,
if (!g_hash_table_contains(impl->alsa_nodes_info, GINT_TO_POINTER (parent_id)))
return;
/* Make sure the port has porperties */
if (!props)
return;
/* Get the port proxy */
proxy = pw_registry_proxy_bind (impl->registry_proxy, id,
PW_TYPE_INTERFACE_Port, PW_VERSION_PORT, 0);
proxy = wp_remote_pipewire_proxy_bind (rp, id, PW_TYPE_INTERFACE_Port);
if (!proxy)
return;
@ -219,90 +206,48 @@ handle_port(struct impl *impl, uint32_t id, uint32_t parent_id,
wp_proxy_port_new(id, proxy, proxy_port_created, pi);
}
static void
registry_global(void *data, uint32_t id, uint32_t parent_id,
uint32_t permissions, uint32_t type, uint32_t version,
const struct spa_dict *props)
{
struct impl *impl = data;
switch (type) {
case PW_TYPE_INTERFACE_Node:
handle_node(impl, id, parent_id, props);
break;
case PW_TYPE_INTERFACE_Port:
handle_port(impl, id, parent_id, props);
break;
default:
break;
}
}
static const struct pw_registry_proxy_events registry_events = {
PW_VERSION_REGISTRY_PROXY_EVENTS,
.global = registry_global,
};
static void
on_connected (WpRemote *remote, WpRemoteState state, struct impl *impl)
{
struct pw_core_proxy *core_proxy = NULL;
struct pw_remote *pw_remote;
g_object_get (remote, "pw-remote", &pw_remote, NULL);
core_proxy = pw_remote_get_core_proxy (pw_remote);
impl->registry_proxy = pw_core_proxy_get_registry (core_proxy,
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
pw_registry_proxy_add_listener(impl->registry_proxy,
&impl->registry_listener, &registry_events, impl);
}
static void
module_destroy (gpointer data)
{
struct impl *impl = data;
/* Set to NULL module and remote pipewire as we don't own the reference */
impl->module = NULL;
impl->remote_pipewire = NULL;
/* Destroy the hash table */
g_hash_table_unref (impl->alsa_nodes_info);
impl->alsa_nodes_info = NULL;
/* Clean up */
g_slice_free (struct impl, impl);
}
struct impl *
module_create (WpModule * module, WpCore * core)
{
struct impl *impl;
WpRemote *remote;
/* Allocate impl */
impl = g_new0(struct impl, 1);
/* Set core */
impl->module = module;
/* Set remote */
remote = wp_core_get_global(core, WP_GLOBAL_REMOTE_PIPEWIRE);
g_signal_connect (remote, "state-changed::connected",
(GCallback) on_connected, impl);
/* Create the hash table */
impl->alsa_nodes_info = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, endpoint_info_destroy);
/* Return the module */
return impl;
}
void
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
/* Create the impl */
struct impl *impl = module_create (module, core);
struct impl *impl;
WpRemotePipewire *rp;
/* Make sure the remote pipewire is valid */
rp = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
if (!rp) {
g_critical ("module-pw-alsa-udev cannot be loaded without a registered "
"WpRemotePipewire object");
return;
}
/* Create the module data */
impl = g_slice_new0(struct impl);
impl->module = module;
impl->remote_pipewire = rp;
impl->alsa_nodes_info = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, endpoint_info_destroy);
/* Set destroy callback for impl */
wp_module_set_destroy_callback (module, module_destroy, impl);
/* Register the global addded callbacks */
g_signal_connect(rp, "global-added::node", (GCallback)handle_node, impl);
g_signal_connect(rp, "global-added::port", (GCallback)handle_port, impl);
}

View file

@ -26,17 +26,13 @@ struct _WpPwAudioSoftdspEndpoint
{
WpEndpoint parent;
/* The remote pipewire */
WpRemotePipewire *remote_pipewire;
/* temporary method to select which endpoint
* is going to be the default input/output */
gboolean selected;
/* Core */
struct pw_core_proxy *core_proxy;
/* Registry */
struct pw_registry_proxy *registry_proxy;
struct spa_hook registry_listener;
/* Direction */
enum pw_direction direction;
@ -132,8 +128,8 @@ on_dsp_running(WpPwAudioSoftdspEndpoint *self)
g_debug ("%p linking DSP to node", self);
/* Create the link */
self->link_proxy = pw_core_proxy_create_object(self->core_proxy,
"link-factory", PW_TYPE_INTERFACE_Link, PW_VERSION_LINK, &props->dict, 0);
self->link_proxy = wp_remote_pipewire_create_object(self->remote_pipewire,
"link-factory", PW_TYPE_INTERFACE_Link, &props->dict);
/* Clean up */
pw_properties_free(props);
@ -264,8 +260,8 @@ emit_audio_dsp_node (WpPwAudioSoftdspEndpoint *self)
MAX_QUANTUM_SIZE * sizeof(float));
/* Set the DSP proxy and listener */
self->dsp_proxy = pw_core_proxy_create_object(self->core_proxy, "audio-dsp",
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, &props->dict, 0);
self->dsp_proxy = wp_remote_pipewire_create_object(self->remote_pipewire,
"audio-dsp", PW_TYPE_INTERFACE_Node, &props->dict);
pw_node_proxy_add_listener(self->dsp_proxy, &self->dsp_listener,
&dsp_node_events, self);
pw_node_proxy_enum_params (self->dsp_proxy, 0, SPA_PARAM_Props, 0, -1, NULL);
@ -284,21 +280,69 @@ emit_audio_dsp_node (WpPwAudioSoftdspEndpoint *self)
pw_properties_free(props);
}
static void
handle_port(WpRemotePipewire *rp, guint id, guint parent_id, gconstpointer p,
gpointer d)
{
WpPwAudioSoftdspEndpoint *self = d;
const struct spa_dict *props = p;
const char *direction_prop = NULL;
enum pw_direction direction;
/* Make sure the dsp port is not already set*/
if (self->dsp_port_id != 0)
return;
/* Make sure the port has porperties */
if (!props)
return;
/* Only handle ports owned by this endpoint */
if (!self->dsp_info || self->dsp_info->id != parent_id)
return;
/* Get the direction property */
direction_prop = spa_dict_lookup(props, "port.direction");
if (!direction_prop)
return;
direction =
!strcmp(direction_prop, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
/* Only handle ports with the oposit direction of the endpoint */
if (self->direction == direction)
return;
/* Set the dsp port id */
self->dsp_port_id = id;
}
static void
endpoint_constructed (GObject * object)
{
WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (object);
g_autoptr (WpCore) core = wp_endpoint_get_core(WP_ENDPOINT(self));
const gchar *media_class = wp_endpoint_get_media_class (WP_ENDPOINT (self));
GVariantDict d;
/* Set Remote Pipewire */
self->remote_pipewire = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
if (!self->remote_pipewire)
g_critical ("failed to get remote pipewire ");
/* Register the global-added::port callback in remote pipewire */
g_signal_connect(self->remote_pipewire, "global-added::port",
(GCallback)handle_port, self);
/* Set the direction */
if (g_str_has_suffix (media_class, "Source")) {
if (g_str_has_suffix (media_class, "Source"))
self->direction = PW_DIRECTION_INPUT;
} else if (g_str_has_suffix (media_class, "Sink")) {
else if (g_str_has_suffix (media_class, "Sink"))
self->direction = PW_DIRECTION_OUTPUT;
} else {
else
g_critical ("failed to parse direction");
}
/* Emit the audio DSP node */
emit_audio_dsp_node(self);
g_variant_dict_init (&d, NULL);
g_variant_dict_insert (&d, "id", "u", 0);
@ -338,6 +382,9 @@ endpoint_finalize (GObject * object)
{
WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (object);
/* Set to NULL remote pipewire as we don't own the reference */
self->remote_pipewire = NULL;
/* Unref the proxy node */
g_clear_object (&self->proxy_node);
@ -500,6 +547,7 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass)
endpoint_class->get_control_value = endpoint_get_control_value;
endpoint_class->set_control_value = endpoint_set_control_value;
/* Instal the properties */
g_object_class_install_property (object_class, PROP_NODE_PROXY,
g_param_spec_object ("node-proxy", "node-proxy",
"Pointer to the node proxy of the device", WP_TYPE_PROXY_NODE,
@ -510,91 +558,22 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass)
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
static void
handle_port(WpPwAudioSoftdspEndpoint *self, uint32_t id, uint32_t parent_id,
const struct spa_dict *props)
{
const char *direction_prop = NULL;
enum pw_direction direction;
/* Make sure the dsp port is not already set*/
if (self->dsp_port_id != 0)
return;
/* Make sure the port has porperties */
if (!props)
return;
/* Only handle ports owned by this endpoint */
if (!self->dsp_info || self->dsp_info->id != parent_id)
return;
/* Get the direction property */
direction_prop = spa_dict_lookup(props, "port.direction");
if (!direction_prop)
return;
direction =
!strcmp(direction_prop, "out") ? PW_DIRECTION_OUTPUT : PW_DIRECTION_INPUT;
/* Only handle ports with the oposit direction of the endpoint */
if (self->direction == direction)
return;
/* Set the dsp port id */
self->dsp_port_id = id;
}
static void
registry_global(void *data, uint32_t id, uint32_t parent_id,
uint32_t permissions, uint32_t type, uint32_t version,
const struct spa_dict *props)
{
WpPwAudioSoftdspEndpoint *self = data;
switch (type) {
case PW_TYPE_INTERFACE_Port:
handle_port(self, id, parent_id, props);
break;
default:
break;
}
}
static const struct pw_registry_proxy_events registry_events = {
PW_VERSION_REGISTRY_PROXY_EVENTS,
.global = registry_global,
};
static gpointer
endpoint_factory (WpFactory * factory, GType type, GVariant * properties)
{
g_autoptr (WpCore) wp_core = NULL;
WpRemote *remote;
struct pw_remote *pw_remote;
g_autoptr (WpCore) core = NULL;
const gchar *name = NULL;
const gchar *media_class = NULL;
guint64 proxy_node, proxy_port;
/* Make sure the type is not the base class type */
if (type != WP_TYPE_ENDPOINT)
return NULL;
/* Make sure the type is correct */
g_return_val_if_fail(type == WP_TYPE_ENDPOINT, NULL);
/* Get the WirePlumber core */
wp_core = wp_factory_get_core(factory);
if (!wp_core) {
g_warning("failed to get wireplumbe core. Skipping...");
return NULL;
}
/* Get the Core */
core = wp_factory_get_core(factory);
g_return_val_if_fail (core, NULL);
/* Get the remote */
remote = wp_core_get_global(wp_core, WP_GLOBAL_REMOTE_PIPEWIRE);
if (!remote) {
g_warning("failed to get core remote. Skipping...");
return NULL;
}
/* Get the name and media-class */
/* Get the properties */
if (!g_variant_lookup (properties, "name", "&s", &name))
return NULL;
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
@ -604,36 +583,14 @@ endpoint_factory (WpFactory * factory, GType type, GVariant * properties)
if (!g_variant_lookup (properties, "proxy-port", "t", &proxy_port))
return NULL;
/* Create the softdsp endpoint object */
WpPwAudioSoftdspEndpoint *ep = g_object_new (endpoint_get_type (),
"core", wp_core,
/* Create and return the softdsp endpoint object */
return g_object_new (endpoint_get_type (),
"core", core,
"name", name,
"media-class", media_class,
"node-proxy", (gpointer) proxy_node,
"port-proxy", (gpointer) proxy_port,
NULL);
if (!ep)
return NULL;
/* Set the core proxy */
g_object_get (remote, "pw-remote", &pw_remote, NULL);
ep->core_proxy = pw_remote_get_core_proxy(pw_remote);
if (!ep->core_proxy) {
g_warning("failed to get core proxy. Skipping...");
return NULL;
}
/* Add registry listener */
ep->registry_proxy = pw_core_proxy_get_registry (ep->core_proxy,
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
pw_registry_proxy_add_listener(ep->registry_proxy, &ep->registry_listener,
&registry_events, ep);
/* Emit the audio DSP node */
emit_audio_dsp_node(ep);
/* Return the object */
return ep;
}
void