Files
wireplumber/modules/module-pw-audio-client.c
George Kiagiadakis a63f2bb99b lib/wp: merge both WpRemote & WpRemotePipewire in WpCore
In practice we always create a remote and connect to pipewire.
Any other scenario is invalid, therefore, it is not justified
to be confused with so many classes for such small functionality.
This simplifies a lot the modules code.

Also, this commit exposes the pw_core and pw_remote objects
out of WpCore. This is in practice useful when dealing with low-level
pw and spa factories, which are used in the monitors. Let's not
add API wrappers for everything... Bindings will never use this
functionality anyway, since it depends on low level pipewire C API.
2019-09-07 17:55:46 +03:00

151 lines
4.3 KiB
C

/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author Julian Bouzas <julian.bouzas@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
/**
* module-pw-audio-client provides a WpEndpoint implementation
* that wraps an audio client node in pipewire into an endpoint
*/
#include <wp/wp.h>
#include <pipewire/pipewire.h>
struct module_data
{
GHashTable *registered_endpoints;
};
static void
on_endpoint_created(GObject *initable, GAsyncResult *res, gpointer d)
{
struct module_data *data = d;
g_autoptr (WpEndpoint) endpoint = NULL;
g_autoptr (WpProxy) proxy = NULL;
guint global_id = 0;
GError *error = NULL;
/* Get the endpoint */
endpoint = wp_endpoint_new_finish(initable, res, &error);
if (error) {
g_warning ("Failed to create client endpoint: %s", error->message);
return;
}
/* Get the endpoint global id */
g_object_get (endpoint, "proxy-node", &proxy, NULL);
global_id = wp_proxy_get_global_id (proxy);
g_debug ("Created client endpoint for global id %d", global_id);
/* Register the endpoint and add it to the table */
wp_endpoint_register (endpoint);
g_hash_table_insert (data->registered_endpoints, GUINT_TO_POINTER(global_id),
g_steal_pointer (&endpoint));
}
static void
on_node_added (WpCore *core, WpProxy *proxy, gpointer d)
{
struct module_data *data = d;
const gchar *name, *media_class;
enum pw_direction direction;
GVariantBuilder b;
g_autoptr (GVariant) endpoint_props = NULL;
guint32 id = wp_proxy_get_global_id (proxy);
g_autoptr (WpProperties) props = wp_proxy_get_global_properties (proxy);
/* Get the media_class */
media_class = wp_properties_get (props, PW_KEY_MEDIA_CLASS);
/* Only handle client Stream nodes */
if (!g_str_has_prefix (media_class, "Stream/"))
return;
/* Get the direction */
if (g_str_has_prefix (media_class, "Stream/Input")) {
direction = PW_DIRECTION_INPUT;
} else if (g_str_has_prefix (media_class, "Stream/Output")) {
direction = PW_DIRECTION_OUTPUT;
} else {
g_critical ("failed to parse direction");
return;
}
/* Get the name */
name = wp_properties_get (props, PW_KEY_MEDIA_NAME);
if (!name)
name = wp_properties_get (props, PW_KEY_NODE_NAME);
/* Set the properties */
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}",
"name", name ?
g_variant_new_take_string (g_strdup_printf ("Stream %u (%s)", id, 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}",
"direction", g_variant_new_uint32 (direction));
g_variant_builder_add (&b, "{sv}",
"proxy-node", g_variant_new_uint64 ((guint64) proxy));
endpoint_props = g_variant_builder_end (&b);
/* Create the endpoint async */
wp_factory_make (core, "pipewire-simple-endpoint", WP_TYPE_ENDPOINT,
endpoint_props, on_endpoint_created, data);
}
static void
on_node_removed (WpCore *core, WpProxy *proxy, gpointer d)
{
struct module_data *data = d;
WpEndpoint *endpoint = NULL;
guint32 id = wp_proxy_get_global_id (proxy);
/* Get the endpoint */
endpoint = g_hash_table_lookup (data->registered_endpoints,
GUINT_TO_POINTER(id));
if (!endpoint)
return;
/* Unregister the endpoint and remove it from the table */
wp_endpoint_unregister (endpoint);
g_hash_table_remove (data->registered_endpoints, GUINT_TO_POINTER(id));
}
static void
module_destroy (gpointer d)
{
struct module_data *data = d;
/* Destroy the registered endpoints table */
g_clear_pointer (&data->registered_endpoints, g_hash_table_unref);
/* Clean up */
g_slice_free (struct module_data, data);
}
void
wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
{
struct module_data *data;
/* Create the module data */
data = g_slice_new0 (struct module_data);
data->registered_endpoints = g_hash_table_new_full (g_direct_hash,
g_direct_equal, NULL, (GDestroyNotify)g_object_unref);
/* Set the module destroy callback */
wp_module_set_destroy_callback (module, module_destroy, data);
/* Register the global added/removed callbacks */
g_signal_connect(core, "remote-global-added::node",
(GCallback) on_node_added, data);
g_signal_connect(core, "remote-global-removed::node",
(GCallback) on_node_removed, data);
}