Files
wireplumber/modules/module-pipewire/simple-endpoint.c

165 lines
4.5 KiB
C

/* WirePlumber
*
* Copyright © 2019 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: LGPL-2.1-or-later
*/
/**
* The simple endpoint is a WpEndpoint implementation that represents
* all ports of a single direction of a single pipewire node.
* It can be used to create an Endpoint for a client node or for any
* other arbitrary node that does not need any kind of internal management.
*/
#include <wp/wp.h>
#include <pipewire/pipewire.h>
struct _WpPipewireSimpleEndpoint
{
WpEndpoint parent;
struct pw_node_proxy *node;
struct spa_hook proxy_listener;
};
enum {
PROP_0,
PROP_NODE_PROXY,
};
G_DECLARE_FINAL_TYPE (WpPipewireSimpleEndpoint,
simple_endpoint, WP_PIPEWIRE, SIMPLE_ENDPOINT, WpEndpoint)
G_DEFINE_TYPE (WpPipewireSimpleEndpoint, simple_endpoint, WP_TYPE_ENDPOINT)
static void
simple_endpoint_init (WpPipewireSimpleEndpoint * self)
{
GVariantBuilder b;
g_variant_builder_init (&b, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&b, "{sv}", "id", g_variant_new_uint32 (0));
g_variant_builder_add (&b, "{sv}", "name", g_variant_new_string ("default"));
wp_endpoint_register_stream (WP_ENDPOINT (self), g_variant_builder_end (&b));
}
static void
simple_endpoint_finalize (GObject * object)
{
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
if (self->node) {
spa_hook_remove (&self->proxy_listener);
pw_proxy_destroy ((struct pw_proxy *) self->node);
}
G_OBJECT_CLASS (simple_endpoint_parent_class)->finalize (object);
}
static void
simple_endpoint_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
switch (property_id) {
case PROP_NODE_PROXY:
self->node = g_value_get_pointer (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
simple_endpoint_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpPipewireSimpleEndpoint *self = WP_PIPEWIRE_SIMPLE_ENDPOINT (object);
switch (property_id) {
case PROP_NODE_PROXY:
g_value_set_pointer (value, self->node);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static gboolean
simple_endpoint_prepare_link (WpEndpoint * self, guint32 stream_id,
WpEndpointLink * link, GVariant ** properties, GError ** error)
{
/* TODO: verify that the remote end supports the same media type */
/* TODO: fill @properties with (node id, array(port ids)) */
return TRUE;
}
static void
simple_endpoint_class_init (WpPipewireSimpleEndpointClass * klass)
{
GObjectClass *object_class = (GObjectClass *) klass;
WpEndpointClass *endpoint_class = (WpEndpointClass *) klass;
object_class->finalize = simple_endpoint_finalize;
object_class->set_property = simple_endpoint_set_property;
object_class->get_property = simple_endpoint_get_property;
endpoint_class->prepare_link = simple_endpoint_prepare_link;
g_object_class_install_property (object_class, PROP_NODE_PROXY,
g_param_spec_pointer ("node-proxy", "node-proxy",
"Pointer to the pw_node_proxy* to wrap",
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
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,
};
gpointer
simple_endpoint_factory (WpFactory * factory, GType type,
GVariant * properties)
{
WpPipewireSimpleEndpoint *ep;
guint64 proxy;
const gchar *name;
const gchar *media_class;
g_return_val_if_fail (type == WP_TYPE_ENDPOINT, NULL);
g_return_val_if_fail (properties != NULL, NULL);
g_return_val_if_fail (g_variant_is_of_type (properties,
G_VARIANT_TYPE_VARDICT), NULL);
if (!g_variant_lookup (properties, "name", "&s", &name))
return NULL;
if (!g_variant_lookup (properties, "media-class", "&s", &media_class))
return NULL;
if (!g_variant_lookup (properties, "node-proxy", "t", &proxy))
return NULL;
ep = g_object_new (simple_endpoint_get_type (),
"name", name,
"media-class", media_class,
"node-proxy", (gpointer) proxy,
NULL);
pw_proxy_add_listener ((gpointer) proxy, &ep->proxy_listener,
&node_proxy_events, ep);
return ep;
}