diff --git a/lib/wp/endpoint.h b/lib/wp/endpoint.h index 3e476eb0029a9d95da6eb14a2680bf5481684b2a..c30474d0498fd0dfc5d3da83b427a5c6616d50d8 100644 --- a/lib/wp/endpoint.h +++ b/lib/wp/endpoint.h @@ -54,6 +54,17 @@ typedef enum { /*< flags >*/ WP_ENDPOINT_FEATURE_STREAMS, } WpEndpointFeatures; +/** + * WP_ENDPOINT_FEATURES_STANDARD: + * + * A constant set of features that contains the standard features that are + * available in the #WpEndpoint class. + */ +#define WP_ENDPOINT_FEATURES_STANDARD \ + (WP_PROXY_FEATURES_STANDARD | \ + WP_ENDPOINT_FEATURE_CONTROLS | \ + WP_ENDPOINT_FEATURE_STREAMS) + /** * WP_TYPE_ENDPOINT: * diff --git a/lib/wp/session.c b/lib/wp/session.c index 7896c39b6c3ba30d81b4d62e79cea3aaf1d58fb6..b05d479b86300dd5d1e66fd7a5dc1891cd9142ac 100644 --- a/lib/wp/session.c +++ b/lib/wp/session.c @@ -50,6 +50,7 @@ struct _WpSessionPrivate struct pw_session_info *info; struct pw_session *iface; struct spa_hook listener; + WpObjectManager *endpoints_om; }; G_DEFINE_TYPE_WITH_PRIVATE (WpSession, wp_session, WP_TYPE_PROXY) @@ -65,6 +66,7 @@ wp_session_finalize (GObject * object) WpSession *self = WP_SESSION (object); WpSessionPrivate *priv = wp_session_get_instance_private (self); + g_clear_object (&priv->endpoints_om); g_clear_pointer (&priv->info, pw_session_info_free); g_clear_pointer (&priv->properties, wp_properties_unref); wp_spa_props_clear (&priv->spa_props); @@ -200,6 +202,59 @@ wp_session_param (WpProxy * proxy, gint seq, guint32 id, guint32 index, } } +static void +wp_session_enable_feature_endpoints (WpSession * self, guint32 bound_id) +{ + WpSessionPrivate *priv = wp_session_get_instance_private (self); + g_autoptr (WpCore) core = wp_proxy_get_core (WP_PROXY (self)); + GVariantBuilder b; + + /* proxy endpoint -> check for session.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_SESSION_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->endpoints_om, + WP_TYPE_ENDPOINT, + g_variant_builder_end (&b), + WP_ENDPOINT_FEATURES_STANDARD); + + /* impl endpoint -> check for session.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_SESSION_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->endpoints_om, + WP_TYPE_IMPL_ENDPOINT, + g_variant_builder_end (&b), + WP_ENDPOINT_FEATURES_STANDARD); + + wp_core_install_object_manager (core, priv->endpoints_om); + wp_proxy_set_feature_ready (WP_PROXY (self), WP_SESSION_FEATURE_ENDPOINTS); +} + +static void +wp_session_bound (WpProxy * proxy, guint32 id) +{ + WpSession *self = WP_SESSION (proxy); + WpSessionPrivate *priv = wp_session_get_instance_private (self); + + if (priv->endpoints_om) + wp_session_enable_feature_endpoints (self, id); +} + static void wp_session_augment (WpProxy * proxy, WpProxyFeatures features) { @@ -217,6 +272,20 @@ wp_session_augment (WpProxy * proxy, WpProxyFeatures features) pw_session_enum_params (pw_proxy, 0, SPA_PARAM_PropInfo, 0, -1, NULL); pw_session_subscribe_params (pw_proxy, ids, SPA_N_ELEMENTS (ids)); } + + if (features & WP_SESSION_FEATURE_ENDPOINTS) { + WpSessionPrivate *priv = + wp_session_get_instance_private (WP_SESSION (proxy)); + + priv->endpoints_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_session_enable_feature_endpoints (WP_SESSION (proxy), + wp_proxy_get_bound_id (proxy)); + } + } } static guint32 @@ -267,6 +336,7 @@ wp_session_class_init (WpSessionClass * klass) proxy_class->pw_proxy_created = wp_session_pw_proxy_created; proxy_class->param = wp_session_param; + proxy_class->bound = wp_session_bound; klass->get_default_endpoint = get_default_endpoint; klass->set_default_endpoint = set_default_endpoint; @@ -323,6 +393,70 @@ wp_session_set_default_endpoint (WpSession * self, WP_SESSION_GET_CLASS (self)->set_default_endpoint (self, type, id); } +/** + * wp_session_get_n_endpoints: + * @self: the session + * + * Returns: the number of endpoints of this session + */ +guint +wp_session_get_n_endpoints (WpSession * self) +{ + g_return_val_if_fail (WP_IS_SESSION (self), 0); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_SESSION_FEATURE_ENDPOINTS, 0); + + WpSessionPrivate *priv = wp_session_get_instance_private (self); + return wp_object_manager_get_n_objects (priv->endpoints_om); +} + +/** + * wp_session_get_endpoint: + * @self: the session + * @bound_id: the bound id of the endpoint object to get + * + * Returns: (transfer full) (nullable): the endpoint that has the given + * @bound_id, or %NULL if there is no such endpoint + */ +WpEndpoint * +wp_session_get_endpoint (WpSession * self, guint32 bound_id) +{ + g_return_val_if_fail (WP_IS_SESSION (self), NULL); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_SESSION_FEATURE_ENDPOINTS, NULL); + + WpSessionPrivate *priv = wp_session_get_instance_private (self); + g_autoptr (GPtrArray) endpoints = + wp_object_manager_get_objects (priv->endpoints_om, 0); + + for (guint i = 0; i < endpoints->len; i++) { + gpointer proxy = g_ptr_array_index (endpoints, i); + g_return_val_if_fail (WP_IS_ENDPOINT (proxy), NULL); + + if (wp_proxy_get_bound_id (WP_PROXY (proxy)) == bound_id) + return WP_ENDPOINT (g_object_ref (proxy)); + } + return NULL; +} + +/** + * wp_session_get_all_endpoints: + * @self: the session + * + * Returns: (transfer full) (element-type WpEndpoint): array with all + * the session endpoints that belong to this session + */ +GPtrArray * +wp_session_get_all_endpoints (WpSession * self) +{ + g_return_val_if_fail (WP_IS_SESSION (self), NULL); + g_return_val_if_fail (wp_proxy_get_features (WP_PROXY (self)) & + WP_SESSION_FEATURE_ENDPOINTS, NULL); + + WpSessionPrivate *priv = wp_session_get_instance_private (self); + return wp_object_manager_get_objects (priv->endpoints_om, 0); +} + /* WpImplSession */ typedef struct _WpImplSession WpImplSession; @@ -556,6 +690,20 @@ wp_impl_session_augment (WpProxy * proxy, WpProxyFeatures features) wp_properties_peek_dict (priv->properties), priv->iface, 0)); } + + if (features & WP_SESSION_FEATURE_ENDPOINTS) { + WpSessionPrivate *priv = + wp_session_get_instance_private (WP_SESSION (proxy)); + + priv->endpoints_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_session_enable_feature_endpoints (WP_SESSION (proxy), + wp_proxy_get_bound_id (proxy)); + } + } } static void diff --git a/lib/wp/session.h b/lib/wp/session.h index 83fe3665a169f88706e00dde1d6a9005b3557fee..0e1ebd6e644b58ac73cb93c6a6928d1407656ae5 100644 --- a/lib/wp/session.h +++ b/lib/wp/session.h @@ -10,6 +10,7 @@ #define __WIREPLUMBER_SESSION_H__ #include "proxy.h" +#include "endpoint.h" G_BEGIN_DECLS @@ -32,13 +33,28 @@ typedef enum { * @WP_SESSION_FEATURE_DEFAULT_ENDPOINT: enables the use of * wp_session_get_default_endpoint() and wp_session_set_default_endpoint() * to store default endpoint preferences on the session + * @WP_SESSION_FEATURE_ENDPOINTS: caches information about endpoints, enabling + * the use of wp_session_get_n_endpoints(), wp_session_get_endpoint() and + * wp_session_get_all_endpoints() * * An extension of #WpProxyFeatures */ typedef enum { /*< flags >*/ WP_SESSION_FEATURE_DEFAULT_ENDPOINT = WP_PROXY_FEATURE_LAST, + WP_SESSION_FEATURE_ENDPOINTS, } WpSessionFeatures; +/** + * WP_SESSION_FEATURES_STANDARD: + * + * A constant set of features that contains the standard features that are + * available in the #WpSession class. + */ +#define WP_SESSION_FEATURES_STANDARD \ + (WP_PROXY_FEATURES_STANDARD | \ + WP_SESSION_FEATURE_DEFAULT_ENDPOINT | \ + WP_SESSION_FEATURE_ENDPOINTS) + /** * WP_TYPE_SESSION: * @@ -66,6 +82,15 @@ WP_API void wp_session_set_default_endpoint (WpSession * self, WpDefaultEndpointType type, guint32 id); +WP_API +guint wp_session_get_n_endpoints (WpSession * self); + +WP_API +WpEndpoint * wp_session_get_endpoint (WpSession * self, guint32 bound_id); + +WP_API +GPtrArray * wp_session_get_all_endpoints (WpSession * self); + /** * WP_TYPE_IMPL_SESSION: * diff --git a/tests/wp/session.c b/tests/wp/session.c index 65df4973a6ac2049010c16d7f8c296c56868d8ff..83150aa3eddb8e502289668bc72b78a04e66d42c 100644 --- a/tests/wp/session.c +++ b/tests/wp/session.c @@ -222,7 +222,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data) (GCallback) test_session_basic_exported_object_removed, fixture); wp_object_manager_add_interest (fixture->export_om, WP_TYPE_IMPL_SESSION, NULL, - WP_PROXY_FEATURES_STANDARD | WP_SESSION_FEATURE_DEFAULT_ENDPOINT); + WP_SESSION_FEATURES_STANDARD); wp_core_install_object_manager (fixture->export_core, fixture->export_om); g_assert_true (wp_core_connect (fixture->export_core)); @@ -234,7 +234,7 @@ test_session_basic (TestSessionFixture *fixture, gconstpointer data) (GCallback) test_session_basic_proxy_object_removed, fixture); wp_object_manager_add_interest (fixture->proxy_om, WP_TYPE_SESSION, NULL, - WP_PROXY_FEATURES_STANDARD | WP_SESSION_FEATURE_DEFAULT_ENDPOINT); + WP_SESSION_FEATURES_STANDARD); wp_core_install_object_manager (fixture->proxy_core, fixture->proxy_om); g_assert_true (wp_core_connect (fixture->proxy_core));