Files
wireplumber/lib/wp/plugin.c

277 lines
7.4 KiB
C

/* WirePlumber
*
* Copyright © 2020 Collabora Ltd.
* @author George Kiagiadakis <george.kiagiadakis@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
/*!
* @file plugin.c
*/
#define G_LOG_DOMAIN "wp-plugin"
#include "plugin.h"
#include "log.h"
#include "private/registry.h"
/*!
* @memberof WpPlugin
*
* @props @b name
*
* @code
* "name" gchar *
* @endcode
*
* The name of this plugin. Implementations should initialize this in the constructor.
*
* Flags : Read / Write / Construct Only
*/
enum {
PROP_0,
PROP_NAME,
};
typedef struct _WpPluginPrivate WpPluginPrivate;
struct _WpPluginPrivate
{
GQuark name_quark;
};
/*!
* @struct WpPlugin
* @section plugin_section Plugins
*
* @brief [WpPlugin](@ref plugin_section) is a base class for objects that
* provide functionality to the WirePlumber daemon.
*
* Typically, a plugin is created within a module and then registered to
* make it available for use by the daemon. The daemon is responsible for
* calling wp_object_activate() on it after all modules have been loaded,
* the core is connected and the initial discovery of global objects is
* done.
*
* Being a [WpObject](@ref object_section) subclass, the plugin inherits
* [WpObject](@ref object_section)'s activation system.
* For most implementations, there is only need for activating one
* feature, %WP_PLUGIN_FEATURE_ENABLED, and this can be done by implementing
* only [WpPluginClass](@ref plugin_class_section).[enable](@ref plugin_class_enable_section)() and
* [WpPluginClass](@ref plugin_class_section).[disable](@ref plugin_class_disable_section)().
* For more advanced plugins that need to have more features, you may implement directly the
* functions of [WpObjectClass](@ref object_class_section) and ignore the ones of
* [WpPluginClass](@ref plugin_class_section).
*
*/
G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (WpPlugin, wp_plugin, WP_TYPE_OBJECT)
static void
wp_plugin_init (WpPlugin * self)
{
}
static void
wp_plugin_set_property (GObject * object, guint property_id,
const GValue * value, GParamSpec * pspec)
{
WpPlugin *self = WP_PLUGIN (object);
WpPluginPrivate *priv = wp_plugin_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_plugin_get_property (GObject * object, guint property_id,
GValue * value, GParamSpec * pspec)
{
WpPlugin *self = WP_PLUGIN (object);
WpPluginPrivate *priv = wp_plugin_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 WpObjectFeatures
wp_plugin_get_supported_features (WpObject * self)
{
return WP_PLUGIN_FEATURE_ENABLED;
}
enum {
STEP_ENABLE = WP_TRANSITION_STEP_CUSTOM_START,
};
static guint
wp_plugin_activate_get_next_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
/* we only support ENABLED, so this is the only
feature that can be in @em missing */
g_return_val_if_fail (missing == WP_PLUGIN_FEATURE_ENABLED,
WP_TRANSITION_STEP_ERROR);
return STEP_ENABLE;
}
static void
wp_plugin_activate_execute_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
switch (step) {
case STEP_ENABLE: {
WpPlugin *self = WP_PLUGIN (object);
wp_info_object (self, "enabling plugin '%s'", wp_plugin_get_name (self));
g_return_if_fail (WP_PLUGIN_GET_CLASS (self)->enable);
WP_PLUGIN_GET_CLASS (self)->enable (self, WP_TRANSITION (transition));
break;
}
case WP_TRANSITION_STEP_ERROR:
break;
default:
g_assert_not_reached ();
}
}
static void
wp_plugin_deactivate (WpObject * object, WpObjectFeatures features)
{
if (features & WP_PLUGIN_FEATURE_ENABLED) {
WpPlugin *self = WP_PLUGIN (object);
wp_info_object (self, "disabling plugin '%s'", wp_plugin_get_name (self));
if (WP_PLUGIN_GET_CLASS (self)->disable)
WP_PLUGIN_GET_CLASS (self)->disable (self);
wp_object_update_features (WP_OBJECT (self), 0, WP_PLUGIN_FEATURE_ENABLED);
}
}
static void
wp_plugin_class_init (WpPluginClass * klass)
{
GObjectClass * object_class = (GObjectClass *) klass;
WpObjectClass * wpobject_class = (WpObjectClass *) klass;
object_class->set_property = wp_plugin_set_property;
object_class->get_property = wp_plugin_get_property;
wpobject_class->get_supported_features = wp_plugin_get_supported_features;
wpobject_class->activate_get_next_step = wp_plugin_activate_get_next_step;
wpobject_class->activate_execute_step = wp_plugin_activate_execute_step;
wpobject_class->deactivate = wp_plugin_deactivate;
/*
* WpPlugin:name:
* @brief The name of this plugin.
* Implementations should initialize this in the constructor.
*/
g_object_class_install_property (object_class, PROP_NAME,
g_param_spec_string ("name", "name",
"The name of this plugin", NULL,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS));
}
/*!
* @memberof WpPlugin
* @param plugin: (transfer full): the plugin
*
* @brief Registers the plugin to its associated core, making it available for use
*/
void
wp_plugin_register (WpPlugin * plugin)
{
g_autoptr (WpCore) core = wp_object_get_core (WP_OBJECT (plugin));
g_return_if_fail (WP_IS_CORE (core));
wp_registry_register_object (wp_core_get_registry (core), plugin);
}
static gboolean
find_plugin_func (gpointer plugin, gpointer name_quark)
{
if (!WP_IS_PLUGIN (plugin))
return FALSE;
WpPluginPrivate *priv = wp_plugin_get_instance_private (plugin);
return priv->name_quark == GPOINTER_TO_UINT (name_quark);
}
/*!
* @memberof WpPlugin
* @param core: the core
* @param plugin_name: the lookup name
*
* @returns (transfer full) (nullable): the plugin matching the lookup name
*/
WpPlugin *
wp_plugin_find (WpCore * core, const gchar * plugin_name)
{
g_return_val_if_fail (WP_IS_CORE (core), NULL);
GQuark q = g_quark_try_string (plugin_name);
if (q == 0)
return NULL;
GObject *p = wp_registry_find_object (wp_core_get_registry (core),
(GEqualFunc) find_plugin_func, GUINT_TO_POINTER (q));
return p ? WP_PLUGIN (p) : NULL;
}
/*!
* @memberof WpPlugin
* @param self: the plugin
*
* @returns the name of this plugin
*/
const gchar *
wp_plugin_get_name (WpPlugin * self)
{
g_return_val_if_fail (WP_IS_PLUGIN (self), NULL);
WpPluginPrivate *priv = wp_plugin_get_instance_private (self);
return g_quark_to_string (priv->name_quark);
}
/**
* WpPluginClass::enable:
*
* @section plugin_class_enable_section enable
*
* @param self: the plugin
* @param transition: the activation transition
*
* @brief Enables the plugin. The plugin is required to start any operations only
* when this method is called and not before.
*
* When enabling the plugin is done, you must call wp_object_update_features()
* with %WP_PLUGIN_FEATURE_ENABLED marked as activated, or return an error
* on @em transition.
*/
/**
* WpPluginClass::disable:
*
* @section plugin_class_disable_section disable
*
* @param self: the plugin
*
* Disables the plugin. The plugin is required to stop all operations and
* release all resources associated with it.
*/