From 1dccdcf415e539f70109208eb9d3045e31c47a4e Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 21 Apr 2020 13:21:03 +0300 Subject: [PATCH] object-manager: replace GPtrArray API with WpIterator + add the useful _find_proxy() method --- lib/wp/endpoint.c | 41 +++-- lib/wp/endpoint.h | 9 +- lib/wp/iterator.c | 6 +- lib/wp/object-manager.c | 142 +++++++++++++++--- lib/wp/object-manager.h | 7 +- lib/wp/policy.c | 40 +++-- lib/wp/session.c | 58 +++---- lib/wp/session.h | 16 +- .../audio-softdsp-endpoint/stream.c | 32 ++-- modules/module-pipewire/video-endpoint.c | 30 ++-- tools/wireplumber-cli.c | 96 +++++++----- 11 files changed, 304 insertions(+), 173 deletions(-) diff --git a/lib/wp/endpoint.c b/lib/wp/endpoint.c index ddca1fa0..7a597c43 100644 --- a/lib/wp/endpoint.c +++ b/lib/wp/endpoint.c @@ -579,50 +579,41 @@ wp_endpoint_get_n_streams (WpEndpoint * self) } /** - * wp_endpoint_get_stream: + * wp_endpoint_find_stream: * @self: the endpoint - * @bound_id: the bound id of the stream object to get + * @bound_id: the bound id of the stream object to find * * 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) +wp_endpoint_find_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; + return (WpEndpointStream *) + wp_object_manager_find_proxy (priv->streams_om, bound_id); } /** - * wp_endpoint_get_all_streams: + * wp_endpoint_iterate_streams: * @self: the endpoint * - * Returns: (transfer full) (element-type WpEndpointStream): array with all + * Returns: (transfer full): a #WpIterator that iterates over all * the endpoint streams that belong to this endpoint */ -GPtrArray * -wp_endpoint_get_all_streams (WpEndpoint * self) +WpIterator * +wp_endpoint_iterate_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); + return wp_object_manager_iterate (priv->streams_om); } /* WpImplEndpoint */ @@ -864,18 +855,20 @@ impl_create_link (void *object, const struct spa_dict *props) g_autoptr (WpEndpoint) peer_ep_proxy = NULL; g_autoptr (WpEndpointStream) peer_stream_proxy = NULL; - peer_ep_proxy = wp_session_get_endpoint (session, peer_ep_id); + peer_ep_proxy = wp_session_find_endpoint (session, peer_ep_id); if (!peer_ep_proxy) { wp_warning_object (self, "endpoint %d not found in session", peer_ep_id); return -EINVAL; } if (peer_stream_id != SPA_ID_INVALID) { - peer_stream_proxy = wp_endpoint_get_stream (peer_ep_proxy, peer_stream_id); + peer_stream_proxy = wp_endpoint_find_stream (peer_ep_proxy, + peer_stream_id); } else { - g_autoptr (GPtrArray) s = wp_endpoint_get_all_streams (peer_ep_proxy); - peer_stream_proxy = (s->len > 0) ? - g_object_ref (g_ptr_array_index (s, 0)) : NULL; + g_autoptr (WpIterator) it = wp_endpoint_iterate_streams (peer_ep_proxy); + g_auto (GValue) val = G_VALUE_INIT; + if (wp_iterator_next (it, &val)) + peer_stream_proxy = g_value_dup_object (&val); } if (!peer_stream_proxy) { diff --git a/lib/wp/endpoint.h b/lib/wp/endpoint.h index c30474d0..4e75d785 100644 --- a/lib/wp/endpoint.h +++ b/lib/wp/endpoint.h @@ -11,6 +11,7 @@ #include "proxy.h" #include "endpoint-stream.h" +#include "iterator.h" G_BEGIN_DECLS @@ -44,8 +45,8 @@ typedef enum { * 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() + * the use of wp_endpoint_get_n_streams(), wp_endpoint_find_stream() and + * wp_endpoint_iterate_streams() * * An extension of #WpProxyFeatures */ @@ -132,10 +133,10 @@ WP_API guint wp_endpoint_get_n_streams (WpEndpoint * self); WP_API -WpEndpointStream * wp_endpoint_get_stream (WpEndpoint * self, guint32 bound_id); +WpEndpointStream * wp_endpoint_find_stream (WpEndpoint * self, guint32 bound_id); WP_API -GPtrArray * wp_endpoint_get_all_streams (WpEndpoint * self); +WpIterator * wp_endpoint_iterate_streams (WpEndpoint * self); G_END_DECLS diff --git a/lib/wp/iterator.c b/lib/wp/iterator.c index 7058340a..c12e0a32 100644 --- a/lib/wp/iterator.c +++ b/lib/wp/iterator.c @@ -149,8 +149,8 @@ wp_iterator_next (WpIterator *self, GValue *item) * wp_iterator_fold: * @self: the iterator * @func: (scope call): the fold function - * @ret: the accumulator data - * @data: the user data + * @ret: (inout): the accumulator data + * @data: (closure): the user data * * Iterates over all items of the iterator calling a function. * @@ -172,7 +172,7 @@ wp_iterator_fold (WpIterator *self, WpIteratorFoldFunc func, GValue *ret, * wp_iterator_foreach: * @self: the iterator * @func: (scope call): the foreach function - * @data: the user data + * @data: (closure): the user data * * Fold a function over the items of the iterator. * diff --git a/lib/wp/object-manager.c b/lib/wp/object-manager.c index b1ed3f7b..845931bf 100644 --- a/lib/wp/object-manager.c +++ b/lib/wp/object-manager.c @@ -33,7 +33,7 @@ * * Upon installing a #WpObjectManager on a #WpCore, any pre-existing objects * that match the interests of this #WpObjectManager will immediately become - * available to get through wp_object_manager_get_objects() and the + * available to get through wp_object_manager_iterate() and the * #WpObjectManager::object-added signal will be emitted for all of them. */ @@ -192,7 +192,7 @@ wp_object_manager_class_init (WpObjectManagerClass * klass) * from this object manager. This signal is useful to get notified only once * when multiple changes happen in a short timespan. The receiving callback * may retrieve the updated list of objects by calling - * wp_object_manager_get_objects() + * wp_object_manager_iterate() */ signals[SIGNAL_OBJECTS_CHANGED] = g_signal_new ( "objects-changed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, @@ -239,7 +239,7 @@ wp_object_manager_new (void) * wp_object_manager_add_interest (om, WP_TYPE_NODE, NULL, * WP_PROXY_FEATURES_STANDARD); * wp_core_install_object_manager (core, om); - * GPtrArray *nodes = wp_object_manager_get_objects (om, 0); + * WpIterator *nodes_it = wp_object_manager_iterate (om); * ]| * * and to discover all 'port' objects that belong to a specific 'node': @@ -262,7 +262,7 @@ wp_object_manager_new (void) * WP_PROXY_FEATURES_STANDARD); * * wp_core_install_object_manager (core, om); - * GPtrArray *ports = wp_object_manager_get_objects (om, 0); + * WpIterator *ports_it = wp_object_manager_iterate (om); * ]| */ void @@ -296,29 +296,125 @@ wp_object_manager_get_n_objects (WpObjectManager * self) return self->objects->len; } -/** - * wp_object_manager_get_objects: - * @self: the object manager - * @type_filter: a #GType filter to get only the objects that are of this type, - * or 0 ( %G_TYPE_INVALID ) to return all the objects - * - * Returns: (transfer full) (element-type GObject*): all the objects managed - * by this #WpObjectManager that match the @type_filter - */ -GPtrArray * -wp_object_manager_get_objects (WpObjectManager *self, GType type_filter) +struct om_iterator_data { - GPtrArray *result = g_ptr_array_new_with_free_func (g_object_unref); - guint i; + WpObjectManager *om; + guint index; +}; - for (i = 0; i < self->objects->len; i++) { - gpointer obj = g_ptr_array_index (self->objects, i); - if (type_filter == 0 || g_type_is_a (G_OBJECT_TYPE (obj), type_filter)) { - g_ptr_array_add (result, g_object_ref (obj)); - } +static void +om_iterator_reset (WpIterator *it) +{ + struct om_iterator_data *it_data = wp_iterator_get_user_data (it); + it_data->index = 0; +} + +static gboolean +om_iterator_next (WpIterator *it, GValue *item) +{ + struct om_iterator_data *it_data = wp_iterator_get_user_data (it); + GPtrArray *objects = it_data->om->objects; + + if (G_LIKELY (it_data->index < objects->len)) { + g_value_init_from_instance (item, + g_ptr_array_index (objects, it_data->index++)); + return TRUE; + } + return FALSE; +} + +static gboolean +om_iterator_fold (WpIterator *it, WpIteratorFoldFunc func, GValue *ret, + gpointer data) +{ + struct om_iterator_data *it_data = wp_iterator_get_user_data (it); + gpointer *obj, *base; + guint len; + + obj = base = it_data->om->objects->pdata; + len = it_data->om->objects->len; + + while ((obj - base) < len) { + g_auto (GValue) item = G_VALUE_INIT; + g_value_init_from_instance (&item, *obj); + if (!func (&item, ret, data)) + return FALSE; + obj++; } - return result; + return TRUE; +} + +static void +om_iterator_finalize (WpIterator *it) +{ + struct om_iterator_data *it_data = wp_iterator_get_user_data (it); + g_object_unref (it_data->om); +} + +static const WpIteratorMethods om_iterator_methods = { + .reset = om_iterator_reset, + .next = om_iterator_next, + .fold = om_iterator_fold, + .finalize = om_iterator_finalize, +}; + +/** + * wp_object_manager_iterate: + * @self: the object manager + * + * Returns: (transfer full): a #WpIterator that iterates over all the managed + * objects of this object manager + */ +WpIterator * +wp_object_manager_iterate (WpObjectManager * self) +{ + WpIterator *it; + struct om_iterator_data *it_data; + + g_return_val_if_fail (WP_IS_OBJECT_MANAGER (self), NULL); + + it = wp_iterator_new (&om_iterator_methods, sizeof (struct om_iterator_data)); + it_data = wp_iterator_get_user_data (it); + it_data->om = g_object_ref (self); + it_data->index = 0; + return it; +} + +static gboolean +find_proxy_fold_func (const GValue *item, GValue *ret, gpointer data) +{ + if (g_type_is_a (G_VALUE_TYPE (item), WP_TYPE_PROXY)) { + WpProxy *proxy = g_value_get_object (item); + if (wp_proxy_get_bound_id (proxy) == GPOINTER_TO_UINT (data)) { + g_value_init_from_instance (ret, proxy); + return FALSE; + } + } + return TRUE; +} + +/** + * wp_object_manager_find_proxy: + * @self: the object manager + * @bound_id: the bound id of the proxy to get + * + * Searches the managed objects to find a #WpProxy that has the given @bound_id + * + * Returns: (transfer full) (nullable): the proxy that has the given @bound_id, + * or %NULL if there is no such proxy managed by this object manager + */ +WpProxy * +wp_object_manager_find_proxy (WpObjectManager *self, guint bound_id) +{ + g_autoptr (WpIterator) it = wp_object_manager_iterate (self); + g_auto (GValue) ret = G_VALUE_INIT; + + if (!wp_iterator_fold (it, find_proxy_fold_func, &ret, + GUINT_TO_POINTER (bound_id))) + return g_value_dup_object (&ret); + + return NULL; } static gboolean diff --git a/lib/wp/object-manager.h b/lib/wp/object-manager.h index 7285635b..4337d42c 100644 --- a/lib/wp/object-manager.h +++ b/lib/wp/object-manager.h @@ -11,6 +11,7 @@ #include #include "proxy.h" +#include "iterator.h" G_BEGIN_DECLS @@ -51,8 +52,10 @@ WP_API guint wp_object_manager_get_n_objects (WpObjectManager * self); WP_API -GPtrArray * wp_object_manager_get_objects (WpObjectManager *self, - GType type_filter); +WpIterator * wp_object_manager_iterate (WpObjectManager * self); + +WP_API +WpProxy * wp_object_manager_find_proxy (WpObjectManager *self, guint bound_id); G_END_DECLS diff --git a/lib/wp/policy.c b/lib/wp/policy.c index d76366c5..5639fccc 100644 --- a/lib/wp/policy.c +++ b/lib/wp/policy.c @@ -150,12 +150,15 @@ wp_policy_manager_get_instance (WpCore *core) WpSession * wp_policy_manager_get_session (WpPolicyManager *self) { - g_autoptr (GPtrArray) arr = NULL; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) val = G_VALUE_INIT; g_return_val_if_fail (WP_IS_POLICY_MANAGER (self), NULL); - arr = wp_object_manager_get_objects (self->sessions_om, 0); - return (arr->len > 0) ? g_object_ref (g_ptr_array_index (arr, 0)) : NULL; + it = wp_object_manager_iterate (self->sessions_om); + if (wp_iterator_next (it, &val)) + return g_value_dup_object (&val); + return NULL; } static inline gboolean @@ -193,6 +196,17 @@ media_class_matches (const gchar * media_class, const gchar * lookup) return TRUE; } +static gboolean +list_endpoints_fold_func (const GValue *item, GValue *ret, gpointer data) +{ + GPtrArray *ret_arr = g_value_get_boxed (ret); + WpBaseEndpoint *ep = g_value_get_object (item); + if (media_class_matches (wp_base_endpoint_get_media_class (ep), + (const gchar *) data)) + g_ptr_array_add (ret_arr, g_object_ref (ep)); + return TRUE; +} + /** * wp_policy_manager_list_endpoints: * @self: the policy manager @@ -205,18 +219,20 @@ GPtrArray * wp_policy_manager_list_endpoints (WpPolicyManager * self, const gchar * media_class) { - GPtrArray * ret; - guint i; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) val = G_VALUE_INIT; + GPtrArray *ret_arr; g_return_val_if_fail (WP_IS_POLICY_MANAGER (self), NULL); - ret = wp_object_manager_get_objects (self->endpoints_om, 0); - for (i = ret->len; i > 0; i--) { - WpBaseEndpoint *ep = g_ptr_array_index (ret, i-1); - if (!media_class_matches (wp_base_endpoint_get_media_class (ep), media_class)) - g_ptr_array_remove_index_fast (ret, i-1); - } - return ret; + ret_arr = g_ptr_array_new_with_free_func (g_object_unref); + g_value_init (&val, G_TYPE_PTR_ARRAY); + g_value_set_boxed (&val, ret_arr); + + it = wp_object_manager_iterate (self->endpoints_om); + wp_iterator_fold (it, list_endpoints_fold_func, &val, (gpointer) media_class); + + return ret_arr; } /* WpPolicy */ diff --git a/lib/wp/session.c b/lib/wp/session.c index eeb4aa5f..c87fcc4f 100644 --- a/lib/wp/session.c +++ b/lib/wp/session.c @@ -470,50 +470,41 @@ wp_session_get_n_endpoints (WpSession * self) } /** - * wp_session_get_endpoint: + * wp_session_find_endpoint: * @self: the session - * @bound_id: the bound id of the endpoint object to get + * @bound_id: the bound id of the endpoint object to find * * 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) +wp_session_find_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; + return (WpEndpoint *) + wp_object_manager_find_proxy (priv->endpoints_om, bound_id); } /** - * wp_session_get_all_endpoints: + * wp_session_iterate_endpoints: * @self: the session * - * Returns: (transfer full) (element-type WpEndpoint): array with all + * Returns: (transfer full): a #WpIterator that iterates over all * the endpoints that belong to this session */ -GPtrArray * -wp_session_get_all_endpoints (WpSession * self) +WpIterator * +wp_session_iterate_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); + return wp_object_manager_iterate (priv->endpoints_om); } /** @@ -534,50 +525,41 @@ wp_session_get_n_links (WpSession * self) } /** - * wp_session_get_link: + * wp_session_find_link: * @self: the session - * @bound_id: the bound id of the link object to get + * @bound_id: the bound id of the link object to find * * Returns: (transfer full) (nullable): the endpoint link that has the given * @bound_id, or %NULL if there is no such endpoint link */ WpEndpointLink * -wp_session_get_link (WpSession * self, guint32 bound_id) +wp_session_find_link (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_LINKS, NULL); WpSessionPrivate *priv = wp_session_get_instance_private (self); - g_autoptr (GPtrArray) links = - wp_object_manager_get_objects (priv->links_om, 0); - - for (guint i = 0; i < links->len; i++) { - gpointer proxy = g_ptr_array_index (links, i); - g_return_val_if_fail (WP_IS_ENDPOINT_LINK (proxy), NULL); - - if (wp_proxy_get_bound_id (WP_PROXY (proxy)) == bound_id) - return WP_ENDPOINT_LINK (g_object_ref (proxy)); - } - return NULL; + return (WpEndpointLink *) + wp_object_manager_find_proxy (priv->links_om, bound_id); } /** - * wp_session_get_all_links: + * wp_session_iterate_links: * @self: the session * - * Returns: (transfer full) (element-type WpEndpointLink): array with all + * Returns: (transfer full): a #WpIterator that iterates over all * the endpoint links that belong to this session */ -GPtrArray * -wp_session_get_all_links (WpSession * self) +WpIterator * +wp_session_iterate_links (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_LINKS, NULL); WpSessionPrivate *priv = wp_session_get_instance_private (self); - return wp_object_manager_get_objects (priv->links_om, 0); + return wp_object_manager_iterate (priv->links_om); } /* WpImplSession */ diff --git a/lib/wp/session.h b/lib/wp/session.h index 329d82d0..2bcb7dc8 100644 --- a/lib/wp/session.h +++ b/lib/wp/session.h @@ -35,11 +35,11 @@ typedef enum { * 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() + * the use of wp_session_get_n_endpoints(), wp_session_find_endpoint() and + * wp_session_iterate_endpoints() * @WP_SESSION_FEATURE_LINKS: caches information about endpoint links, enabling - * the use of wp_session_get_n_links(), wp_session_get_link() and - * wp_session_get_all_links() + * the use of wp_session_get_n_links(), wp_session_find_link() and + * wp_session_iterate_links() * * An extension of #WpProxyFeatures */ @@ -92,19 +92,19 @@ WP_API guint wp_session_get_n_endpoints (WpSession * self); WP_API -WpEndpoint * wp_session_get_endpoint (WpSession * self, guint32 bound_id); +WpEndpoint * wp_session_find_endpoint (WpSession * self, guint32 bound_id); WP_API -GPtrArray * wp_session_get_all_endpoints (WpSession * self); +WpIterator * wp_session_iterate_endpoints (WpSession * self); WP_API guint wp_session_get_n_links (WpSession * self); WP_API -WpEndpointLink * wp_session_get_link (WpSession * self, guint32 bound_id); +WpEndpointLink * wp_session_find_link (WpSession * self, guint32 bound_id); WP_API -GPtrArray * wp_session_get_all_links (WpSession * self); +WpIterator * wp_session_iterate_links (WpSession * self); /** * WP_TYPE_IMPL_SESSION: diff --git a/modules/module-pipewire/audio-softdsp-endpoint/stream.c b/modules/module-pipewire/audio-softdsp-endpoint/stream.c index 8309a00a..1bb91489 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/stream.c +++ b/modules/module-pipewire/audio-softdsp-endpoint/stream.c @@ -46,7 +46,6 @@ struct _WpAudioStreamPrivate WpObjectManager *ports_om; WpObjectManager *audio_fade_source_ports_om; - GVariantBuilder port_vb; gboolean port_config_done; gboolean port_control_pending; @@ -610,10 +609,11 @@ wp_audio_stream_get_info (WpAudioStream * self) return wp_proxy_get_info (WP_PROXY (priv->proxy)); } -static void -port_proxies_foreach_func(gpointer data, gpointer user_data) +static gboolean +port_proxies_fold_func (const GValue *item, GValue *ret, gpointer user_data) { - WpProxy *port = WP_PROXY (data); + WpProxy *port = g_value_get_object (item); + GVariantBuilder *b = g_value_get_pointer (ret); WpAudioStream *self = WP_AUDIO_STREAM (user_data); WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); const struct pw_node_info *node_info; @@ -623,16 +623,16 @@ port_proxies_foreach_func(gpointer data, gpointer user_data) uint32_t channel_n = SPA_AUDIO_CHANNEL_UNKNOWN; node_info = wp_proxy_get_info (WP_PROXY (priv->proxy)); - g_return_if_fail (node_info); + g_return_val_if_fail (node_info, TRUE); port_info = wp_proxy_get_info (port); - g_return_if_fail (port_info); + g_return_val_if_fail (port_info, TRUE); props = wp_proxy_get_properties (port); /* skip control ports */ if (is_stream_control_port (WP_PORT (port))) - return; + return TRUE; channel = wp_properties_get (props, PW_KEY_AUDIO_CHANNEL); if (channel) { @@ -652,8 +652,9 @@ port_proxies_foreach_func(gpointer data, gpointer user_data) uint32 channel; // enum spa_audio_channel uint8 direction; // enum spa_direction */ - g_variant_builder_add (&priv->port_vb, "(uuuy)", node_info->id, + g_variant_builder_add (b, "(uuuy)", node_info->id, port_info->id, channel_n, (guint8) port_info->direction); + return TRUE; } gboolean @@ -661,14 +662,19 @@ wp_audio_stream_prepare_link (WpAudioStream * self, GVariant ** properties, GError ** error) { WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); - g_autoptr (GPtrArray) port_proxies = - wp_object_manager_get_objects (priv->ports_om, 0); + GVariantBuilder b; + g_auto (GValue) val = G_VALUE_INIT; + g_autoptr (WpIterator) it = NULL; /* Create a variant array with all the ports */ - g_variant_builder_init (&priv->port_vb, G_VARIANT_TYPE ("a(uuuy)")); - g_ptr_array_foreach (port_proxies, port_proxies_foreach_func, self); - *properties = g_variant_builder_end (&priv->port_vb); + g_variant_builder_init (&b, G_VARIANT_TYPE ("a(uuuy)")); + g_value_init (&val, G_TYPE_POINTER); + g_value_set_pointer (&val, &b); + it = wp_object_manager_iterate (priv->ports_om); + wp_iterator_fold (it, port_proxies_fold_func, &val, self); + + *properties = g_variant_builder_end (&b); return TRUE; } diff --git a/modules/module-pipewire/video-endpoint.c b/modules/module-pipewire/video-endpoint.c index 2d1b004b..7def0822 100644 --- a/modules/module-pipewire/video-endpoint.c +++ b/modules/module-pipewire/video-endpoint.c @@ -20,7 +20,6 @@ struct _WpVideoEndpoint /* The task to signal the endpoint is initialized */ GTask *init_task; - GVariantBuilder port_vb; WpObjectManager *ports_om; }; @@ -65,19 +64,20 @@ wp_video_endpoint_get_global_id (WpBaseEndpoint *ep) return wp_proxy_get_bound_id (WP_PROXY (self->node)); } -static void -port_proxies_foreach_func (gpointer data, gpointer user_data) +static gboolean +port_proxies_fold_func (const GValue *item, GValue *ret, gpointer user_data) { - WpProxy *port = WP_PROXY (data); + WpProxy *port = g_value_get_object (item); + GVariantBuilder *b = g_value_get_pointer (ret); WpVideoEndpoint *self = WP_VIDEO_ENDPOINT (user_data); const struct pw_node_info *node_info; const struct pw_port_info *port_info; node_info = wp_proxy_get_info (WP_PROXY (self->node)); - g_return_if_fail (node_info); + g_return_val_if_fail (node_info, TRUE); port_info = wp_proxy_get_info (port); - g_return_if_fail (port_info); + g_return_val_if_fail (port_info, TRUE); /* tuple format: uint32 node_id; @@ -85,8 +85,9 @@ port_proxies_foreach_func (gpointer data, gpointer user_data) uint32 channel; // always 0 for video uint8 direction; // enum spa_direction */ - g_variant_builder_add (&self->port_vb, "(uuuy)", node_info->id, + g_variant_builder_add (b, "(uuuy)", node_info->id, port_info->id, 0, (guint8) port_info->direction); + return TRUE; } static gboolean @@ -94,14 +95,19 @@ wp_video_endpoint_prepare_link (WpBaseEndpoint * ep, guint32 stream_id, WpBaseEndpointLink * link, GVariant ** properties, GError ** error) { WpVideoEndpoint *self = WP_VIDEO_ENDPOINT (ep); - g_autoptr (GPtrArray) port_proxies = wp_object_manager_get_objects ( - self->ports_om, 0); + GVariantBuilder b; + g_auto (GValue) val = G_VALUE_INIT; + g_autoptr (WpIterator) it = NULL; /* Create a variant array with all the ports */ - g_variant_builder_init (&self->port_vb, G_VARIANT_TYPE ("a(uuuy)")); - g_ptr_array_foreach (port_proxies, port_proxies_foreach_func, self); - *properties = g_variant_builder_end (&self->port_vb); + g_variant_builder_init (&b, G_VARIANT_TYPE ("a(uuuy)")); + g_value_init (&val, G_TYPE_POINTER); + g_value_set_pointer (&val, &b); + it = wp_object_manager_iterate (self->ports_om); + wp_iterator_fold (it, port_proxies_fold_func, &val, self); + + *properties = g_variant_builder_end (&b); return TRUE; } diff --git a/tools/wireplumber-cli.c b/tools/wireplumber-cli.c index 76cac022..83e245f7 100644 --- a/tools/wireplumber-cli.c +++ b/tools/wireplumber-cli.c @@ -64,34 +64,52 @@ print_client_endpoint (WpEndpoint *ep) static void list_endpoints (WpObjectManager * om, struct WpCliData * d) { - g_autoptr (GPtrArray) arr = NULL; + g_autoptr (WpIterator) it = NULL; g_autoptr (WpSession) session = NULL; - guint i; + g_auto (GValue) val = G_VALUE_INIT; - arr = wp_object_manager_get_objects (om, WP_TYPE_SESSION); - if (arr->len > 0) - session = WP_SESSION (g_object_ref (g_ptr_array_index (arr, 0))); - g_clear_pointer (&arr, g_ptr_array_unref); + it = wp_object_manager_iterate (om); + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_SESSION); + g_value_unset (&val)) + { + session = g_value_dup_object (&val); + g_value_unset (&val); + break; + } - arr = wp_object_manager_get_objects (om, WP_TYPE_ENDPOINT); + wp_iterator_reset (it); g_print ("Audio capture devices:\n"); - for (i = 0; i < arr->len; i++) { - WpEndpoint *ep = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_ENDPOINT); + g_value_unset (&val)) + { + WpEndpoint *ep = g_value_get_object (&val); if (g_strcmp0 (wp_endpoint_get_media_class (ep), "Audio/Source") == 0) print_dev_endpoint (ep, session, WP_DEFAULT_ENDPOINT_TYPE_AUDIO_SOURCE); } + wp_iterator_reset (it); + g_print ("\nAudio playback devices:\n"); - for (i = 0; i < arr->len; i++) { - WpEndpoint *ep = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_ENDPOINT); + g_value_unset (&val)) + { + WpEndpoint *ep = g_value_get_object (&val); if (g_strcmp0 (wp_endpoint_get_media_class (ep), "Audio/Sink") == 0) print_dev_endpoint (ep, session, WP_DEFAULT_ENDPOINT_TYPE_AUDIO_SINK); } + wp_iterator_reset (it); + g_print ("\nClient streams:\n"); - for (i = 0; i < arr->len; i++) { - WpEndpoint *ep = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_ENDPOINT); + g_value_unset (&val)) + { + WpEndpoint *ep = g_value_get_object (&val); if (g_str_has_suffix (wp_endpoint_get_media_class (ep), "/Audio")) print_client_endpoint (ep); } @@ -102,14 +120,20 @@ list_endpoints (WpObjectManager * om, struct WpCliData * d) static void set_default (WpObjectManager * om, struct WpCliData * d) { - g_autoptr (GPtrArray) arr = NULL; + g_autoptr (WpIterator) it = NULL; g_autoptr (WpSession) session = NULL; - guint i; + g_auto (GValue) val = G_VALUE_INIT; - arr = wp_object_manager_get_objects (om, WP_TYPE_SESSION); - if (arr->len > 0) - session = WP_SESSION (g_object_ref (g_ptr_array_index (arr, 0))); - g_clear_pointer (&arr, g_ptr_array_unref); + it = wp_object_manager_iterate (om); + + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_SESSION); + g_value_unset (&val)) + { + session = g_value_dup_object (&val); + g_value_unset (&val); + break; + } if (!session) { g_print ("No Session object - changing the default endpoint is not supported\n"); @@ -117,10 +141,13 @@ set_default (WpObjectManager * om, struct WpCliData * d) return; } - arr = wp_object_manager_get_objects (om, WP_TYPE_ENDPOINT); + wp_iterator_reset (it); - for (i = 0; i < arr->len; i++) { - WpEndpoint *ep = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val) && + g_type_is_a (G_VALUE_TYPE (&val), WP_TYPE_ENDPOINT); + g_value_unset (&val)) + { + WpEndpoint *ep = g_value_get_object (&val); guint32 id = wp_proxy_get_bound_id (WP_PROXY (ep)); if (id == d->params.set_default.id) { @@ -148,13 +175,13 @@ set_default (WpObjectManager * om, struct WpCliData * d) static void set_volume (WpObjectManager * om, struct WpCliData * d) { - g_autoptr (GPtrArray) arr = NULL; - guint i; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) val = G_VALUE_INIT; - arr = wp_object_manager_get_objects (om, WP_TYPE_ENDPOINT); + it = wp_object_manager_iterate (om); - for (i = 0; i < arr->len; i++) { - WpEndpoint *ep = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val); g_value_unset (&val)) { + WpEndpoint *ep = g_value_get_object (&val); guint32 id = wp_proxy_get_bound_id (WP_PROXY (ep)); if (id == d->params.set_volume.id) { @@ -172,17 +199,17 @@ set_volume (WpObjectManager * om, struct WpCliData * d) static void device_node_props (WpObjectManager * om, struct WpCliData * d) { - g_autoptr (GPtrArray) arr = NULL; - guint i; + g_autoptr (WpIterator) it = NULL; + g_auto (GValue) val = G_VALUE_INIT; const struct spa_dict * dict; const struct spa_dict_item *item; - arr = wp_object_manager_get_objects (om, WP_TYPE_NODE); + it = wp_object_manager_iterate (om); g_print ("Capture device nodes:\n"); - for (i = 0; i < arr->len; i++) { - WpProxy *node = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val); g_value_unset (&val)) { + WpProxy *node = g_value_get_object (&val); g_autoptr (WpProperties) props = wp_proxy_get_properties (node); if (g_strcmp0 (wp_properties_get (props, "media.class"), "Audio/Source") != 0) @@ -198,10 +225,11 @@ device_node_props (WpObjectManager * om, struct WpCliData * d) g_print ("\n"); } + wp_iterator_reset (it); g_print ("Playback device nodes:\n"); - for (i = 0; i < arr->len; i++) { - WpProxy *node = g_ptr_array_index (arr, i); + for (; wp_iterator_next (it, &val); g_value_unset (&val)) { + WpProxy *node = g_value_get_object (&val); g_autoptr (WpProperties) props = wp_proxy_get_properties (node); if (g_strcmp0 (wp_properties_get (props, "media.class"), "Audio/Sink") != 0)