lib: Introduce WpSettings API

- WpSettings is a singleton object which attaches itself to the core
  and registry, it provides a get_instance () for its clients.
- WpSettings provides API to get/set wireplumber settings and rules.
- main.c loads the new object and makes sure it is available for
  for all the modules and scripts. This is achieved by introducing
  a new activation step.
- Add the lua bindings for get_setting API.
This commit is contained in:
Ashok Sidipotu
2022-03-22 03:38:35 +05:30
committed by Julian Bouzas
parent e9391b195f
commit 8fd8b01b7a
9 changed files with 351 additions and 5 deletions

View File

@@ -12,6 +12,7 @@ wp_lib_sources = files(
'link.c',
'log.c',
'metadata.c',
'settings.c',
'module.c',
'node.c',
'object.c',
@@ -51,6 +52,7 @@ wp_lib_headers = files(
'link.h',
'log.h',
'metadata.h',
'settings.h',
'module.h',
'node.h',
'object.h',

214
lib/wp/settings.c Normal file
View File

@@ -0,0 +1,214 @@
/* WirePlumber
*
* Copyright © 2022 Collabora Ltd.
* @author Ashok Sidipotu <ashok.sidipotu@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#define G_LOG_DOMAIN "wp-settings"
#include <wp/wp.h>
#include "settings.h"
#include "metadata.h"
#include "log.h"
#include "private/registry.h"
/*! \defgroup WpSettings */
/*!
* \struct WpSettings
*
* WpSettings parses `sm-settings` metadata(contains wireplumber settings
* and rules), provides APIs to its clients(modules, lua scripts etc) to
* access and change them.
*
* Being a WpObject subclass, the settings inherits WpObject's activation
* system.
*
*/
struct _WpSettings
{
WpObject parent;
GWeakRef core;
WpProperties *settings;
WpObjectManager *metadata_om;
};
G_DEFINE_TYPE (WpSettings, wp_settings, WP_TYPE_OBJECT)
static void
wp_settings_init (WpSettings * self)
{
}
/*!
* \brief gets the value of a setting.
*
* \ingroup wpsetting
* \param self the handle
* \param setting name of the setting
* \returns (transfer none): boolean value of the string.
*/
gboolean wp_settings_get_boolean (WpSettings *self, const gchar *setting)
{
g_return_val_if_fail (self, false);
g_return_val_if_fail (setting, false);
return spa_atob (wp_properties_get (self->settings, setting));
}
/*!
* \brief applies the rules and returns the applied props.
*
* This funtion applies the rules on the client properties and if
* there is a match, returns true and also copies the applied props.
*
* \ingroup wpsetting
* \param self the handle
* \param setting name of the setting
* \param rule name of the rule, this will match with the section mentioned
* in the conf file.
* \param client_props client props array, these properties are inputs on which
* the rules are applied.
* \param applied_props the resultant actions/properties as a result of the
* application of rules are copied here.
* \returns TRUE if there is a match for the client_props and
* returns the applied props for the match.
*/
gboolean wp_settings_apply_rule (WpSettings *self, const gchar *rule,
WpProperties *client_props, WpProperties *applied_props)
{
/* get the rule */
return true;
}
enum {
STEP_LOAD = WP_TRANSITION_STEP_CUSTOM_START,
};
static WpObjectFeatures
wp_settings_get_supported_features (WpObject * self)
{
return WP_SETTINGS_LOADED;
}
static guint
wp_settings_activate_get_next_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
g_return_val_if_fail (missing == WP_SETTINGS_LOADED,
WP_TRANSITION_STEP_ERROR);
return STEP_LOAD;
}
/*!
* \brief Returns the wpsettings instance that is associated with the
* given core.
*
* This method will also create the instance and register it with the core
* if it had not been created before.
*
* \param core the core
* \return (transfer full): the wpsettings instance
*/
WpSettings *
wp_settings_get_instance (WpCore * core)
{
WpRegistry *registry = wp_core_get_registry (core);
WpSettings *settings = wp_registry_find_object (registry,
(GEqualFunc) WP_IS_SETTINGS, NULL);
if (G_UNLIKELY (!settings)) {
settings = g_object_new (WP_TYPE_SETTINGS,
"core", core,
NULL);
g_weak_ref_set (&settings->core, core);
wp_registry_register_object (registry, g_object_ref (settings));
}
return settings;
}
static void
on_metadata_added (WpObjectManager *om, WpMetadata *m, gpointer d)
{
WpTransition * transition = WP_TRANSITION (d);
WpSettings * self = wp_transition_get_source_object (transition);
g_autoptr (WpIterator) it = wp_metadata_new_iterator (WP_METADATA (m), 0);
g_auto (GValue) val = G_VALUE_INIT;
for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
const gchar *setting, *value;
wp_metadata_iterator_item_extract (&val, NULL, &setting, NULL, &value);
wp_properties_set (self->settings, setting, value);
wp_debug_object (self, "%s(%lu) = %s", setting, strlen(value), value);
}
wp_info_object (self, "loaded %d settings from metadata",
wp_properties_get_count (self->settings));
wp_object_update_features (WP_OBJECT (self), WP_SETTINGS_LOADED, 0);
}
static void
wp_settings_activate_execute_step (WpObject * object,
WpFeatureActivationTransition * transition, guint step,
WpObjectFeatures missing)
{
WpSettings * self = WP_SETTINGS (object);
g_autoptr (WpCore) core = wp_object_get_core (object);
switch (step) {
case STEP_LOAD: {
self->settings = wp_properties_new_empty ();
self->metadata_om = wp_object_manager_new ();
wp_object_manager_add_interest (self->metadata_om, WP_TYPE_METADATA,
WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY, "metadata.name", "=s",
"sm-settings", NULL);
wp_object_manager_request_object_features (self->metadata_om,
WP_TYPE_METADATA, WP_OBJECT_FEATURES_ALL);
g_signal_connect_object (self->metadata_om, "object-added",
G_CALLBACK (on_metadata_added), transition, 0);
wp_core_install_object_manager (core, self->metadata_om);
break;
}
case WP_TRANSITION_STEP_ERROR:
break;
default:
g_assert_not_reached ();
}
}
static void
wp_settings_deactivate (WpObject * object, WpObjectFeatures features)
{
WpSettings *self = WP_SETTINGS (object);
g_clear_pointer (&self->settings, wp_properties_unref);
g_clear_object (&self->metadata_om);
wp_object_update_features (WP_OBJECT (self), 0, WP_OBJECT_FEATURES_ALL);
}
static void
wp_settings_class_init (WpSettingsClass * klass)
{
WpObjectClass * wpobject_class = (WpObjectClass *) klass;
wpobject_class->activate_get_next_step = wp_settings_activate_get_next_step;
wpobject_class->activate_execute_step = wp_settings_activate_execute_step;
wpobject_class->deactivate = wp_settings_deactivate;
wpobject_class->get_supported_features = wp_settings_get_supported_features;
}

