module-pipewire and simple-endpoint: use the new Proxy API
This commit is contained in:
@@ -27,150 +27,258 @@ struct module_data
|
|||||||
{
|
{
|
||||||
WpModule *module;
|
WpModule *module;
|
||||||
|
|
||||||
|
/* Registry */
|
||||||
struct pw_registry_proxy *registry_proxy;
|
struct pw_registry_proxy *registry_proxy;
|
||||||
struct spa_hook registry_listener;
|
struct spa_hook registry_listener;
|
||||||
|
|
||||||
struct pw_core_proxy *core_proxy;
|
/* Client nodes info */
|
||||||
struct spa_hook core_listener;
|
GHashTable *client_nodes_info;
|
||||||
GQueue *done_queue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct endpoint_info
|
||||||
typedef void (*WpDoneCallback)(gpointer, gpointer);
|
|
||||||
|
|
||||||
struct done_data
|
|
||||||
{
|
{
|
||||||
WpDoneCallback callback;
|
gchar *name;
|
||||||
gpointer data;
|
gchar *media_class;
|
||||||
GDestroyNotify data_destroy;
|
const struct pw_proxy *proxy;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct proxy_info
|
||||||
|
{
|
||||||
|
const struct module_data *data;
|
||||||
|
uint32_t node_id;
|
||||||
|
WpProxyPort *proxy_port;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
done_data_destroy(gpointer p)
|
endpoint_info_destroy(gpointer p)
|
||||||
{
|
{
|
||||||
struct done_data *dd = p;
|
struct endpoint_info *ei = p;
|
||||||
if (dd->data_destroy) {
|
|
||||||
dd->data_destroy(dd->data);
|
/* Free the name */
|
||||||
dd->data = NULL;
|
if (ei->name) {
|
||||||
|
g_free (ei->name);
|
||||||
|
ei->name = NULL;
|
||||||
}
|
}
|
||||||
g_slice_free (struct done_data, dd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
/* Free the media class */
|
||||||
sync_core_with_callback(struct module_data* impl, WpDoneCallback callback,
|
if (ei->media_class) {
|
||||||
gpointer data, GDestroyNotify data_destroy)
|
g_free (ei->media_class);
|
||||||
{
|
ei->media_class = NULL;
|
||||||
struct done_data *dd = g_new0(struct done_data, 1);
|
|
||||||
|
|
||||||
/* Set the data */
|
|
||||||
dd->callback = callback;
|
|
||||||
dd->data = data;
|
|
||||||
dd->data_destroy = data_destroy;
|
|
||||||
|
|
||||||
/* Add the data to the queue */
|
|
||||||
g_queue_push_tail (impl->done_queue, dd);
|
|
||||||
|
|
||||||
/* Sync the core */
|
|
||||||
pw_core_proxy_sync(impl->core_proxy, 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
core_done(void *d, uint32_t id, int seq)
|
|
||||||
{
|
|
||||||
struct module_data * impl = d;
|
|
||||||
struct done_data * dd = NULL;
|
|
||||||
|
|
||||||
/* Process all the done_data queue */
|
|
||||||
while ((dd = g_queue_pop_head(impl->done_queue))) {
|
|
||||||
if (dd->callback)
|
|
||||||
dd->callback(impl, dd->data);
|
|
||||||
done_data_destroy(dd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
g_slice_free (struct endpoint_info, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct pw_core_proxy_events core_events = {
|
|
||||||
PW_VERSION_CORE_EVENTS,
|
|
||||||
.done = core_done
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
register_endpoint (struct module_data* data, WpEndpoint *ep)
|
proxy_info_destroy(gpointer p)
|
||||||
{
|
{
|
||||||
g_autoptr (WpCore) core = NULL;
|
struct proxy_info *pi = p;
|
||||||
core = wp_module_get_core (data->module);
|
|
||||||
g_return_if_fail (core != NULL);
|
/* Unref the proxy port */
|
||||||
wp_endpoint_register (ep, core);
|
if (pi->proxy_port) {
|
||||||
|
g_object_unref (pi->proxy_port);
|
||||||
|
pi->proxy_port = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
g_slice_free (struct proxy_info, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
registry_global (void * d, uint32_t id, uint32_t parent_id,
|
proxy_node_created(GObject *initable, GAsyncResult *res, gpointer d)
|
||||||
uint32_t permissions, uint32_t type, uint32_t version,
|
{
|
||||||
|
struct proxy_info *pi = d;
|
||||||
|
const struct module_data *data = pi->data;
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||||
|
WpProxyNode *proxy_node = NULL;
|
||||||
|
struct endpoint_info *ei = NULL;
|
||||||
|
WpEndpoint *endpoint = NULL;
|
||||||
|
g_autoptr (GVariant) endpoint_props = NULL;
|
||||||
|
GVariantBuilder b;
|
||||||
|
|
||||||
|
/* Get the proxy */
|
||||||
|
proxy_node = wp_proxy_node_new_finish(initable, res, NULL);
|
||||||
|
if (!proxy_node)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Register the proxy node */
|
||||||
|
wp_proxy_register(WP_PROXY(proxy_node));
|
||||||
|
|
||||||
|
/* Get the client node info */
|
||||||
|
ei = g_hash_table_lookup(data->client_nodes_info,
|
||||||
|
GINT_TO_POINTER(pi->node_id));
|
||||||
|
if (!ei)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Set the properties */
|
||||||
|
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||||
|
g_variant_builder_add (&b, "{sv}",
|
||||||
|
"name", ei->name ? g_variant_new_string (ei->name) :
|
||||||
|
g_variant_new_take_string (
|
||||||
|
g_strdup_printf ("Stream %u", pi->node_id)));
|
||||||
|
g_variant_builder_add (&b, "{sv}",
|
||||||
|
"media-class", g_variant_new_string (ei->media_class));
|
||||||
|
g_variant_builder_add (&b, "{sv}",
|
||||||
|
"proxy-node", g_variant_new_uint64 ((guint64) proxy_node));
|
||||||
|
g_variant_builder_add (&b, "{sv}",
|
||||||
|
"proxy-port", g_variant_new_uint64 ((guint64)
|
||||||
|
g_object_ref(pi->proxy_port)));
|
||||||
|
endpoint_props = g_variant_builder_end (&b);
|
||||||
|
|
||||||
|
/* Create the endpoint */
|
||||||
|
endpoint = wp_factory_make (core, "pipewire-simple-endpoint",
|
||||||
|
WP_TYPE_ENDPOINT, endpoint_props);
|
||||||
|
|
||||||
|
/* Register the endpoint */
|
||||||
|
wp_endpoint_register (endpoint, core);
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
|
proxy_info_destroy (pi);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
proxy_port_created(GObject *initable, GAsyncResult *res, gpointer d)
|
||||||
|
{
|
||||||
|
struct proxy_info *pi = d;
|
||||||
|
const struct module_data *data = pi->data;
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||||
|
WpProxyPort *proxy_port = NULL;
|
||||||
|
struct pw_proxy *proxy = NULL;
|
||||||
|
|
||||||
|
/* Get the proxy port */
|
||||||
|
proxy_port = wp_proxy_port_new_finish(initable, res, NULL);
|
||||||
|
if (!proxy_port)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Register the proxy port */
|
||||||
|
wp_proxy_register(WP_PROXY(proxy_port));
|
||||||
|
|
||||||
|
/* Forward the proxy port */
|
||||||
|
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)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Create the proxy node asynchronically */
|
||||||
|
wp_proxy_node_new(core, 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)
|
const struct spa_dict * props)
|
||||||
{
|
{
|
||||||
struct module_data *data = d;
|
struct endpoint_info *ei = NULL;
|
||||||
const gchar *name;
|
const gchar *name;
|
||||||
const gchar *media_class;
|
const gchar *media_class;
|
||||||
struct pw_proxy *proxy;
|
struct pw_proxy *proxy;
|
||||||
GVariantBuilder b;
|
|
||||||
g_autoptr (GVariant) endpoint_props = NULL;
|
|
||||||
g_autoptr (WpCore) core = NULL;
|
|
||||||
g_autoptr (WpEndpoint) endpoint = NULL;
|
|
||||||
struct spa_audio_info_raw format = { 0, };
|
struct spa_audio_info_raw format = { 0, };
|
||||||
struct spa_pod *param;
|
struct spa_pod *param;
|
||||||
struct spa_pod_builder pod_builder = { 0, };
|
struct spa_pod_builder pod_builder = { 0, };
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
|
|
||||||
/* listen for client "Stream" nodes and create endpoints for them */
|
/* Make sure the node has properties */
|
||||||
if (type == PW_TYPE_INTERFACE_Node &&
|
if (!props) {
|
||||||
props && (media_class = spa_dict_lookup(props, "media.class")) &&
|
g_warning("node has no properties, skipping...");
|
||||||
g_str_has_prefix (media_class, "Stream/"))
|
return;
|
||||||
{
|
}
|
||||||
name = spa_dict_lookup (props, "media.name");
|
|
||||||
if (!name)
|
|
||||||
name = spa_dict_lookup (props, "node.name");
|
|
||||||
|
|
||||||
g_debug ("found stream node: id:%u ; name:%s ; media_class:%s", id, name,
|
/* Get the media_class */
|
||||||
media_class);
|
media_class = spa_dict_lookup(props, "media.class");
|
||||||
|
|
||||||
proxy = pw_registry_proxy_bind (data->registry_proxy,
|
/* Only handle client Stream nodes */
|
||||||
id, type, PW_VERSION_NODE, 0);
|
if (!g_str_has_prefix (media_class, "Stream/"))
|
||||||
|
return;
|
||||||
|
|
||||||
/* TODO: we need to get this from the EnumFormat event */
|
/* Get the name */
|
||||||
format.format = SPA_AUDIO_FORMAT_F32P;
|
name = spa_dict_lookup (props, "media.name");
|
||||||
format.flags = 1;
|
if (!name)
|
||||||
format.rate = 48000;
|
name = spa_dict_lookup (props, "node.name");
|
||||||
format.channels = 2;
|
|
||||||
format.position[0] = 0;
|
|
||||||
format.position[1] = 0;
|
|
||||||
|
|
||||||
/* Set the profile */
|
g_debug ("found stream node: id:%u ; name:%s ; media_class:%s", id, name,
|
||||||
spa_pod_builder_init(&pod_builder, buf, sizeof(buf));
|
media_class);
|
||||||
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
|
||||||
param = spa_pod_builder_add_object(&pod_builder,
|
|
||||||
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
|
|
||||||
SPA_PARAM_PROFILE_direction, SPA_POD_Id(PW_DIRECTION_OUTPUT),
|
|
||||||
SPA_PARAM_PROFILE_format, SPA_POD_Pod(param));
|
|
||||||
pw_node_proxy_set_param((struct pw_node_proxy*)proxy,
|
|
||||||
SPA_PARAM_Profile, 0, param);
|
|
||||||
|
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
/* Get the proxy */
|
||||||
g_variant_builder_add (&b, "{sv}", "node-id", g_variant_new_uint32 (id));
|
proxy = pw_registry_proxy_bind (data->registry_proxy, id,
|
||||||
g_variant_builder_add (&b, "{sv}",
|
PW_TYPE_INTERFACE_Node, PW_VERSION_NODE, 0);
|
||||||
"name", name ? g_variant_new_string (name) :
|
|
||||||
g_variant_new_take_string (g_strdup_printf ("Stream %u", id)));
|
|
||||||
g_variant_builder_add (&b, "{sv}",
|
|
||||||
"media-class", g_variant_new_string (media_class));
|
|
||||||
g_variant_builder_add (&b, "{sv}",
|
|
||||||
"node-proxy", g_variant_new_uint64 ((guint64) proxy));
|
|
||||||
endpoint_props = g_variant_builder_end (&b);
|
|
||||||
|
|
||||||
core = wp_module_get_core (data->module);
|
/* TODO: Assume all clients have this format for now */
|
||||||
g_return_if_fail (core != NULL);
|
format.format = SPA_AUDIO_FORMAT_F32P;
|
||||||
|
format.flags = 1;
|
||||||
|
format.rate = 48000;
|
||||||
|
format.channels = 1;
|
||||||
|
format.position[0] = 0;
|
||||||
|
|
||||||
endpoint = wp_factory_make (core, "pipewire-simple-endpoint",
|
/* Set the profile */
|
||||||
WP_TYPE_ENDPOINT, endpoint_props);
|
spa_pod_builder_init(&pod_builder, buf, sizeof(buf));
|
||||||
sync_core_with_callback (data, (WpDoneCallback) register_endpoint,
|
param = spa_format_audio_raw_build(&pod_builder, SPA_PARAM_Format, &format);
|
||||||
g_steal_pointer (&endpoint), g_object_unref);
|
param = spa_pod_builder_add_object(&pod_builder,
|
||||||
|
SPA_TYPE_OBJECT_ParamProfile, SPA_PARAM_Profile,
|
||||||
|
SPA_PARAM_PROFILE_direction, SPA_POD_Id(PW_DIRECTION_OUTPUT),
|
||||||
|
SPA_PARAM_PROFILE_format, SPA_POD_Pod(param));
|
||||||
|
pw_node_proxy_set_param((struct pw_node_proxy*)proxy,
|
||||||
|
SPA_PARAM_Profile, 0, param);
|
||||||
|
|
||||||
|
/* Create the endpoint info */
|
||||||
|
ei = g_new0(struct endpoint_info, 1);
|
||||||
|
ei->name = g_strdup(name);
|
||||||
|
ei->media_class = g_strdup(media_class);
|
||||||
|
ei->proxy = proxy;
|
||||||
|
|
||||||
|
/* Insert the client node info in the hash table */
|
||||||
|
g_hash_table_insert(data->client_nodes_info, GINT_TO_POINTER (id), ei);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_port(struct module_data *data, uint32_t id, uint32_t parent_id,
|
||||||
|
const struct spa_dict *props)
|
||||||
|
{
|
||||||
|
g_autoptr (WpCore) core = wp_module_get_core (data->module);
|
||||||
|
struct proxy_info *pi = NULL;
|
||||||
|
struct pw_proxy *proxy = NULL;
|
||||||
|
|
||||||
|
/* Only handle ports whose parent is an alsa node */
|
||||||
|
if (!g_hash_table_contains(data->client_nodes_info,
|
||||||
|
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);
|
||||||
|
if (!proxy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Create the port info */
|
||||||
|
pi = g_new0(struct proxy_info, 1);
|
||||||
|
pi->data = data;
|
||||||
|
pi->node_id = parent_id;
|
||||||
|
pi->proxy_port = NULL;
|
||||||
|
|
||||||
|
/* Create the proxy port asynchronically */
|
||||||
|
wp_proxy_port_new(core, 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,9 +296,7 @@ on_remote_connected (WpRemote *remote, WpRemoteState state,
|
|||||||
|
|
||||||
g_object_get (remote, "pw-remote", &pw_remote, NULL);
|
g_object_get (remote, "pw-remote", &pw_remote, NULL);
|
||||||
|
|
||||||
core_proxy = data->core_proxy = pw_remote_get_core_proxy (pw_remote);
|
core_proxy = pw_remote_get_core_proxy (pw_remote);
|
||||||
pw_core_proxy_add_listener(data->core_proxy, &data->core_listener,
|
|
||||||
&core_events, data);
|
|
||||||
data->registry_proxy = pw_core_proxy_get_registry (core_proxy,
|
data->registry_proxy = pw_core_proxy_get_registry (core_proxy,
|
||||||
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
|
PW_TYPE_INTERFACE_Registry, PW_VERSION_REGISTRY, 0);
|
||||||
pw_registry_proxy_add_listener(data->registry_proxy,
|
pw_registry_proxy_add_listener(data->registry_proxy,
|
||||||
@@ -202,7 +308,13 @@ module_destroy (gpointer d)
|
|||||||
{
|
{
|
||||||
struct module_data *data = d;
|
struct module_data *data = d;
|
||||||
|
|
||||||
g_queue_free_full(data->done_queue, done_data_destroy);
|
/* Destroy the hash table */
|
||||||
|
if (data->client_nodes_info) {
|
||||||
|
g_hash_table_destroy(data->client_nodes_info);
|
||||||
|
data->client_nodes_info = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean up */
|
||||||
g_slice_free (struct module_data, data);
|
g_slice_free (struct module_data, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,9 +333,12 @@ wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Create the module data */
|
||||||
data = g_slice_new0 (struct module_data);
|
data = g_slice_new0 (struct module_data);
|
||||||
data->module = module;
|
data->module = module;
|
||||||
data->done_queue = g_queue_new();
|
data->client_nodes_info = g_hash_table_new_full (g_direct_hash,
|
||||||
|
g_direct_equal, NULL, endpoint_info_destroy);
|
||||||
|
|
||||||
wp_module_set_destroy_callback (module, module_destroy, data);
|
wp_module_set_destroy_callback (module, module_destroy, data);
|
||||||
|
|
||||||
g_signal_connect (remote, "state-changed::connected",
|
g_signal_connect (remote, "state-changed::connected",
|
||||||
|
@@ -22,14 +22,11 @@ struct _WpPipewireSimpleEndpoint
|
|||||||
{
|
{
|
||||||
WpEndpoint parent;
|
WpEndpoint parent;
|
||||||
|
|
||||||
/* Node */
|
/* Proxy */
|
||||||
struct pw_node_proxy *node;
|
WpProxyNode *proxy_node;
|
||||||
struct spa_hook proxy_listener;
|
WpProxyPort *proxy_port;
|
||||||
struct spa_hook node_proxy_listener;
|
struct spa_hook node_proxy_listener;
|
||||||
|
|
||||||
/* Info */
|
|
||||||
struct pw_node_info *info;
|
|
||||||
|
|
||||||
/* controls cache */
|
/* controls cache */
|
||||||
gfloat volume;
|
gfloat volume;
|
||||||
gboolean mute;
|
gboolean mute;
|
||||||
@@ -38,6 +35,7 @@ struct _WpPipewireSimpleEndpoint
|
|||||||
enum {
|
enum {
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_NODE_PROXY,
|
PROP_NODE_PROXY,
|
||||||
|
PROP_PORT_PROXY
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -96,15 +94,8 @@ node_proxy_param (void *object, int seq, uint32_t id,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void node_proxy_info(void *object, const struct pw_node_info *info)
|
|
||||||
{
|
|
||||||
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
|
|
||||||
self->info = pw_node_info_update(self->info, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_node_proxy_events node_node_proxy_events = {
|
static const struct pw_node_proxy_events node_node_proxy_events = {
|
||||||
PW_VERSION_NODE_PROXY_EVENTS,
|
PW_VERSION_NODE_PROXY_EVENTS,
|
||||||
.info = node_proxy_info,
|
|
||||||
.param = node_proxy_param,
|
.param = node_proxy_param,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,21 +104,6 @@ simple_endpoint_init (WpPipewireSimpleEndpoint * self)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
node_proxy_destroy (void *data)
|
|
||||||
{
|
|
||||||
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (data);
|
|
||||||
self->node = NULL;
|
|
||||||
|
|
||||||
wp_endpoint_unregister (WP_ENDPOINT (self));
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct pw_proxy_events node_proxy_events = {
|
|
||||||
PW_VERSION_PROXY_EVENTS,
|
|
||||||
.destroy = node_proxy_destroy,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
simple_endpoint_constructed (GObject * object)
|
simple_endpoint_constructed (GObject * object)
|
||||||
{
|
{
|
||||||
@@ -135,13 +111,13 @@ simple_endpoint_constructed (GObject * object)
|
|||||||
GVariantDict d;
|
GVariantDict d;
|
||||||
uint32_t ids[1] = { SPA_PARAM_Props };
|
uint32_t ids[1] = { SPA_PARAM_Props };
|
||||||
uint32_t n_ids = 1;
|
uint32_t n_ids = 1;
|
||||||
|
struct pw_node_proxy *node_proxy = NULL;
|
||||||
|
|
||||||
pw_proxy_add_listener ((struct pw_proxy *) self->node, &self->proxy_listener,
|
/* Add a custom node proxy event listener */
|
||||||
&node_proxy_events, self);
|
node_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy_node));
|
||||||
|
pw_node_proxy_add_listener (node_proxy, &self->node_proxy_listener,
|
||||||
pw_node_proxy_add_listener (self->node, &self->node_proxy_listener,
|
|
||||||
&node_node_proxy_events, self);
|
&node_node_proxy_events, self);
|
||||||
pw_node_proxy_subscribe_params (self->node, ids, n_ids);
|
pw_node_proxy_subscribe_params (node_proxy, ids, n_ids);
|
||||||
|
|
||||||
g_variant_dict_init (&d, NULL);
|
g_variant_dict_init (&d, NULL);
|
||||||
g_variant_dict_insert (&d, "id", "u", 0);
|
g_variant_dict_insert (&d, "id", "u", 0);
|
||||||
@@ -176,9 +152,10 @@ simple_endpoint_finalize (GObject * object)
|
|||||||
{
|
{
|
||||||
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
|
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
|
||||||
|
|
||||||
if (self->node) {
|
/* Unref the proxy node */
|
||||||
spa_hook_remove (&self->proxy_listener);
|
if (self->proxy_node) {
|
||||||
pw_proxy_destroy ((struct pw_proxy *) self->node);
|
g_object_unref(self->proxy_node);
|
||||||
|
self->proxy_node = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
G_OBJECT_CLASS (simple_endpoint_parent_class)->finalize (object);
|
G_OBJECT_CLASS (simple_endpoint_parent_class)->finalize (object);
|
||||||
@@ -192,7 +169,12 @@ simple_endpoint_set_property (GObject * object, guint property_id,
|
|||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_NODE_PROXY:
|
case PROP_NODE_PROXY:
|
||||||
self->node = g_value_get_pointer (value);
|
g_clear_object(&self->proxy_node);
|
||||||
|
self->proxy_node = g_value_get_object(value);
|
||||||
|
break;
|
||||||
|
case PROP_PORT_PROXY:
|
||||||
|
g_clear_object(&self->proxy_port);
|
||||||
|
self->proxy_port = g_value_get_object(value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
@@ -208,7 +190,10 @@ simple_endpoint_get_property (GObject * object, guint property_id,
|
|||||||
|
|
||||||
switch (property_id) {
|
switch (property_id) {
|
||||||
case PROP_NODE_PROXY:
|
case PROP_NODE_PROXY:
|
||||||
g_value_set_pointer (value, self->node);
|
g_value_set_object (value, self->proxy_node);
|
||||||
|
break;
|
||||||
|
case PROP_PORT_PROXY:
|
||||||
|
g_value_set_object (value, self->proxy_port);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
@@ -221,6 +206,7 @@ simple_endpoint_prepare_link (WpEndpoint * ep, guint32 stream_id,
|
|||||||
WpEndpointLink * link, GVariant ** properties, GError ** error)
|
WpEndpointLink * link, GVariant ** properties, GError ** error)
|
||||||
{
|
{
|
||||||
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (ep);
|
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (ep);
|
||||||
|
const struct pw_node_info *node_info = NULL;
|
||||||
GVariantBuilder b;
|
GVariantBuilder b;
|
||||||
|
|
||||||
/* TODO: Since the linking with a 1 port client works when passing -1 as
|
/* TODO: Since the linking with a 1 port client works when passing -1 as
|
||||||
@@ -228,12 +214,15 @@ simple_endpoint_prepare_link (WpEndpoint * ep, guint32 stream_id,
|
|||||||
* properties. However, we need to add logic here and select the correct
|
* properties. However, we need to add logic here and select the correct
|
||||||
* port in case the client has more than 1 port */
|
* port in case the client has more than 1 port */
|
||||||
|
|
||||||
/* Set the port format here */
|
/* Get the node info */
|
||||||
|
node_info = wp_proxy_node_get_info(self->proxy_node);
|
||||||
|
if (!node_info)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
/* Set the properties */
|
/* Set the properties */
|
||||||
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
|
||||||
g_variant_builder_add (&b, "{sv}", "node-id",
|
g_variant_builder_add (&b, "{sv}", "node-id",
|
||||||
g_variant_new_uint32 (self->info->id));
|
g_variant_new_uint32 (node_info->id));
|
||||||
g_variant_builder_add (&b, "{sv}", "node-port-id",
|
g_variant_builder_add (&b, "{sv}", "node-port-id",
|
||||||
g_variant_new_uint32 (-1));
|
g_variant_new_uint32 (-1));
|
||||||
*properties = g_variant_builder_end (&b);
|
*properties = g_variant_builder_end (&b);
|
||||||
@@ -266,6 +255,10 @@ simple_endpoint_set_control_value (WpEndpoint * ep, guint32 control_id,
|
|||||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||||
float volume;
|
float volume;
|
||||||
bool mute;
|
bool mute;
|
||||||
|
struct pw_node_proxy *node_proxy = NULL;
|
||||||
|
|
||||||
|
/* Get the node proxy */
|
||||||
|
node_proxy = wp_proxy_get_pw_proxy(WP_PROXY(self->proxy_node));
|
||||||
|
|
||||||
switch (control_id) {
|
switch (control_id) {
|
||||||
case CONTROL_VOLUME:
|
case CONTROL_VOLUME:
|
||||||
@@ -274,7 +267,7 @@ simple_endpoint_set_control_value (WpEndpoint * ep, guint32 control_id,
|
|||||||
g_debug("WpEndpoint:%p set volume control (%u) value, vol:%f", self,
|
g_debug("WpEndpoint:%p set volume control (%u) value, vol:%f", self,
|
||||||
control_id, volume);
|
control_id, volume);
|
||||||
|
|
||||||
pw_node_proxy_set_param (self->node,
|
pw_node_proxy_set_param (node_proxy,
|
||||||
SPA_PARAM_Props, 0,
|
SPA_PARAM_Props, 0,
|
||||||
spa_pod_builder_add_object (&b,
|
spa_pod_builder_add_object (&b,
|
||||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
||||||
@@ -288,7 +281,7 @@ simple_endpoint_set_control_value (WpEndpoint * ep, guint32 control_id,
|
|||||||
g_debug("WpEndpoint:%p set mute control (%u) value, mute:%d", self,
|
g_debug("WpEndpoint:%p set mute control (%u) value, mute:%d", self,
|
||||||
control_id, mute);
|
control_id, mute);
|
||||||
|
|
||||||
pw_node_proxy_set_param (self->node,
|
pw_node_proxy_set_param (node_proxy,
|
||||||
SPA_PARAM_Props, 0,
|
SPA_PARAM_Props, 0,
|
||||||
spa_pod_builder_add_object (&b,
|
spa_pod_builder_add_object (&b,
|
||||||
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
SPA_TYPE_OBJECT_Props, SPA_PARAM_Props,
|
||||||
@@ -320,8 +313,12 @@ simple_endpoint_class_init (WpPipewireSimpleEndpointClass * klass)
|
|||||||
endpoint_class->set_control_value = simple_endpoint_set_control_value;
|
endpoint_class->set_control_value = simple_endpoint_set_control_value;
|
||||||
|
|
||||||
g_object_class_install_property (object_class, PROP_NODE_PROXY,
|
g_object_class_install_property (object_class, PROP_NODE_PROXY,
|
||||||
g_param_spec_pointer ("node-proxy", "node-proxy",
|
g_param_spec_object ("node-proxy", "node-proxy",
|
||||||
"Pointer to the pw_node_proxy* to wrap",
|
"Pointer to the node proxy of the client", WP_TYPE_PROXY_NODE,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
|
g_object_class_install_property (object_class, PROP_PORT_PROXY,
|
||||||
|
g_param_spec_object ("port-proxy", "port-proxy",
|
||||||
|
"Pointer to the port proxy of the client", WP_TYPE_PROXY_PORT,
|
||||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,7 +326,8 @@ gpointer
|
|||||||
simple_endpoint_factory (WpFactory * factory, GType type,
|
simple_endpoint_factory (WpFactory * factory, GType type,
|
||||||
GVariant * properties)
|
GVariant * properties)
|
||||||
{
|
{
|
||||||
guint64 proxy;
|
guint64 proxy_node;
|
||||||
|
guint64 proxy_port;
|
||||||
const gchar *name;
|
const gchar *name;
|
||||||
const gchar *media_class;
|
const gchar *media_class;
|
||||||
|
|
||||||
@@ -342,12 +340,15 @@ simple_endpoint_factory (WpFactory * factory, GType type,
|
|||||||
return NULL;
|
return NULL;
|
||||||
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
|
||||||
return NULL;
|
return NULL;
|
||||||
if (!g_variant_lookup (properties, "node-proxy", "t", &proxy))
|
if (!g_variant_lookup (properties, "proxy-node", "t", &proxy_node))
|
||||||
|
return NULL;
|
||||||
|
if (!g_variant_lookup (properties, "proxy-port", "t", &proxy_port))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return g_object_new (simple_endpoint_get_type (),
|
return g_object_new (simple_endpoint_get_type (),
|
||||||
"name", name,
|
"name", name,
|
||||||
"media-class", media_class,
|
"media-class", media_class,
|
||||||
"node-proxy", (gpointer) proxy,
|
"node-proxy", (gpointer) proxy_node,
|
||||||
|
"port-proxy", (gpointer) proxy_port,
|
||||||
NULL);
|
NULL);
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user