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:

committed by
Julian Bouzas

parent
e9391b195f
commit
8fd8b01b7a
@@ -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
214
lib/wp/settings.c
Normal 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
47
lib/wp/settings.h
Normal 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
|
@@ -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
|
||||
|
@@ -42,6 +42,7 @@
|
||||
#include "wpenums.h"
|
||||
#include "wpversion.h"
|
||||
#include "factory.h"
|
||||
#include "settings.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -210,4 +210,6 @@ SANDBOX_EXPORT = {
|
||||
State = WpState_new,
|
||||
LocalModule = WpImplModule_new,
|
||||
ImplMetadata = WpImplMetadata_new,
|
||||
Settings = WpSettings,
|
||||
I18n = I18n
|
||||
}
|
||||
|
@@ -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));
|
||||
|
||||
|
||||
|
59
src/main.c
59
src/main.c
@@ -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");
|
||||
|
||||
|
Reference in New Issue
Block a user