From cb1b3ebfadcebb9d7b33341771f29163319024e0 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Tue, 23 Apr 2019 16:28:13 +0300 Subject: [PATCH] proxy: expose pw properties as a spa_dict and store them in a pw_properties Exposing a spa_dict is necessary to allow using native pipewire API that deals with these properties. The internal structure change avoids mem copies when we need to return a spa_dict. This commits also removes exposing internal info structures via the properties mechanism. This needs more thinking... --- lib/wp/object.c | 18 +++++++ lib/wp/object.h | 5 ++ lib/wp/proxy.c | 137 ++++++++---------------------------------------- 3 files changed, 46 insertions(+), 114 deletions(-) diff --git a/lib/wp/object.c b/lib/wp/object.c index 6efa6511..53c58ec3 100644 --- a/lib/wp/object.c +++ b/lib/wp/object.c @@ -218,3 +218,21 @@ wp_pipewire_properties_get (WpPipewireProperties * self, const gchar * key) return iface->get (self, key); } + +/** + * wp_pipewire_properties_get_as_spa_dict: (virtual get_as_spa_dict) + * @self: the interface + * + * Return: (transfer none): The underlying `struct spa_dict` that holds + * the properties + */ +const struct spa_dict * +wp_pipewire_properties_get_as_spa_dict (WpPipewireProperties * self) +{ + WpPipewirePropertiesInterface *iface = WP_PIPEWIRE_PROPERTIES_GET_IFACE (self); + + g_return_val_if_fail (WP_IS_PIPEWIRE_PROPERTIES (self), NULL); + g_return_val_if_fail (iface->get_as_spa_dict, NULL); + + return iface->get_as_spa_dict (self); +} diff --git a/lib/wp/object.h b/lib/wp/object.h index 63c6d351..0d6bee7b 100644 --- a/lib/wp/object.h +++ b/lib/wp/object.h @@ -34,15 +34,20 @@ gboolean wp_object_attach_interface_impl (WpObject * self, gpointer impl, G_DECLARE_INTERFACE (WpPipewireProperties, wp_pipewire_properties, WP, PIPEWIRE_PROPERTIES, GObject) +struct spa_dict; + struct _WpPipewirePropertiesInterface { GTypeInterface parent; const gchar * (*get) (WpPipewireProperties * self, const gchar * key); + const struct spa_dict * (*get_as_spa_dict) (WpPipewireProperties * self); }; const gchar * wp_pipewire_properties_get (WpPipewireProperties * self, const gchar * key); +const struct spa_dict * wp_pipewire_properties_get_as_spa_dict ( + WpPipewireProperties * self); G_END_DECLS diff --git a/lib/wp/proxy.c b/lib/wp/proxy.c index aaa4784d..005ef04c 100644 --- a/lib/wp/proxy.c +++ b/lib/wp/proxy.c @@ -27,7 +27,7 @@ struct _WpProxy union { const struct spa_dict *initial_properties; - GHashTable *properties; + struct pw_properties *properties; }; }; @@ -56,65 +56,15 @@ G_DEFINE_TYPE_WITH_CODE (WpProxy, wp_proxy, WP_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (WP_TYPE_PIPEWIRE_PROPERTIES, wp_proxy_pw_properties_init); ) -static void -spa_dict_to_hashtable (const struct spa_dict * dict, GHashTable * htable) -{ - const struct spa_dict_item *item; - spa_dict_for_each (item, dict) { - g_hash_table_insert (htable, - GUINT_TO_POINTER (g_quark_from_string (item->key)), - g_strdup (item->value)); - } -} - -#define UPDATE_PROP(name, lvalue) \ - { \ - static GQuark _quark = 0; \ - if (!_quark) \ - _quark = g_quark_from_static_string (name); \ - g_hash_table_insert (self->properties, GUINT_TO_POINTER (_quark), lvalue); \ - } - -#define STATIC_PROP(name, lvalue) \ - { \ - static GQuark _quark = 0; \ - if (!_quark) \ - _quark = g_quark_from_static_string (name); \ - if (!g_hash_table_contains (self->properties, GUINT_TO_POINTER (_quark))) { \ - g_hash_table_insert (self->properties, GUINT_TO_POINTER (_quark), lvalue); \ - } \ - } - static void node_event_info (void *object, const struct pw_node_info *info) { WpProxy *self = WP_PROXY (object); - if (info->change_mask & PW_NODE_CHANGE_MASK_NAME) { - UPDATE_PROP ("node-info.name", g_strdup (info->name)); - } - if (info->change_mask & PW_NODE_CHANGE_MASK_INPUT_PORTS) { - UPDATE_PROP ("node-info.n-input-ports", - g_strdup_printf ("%u", info->n_input_ports)); - UPDATE_PROP ("node-info.max-input-ports", - g_strdup_printf ("%u", info->max_input_ports)); - } - if (info->change_mask & PW_NODE_CHANGE_MASK_OUTPUT_PORTS) { - UPDATE_PROP ("node-info.n-output-ports", - g_strdup_printf ("%u", info->n_output_ports)); - UPDATE_PROP ("node-info.max-output-ports", - g_strdup_printf ("%u", info->max_output_ports)); - } - if (info->change_mask & PW_NODE_CHANGE_MASK_STATE) { - UPDATE_PROP ("node-info.state", - g_strdup (pw_node_state_as_string (info->state))); - UPDATE_PROP ("node-info.error", g_strdup (info->error)); - } if (info->change_mask & PW_NODE_CHANGE_MASK_PROPS) { - spa_dict_to_hashtable (info->props, self->properties); + g_clear_pointer (&self->properties, pw_properties_free); + self->properties = pw_properties_new_dict (info->props); } - // TODO: PW_NODE_CHANGE_MASK_PARAMS - g_signal_emit (self, signals[SIGNAL_CHANGED], 0); } @@ -123,53 +73,14 @@ static const struct pw_node_proxy_events node_events = { .info = node_event_info }; -static void -port_event_info (void *object, const struct pw_port_info *info) -{ - WpProxy *self = WP_PROXY (object); - - STATIC_PROP ("port-info.direction", - g_strdup (pw_direction_as_string (info->direction))); - - if (info->change_mask & PW_PORT_CHANGE_MASK_PROPS) { - spa_dict_to_hashtable (info->props, self->properties); - } - // TODO: PW_PORT_CHANGE_MASK_PARAMS - - g_signal_emit (self, signals[SIGNAL_CHANGED], 0); -} - -static const struct pw_port_proxy_events port_events = { - PW_VERSION_PORT_PROXY_EVENTS, - .info = port_event_info -}; - static void link_event_info (void *object, const struct pw_link_info *info) { WpProxy *self = WP_PROXY (object); - if (info->change_mask & PW_LINK_CHANGE_MASK_OUTPUT) { - UPDATE_PROP ("link-info.output-node-id", - g_strdup_printf ("%u", info->output_node_id)); - UPDATE_PROP ("link-info.output-port-id", - g_strdup_printf ("%u", info->output_port_id)); - } - if (info->change_mask & PW_LINK_CHANGE_MASK_INPUT) { - UPDATE_PROP ("link-info.input-node-id", - g_strdup_printf ("%u", info->input_node_id)); - UPDATE_PROP ("link-info.input-port-id", - g_strdup_printf ("%u", info->input_port_id)); - } - if (info->change_mask & PW_LINK_CHANGE_MASK_STATE) { - UPDATE_PROP ("link-info.state", - g_strdup (pw_link_state_as_string (info->state))); - UPDATE_PROP ("link-info.error", g_strdup (info->error)); - } - //TODO: PW_LINK_CHANGE_MASK_FORMAT - if (info->change_mask & PW_LINK_CHANGE_MASK_PROPS) { - spa_dict_to_hashtable (info->props, self->properties); + g_clear_pointer (&self->properties, pw_properties_free); + self->properties = pw_properties_new_dict (info->props); } g_signal_emit (self, signals[SIGNAL_CHANGED], 0); @@ -186,7 +97,8 @@ client_event_info (void *object, const struct pw_client_info *info) WpProxy *self = WP_PROXY (object); if (info->change_mask & PW_CLIENT_CHANGE_MASK_PROPS) { - spa_dict_to_hashtable (info->props, self->properties); + g_clear_pointer (&self->properties, pw_properties_free); + self->properties = pw_properties_new_dict (info->props); } g_signal_emit (self, signals[SIGNAL_CHANGED], 0); @@ -202,12 +114,10 @@ device_event_info (void *object, const struct pw_device_info *info) { WpProxy *self = WP_PROXY (object); - STATIC_PROP ("device-info.name", g_strdup (info->name)); - if (info->change_mask & PW_DEVICE_CHANGE_MASK_PROPS) { - spa_dict_to_hashtable (info->props, self->properties); + g_clear_pointer (&self->properties, pw_properties_free); + self->properties = pw_properties_new_dict (info->props); } - //TODO: PW_DEVICE_CHANGE_MASK_PARAMS g_signal_emit (self, signals[SIGNAL_CHANGED], 0); } @@ -243,7 +153,6 @@ wp_proxy_constructed (GObject * object) { WpProxy *self = WP_PROXY (object); g_autoptr (WpProxyRegistry) pr = NULL; - GHashTable *properties; struct pw_registry_proxy *reg_proxy; const void *events = NULL; uint32_t ver = 0; @@ -258,10 +167,6 @@ wp_proxy_constructed (GObject * object) events = &node_events; ver = PW_VERSION_NODE; break; - case PW_TYPE_INTERFACE_Port: - events = &port_events; - ver = PW_VERSION_PORT; - break; case PW_TYPE_INTERFACE_Link: events = &link_events; ver = PW_VERSION_LINK; @@ -293,13 +198,12 @@ wp_proxy_constructed (GObject * object) /* * initial_properties is a stack-allocated const spa_dict * * that is not safe to access beyond the scope of the g_object_new() - * call, so we replace it with a GHashTable + * call, so we replace it with a pw_properties */ - properties = g_hash_table_new_full (g_direct_hash, g_direct_equal, - NULL, g_free); if (self->initial_properties) - spa_dict_to_hashtable (self->initial_properties, properties); - self->properties = properties; + self->properties = pw_properties_new_dict (self->initial_properties); + else + self->properties = pw_properties_new (NULL); G_OBJECT_CLASS (wp_proxy_parent_class)->constructed (object); } @@ -309,7 +213,7 @@ wp_proxy_finalize (GObject * object) { WpProxy *self = WP_PROXY (object); - g_hash_table_unref (self->properties); + g_clear_pointer (&self->properties, pw_properties_free); g_clear_object (&self->core); G_OBJECT_CLASS (wp_proxy_parent_class)->finalize (object); @@ -427,20 +331,25 @@ wp_proxy_class_init (WpProxyClass * klass) G_TYPE_NONE, 0); } -const gchar * +static const gchar * wp_proxy_pw_properties_get (WpPipewireProperties * p, const gchar * property) { WpProxy * self = WP_PROXY (p); - GQuark quark = g_quark_try_string (property); + return pw_properties_get (self->properties, property); +} - return quark ? - g_hash_table_lookup (self->properties, GUINT_TO_POINTER (quark)) : NULL; +static const struct spa_dict * +wp_proxy_pw_properties_get_as_spa_dict (WpPipewireProperties * p) +{ + WpProxy * self = WP_PROXY (p); + return &self->properties->dict; } static void wp_proxy_pw_properties_init (WpPipewirePropertiesInterface * iface) { iface->get = wp_proxy_pw_properties_get; + iface->get_as_spa_dict = wp_proxy_pw_properties_get_as_spa_dict; } /**