diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c index 50a06535c17a4ef6637535d2edb8873bd09215ae..714d6e4418bf7f8255156b611ccc6832122538d9 100644 --- a/lib/wp/endpoint.c +++ b/lib/wp/endpoint.c @@ -52,6 +52,7 @@ struct _WpEndpointPrivate struct pw_endpoint_info *info; struct pw_endpoint *iface; struct spa_hook listener; + WpObjectManager *streams_om; }; G_DEFINE_TYPE_WITH_PRIVATE (WpEndpoint, wp_endpoint, WP_TYPE_PROXY) @@ -67,6 +68,7 @@ wp_endpoint_finalize (GObject * object) WpEndpoint *self = WP_ENDPOINT (object); WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + g_clear_object (&priv->streams_om); g_clear_pointer (&priv->properties, wp_properties_unref); g_clear_pointer (&priv->info, pw_endpoint_info_free); wp_spa_props_clear (&priv->spa_props); @@ -74,6 +76,49 @@ wp_endpoint_finalize (GObject * object) G_OBJECT_CLASS (wp_endpoint_parent_class)->finalize (object); } +static void +wp_endpoint_enable_feature_streams (WpEndpoint * self, guint32 bound_id) +{ + WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (self)); + GVariantBuilder b; + + /* proxy endpoint stream -> check for endpoint.id in global properties */ + g_variant_builder_init (&b, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_open (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "type", + g_variant_new_int32 (WP_OBJECT_MANAGER_CONSTRAINT_PW_GLOBAL_PROPERTY)); + g_variant_builder_add (&b, "{sv}", "name", + g_variant_new_string (PW_KEY_ENDPOINT_ID)); + g_variant_builder_add (&b, "{sv}", "value", + g_variant_new_take_string (g_strdup_printf ("%u", bound_id))); + g_variant_builder_close (&b); + + wp_object_manager_add_interest (priv->streams_om, + WP_TYPE_ENDPOINT_STREAM, + g_variant_builder_end (&b), + WP_PROXY_FEATURES_STANDARD); + + /* impl endpoint stream -> check for endpoint.id in standard properties */ + g_variant_builder_init (&b, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_open (&b, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add (&b, "{sv}", "type", + g_variant_new_int32 (WP_OBJECT_MANAGER_CONSTRAINT_PW_PROPERTY)); + g_variant_builder_add (&b, "{sv}", "name", + g_variant_new_string (PW_KEY_ENDPOINT_ID)); + g_variant_builder_add (&b, "{sv}", "value", + g_variant_new_take_string (g_strdup_printf ("%u", bound_id))); + g_variant_builder_close (&b); + + wp_object_manager_add_interest (priv->streams_om, + WP_TYPE_IMPL_ENDPOINT_STREAM, + g_variant_builder_end (&b), + WP_PROXY_FEATURES_STANDARD); + + wp_core_install_object_manager (core, priv->streams_om); + wp_proxy_set_feature_ready (WP_PROXY (self), WP_ENDPOINT_FEATURE_STREAMS); +} + static void wp_endpoint_augment (WpProxy * proxy, WpProxyFeatures features) { @@ -91,6 +136,20 @@ wp_endpoint_augment (WpProxy * proxy, WpProxyFeatures features) pw_endpoint_enum_params (pw_proxy, 0, SPA_PARAM_PropInfo, 0, -1, NULL); pw_endpoint_subscribe_params (pw_proxy, ids, SPA_N_ELEMENTS (ids)); } + + if (features & WP_ENDPOINT_FEATURE_STREAMS) { + WpEndpointPrivate *priv = + wp_endpoint_get_instance_private (WP_ENDPOINT (proxy)); + + priv->streams_om = wp_object_manager_new (); + + /* if we are already bound, enable right away; + else, continue in the bound() event */ + if (wp_proxy_get_features (proxy) & WP_PROXY_FEATURE_BOUND) { + wp_endpoint_enable_feature_streams (WP_ENDPOINT (proxy), + wp_proxy_get_bound_id (proxy)); + } + } } static gconstpointer @@ -192,6 +251,16 @@ wp_endpoint_pw_proxy_created (WpProxy * proxy, struct pw_proxy * pw_proxy) self); } +static void +wp_endpoint_bound (WpProxy * proxy, guint32 id) +{ + WpEndpoint *self = WP_ENDPOINT (proxy); + WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + + if (priv->streams_om) + wp_endpoint_enable_feature_streams (self, id); +} + static void wp_endpoint_param (WpProxy * proxy, gint seq, guint32 id, guint32 index, guint32 next, const struct spa_pod *param) @@ -284,6 +353,7 @@ wp_endpoint_class_init (WpEndpointClass * klass) proxy_class->set_param = wp_endpoint_set_param; proxy_class->pw_proxy_created = wp_endpoint_pw_proxy_created; + proxy_class->bound = wp_endpoint_bound; proxy_class->param = wp_endpoint_param; klass->get_name = get_name; @@ -491,6 +561,70 @@ wp_endpoint_set_control_float (WpEndpoint * self, guint32 control_id, buffer, sizeof (buffer), SPA_POD_Float (value), 0)); } +/** + * wp_endpoint_get_n_streams: + * @self: the endpoint + * + * Returns: the number of streams of this endpoint + */ +guint +wp_endpoint_get_n_streams (WpEndpoint * self) +{ + g_return_val_if_fail (WP_IS_ENDPOINT (self), 0); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_ENDPOINT_FEATURE_STREAMS, 0); + + WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + return wp_object_manager_get_n_objects (priv->streams_om); +} + +/** + * wp_endpoint_get_stream: + * @self: the endpoint + * @bound_id: the bound id of the stream object to get + * + * Returns: (transfer full) (nullable): the endpoint stream that has the given + * @bound_id, or %NULL if there is no such stream + */ +WpEndpointStream * +wp_endpoint_get_stream (WpEndpoint * self, guint32 bound_id) +{ + g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_ENDPOINT_FEATURE_STREAMS, NULL); + + WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + g_autoptr (GPtrArray) streams = + wp_object_manager_get_objects (priv->streams_om, 0); + + for (guint i = 0; i < streams->len; i++) { + gpointer proxy = g_ptr_array_index (streams, i); + g_return_val_if_fail (WP_IS_ENDPOINT_STREAM (proxy), NULL); + + if (wp_proxy_get_bound_id (WP_PROXY (proxy)) == bound_id) + return WP_ENDPOINT_STREAM (g_object_ref (proxy)); + } + return NULL; +} + +/** + * wp_endpoint_get_all_streams: + * @self: the endpoint + * + * Returns: (transfer full) (element-type WpEndpointStream): array with all + * the endpoint streams that belong to this endpoint + */ +GPtrArray * +wp_endpoint_get_all_streams (WpEndpoint * self) +{ + g_return_val_if_fail (WP_IS_ENDPOINT (self), NULL); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_ENDPOINT_FEATURE_STREAMS, NULL); + + WpEndpointPrivate *priv = wp_endpoint_get_instance_private (self); + return wp_object_manager_get_objects (priv->streams_om, 0); +} + /* WpImplEndpoint */ enum { @@ -825,6 +959,17 @@ wp_impl_endpoint_augment (WpProxy * proxy, WpProxyFeatures features) wp_properties_peek_dict (props), priv->iface, 0)); } + + if (features & WP_ENDPOINT_FEATURE_STREAMS) { + priv->streams_om = wp_object_manager_new (); + + /* if we are already bound, enable right away; + else, continue in the bound() event */ + if (wp_proxy_get_features (proxy) & WP_PROXY_FEATURE_BOUND) { + wp_endpoint_enable_feature_streams (WP_ENDPOINT (proxy), + wp_proxy_get_bound_id (proxy)); + } + } } static void diff --git a/lib/wp/endpoint.h b/lib/wp/endpoint.h index ad500c7c564ab2b553cb47a1184260867b4f7b9f..3e476eb0029a9d95da6eb14a2680bf5481684b2a 100644 --- a/lib/wp/endpoint.h +++ b/lib/wp/endpoint.h @@ -10,6 +10,7 @@ #define __WIREPLUMBER_ENDPOINT_H__ #include "proxy.h" +#include "endpoint-stream.h" G_BEGIN_DECLS @@ -42,11 +43,15 @@ typedef enum { * @WP_ENDPOINT_FEATURE_CONTROLS: enables the use of the * wp_endpoint_get_control() and wp_endpoint_set_control() families of * functions to be able to work with endpoint-specific controls + * @WP_ENDPOINT_FEATURE_STREAMS: caches information about streams, enabling + * the use of wp_endpoint_get_n_streams(), wp_endpoint_get_stream() and + * wp_endpoint_get_all_streams() * * An extension of #WpProxyFeatures */ typedef enum { /*< flags >*/ WP_ENDPOINT_FEATURE_CONTROLS = WP_PROXY_FEATURE_LAST, + WP_ENDPOINT_FEATURE_STREAMS, } WpEndpointFeatures; /** @@ -112,6 +117,15 @@ WP_API gboolean wp_endpoint_set_control_float (WpEndpoint * self, guint32 control_id, gfloat value); +WP_API +guint wp_endpoint_get_n_streams (WpEndpoint * self); + +WP_API +WpEndpointStream * wp_endpoint_get_stream (WpEndpoint * self, guint32 bound_id); + +WP_API +GPtrArray * wp_endpoint_get_all_streams (WpEndpoint * self); + G_END_DECLS #endif