47
lib/wp/settings.h Normal file
View File

@@ -0,0 +1,47 @@
/* WirePlumber
*
* Copyright © 2022 Collabora Ltd.
* @author Ashok Sidipotu <ashok.sidipotu@collabora.com>
*
* SPDX-License-Identifier: MIT
*/
#ifndef __WIREPLUMBER_SETTINGS_H__
#define __WIREPLUMBER_SETTINGS_H__
#include "object.h"
G_BEGIN_DECLS
/*!
* \brief Flags to be used as WpObjectFeatures on WpSettings subclasses.
* \ingroup wpsettings
*/
typedef enum {
/* loads the metadata */
WP_SETTINGS_LOADED = (1 << 0),
} WpSettingsFeatures;
/*!
* \brief The WpSettings GType
* \ingroup wpsettings
*/
#define WP_TYPE_SETTINGS (wp_settings_get_type ())
WP_API
G_DECLARE_FINAL_TYPE (WpSettings, wp_settings, WP, SETTINGS, WpObject)
WP_API
WpSettings *
wp_settings_get_instance (WpCore * core);
WP_API
gboolean wp_settings_get_boolean (WpSettings *self, const gchar *setting);
WP_API
gboolean wp_settings_apply_rule (WpSettings *self, const gchar *rule,
WpProperties *client_props, WpProperties *applied_props);
G_END_DECLS
#endif

View File

@@ -29,7 +29,7 @@
* code must call wp_transition_return_error() instead, in which case the
* transition completes immediately and wp_transition_had_error() returns TRUE.
*
* Typically, every step will start an asynchronous operation. Although is is
* Typically, every step will start an asynchronous operation. Although it is
* possible, the WpTransition base class does not expect
* _WpTransitionClass::execute_step() to call wp_transition_advance() directly.
* Instead, it is expected that wp_transition_advance() will be called from

View File

@@ -42,6 +42,7 @@
#include "wpenums.h"
#include "wpversion.h"
#include "factory.h"
#include "settings.h"
G_BEGIN_DECLS

View File

