diff --git a/lib/wp/meson.build b/lib/wp/meson.build index b79aa46d..fc939959 100644 --- a/lib/wp/meson.build +++ b/lib/wp/meson.build @@ -17,6 +17,7 @@ wp_lib_sources = files( 'proxy.c', 'session.c', 'session-item.c', + 'si-factory.c', 'si-interfaces.c', 'spa-props.c', 'transition.c', @@ -43,6 +44,7 @@ wp_lib_headers = files( 'session.h', 'session-item.h', 'si-interfaces.h', + 'si-factory.h', 'transition.h', 'wp.h', ) diff --git a/lib/wp/session-item.c b/lib/wp/session-item.c index 0f536b6f..623de048 100644 --- a/lib/wp/session-item.c +++ b/lib/wp/session-item.c @@ -8,6 +8,7 @@ /** * SECTION: WpSessionItem + * @title: Session Items */ #include "session-item.h" @@ -27,6 +28,9 @@ enum { guint32 signals[N_SIGNALS] = {0}; +/** + * WpSessionItem: + */ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpSessionItem, wp_session_item, G_TYPE_OBJECT) static void diff --git a/lib/wp/si-factory.c b/lib/wp/si-factory.c new file mode 100644 index 00000000..306506ac --- /dev/null +++ b/lib/wp/si-factory.c @@ -0,0 +1,306 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: MIT + */ + +/** + * SECTION: WpSiFactory + * @title: Session Items Factory + */ + +#include "si-factory.h" +#include "private.h" + +enum { + PROP_0, + PROP_NAME, +}; + +typedef struct _WpSiFactoryPrivate WpSiFactoryPrivate; +struct _WpSiFactoryPrivate +{ + GQuark name_quark; +}; + +/** + * WpSiFactory: + * + * A factory for session items. + * + * The most simple way to register a new item implementation would be: + * |[ + * GVariantBuilder b = G_VARIANT_BUILDER_INIT ("a(ssymv)"); + * g_variant_builder_add (&b, ...); + * wp_si_factory_register (core, wp_si_factory_new_simple ( + * "foobar", FOO_TYPE_BAR, g_variant_builder_end (&b))); + * ]| + * + * And the most simple way to construct an item from a registered factory: + * |[ + * item = wp_session_item_make (core, "foobar"); + * ]| + */ +G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpSiFactory, wp_si_factory, G_TYPE_OBJECT) + +static void +wp_si_factory_init (WpSiFactory * self) +{ +} + +static void +wp_si_factory_set_property (GObject * object, guint property_id, + const GValue * value, GParamSpec * pspec) +{ + WpSiFactory *self = WP_SI_FACTORY (object); + WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self); + + switch (property_id) { + case PROP_NAME: + priv->name_quark = g_quark_from_string (g_value_get_string (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wp_si_factory_get_property (GObject * object, guint property_id, GValue * value, + GParamSpec * pspec) +{ + WpSiFactory *self = WP_SI_FACTORY (object); + WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self); + + switch (property_id) { + case PROP_NAME: + g_value_set_string (value, g_quark_to_string (priv->name_quark)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +wp_si_factory_class_init (WpSiFactoryClass * klass) +{ + GObjectClass * object_class = (GObjectClass *) klass; + + object_class->get_property = wp_si_factory_get_property; + object_class->set_property = wp_si_factory_set_property; + + g_object_class_install_property (object_class, PROP_NAME, + g_param_spec_string ("name", "name", "The factory's name", "", + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); +} + +/** + * wp_si_factory_get_name: + * @self: the factory + * + * Returns: the factory name + */ +const gchar * +wp_si_factory_get_name (WpSiFactory * self) +{ + g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL); + + WpSiFactoryPrivate *priv = wp_si_factory_get_instance_private (self); + return g_quark_to_string (priv->name_quark); +} + +/** + * wp_si_factory_construct: + * @self: the factory + * + * Creates a new instance of the session item that is constructed + * by this factory + * + * Returns: (transfer full): a new session item instance + */ +WpSessionItem * +wp_si_factory_construct (WpSiFactory * self) +{ + g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL); + g_return_val_if_fail (WP_SI_FACTORY_GET_CLASS (self)->construct, NULL); + + return WP_SI_FACTORY_GET_CLASS (self)->construct (self); +} + +/** + * wp_si_factory_get_config_spec: + * @self: the factory + * + * Returns a description of all the configuration options that the constructed + * items of this factory have. Configuration options are a way for items to + * accept input from external sources that affects their behavior, or to + * provide output for other items to consume as their configuration. + * + * The returned GVariant has the a(ssymv) type. This is an array of tuples, + * where each tuple has the following values, in order: + * * s (string): the name of the option + * * s (string): a GVariant type string, describing the type of the data + * * y (byte): a combination of #WpSiConfigOptionFlags + * * mv (optional variant): optionally, an additional variant + * This is provided to allow extensions. + * + * Returns: (transfer full): the configuration description + */ +GVariant * +wp_si_factory_get_config_spec (WpSiFactory * self) +{ + g_return_val_if_fail (WP_IS_SI_FACTORY (self), NULL); + g_return_val_if_fail (WP_SI_FACTORY_GET_CLASS (self)->get_config_spec, NULL); + + return WP_SI_FACTORY_GET_CLASS (self)->get_config_spec (self); +} + +/** + * wp_si_factory_register: + * @core: the core + * @factory: (transfer full): the factory to register + * + * Registers the @factory on the @core. + */ +void +wp_si_factory_register (WpCore * core, WpSiFactory * factory) +{ + g_return_if_fail (WP_IS_CORE (core)); + g_return_if_fail (WP_IS_SI_FACTORY (factory)); + + wp_registry_register_object (wp_core_get_registry (core), factory); +} + +static gboolean +find_factory_func (gpointer factory, gpointer name_quark) +{ + if (!WP_IS_SI_FACTORY (factory)) + return FALSE; + + WpSiFactoryPrivate *priv = + wp_si_factory_get_instance_private ((WpSiFactory *) factory); + return priv->name_quark == GPOINTER_TO_UINT (name_quark); +} + +/** + * wp_si_factory_find: + * @core: the core + * @factory_name: the lookup name + * + * Returns: (transfer full) (nullable): the factory matching the lookup name + */ +WpSiFactory * +wp_si_factory_find (WpCore * core, const gchar * factory_name) +{ + g_return_val_if_fail (WP_IS_CORE (core), NULL); + + GQuark q = g_quark_try_string (factory_name); + if (q == 0) + return NULL; + GObject *f = wp_registry_find_object (wp_core_get_registry (core), + (GEqualFunc) find_factory_func, GUINT_TO_POINTER (q)); + return f ? WP_SI_FACTORY (f) : NULL; +} + +/** + * wp_session_item_make: + * @core: the #WpCore + * @factory_name: the name of the factory to be used for constructing the object + * + * Finds the factory associated with the given @name from the @core and + * uses it to construct a new #WpSessionItem. + * + * Returns: (transfer full) (nullable): the new session item + */ +WpSessionItem * +wp_session_item_make (WpCore * core, const gchar * factory_name) +{ + g_autoptr (WpSiFactory) f = wp_si_factory_find (core, factory_name); + return f ? wp_si_factory_construct (f) : NULL; +} + +struct _WpSimpleSiFactory +{ + WpSiFactory parent; + GType si_type; + GVariant *config_spec; +}; + +G_DECLARE_FINAL_TYPE (WpSimpleSiFactory, wp_simple_si_factory, + WP, SIMPLE_SI_FACTORY, WpSiFactory) +G_DEFINE_TYPE (WpSimpleSiFactory, wp_simple_si_factory, WP_TYPE_SI_FACTORY) + +static void +wp_simple_si_factory_init (WpSimpleSiFactory * self) +{ +} + +static void +wp_simple_si_factory_finalize (GObject * object) +{ + WpSimpleSiFactory * self = WP_SIMPLE_SI_FACTORY (object); + + g_clear_pointer (&self->config_spec, g_variant_unref); + + G_OBJECT_CLASS (wp_simple_si_factory_parent_class)->finalize (object); +} + +static WpSessionItem * +wp_simple_si_factory_construct (WpSiFactory * self) +{ + return g_object_new (WP_SIMPLE_SI_FACTORY (self)->si_type, NULL); +} + +static GVariant * +wp_simple_si_factory_get_config_spec (WpSiFactory * self) +{ + return g_variant_ref (WP_SIMPLE_SI_FACTORY (self)->config_spec); +} + +static void +wp_simple_si_factory_class_init (WpSimpleSiFactoryClass * klass) +{ + GObjectClass * object_class = (GObjectClass *) klass; + WpSiFactoryClass * factory_class = (WpSiFactoryClass *) klass; + + object_class->finalize = wp_simple_si_factory_finalize; + + factory_class->construct = wp_simple_si_factory_construct; + factory_class->get_config_spec = wp_simple_si_factory_get_config_spec; +} + +/** + * wp_si_factory_new_simple: + * @factory_name: the factory name; must be a static string! + * @si_type: the #WpSessionItem subclass type to instantiate for + * constructing items + * @config_spec: (transfer floating): the config spec that will be returned + * by wp_si_factory_get_config_spec() + * + * Returns: (transfer full): the new factory + */ +WpSiFactory * +wp_si_factory_new_simple (const gchar * factory_name, + GType si_type, GVariant * config_spec) +{ + g_return_val_if_fail (factory_name != NULL, NULL); + g_return_val_if_fail (g_type_is_a (si_type, WP_TYPE_SESSION_ITEM), NULL); + g_return_val_if_fail ( + g_variant_is_of_type (config_spec, G_VARIANT_TYPE ("a{sv}")), NULL); + + WpSimpleSiFactory *self = g_object_new ( + wp_simple_si_factory_get_type (), NULL); + + /* assign the quark directly to use g_quark_from_static_string */ + WpSiFactoryPrivate *priv = + wp_si_factory_get_instance_private (WP_SI_FACTORY (self)); + priv->name_quark = g_quark_from_static_string (factory_name); + + self->si_type = si_type; + self->config_spec = g_variant_ref_sink (config_spec); + + return WP_SI_FACTORY (self); +} diff --git a/lib/wp/si-factory.h b/lib/wp/si-factory.h new file mode 100644 index 00000000..1eb588ca --- /dev/null +++ b/lib/wp/si-factory.h @@ -0,0 +1,58 @@ +/* WirePlumber + * + * Copyright © 2020 Collabora Ltd. + * @author George Kiagiadakis + * + * SPDX-License-Identifier: MIT + */ + +#ifndef __WIREPLUMBER_SI_FACTORY_H__ +#define __WIREPLUMBER_SI_FACTORY_H__ + +#include "core.h" +#include "session-item.h" + +G_BEGIN_DECLS + +/** + * WP_TYPE_SI_FACTORY: + * + * The #WpSiFactory #GType + */ +#define WP_TYPE_SI_FACTORY (wp_si_factory_get_type ()) +WP_API +G_DECLARE_DERIVABLE_TYPE (WpSiFactory, wp_si_factory, WP, SI_FACTORY, GObject) + +struct _WpSiFactoryClass +{ + GObjectClass parent_class; + + WpSessionItem * (*construct) (WpSiFactory * self); + GVariant * (*get_config_spec) (WpSiFactory * self); +}; + +WP_API +WpSiFactory * wp_si_factory_new_simple (const gchar * factory_name, + GType si_type, GVariant * config_spec); + +WP_API +const gchar * wp_si_factory_get_name (WpSiFactory * self); + +WP_API +WpSessionItem * wp_si_factory_construct (WpSiFactory * self); + +WP_API +GVariant * wp_si_factory_get_config_spec (WpSiFactory * self); + +WP_API +void wp_si_factory_register (WpCore * core, WpSiFactory * factory); + +WP_API +WpSiFactory * wp_si_factory_find (WpCore * core, const gchar * factory_name); + +WP_API +WpSessionItem * wp_session_item_make (WpCore * core, const gchar * factory_name); + +G_END_DECLS + +#endif diff --git a/lib/wp/wp.h b/lib/wp/wp.h index 3c135cdf..f1c8c954 100644 --- a/lib/wp/wp.h +++ b/lib/wp/wp.h @@ -25,5 +25,6 @@ #include "session.h" #include "session-item.h" #include "si-interfaces.h" +#include "si-factory.h" #include "transition.h" #include "wpenums.h"