@@ -1472,6 +1472,26 @@ impl_module_new (lua_State *L)
}
}
static int
get_setting (lua_State *L)
{
const char *setting = luaL_checkstring (L, 1);
WpSettings *s = wp_settings_get_instance (get_wp_core (L));
if (s)
{
gboolean value = wp_settings_get_boolean (s, setting);
lua_pushboolean (L, value);
}
else
lua_pushnil (L);
return 1;
}
static const luaL_Reg settings_methods[] = {
{ "get_setting", get_setting },
{ NULL, NULL }
};
void
wp_lua_scripting_api_init (lua_State *L)
{
@@ -1492,6 +1512,9 @@ wp_lua_scripting_api_init (lua_State *L)
luaL_newlib (L, plugin_funcs);
lua_setglobal (L, "WpPlugin");
luaL_newlib (L, settings_methods);
lua_setglobal (L, "WpSettings");
wp_lua_scripting_pod_init (L);
wp_lua_scripting_json_init (L);

View File

@@ -210,4 +210,6 @@ SANDBOX_EXPORT = {
State = WpState_new,
LocalModule = WpImplModule_new,
ImplMetadata = WpImplMetadata_new,
Settings = WpSettings,
I18n = I18n
}

View File

@@ -133,8 +133,8 @@ do_parse_settings (void *data, const char *location,
struct data *d = data;
WpTransition *transition = d->transition;
WpSettingsPlugin *self = wp_transition_get_source_object (transition);
g_autoptr (WpSpaJson) *json = wp_spa_json_new_from_stringn (str, len);
g_autoptr (WpIterator) *iter = wp_spa_json_new_iterator (json);
g_autoptr (WpSpaJson) json = wp_spa_json_new_from_stringn (str, len);
g_autoptr (WpIterator) iter = wp_spa_json_new_iterator (json);
g_auto (GValue) item = G_VALUE_INIT;
@@ -268,7 +268,7 @@ on_metadata_activated (WpMetadata * m, GAsyncResult * res, gpointer user_data)
wp_debug_object (self, "%s(%lu) = %s", setting, strlen(value), value);
wp_metadata_set (m, 0, setting, "Spa:String:JSON", value);
}
wp_info_object(self, "loaded settings(%d) to \"sm-settings\" metadata",
wp_info_object (self, "loaded settings(%d) to \"sm-settings\" metadata",
wp_properties_get_count (self->settings));

View File

@@ -49,6 +49,7 @@ enum {
STEP_LOAD_COMPONENTS = WP_TRANSITION_STEP_CUSTOM_START,
STEP_CONNECT,
STEP_CHECK_MEDIA_SESSION,
STEP_ACTIVATE_SETTINGS,
STEP_ACTIVATE_PLUGINS,
STEP_ACTIVATE_SCRIPTS,
STEP_CLEANUP,
@@ -70,7 +71,8 @@ wp_init_transition_get_next_step (WpTransition * transition, guint step)
case WP_TRANSITION_STEP_NONE: return STEP_LOAD_COMPONENTS;
case STEP_LOAD_COMPONENTS: return STEP_CONNECT;
case STEP_CONNECT: return STEP_CHECK_MEDIA_SESSION;
case STEP_CHECK_MEDIA_SESSION:return STEP_ACTIVATE_PLUGINS;
case STEP_CHECK_MEDIA_SESSION:return STEP_ACTIVATE_SETTINGS;
case STEP_ACTIVATE_SETTINGS: return STEP_ACTIVATE_PLUGINS;
case STEP_CLEANUP: return WP_TRANSITION_STEP_NONE;
case STEP_ACTIVATE_PLUGINS: {
@@ -181,6 +183,44 @@ do_load_components(void *data, const char *location, const char *section,
return 0;
}
static void
on_settings_ready (WpSettings *s, GAsyncResult *res, gpointer data)
{
WpCore *self = WP_CORE (data);
g_autoptr (GError) error = NULL;
wp_info_object(self, "wpsettings object ready");
if (!wp_object_activate_finish (WP_OBJECT (s), res, &error)) {
wp_debug_object (self, "wpsettings activation failed: %s", error->message);
return;
}
wp_transition_advance (WP_TRANSITION (self));
}
static void
on_settings_plugin_ready (WpPlugin *s, GAsyncResult *res, gpointer data)
{
WpInitTransition *self = WP_INIT_TRANSITION (data);
WpTransition *transition = WP_TRANSITION (data);
WpCore *core = wp_transition_get_source_object (transition);
g_autoptr (GError) error = NULL;
g_autoptr (WpSettings) settings = wp_settings_get_instance (core);
wp_info_object (self, "wpsettingsplugin object ready");
if (!wp_object_activate_finish (WP_OBJECT (s), res, &error)) {
wp_debug_object (self, "wpSettingsPlugin activation failed: %s",
error->message);
return;
}
wp_object_activate (WP_OBJECT (settings), WP_OBJECT_FEATURES_ALL, NULL,
(GAsyncReadyCallback) on_settings_ready, g_object_ref (self));
}
static void
wp_init_transition_execute_step (WpTransition * transition, guint step)
{
@@ -256,6 +296,23 @@ wp_init_transition_execute_step (WpTransition * transition, guint step)
break;
}
case STEP_ACTIVATE_SETTINGS: {
/* find and activate settings plugin */
WpPlugin *p = wp_plugin_find (core, "settings");
if (!p) {
wp_transition_return_error (transition, g_error_new (
WP_DOMAIN_DAEMON, WP_EXIT_CONFIG,
"unable to find settings plugin"));
return;
}
wp_info_object (self, "Activating wpsettings plugin");
wp_object_activate (WP_OBJECT (p), WP_OBJECT_FEATURES_ALL, NULL,
(GAsyncReadyCallback) on_settings_plugin_ready, g_object_ref (self));
break;
}
case STEP_ACTIVATE_PLUGINS: {
const char *engine = pw_properties_get (props, "wireplumber.script-engine");